From bfcbc6cdca2ab0d9ecb9a3421986bfb75262b38c Mon Sep 17 00:00:00 2001 From: Michael Kennedy Date: Fri, 3 Dec 2021 17:21:12 -0800 Subject: [PATCH 01/21] Add the jQuery/Bootstrap JS needed for responsive nav bars in Bootstrap. --- .../static/js/bootstrap-4.6.1.min.js | 7 +++++++ .../static/js/jquery-3.5.1.slim.min.js | 2 ++ .../static/js/popper-1.16.1.min.js | 5 +++++ .../templates/shared/_layout.html | 5 +++++ 4 files changed, 19 insertions(+) create mode 100644 code/ch7_infinite_scroll/ch7_final_video_collector/static/js/bootstrap-4.6.1.min.js create mode 100644 code/ch7_infinite_scroll/ch7_final_video_collector/static/js/jquery-3.5.1.slim.min.js create mode 100644 code/ch7_infinite_scroll/ch7_final_video_collector/static/js/popper-1.16.1.min.js diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/bootstrap-4.6.1.min.js b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/bootstrap-4.6.1.min.js new file mode 100644 index 0000000..50720ea --- /dev/null +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/bootstrap-4.6.1.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.6.1 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap={},t.jQuery,t.Popper)}(this,(function(t,e,n){"use strict";function i(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var o=i(e),a=i(n);function s(t,e){for(var n=0;n=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}};d.jQueryDetection(),o.default.fn.emulateTransitionEnd=function(t){var e=this,n=!1;return o.default(this).one(d.TRANSITION_END,(function(){n=!0})),setTimeout((function(){n||d.triggerTransitionEnd(e)}),t),this},o.default.event.special[d.TRANSITION_END]={bindType:f,delegateType:f,handle:function(t){if(o.default(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}};var c="bs.alert",h=o.default.fn.alert,g=function(){function t(t){this._element=t}var e=t.prototype;return e.close=function(t){var e=this._element;t&&(e=this._getRootElement(t)),this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.dispose=function(){o.default.removeData(this._element,c),this._element=null},e._getRootElement=function(t){var e=d.getSelectorFromElement(t),n=!1;return e&&(n=document.querySelector(e)),n||(n=o.default(t).closest(".alert")[0]),n},e._triggerCloseEvent=function(t){var e=o.default.Event("close.bs.alert");return o.default(t).trigger(e),e},e._removeElement=function(t){var e=this;if(o.default(t).removeClass("show"),o.default(t).hasClass("fade")){var n=d.getTransitionDurationFromElement(t);o.default(t).one(d.TRANSITION_END,(function(n){return e._destroyElement(t,n)})).emulateTransitionEnd(n)}else this._destroyElement(t)},e._destroyElement=function(t){o.default(t).detach().trigger("closed.bs.alert").remove()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(c);i||(i=new t(this),n.data(c,i)),"close"===e&&i[e](this)}))},t._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',g._handleDismiss(new g)),o.default.fn.alert=g._jQueryInterface,o.default.fn.alert.Constructor=g,o.default.fn.alert.noConflict=function(){return o.default.fn.alert=h,g._jQueryInterface};var m="bs.button",p=o.default.fn.button,_="active",v='[data-toggle^="button"]',y='input:not([type="hidden"])',b=".btn",E=function(){function t(t){this._element=t,this.shouldAvoidTriggerChange=!1}var e=t.prototype;return e.toggle=function(){var t=!0,e=!0,n=o.default(this._element).closest('[data-toggle="buttons"]')[0];if(n){var i=this._element.querySelector(y);if(i){if("radio"===i.type)if(i.checked&&this._element.classList.contains(_))t=!1;else{var a=n.querySelector(".active");a&&o.default(a).removeClass(_)}t&&("checkbox"!==i.type&&"radio"!==i.type||(i.checked=!this._element.classList.contains(_)),this.shouldAvoidTriggerChange||o.default(i).trigger("change")),i.focus(),e=!1}}this._element.hasAttribute("disabled")||this._element.classList.contains("disabled")||(e&&this._element.setAttribute("aria-pressed",!this._element.classList.contains(_)),t&&o.default(this._element).toggleClass(_))},e.dispose=function(){o.default.removeData(this._element,m),this._element=null},t._jQueryInterface=function(e,n){return this.each((function(){var i=o.default(this),a=i.data(m);a||(a=new t(this),i.data(m,a)),a.shouldAvoidTriggerChange=n,"toggle"===e&&a[e]()}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.button.data-api",v,(function(t){var e=t.target,n=e;if(o.default(e).hasClass("btn")||(e=o.default(e).closest(b)[0]),!e||e.hasAttribute("disabled")||e.classList.contains("disabled"))t.preventDefault();else{var i=e.querySelector(y);if(i&&(i.hasAttribute("disabled")||i.classList.contains("disabled")))return void t.preventDefault();"INPUT"!==n.tagName&&"LABEL"===e.tagName||E._jQueryInterface.call(o.default(e),"toggle","INPUT"===n.tagName)}})).on("focus.bs.button.data-api blur.bs.button.data-api",v,(function(t){var e=o.default(t.target).closest(b)[0];o.default(e).toggleClass("focus",/^focus(in)?$/.test(t.type))})),o.default(window).on("load.bs.button.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-toggle="buttons"] .btn')),e=0,n=t.length;e0,this._pointerEvent=Boolean(window.PointerEvent||window.MSPointerEvent),this._addEventListeners()}var e=t.prototype;return e.next=function(){this._isSliding||this._slide(N)},e.nextWhenVisible=function(){var t=o.default(this._element);!document.hidden&&t.is(":visible")&&"hidden"!==t.css("visibility")&&this.next()},e.prev=function(){this._isSliding||this._slide(D)},e.pause=function(t){t||(this._isPaused=!0),this._element.querySelector(".carousel-item-next, .carousel-item-prev")&&(d.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},e.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},e.to=function(t){var e=this;this._activeElement=this._element.querySelector(I);var n=this._getItemIndex(this._activeElement);if(!(t>this._items.length-1||t<0))if(this._isSliding)o.default(this._element).one(A,(function(){return e.to(t)}));else{if(n===t)return this.pause(),void this.cycle();var i=t>n?N:D;this._slide(i,this._items[t])}},e.dispose=function(){o.default(this._element).off(".bs.carousel"),o.default.removeData(this._element,w),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},e._getConfig=function(t){return t=r({},k,t),d.typeCheckConfig(T,t,O),t},e._handleSwipe=function(){var t=Math.abs(this.touchDeltaX);if(!(t<=40)){var e=t/this.touchDeltaX;this.touchDeltaX=0,e>0&&this.prev(),e<0&&this.next()}},e._addEventListeners=function(){var t=this;this._config.keyboard&&o.default(this._element).on("keydown.bs.carousel",(function(e){return t._keydown(e)})),"hover"===this._config.pause&&o.default(this._element).on("mouseenter.bs.carousel",(function(e){return t.pause(e)})).on("mouseleave.bs.carousel",(function(e){return t.cycle(e)})),this._config.touch&&this._addTouchEventListeners()},e._addTouchEventListeners=function(){var t=this;if(this._touchSupported){var e=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]?t.touchStartX=e.originalEvent.clientX:t._pointerEvent||(t.touchStartX=e.originalEvent.touches[0].clientX)},n=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]&&(t.touchDeltaX=e.originalEvent.clientX-t.touchStartX),t._handleSwipe(),"hover"===t._config.pause&&(t.pause(),t.touchTimeout&&clearTimeout(t.touchTimeout),t.touchTimeout=setTimeout((function(e){return t.cycle(e)}),500+t._config.interval))};o.default(this._element.querySelectorAll(".carousel-item img")).on("dragstart.bs.carousel",(function(t){return t.preventDefault()})),this._pointerEvent?(o.default(this._element).on("pointerdown.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("pointerup.bs.carousel",(function(t){return n(t)})),this._element.classList.add("pointer-event")):(o.default(this._element).on("touchstart.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("touchmove.bs.carousel",(function(e){return function(e){t.touchDeltaX=e.originalEvent.touches&&e.originalEvent.touches.length>1?0:e.originalEvent.touches[0].clientX-t.touchStartX}(e)})),o.default(this._element).on("touchend.bs.carousel",(function(t){return n(t)})))}},e._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next()}},e._getItemIndex=function(t){return this._items=t&&t.parentNode?[].slice.call(t.parentNode.querySelectorAll(".carousel-item")):[],this._items.indexOf(t)},e._getItemByDirection=function(t,e){var n=t===N,i=t===D,o=this._getItemIndex(e),a=this._items.length-1;if((i&&0===o||n&&o===a)&&!this._config.wrap)return e;var s=(o+(t===D?-1:1))%this._items.length;return-1===s?this._items[this._items.length-1]:this._items[s]},e._triggerSlideEvent=function(t,e){var n=this._getItemIndex(t),i=this._getItemIndex(this._element.querySelector(I)),a=o.default.Event("slide.bs.carousel",{relatedTarget:t,direction:e,from:i,to:n});return o.default(this._element).trigger(a),a},e._setActiveIndicatorElement=function(t){if(this._indicatorsElement){var e=[].slice.call(this._indicatorsElement.querySelectorAll(".active"));o.default(e).removeClass(S);var n=this._indicatorsElement.children[this._getItemIndex(t)];n&&o.default(n).addClass(S)}},e._updateInterval=function(){var t=this._activeElement||this._element.querySelector(I);if(t){var e=parseInt(t.getAttribute("data-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}},e._slide=function(t,e){var n,i,a,s=this,l=this._element.querySelector(I),r=this._getItemIndex(l),u=e||l&&this._getItemByDirection(t,l),f=this._getItemIndex(u),c=Boolean(this._interval);if(t===N?(n="carousel-item-left",i="carousel-item-next",a="left"):(n="carousel-item-right",i="carousel-item-prev",a="right"),u&&o.default(u).hasClass(S))this._isSliding=!1;else if(!this._triggerSlideEvent(u,a).isDefaultPrevented()&&l&&u){this._isSliding=!0,c&&this.pause(),this._setActiveIndicatorElement(u),this._activeElement=u;var h=o.default.Event(A,{relatedTarget:u,direction:a,from:r,to:f});if(o.default(this._element).hasClass("slide")){o.default(u).addClass(i),d.reflow(u),o.default(l).addClass(n),o.default(u).addClass(n);var g=d.getTransitionDurationFromElement(l);o.default(l).one(d.TRANSITION_END,(function(){o.default(u).removeClass(n+" "+i).addClass(S),o.default(l).removeClass("active "+i+" "+n),s._isSliding=!1,setTimeout((function(){return o.default(s._element).trigger(h)}),0)})).emulateTransitionEnd(g)}else o.default(l).removeClass(S),o.default(u).addClass(S),this._isSliding=!1,o.default(this._element).trigger(h);c&&this.cycle()}},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(w),i=r({},k,o.default(this).data());"object"==typeof e&&(i=r({},i,e));var a="string"==typeof e?e:i.slide;if(n||(n=new t(this,i),o.default(this).data(w,n)),"number"==typeof e)n.to(e);else if("string"==typeof a){if("undefined"==typeof n[a])throw new TypeError('No method named "'+a+'"');n[a]()}else i.interval&&i.ride&&(n.pause(),n.cycle())}))},t._dataApiClickHandler=function(e){var n=d.getSelectorFromElement(this);if(n){var i=o.default(n)[0];if(i&&o.default(i).hasClass("carousel")){var a=r({},o.default(i).data(),o.default(this).data()),s=this.getAttribute("data-slide-to");s&&(a.interval=!1),t._jQueryInterface.call(o.default(i),a),s&&o.default(i).data(w).to(s),e.preventDefault()}}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return k}}]),t}();o.default(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",P._dataApiClickHandler),o.default(window).on("load.bs.carousel.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-ride="carousel"]')),e=0,n=t.length;e0&&(this._selector=s,this._triggerArray.push(a))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}var e=t.prototype;return e.toggle=function(){o.default(this._element).hasClass(q)?this.hide():this.show()},e.show=function(){var e,n,i=this;if(!(this._isTransitioning||o.default(this._element).hasClass(q)||(this._parent&&0===(e=[].slice.call(this._parent.querySelectorAll(".show, .collapsing")).filter((function(t){return"string"==typeof i._config.parent?t.getAttribute("data-parent")===i._config.parent:t.classList.contains(F)}))).length&&(e=null),e&&(n=o.default(e).not(this._selector).data(R))&&n._isTransitioning))){var a=o.default.Event("show.bs.collapse");if(o.default(this._element).trigger(a),!a.isDefaultPrevented()){e&&(t._jQueryInterface.call(o.default(e).not(this._selector),"hide"),n||o.default(e).data(R,null));var s=this._getDimension();o.default(this._element).removeClass(F).addClass(Q),this._element.style[s]=0,this._triggerArray.length&&o.default(this._triggerArray).removeClass(B).attr("aria-expanded",!0),this.setTransitioning(!0);var l="scroll"+(s[0].toUpperCase()+s.slice(1)),r=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,(function(){o.default(i._element).removeClass(Q).addClass("collapse show"),i._element.style[s]="",i.setTransitioning(!1),o.default(i._element).trigger("shown.bs.collapse")})).emulateTransitionEnd(r),this._element.style[s]=this._element[l]+"px"}}},e.hide=function(){var t=this;if(!this._isTransitioning&&o.default(this._element).hasClass(q)){var e=o.default.Event("hide.bs.collapse");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){var n=this._getDimension();this._element.style[n]=this._element.getBoundingClientRect()[n]+"px",d.reflow(this._element),o.default(this._element).addClass(Q).removeClass("collapse show");var i=this._triggerArray.length;if(i>0)for(var a=0;a0},e._getOffset=function(){var t=this,e={};return"function"==typeof this._config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t._config.offset(e.offsets,t._element)),e}:e.offset=this._config.offset,e},e._getPopperConfig=function(){var t={placement:this._getPlacement(),modifiers:{offset:this._getOffset(),flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}};return"static"===this._config.display&&(t.modifiers.applyStyle={enabled:!1}),r({},t,this._config.popperConfig)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(K);if(n||(n=new t(this,"object"==typeof e?e:null),o.default(this).data(K,n)),"string"==typeof e){if("undefined"==typeof n[e])throw new TypeError('No method named "'+e+'"');n[e]()}}))},t._clearMenus=function(e){if(!e||3!==e.which&&("keyup"!==e.type||9===e.which))for(var n=[].slice.call(document.querySelectorAll(it)),i=0,a=n.length;i0&&s--,40===e.which&&sdocument.documentElement.clientHeight;n||(this._element.style.overflowY="hidden"),this._element.classList.add(ht);var i=d.getTransitionDurationFromElement(this._dialog);o.default(this._element).off(d.TRANSITION_END),o.default(this._element).one(d.TRANSITION_END,(function(){t._element.classList.remove(ht),n||o.default(t._element).one(d.TRANSITION_END,(function(){t._element.style.overflowY=""})).emulateTransitionEnd(t._element,i)})).emulateTransitionEnd(i),this._element.focus()}},e._showElement=function(t){var e=this,n=o.default(this._element).hasClass(dt),i=this._dialog?this._dialog.querySelector(".modal-body"):null;this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),o.default(this._dialog).hasClass("modal-dialog-scrollable")&&i?i.scrollTop=0:this._element.scrollTop=0,n&&d.reflow(this._element),o.default(this._element).addClass(ct),this._config.focus&&this._enforceFocus();var a=o.default.Event("shown.bs.modal",{relatedTarget:t}),s=function(){e._config.focus&&e._element.focus(),e._isTransitioning=!1,o.default(e._element).trigger(a)};if(n){var l=d.getTransitionDurationFromElement(this._dialog);o.default(this._dialog).one(d.TRANSITION_END,s).emulateTransitionEnd(l)}else s()},e._enforceFocus=function(){var t=this;o.default(document).off(pt).on(pt,(function(e){document!==e.target&&t._element!==e.target&&0===o.default(t._element).has(e.target).length&&t._element.focus()}))},e._setEscapeEvent=function(){var t=this;this._isShown?o.default(this._element).on(yt,(function(e){t._config.keyboard&&27===e.which?(e.preventDefault(),t.hide()):t._config.keyboard||27!==e.which||t._triggerBackdropTransition()})):this._isShown||o.default(this._element).off(yt)},e._setResizeEvent=function(){var t=this;this._isShown?o.default(window).on(_t,(function(e){return t.handleUpdate(e)})):o.default(window).off(_t)},e._hideModal=function(){var t=this;this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._showBackdrop((function(){o.default(document.body).removeClass(ft),t._resetAdjustments(),t._resetScrollbar(),o.default(t._element).trigger(gt)}))},e._removeBackdrop=function(){this._backdrop&&(o.default(this._backdrop).remove(),this._backdrop=null)},e._showBackdrop=function(t){var e=this,n=o.default(this._element).hasClass(dt)?dt:"";if(this._isShown&&this._config.backdrop){if(this._backdrop=document.createElement("div"),this._backdrop.className="modal-backdrop",n&&this._backdrop.classList.add(n),o.default(this._backdrop).appendTo(document.body),o.default(this._element).on(vt,(function(t){e._ignoreBackdropClick?e._ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"===e._config.backdrop?e._triggerBackdropTransition():e.hide())})),n&&d.reflow(this._backdrop),o.default(this._backdrop).addClass(ct),!t)return;if(!n)return void t();var i=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,t).emulateTransitionEnd(i)}else if(!this._isShown&&this._backdrop){o.default(this._backdrop).removeClass(ct);var a=function(){e._removeBackdrop(),t&&t()};if(o.default(this._element).hasClass(dt)){var s=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a()}else t&&t()},e._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},e._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},e._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=Math.round(t.left+t.right)
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",customClass:"",sanitize:!0,sanitizeFn:null,whiteList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},Ut={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string|function)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",whiteList:"object",popperConfig:"(null|object)"},Mt={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},Wt=function(){function t(t,e){if("undefined"==typeof a.default)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var e=t.prototype;return e.enable=function(){this._isEnabled=!0},e.disable=function(){this._isEnabled=!1},e.toggleEnabled=function(){this._isEnabled=!this._isEnabled},e.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=o.default(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(o.default(this.getTipElement()).hasClass(Rt))return void this._leave(null,this);this._enter(null,this)}},e.dispose=function(){clearTimeout(this._timeout),o.default.removeData(this.element,this.constructor.DATA_KEY),o.default(this.element).off(this.constructor.EVENT_KEY),o.default(this.element).closest(".modal").off("hide.bs.modal",this._hideModalHandler),this.tip&&o.default(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},e.show=function(){var t=this;if("none"===o.default(this.element).css("display"))throw new Error("Please use show on visible elements");var e=o.default.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){o.default(this.element).trigger(e);var n=d.findShadowRoot(this.element),i=o.default.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(e.isDefaultPrevented()||!i)return;var s=this.getTipElement(),l=d.getUID(this.constructor.NAME);s.setAttribute("id",l),this.element.setAttribute("aria-describedby",l),this.setContent(),this.config.animation&&o.default(s).addClass(Lt);var r="function"==typeof this.config.placement?this.config.placement.call(this,s,this.element):this.config.placement,u=this._getAttachment(r);this.addAttachmentClass(u);var f=this._getContainer();o.default(s).data(this.constructor.DATA_KEY,this),o.default.contains(this.element.ownerDocument.documentElement,this.tip)||o.default(s).appendTo(f),o.default(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new a.default(this.element,s,this._getPopperConfig(u)),o.default(s).addClass(Rt),o.default(s).addClass(this.config.customClass),"ontouchstart"in document.documentElement&&o.default(document.body).children().on("mouseover",null,o.default.noop);var c=function(){t.config.animation&&t._fixTransition();var e=t._hoverState;t._hoverState=null,o.default(t.element).trigger(t.constructor.Event.SHOWN),e===qt&&t._leave(null,t)};if(o.default(this.tip).hasClass(Lt)){var h=d.getTransitionDurationFromElement(this.tip);o.default(this.tip).one(d.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},e.hide=function(t){var e=this,n=this.getTipElement(),i=o.default.Event(this.constructor.Event.HIDE),a=function(){e._hoverState!==xt&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),o.default(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(o.default(this.element).trigger(i),!i.isDefaultPrevented()){if(o.default(n).removeClass(Rt),"ontouchstart"in document.documentElement&&o.default(document.body).children().off("mouseover",null,o.default.noop),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,o.default(this.tip).hasClass(Lt)){var s=d.getTransitionDurationFromElement(n);o.default(n).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a();this._hoverState=""}},e.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},e.isWithContent=function(){return Boolean(this.getTitle())},e.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-tooltip-"+t)},e.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},e.setContent=function(){var t=this.getTipElement();this.setElementContent(o.default(t.querySelectorAll(".tooltip-inner")),this.getTitle()),o.default(t).removeClass("fade show")},e.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=At(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?o.default(e).parent().is(t)||t.empty().append(e):t.text(o.default(e).text())},e.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},e._getPopperConfig=function(t){var e=this;return r({},{placement:t,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:".arrow"},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}},this.config.popperConfig)},e._getOffset=function(){var t=this,e={};return"function"==typeof this.config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t.config.offset(e.offsets,t.element)),e}:e.offset=this.config.offset,e},e._getContainer=function(){return!1===this.config.container?document.body:d.isElement(this.config.container)?o.default(this.config.container):o.default(document).find(this.config.container)},e._getAttachment=function(t){return Bt[t.toUpperCase()]},e._setListeners=function(){var t=this;this.config.trigger.split(" ").forEach((function(e){if("click"===e)o.default(t.element).on(t.constructor.Event.CLICK,t.config.selector,(function(e){return t.toggle(e)}));else if("manual"!==e){var n=e===Ft?t.constructor.Event.MOUSEENTER:t.constructor.Event.FOCUSIN,i=e===Ft?t.constructor.Event.MOUSELEAVE:t.constructor.Event.FOCUSOUT;o.default(t.element).on(n,t.config.selector,(function(e){return t._enter(e)})).on(i,t.config.selector,(function(e){return t._leave(e)}))}})),this._hideModalHandler=function(){t.element&&t.hide()},o.default(this.element).closest(".modal").on("hide.bs.modal",this._hideModalHandler),this.config.selector?this.config=r({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},e._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},e._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Qt:Ft]=!0),o.default(e.getTipElement()).hasClass(Rt)||e._hoverState===xt?e._hoverState=xt:(clearTimeout(e._timeout),e._hoverState=xt,e.config.delay&&e.config.delay.show?e._timeout=setTimeout((function(){e._hoverState===xt&&e.show()}),e.config.delay.show):e.show())},e._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Qt:Ft]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=qt,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout((function(){e._hoverState===qt&&e.hide()}),e.config.delay.hide):e.hide())},e._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},e._getConfig=function(t){var e=o.default(this.element).data();return Object.keys(e).forEach((function(t){-1!==Pt.indexOf(t)&&delete e[t]})),"number"==typeof(t=r({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),d.typeCheckConfig(It,t,this.constructor.DefaultType),t.sanitize&&(t.template=At(t.template,t.whiteList,t.sanitizeFn)),t},e._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},e._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(jt);null!==e&&e.length&&t.removeClass(e.join(""))},e._handlePopperPlacementChange=function(t){this.tip=t.instance.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},e._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(o.default(t).removeClass(Lt),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(kt),a="object"==typeof e&&e;if((i||!/dispose|hide/.test(e))&&(i||(i=new t(this,a),n.data(kt,i)),"string"==typeof e)){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Ht}},{key:"NAME",get:function(){return It}},{key:"DATA_KEY",get:function(){return kt}},{key:"Event",get:function(){return Mt}},{key:"EVENT_KEY",get:function(){return".bs.tooltip"}},{key:"DefaultType",get:function(){return Ut}}]),t}();o.default.fn.tooltip=Wt._jQueryInterface,o.default.fn.tooltip.Constructor=Wt,o.default.fn.tooltip.noConflict=function(){return o.default.fn.tooltip=Ot,Wt._jQueryInterface};var Vt="bs.popover",zt=o.default.fn.popover,Kt=new RegExp("(^|\\s)bs-popover\\S+","g"),Xt=r({},Wt.Default,{placement:"right",trigger:"click",content:"",template:''}),Yt=r({},Wt.DefaultType,{content:"(string|element|function)"}),$t={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"},Jt=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),e.prototype.constructor=e,u(e,n);var a=i.prototype;return a.isWithContent=function(){return this.getTitle()||this._getContent()},a.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-popover-"+t)},a.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},a.setContent=function(){var t=o.default(this.getTipElement());this.setElementContent(t.find(".popover-header"),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(".popover-body"),e),t.removeClass("fade show")},a._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},a._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(Kt);null!==e&&e.length>0&&t.removeClass(e.join(""))},i._jQueryInterface=function(t){return this.each((function(){var e=o.default(this).data(Vt),n="object"==typeof t?t:null;if((e||!/dispose|hide/.test(t))&&(e||(e=new i(this,n),o.default(this).data(Vt,e)),"string"==typeof t)){if("undefined"==typeof e[t])throw new TypeError('No method named "'+t+'"');e[t]()}}))},l(i,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Xt}},{key:"NAME",get:function(){return"popover"}},{key:"DATA_KEY",get:function(){return Vt}},{key:"Event",get:function(){return $t}},{key:"EVENT_KEY",get:function(){return".bs.popover"}},{key:"DefaultType",get:function(){return Yt}}]),i}(Wt);o.default.fn.popover=Jt._jQueryInterface,o.default.fn.popover.Constructor=Jt,o.default.fn.popover.noConflict=function(){return o.default.fn.popover=zt,Jt._jQueryInterface};var Gt="scrollspy",Zt="bs.scrollspy",te=o.default.fn[Gt],ee="active",ne="position",ie=".nav, .list-group",oe={offset:10,method:"auto",target:""},ae={offset:"number",method:"string",target:"(string|element)"},se=function(){function t(t,e){var n=this;this._element=t,this._scrollElement="BODY"===t.tagName?window:t,this._config=this._getConfig(e),this._selector=this._config.target+" .nav-link,"+this._config.target+" .list-group-item,"+this._config.target+" .dropdown-item",this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,o.default(this._scrollElement).on("scroll.bs.scrollspy",(function(t){return n._process(t)})),this.refresh(),this._process()}var e=t.prototype;return e.refresh=function(){var t=this,e=this._scrollElement===this._scrollElement.window?"offset":ne,n="auto"===this._config.method?e:this._config.method,i=n===ne?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),[].slice.call(document.querySelectorAll(this._selector)).map((function(t){var e,a=d.getSelectorFromElement(t);if(a&&(e=document.querySelector(a)),e){var s=e.getBoundingClientRect();if(s.width||s.height)return[o.default(e)[n]().top+i,a]}return null})).filter((function(t){return t})).sort((function(t,e){return t[0]-e[0]})).forEach((function(e){t._offsets.push(e[0]),t._targets.push(e[1])}))},e.dispose=function(){o.default.removeData(this._element,Zt),o.default(this._scrollElement).off(".bs.scrollspy"),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},e._getConfig=function(t){if("string"!=typeof(t=r({},oe,"object"==typeof t&&t?t:{})).target&&d.isElement(t.target)){var e=o.default(t.target).attr("id");e||(e=d.getUID(Gt),o.default(t.target).attr("id",e)),t.target="#"+e}return d.typeCheckConfig(Gt,t,ae),t},e._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},e._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},e._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},e._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;)this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||t li > .active",ge=function(){function t(t){this._element=t}var e=t.prototype;return e.show=function(){var t=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&o.default(this._element).hasClass(ue)||o.default(this._element).hasClass("disabled"))){var e,n,i=o.default(this._element).closest(".nav, .list-group")[0],a=d.getSelectorFromElement(this._element);if(i){var s="UL"===i.nodeName||"OL"===i.nodeName?he:ce;n=(n=o.default.makeArray(o.default(i).find(s)))[n.length-1]}var l=o.default.Event("hide.bs.tab",{relatedTarget:this._element}),r=o.default.Event("show.bs.tab",{relatedTarget:n});if(n&&o.default(n).trigger(l),o.default(this._element).trigger(r),!r.isDefaultPrevented()&&!l.isDefaultPrevented()){a&&(e=document.querySelector(a)),this._activate(this._element,i);var u=function(){var e=o.default.Event("hidden.bs.tab",{relatedTarget:t._element}),i=o.default.Event("shown.bs.tab",{relatedTarget:n});o.default(n).trigger(e),o.default(t._element).trigger(i)};e?this._activate(e,e.parentNode,u):u()}}},e.dispose=function(){o.default.removeData(this._element,le),this._element=null},e._activate=function(t,e,n){var i=this,a=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?o.default(e).children(ce):o.default(e).find(he))[0],s=n&&a&&o.default(a).hasClass(fe),l=function(){return i._transitionComplete(t,a,n)};if(a&&s){var r=d.getTransitionDurationFromElement(a);o.default(a).removeClass(de).one(d.TRANSITION_END,l).emulateTransitionEnd(r)}else l()},e._transitionComplete=function(t,e,n){if(e){o.default(e).removeClass(ue);var i=o.default(e.parentNode).find("> .dropdown-menu .active")[0];i&&o.default(i).removeClass(ue),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}o.default(t).addClass(ue),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),d.reflow(t),t.classList.contains(fe)&&t.classList.add(de);var a=t.parentNode;if(a&&"LI"===a.nodeName&&(a=a.parentNode),a&&o.default(a).hasClass("dropdown-menu")){var s=o.default(t).closest(".dropdown")[0];if(s){var l=[].slice.call(s.querySelectorAll(".dropdown-toggle"));o.default(l).addClass(ue)}t.setAttribute("aria-expanded",!0)}n&&n()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(le);if(i||(i=new t(this),n.data(le,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',(function(t){t.preventDefault(),ge._jQueryInterface.call(o.default(this),"show")})),o.default.fn.tab=ge._jQueryInterface,o.default.fn.tab.Constructor=ge,o.default.fn.tab.noConflict=function(){return o.default.fn.tab=re,ge._jQueryInterface};var me="bs.toast",pe=o.default.fn.toast,_e="hide",ve="show",ye="showing",be="click.dismiss.bs.toast",Ee={animation:!0,autohide:!0,delay:500},Te={animation:"boolean",autohide:"boolean",delay:"number"},we=function(){function t(t,e){this._element=t,this._config=this._getConfig(e),this._timeout=null,this._setListeners()}var e=t.prototype;return e.show=function(){var t=this,e=o.default.Event("show.bs.toast");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){this._clearTimeout(),this._config.animation&&this._element.classList.add("fade");var n=function(){t._element.classList.remove(ye),t._element.classList.add(ve),o.default(t._element).trigger("shown.bs.toast"),t._config.autohide&&(t._timeout=setTimeout((function(){t.hide()}),t._config.delay))};if(this._element.classList.remove(_e),d.reflow(this._element),this._element.classList.add(ye),this._config.animation){var i=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,n).emulateTransitionEnd(i)}else n()}},e.hide=function(){if(this._element.classList.contains(ve)){var t=o.default.Event("hide.bs.toast");o.default(this._element).trigger(t),t.isDefaultPrevented()||this._close()}},e.dispose=function(){this._clearTimeout(),this._element.classList.contains(ve)&&this._element.classList.remove(ve),o.default(this._element).off(be),o.default.removeData(this._element,me),this._element=null,this._config=null},e._getConfig=function(t){return t=r({},Ee,o.default(this._element).data(),"object"==typeof t&&t?t:{}),d.typeCheckConfig("toast",t,this.constructor.DefaultType),t},e._setListeners=function(){var t=this;o.default(this._element).on(be,'[data-dismiss="toast"]',(function(){return t.hide()}))},e._close=function(){var t=this,e=function(){t._element.classList.add(_e),o.default(t._element).trigger("hidden.bs.toast")};if(this._element.classList.remove(ve),this._config.animation){var n=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},e._clearTimeout=function(){clearTimeout(this._timeout),this._timeout=null},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(me);if(i||(i=new t(this,"object"==typeof e&&e),n.data(me,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e](this)}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"DefaultType",get:function(){return Te}},{key:"Default",get:function(){return Ee}}]),t}();o.default.fn.toast=we._jQueryInterface,o.default.fn.toast.Constructor=we,o.default.fn.toast.noConflict=function(){return o.default.fn.toast=pe,we._jQueryInterface},t.Alert=g,t.Button=E,t.Carousel=P,t.Collapse=V,t.Dropdown=lt,t.Modal=Ct,t.Popover=Jt,t.Scrollspy=se,t.Tab=ge,t.Toast=we,t.Tooltip=Wt,t.Util=d,Object.defineProperty(t,"__esModule",{value:!0})})); +//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/jquery-3.5.1.slim.min.js b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/jquery-3.5.1.slim.min.js new file mode 100644 index 0000000..36b4e1a --- /dev/null +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/jquery-3.5.1.slim.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(g,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,v=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),m={},b=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},w=g.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function C(e,t,n){var r,i,o=(n=n||w).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function T(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector",E=function(e,t){return new E.fn.init(e,t)};function d(e){var t=!!e&&"length"in e&&e.length,n=T(e);return!b(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+R+")"+R+"*"),U=new RegExp(R+"|>"),V=new RegExp(W),X=new RegExp("^"+B+"$"),Q={ID:new RegExp("^#("+B+")"),CLASS:new RegExp("^\\.("+B+")"),TAG:new RegExp("^("+B+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+R+"*(even|odd|(([+-]|)(\\d*)n|)"+R+"*(?:([+-]|)"+R+"*(\\d+)|))"+R+"*\\)|)","i"),bool:new RegExp("^(?:"+I+")$","i"),needsContext:new RegExp("^"+R+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+R+"*((?:-\\d)?\\d*)"+R+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,G=/^(?:input|select|textarea|button)$/i,K=/^h\d$/i,J=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+R+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){C()},ae=xe(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{O.apply(t=P.call(d.childNodes),d.childNodes),t[d.childNodes.length].nodeType}catch(e){O={apply:t.length?function(e,t){q.apply(e,P.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,d=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==d&&9!==d&&11!==d)return n;if(!r&&(C(e),e=e||T,E)){if(11!==d&&(u=Z.exec(t)))if(i=u[1]){if(9===d){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return O.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&p.getElementsByClassName&&e.getElementsByClassName)return O.apply(n,e.getElementsByClassName(i)),n}if(p.qsa&&!k[t+" "]&&(!v||!v.test(t))&&(1!==d||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===d&&(U.test(t)||_.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&p.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=A)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+be(l[o]);c=l.join(",")}try{return O.apply(n,f.querySelectorAll(c)),n}catch(e){k(t,!0)}finally{s===A&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>x.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[A]=!0,e}function ce(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)x.attrHandle[n[r]]=t}function de(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pe(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in p=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},C=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:d;return r!=T&&9===r.nodeType&&r.documentElement&&(a=(T=r).documentElement,E=!i(T),d!=T&&(n=T.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),p.scope=ce(function(e){return a.appendChild(e).appendChild(T.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),p.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),p.getElementsByTagName=ce(function(e){return e.appendChild(T.createComment("")),!e.getElementsByTagName("*").length}),p.getElementsByClassName=J.test(T.getElementsByClassName),p.getById=ce(function(e){return a.appendChild(e).id=A,!T.getElementsByName||!T.getElementsByName(A).length}),p.getById?(x.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(x.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),x.find.TAG=p.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):p.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},x.find.CLASS=p.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(p.qsa=J.test(T.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+R+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+R+"*(?:value|"+I+")"),e.querySelectorAll("[id~="+A+"-]").length||v.push("~="),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+R+"*name"+R+"*="+R+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+A+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=T.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+R+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(p.matchesSelector=J.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){p.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",W)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=J.test(a.compareDocumentPosition),y=t||J.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!p.sortDetached&&t.compareDocumentPosition(e)===n?e==T||e.ownerDocument==d&&y(d,e)?-1:t==T||t.ownerDocument==d&&y(d,t)?1:u?H(u,e)-H(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==T?-1:t==T?1:i?-1:o?1:u?H(u,e)-H(u,t):0;if(i===o)return de(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?de(a[r],s[r]):a[r]==d?-1:s[r]==d?1:0}),T},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(C(e),p.matchesSelector&&E&&!k[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||p.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){k(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&V.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+R+")"+e+"("+R+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return b(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):"string"!=typeof n?E.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||L,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:j.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:w,!0)),k.test(r[1])&&E.isPlainObject(t))for(r in t)b(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=w.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):b(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,L=E(w);var q=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,pe=/^$|^module$|\/(?:java|ecma)script/i;le=w.createDocumentFragment().appendChild(w.createElement("div")),(ce=w.createElement("input")).setAttribute("type","radio"),ce.setAttribute("checked","checked"),ce.setAttribute("name","t"),le.appendChild(ce),m.checkClone=le.cloneNode(!0).cloneNode(!0).lastChild.checked,le.innerHTML="",m.noCloneChecked=!!le.cloneNode(!0).lastChild.defaultValue,le.innerHTML="",m.option=!!le.lastChild;var he={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ge(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&S(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var ye=/<|&#?\w+;/;function me(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),d=[],p=0,h=e.length;p\s*$/g;function Le(e,t){return S(e,"table")&&S(11!==t.nodeType?t:t.firstChild,"tr")&&E(e).children("tbody")[0]||e}function je(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n
",2===ft.childNodes.length),E.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(m.createHTMLDocument?((r=(t=w.implementation.createHTMLDocument("")).createElement("base")).href=w.location.href,t.head.appendChild(r)):t=w),o=!n&&[],(i=k.exec(e))?[t.createElement(i[1])]:(i=me([e],t,o),o&&o.length&&E(o).remove(),E.merge([],i.childNodes)));var r,i,o},E.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=E.css(e,"position"),c=E(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=E.css(e,"top"),u=E.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),b(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===E.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===E.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=E(e).offset()).top+=E.css(e,"borderTopWidth",!0),i.left+=E.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-E.css(r,"marginTop",!0),left:t.left-i.left-E.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===E.css(e,"position"))e=e.offsetParent;return e||re})}}),E.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;E.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each(["top","left"],function(e,n){E.cssHooks[n]=Fe(m.pixelPosition,function(e,t){if(t)return t=We(e,n),Ie.test(t)?E(e).position()[n]+"px":t})}),E.each({Height:"height",Width:"width"},function(a,s){E.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){E.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?E.css(e,t,i):E.style(e,t,n,i)},s,n?e:void 0,n)}})}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){E.fn[n]=function(e,t){return 0=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),ae({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=le({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f]),E=parseFloat(w['border'+f+'Width']),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},ae(n,m,$(v)),ae(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ce.FLIP:p=[n,i];break;case ce.CLOCKWISE:p=G(n);break;case ce.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u),E=!!t.flipVariationsByContent&&(w&&'start'===r&&c||w&&'end'===r&&h||!w&&'start'===r&&u||!w&&'end'===r&&g),v=y||E;(m||b||v)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),v&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=le({},e.offsets.popper,C(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport',flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=D(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.rightwindow.devicePixelRatio||!fe),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=B('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=le({},E,e.attributes),e.styles=le({},m,e.styles),e.arrowStyles=le({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return V(e.instance.popper,e.styles),j(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&V(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),V(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ge}); +//# sourceMappingURL=popper.min.js.map diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/templates/shared/_layout.html b/code/ch7_infinite_scroll/ch7_final_video_collector/templates/shared/_layout.html index fccc4a6..4a255e6 100644 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/templates/shared/_layout.html +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/templates/shared/_layout.html @@ -54,6 +54,11 @@ + + + + + {% block additional_js %}{% endblock %} From 6b7ad53a064251ef8128f5ecce285e5ae90d11c3 Mon Sep 17 00:00:00 2001 From: Michael Kennedy Date: Fri, 3 Dec 2021 17:22:31 -0800 Subject: [PATCH 02/21] Add the jQuery/Bootstrap JS needed for responsive nav bars in Bootstrap. --- .../static/js/bootstrap-4.6.1.min.js | 7 +++++++ .../static/js/jquery-3.5.1.slim.min.js | 2 ++ .../static/js/popper-1.16.1.min.js | 5 +++++ .../static/js/bootstrap-4.6.1.min.js | 7 +++++++ .../static/js/jquery-3.5.1.slim.min.js | 2 ++ .../static/js/popper-1.16.1.min.js | 5 +++++ .../static/js/bootstrap-4.6.1.min.js | 7 +++++++ .../static/js/jquery-3.5.1.slim.min.js | 2 ++ .../static/js/popper-1.16.1.min.js | 5 +++++ .../static/js/bootstrap-4.6.1.min.js | 7 +++++++ .../static/js/jquery-3.5.1.slim.min.js | 2 ++ .../static/js/popper-1.16.1.min.js | 5 +++++ .../static/js/bootstrap-4.6.1.min.js | 7 +++++++ .../static/js/jquery-3.5.1.slim.min.js | 2 ++ .../static/js/popper-1.16.1.min.js | 5 +++++ .../static/js/bootstrap-4.6.1.min.js | 7 +++++++ .../static/js/jquery-3.5.1.slim.min.js | 2 ++ .../static/js/popper-1.16.1.min.js | 5 +++++ .../static/js/bootstrap-4.6.1.min copy.js | 7 +++++++ .../static/js/jquery-3.5.1.slim.min copy.js | 2 ++ .../static/js/popper-1.16.1.min copy.js | 5 +++++ .../static/js/bootstrap-4.6.1.min.js | 7 +++++++ .../static/js/jquery-3.5.1.slim.min.js | 2 ++ .../static/js/popper-1.16.1.min.js | 5 +++++ .../static/js/bootstrap-4.6.1.min.js | 7 +++++++ .../static/js/jquery-3.5.1.slim.min.js | 2 ++ .../starter_video_collector/static/js/popper-1.16.1.min.js | 5 +++++ 27 files changed, 126 insertions(+) create mode 100644 code/ch4_app/ch4_final_video_collector/static/js/bootstrap-4.6.1.min.js create mode 100644 code/ch4_app/ch4_final_video_collector/static/js/jquery-3.5.1.slim.min.js create mode 100644 code/ch4_app/ch4_final_video_collector/static/js/popper-1.16.1.min.js create mode 100644 code/ch4_app/ch4_starter_video_collector/static/js/bootstrap-4.6.1.min.js create mode 100644 code/ch4_app/ch4_starter_video_collector/static/js/jquery-3.5.1.slim.min.js create mode 100644 code/ch4_app/ch4_starter_video_collector/static/js/popper-1.16.1.min.js create mode 100644 code/ch5_partials/ch5_final_video_collector/static/js/bootstrap-4.6.1.min.js create mode 100644 code/ch5_partials/ch5_final_video_collector/static/js/jquery-3.5.1.slim.min.js create mode 100644 code/ch5_partials/ch5_final_video_collector/static/js/popper-1.16.1.min.js create mode 100644 code/ch5_partials/ch5_starter_video_collector/static/js/bootstrap-4.6.1.min.js create mode 100644 code/ch5_partials/ch5_starter_video_collector/static/js/jquery-3.5.1.slim.min.js create mode 100644 code/ch5_partials/ch5_starter_video_collector/static/js/popper-1.16.1.min.js create mode 100644 code/ch6_active_search/ch6_final_video_collector/static/js/bootstrap-4.6.1.min.js create mode 100644 code/ch6_active_search/ch6_final_video_collector/static/js/jquery-3.5.1.slim.min.js create mode 100644 code/ch6_active_search/ch6_final_video_collector/static/js/popper-1.16.1.min.js create mode 100644 code/ch6_active_search/ch6_starter_video_collector/static/js/bootstrap-4.6.1.min.js create mode 100644 code/ch6_active_search/ch6_starter_video_collector/static/js/jquery-3.5.1.slim.min.js create mode 100644 code/ch6_active_search/ch6_starter_video_collector/static/js/popper-1.16.1.min.js create mode 100644 code/ch7_infinite_scroll/ch7_final_video_collector/static/js/bootstrap-4.6.1.min copy.js create mode 100644 code/ch7_infinite_scroll/ch7_final_video_collector/static/js/jquery-3.5.1.slim.min copy.js create mode 100644 code/ch7_infinite_scroll/ch7_final_video_collector/static/js/popper-1.16.1.min copy.js create mode 100644 code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/bootstrap-4.6.1.min.js create mode 100644 code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/jquery-3.5.1.slim.min.js create mode 100644 code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/popper-1.16.1.min.js create mode 100644 code/starter_video_collector/static/js/bootstrap-4.6.1.min.js create mode 100644 code/starter_video_collector/static/js/jquery-3.5.1.slim.min.js create mode 100644 code/starter_video_collector/static/js/popper-1.16.1.min.js diff --git a/code/ch4_app/ch4_final_video_collector/static/js/bootstrap-4.6.1.min.js b/code/ch4_app/ch4_final_video_collector/static/js/bootstrap-4.6.1.min.js new file mode 100644 index 0000000..50720ea --- /dev/null +++ b/code/ch4_app/ch4_final_video_collector/static/js/bootstrap-4.6.1.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.6.1 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap={},t.jQuery,t.Popper)}(this,(function(t,e,n){"use strict";function i(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var o=i(e),a=i(n);function s(t,e){for(var n=0;n=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}};d.jQueryDetection(),o.default.fn.emulateTransitionEnd=function(t){var e=this,n=!1;return o.default(this).one(d.TRANSITION_END,(function(){n=!0})),setTimeout((function(){n||d.triggerTransitionEnd(e)}),t),this},o.default.event.special[d.TRANSITION_END]={bindType:f,delegateType:f,handle:function(t){if(o.default(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}};var c="bs.alert",h=o.default.fn.alert,g=function(){function t(t){this._element=t}var e=t.prototype;return e.close=function(t){var e=this._element;t&&(e=this._getRootElement(t)),this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.dispose=function(){o.default.removeData(this._element,c),this._element=null},e._getRootElement=function(t){var e=d.getSelectorFromElement(t),n=!1;return e&&(n=document.querySelector(e)),n||(n=o.default(t).closest(".alert")[0]),n},e._triggerCloseEvent=function(t){var e=o.default.Event("close.bs.alert");return o.default(t).trigger(e),e},e._removeElement=function(t){var e=this;if(o.default(t).removeClass("show"),o.default(t).hasClass("fade")){var n=d.getTransitionDurationFromElement(t);o.default(t).one(d.TRANSITION_END,(function(n){return e._destroyElement(t,n)})).emulateTransitionEnd(n)}else this._destroyElement(t)},e._destroyElement=function(t){o.default(t).detach().trigger("closed.bs.alert").remove()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(c);i||(i=new t(this),n.data(c,i)),"close"===e&&i[e](this)}))},t._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',g._handleDismiss(new g)),o.default.fn.alert=g._jQueryInterface,o.default.fn.alert.Constructor=g,o.default.fn.alert.noConflict=function(){return o.default.fn.alert=h,g._jQueryInterface};var m="bs.button",p=o.default.fn.button,_="active",v='[data-toggle^="button"]',y='input:not([type="hidden"])',b=".btn",E=function(){function t(t){this._element=t,this.shouldAvoidTriggerChange=!1}var e=t.prototype;return e.toggle=function(){var t=!0,e=!0,n=o.default(this._element).closest('[data-toggle="buttons"]')[0];if(n){var i=this._element.querySelector(y);if(i){if("radio"===i.type)if(i.checked&&this._element.classList.contains(_))t=!1;else{var a=n.querySelector(".active");a&&o.default(a).removeClass(_)}t&&("checkbox"!==i.type&&"radio"!==i.type||(i.checked=!this._element.classList.contains(_)),this.shouldAvoidTriggerChange||o.default(i).trigger("change")),i.focus(),e=!1}}this._element.hasAttribute("disabled")||this._element.classList.contains("disabled")||(e&&this._element.setAttribute("aria-pressed",!this._element.classList.contains(_)),t&&o.default(this._element).toggleClass(_))},e.dispose=function(){o.default.removeData(this._element,m),this._element=null},t._jQueryInterface=function(e,n){return this.each((function(){var i=o.default(this),a=i.data(m);a||(a=new t(this),i.data(m,a)),a.shouldAvoidTriggerChange=n,"toggle"===e&&a[e]()}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.button.data-api",v,(function(t){var e=t.target,n=e;if(o.default(e).hasClass("btn")||(e=o.default(e).closest(b)[0]),!e||e.hasAttribute("disabled")||e.classList.contains("disabled"))t.preventDefault();else{var i=e.querySelector(y);if(i&&(i.hasAttribute("disabled")||i.classList.contains("disabled")))return void t.preventDefault();"INPUT"!==n.tagName&&"LABEL"===e.tagName||E._jQueryInterface.call(o.default(e),"toggle","INPUT"===n.tagName)}})).on("focus.bs.button.data-api blur.bs.button.data-api",v,(function(t){var e=o.default(t.target).closest(b)[0];o.default(e).toggleClass("focus",/^focus(in)?$/.test(t.type))})),o.default(window).on("load.bs.button.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-toggle="buttons"] .btn')),e=0,n=t.length;e0,this._pointerEvent=Boolean(window.PointerEvent||window.MSPointerEvent),this._addEventListeners()}var e=t.prototype;return e.next=function(){this._isSliding||this._slide(N)},e.nextWhenVisible=function(){var t=o.default(this._element);!document.hidden&&t.is(":visible")&&"hidden"!==t.css("visibility")&&this.next()},e.prev=function(){this._isSliding||this._slide(D)},e.pause=function(t){t||(this._isPaused=!0),this._element.querySelector(".carousel-item-next, .carousel-item-prev")&&(d.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},e.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},e.to=function(t){var e=this;this._activeElement=this._element.querySelector(I);var n=this._getItemIndex(this._activeElement);if(!(t>this._items.length-1||t<0))if(this._isSliding)o.default(this._element).one(A,(function(){return e.to(t)}));else{if(n===t)return this.pause(),void this.cycle();var i=t>n?N:D;this._slide(i,this._items[t])}},e.dispose=function(){o.default(this._element).off(".bs.carousel"),o.default.removeData(this._element,w),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},e._getConfig=function(t){return t=r({},k,t),d.typeCheckConfig(T,t,O),t},e._handleSwipe=function(){var t=Math.abs(this.touchDeltaX);if(!(t<=40)){var e=t/this.touchDeltaX;this.touchDeltaX=0,e>0&&this.prev(),e<0&&this.next()}},e._addEventListeners=function(){var t=this;this._config.keyboard&&o.default(this._element).on("keydown.bs.carousel",(function(e){return t._keydown(e)})),"hover"===this._config.pause&&o.default(this._element).on("mouseenter.bs.carousel",(function(e){return t.pause(e)})).on("mouseleave.bs.carousel",(function(e){return t.cycle(e)})),this._config.touch&&this._addTouchEventListeners()},e._addTouchEventListeners=function(){var t=this;if(this._touchSupported){var e=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]?t.touchStartX=e.originalEvent.clientX:t._pointerEvent||(t.touchStartX=e.originalEvent.touches[0].clientX)},n=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]&&(t.touchDeltaX=e.originalEvent.clientX-t.touchStartX),t._handleSwipe(),"hover"===t._config.pause&&(t.pause(),t.touchTimeout&&clearTimeout(t.touchTimeout),t.touchTimeout=setTimeout((function(e){return t.cycle(e)}),500+t._config.interval))};o.default(this._element.querySelectorAll(".carousel-item img")).on("dragstart.bs.carousel",(function(t){return t.preventDefault()})),this._pointerEvent?(o.default(this._element).on("pointerdown.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("pointerup.bs.carousel",(function(t){return n(t)})),this._element.classList.add("pointer-event")):(o.default(this._element).on("touchstart.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("touchmove.bs.carousel",(function(e){return function(e){t.touchDeltaX=e.originalEvent.touches&&e.originalEvent.touches.length>1?0:e.originalEvent.touches[0].clientX-t.touchStartX}(e)})),o.default(this._element).on("touchend.bs.carousel",(function(t){return n(t)})))}},e._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next()}},e._getItemIndex=function(t){return this._items=t&&t.parentNode?[].slice.call(t.parentNode.querySelectorAll(".carousel-item")):[],this._items.indexOf(t)},e._getItemByDirection=function(t,e){var n=t===N,i=t===D,o=this._getItemIndex(e),a=this._items.length-1;if((i&&0===o||n&&o===a)&&!this._config.wrap)return e;var s=(o+(t===D?-1:1))%this._items.length;return-1===s?this._items[this._items.length-1]:this._items[s]},e._triggerSlideEvent=function(t,e){var n=this._getItemIndex(t),i=this._getItemIndex(this._element.querySelector(I)),a=o.default.Event("slide.bs.carousel",{relatedTarget:t,direction:e,from:i,to:n});return o.default(this._element).trigger(a),a},e._setActiveIndicatorElement=function(t){if(this._indicatorsElement){var e=[].slice.call(this._indicatorsElement.querySelectorAll(".active"));o.default(e).removeClass(S);var n=this._indicatorsElement.children[this._getItemIndex(t)];n&&o.default(n).addClass(S)}},e._updateInterval=function(){var t=this._activeElement||this._element.querySelector(I);if(t){var e=parseInt(t.getAttribute("data-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}},e._slide=function(t,e){var n,i,a,s=this,l=this._element.querySelector(I),r=this._getItemIndex(l),u=e||l&&this._getItemByDirection(t,l),f=this._getItemIndex(u),c=Boolean(this._interval);if(t===N?(n="carousel-item-left",i="carousel-item-next",a="left"):(n="carousel-item-right",i="carousel-item-prev",a="right"),u&&o.default(u).hasClass(S))this._isSliding=!1;else if(!this._triggerSlideEvent(u,a).isDefaultPrevented()&&l&&u){this._isSliding=!0,c&&this.pause(),this._setActiveIndicatorElement(u),this._activeElement=u;var h=o.default.Event(A,{relatedTarget:u,direction:a,from:r,to:f});if(o.default(this._element).hasClass("slide")){o.default(u).addClass(i),d.reflow(u),o.default(l).addClass(n),o.default(u).addClass(n);var g=d.getTransitionDurationFromElement(l);o.default(l).one(d.TRANSITION_END,(function(){o.default(u).removeClass(n+" "+i).addClass(S),o.default(l).removeClass("active "+i+" "+n),s._isSliding=!1,setTimeout((function(){return o.default(s._element).trigger(h)}),0)})).emulateTransitionEnd(g)}else o.default(l).removeClass(S),o.default(u).addClass(S),this._isSliding=!1,o.default(this._element).trigger(h);c&&this.cycle()}},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(w),i=r({},k,o.default(this).data());"object"==typeof e&&(i=r({},i,e));var a="string"==typeof e?e:i.slide;if(n||(n=new t(this,i),o.default(this).data(w,n)),"number"==typeof e)n.to(e);else if("string"==typeof a){if("undefined"==typeof n[a])throw new TypeError('No method named "'+a+'"');n[a]()}else i.interval&&i.ride&&(n.pause(),n.cycle())}))},t._dataApiClickHandler=function(e){var n=d.getSelectorFromElement(this);if(n){var i=o.default(n)[0];if(i&&o.default(i).hasClass("carousel")){var a=r({},o.default(i).data(),o.default(this).data()),s=this.getAttribute("data-slide-to");s&&(a.interval=!1),t._jQueryInterface.call(o.default(i),a),s&&o.default(i).data(w).to(s),e.preventDefault()}}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return k}}]),t}();o.default(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",P._dataApiClickHandler),o.default(window).on("load.bs.carousel.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-ride="carousel"]')),e=0,n=t.length;e0&&(this._selector=s,this._triggerArray.push(a))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}var e=t.prototype;return e.toggle=function(){o.default(this._element).hasClass(q)?this.hide():this.show()},e.show=function(){var e,n,i=this;if(!(this._isTransitioning||o.default(this._element).hasClass(q)||(this._parent&&0===(e=[].slice.call(this._parent.querySelectorAll(".show, .collapsing")).filter((function(t){return"string"==typeof i._config.parent?t.getAttribute("data-parent")===i._config.parent:t.classList.contains(F)}))).length&&(e=null),e&&(n=o.default(e).not(this._selector).data(R))&&n._isTransitioning))){var a=o.default.Event("show.bs.collapse");if(o.default(this._element).trigger(a),!a.isDefaultPrevented()){e&&(t._jQueryInterface.call(o.default(e).not(this._selector),"hide"),n||o.default(e).data(R,null));var s=this._getDimension();o.default(this._element).removeClass(F).addClass(Q),this._element.style[s]=0,this._triggerArray.length&&o.default(this._triggerArray).removeClass(B).attr("aria-expanded",!0),this.setTransitioning(!0);var l="scroll"+(s[0].toUpperCase()+s.slice(1)),r=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,(function(){o.default(i._element).removeClass(Q).addClass("collapse show"),i._element.style[s]="",i.setTransitioning(!1),o.default(i._element).trigger("shown.bs.collapse")})).emulateTransitionEnd(r),this._element.style[s]=this._element[l]+"px"}}},e.hide=function(){var t=this;if(!this._isTransitioning&&o.default(this._element).hasClass(q)){var e=o.default.Event("hide.bs.collapse");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){var n=this._getDimension();this._element.style[n]=this._element.getBoundingClientRect()[n]+"px",d.reflow(this._element),o.default(this._element).addClass(Q).removeClass("collapse show");var i=this._triggerArray.length;if(i>0)for(var a=0;a0},e._getOffset=function(){var t=this,e={};return"function"==typeof this._config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t._config.offset(e.offsets,t._element)),e}:e.offset=this._config.offset,e},e._getPopperConfig=function(){var t={placement:this._getPlacement(),modifiers:{offset:this._getOffset(),flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}};return"static"===this._config.display&&(t.modifiers.applyStyle={enabled:!1}),r({},t,this._config.popperConfig)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(K);if(n||(n=new t(this,"object"==typeof e?e:null),o.default(this).data(K,n)),"string"==typeof e){if("undefined"==typeof n[e])throw new TypeError('No method named "'+e+'"');n[e]()}}))},t._clearMenus=function(e){if(!e||3!==e.which&&("keyup"!==e.type||9===e.which))for(var n=[].slice.call(document.querySelectorAll(it)),i=0,a=n.length;i0&&s--,40===e.which&&sdocument.documentElement.clientHeight;n||(this._element.style.overflowY="hidden"),this._element.classList.add(ht);var i=d.getTransitionDurationFromElement(this._dialog);o.default(this._element).off(d.TRANSITION_END),o.default(this._element).one(d.TRANSITION_END,(function(){t._element.classList.remove(ht),n||o.default(t._element).one(d.TRANSITION_END,(function(){t._element.style.overflowY=""})).emulateTransitionEnd(t._element,i)})).emulateTransitionEnd(i),this._element.focus()}},e._showElement=function(t){var e=this,n=o.default(this._element).hasClass(dt),i=this._dialog?this._dialog.querySelector(".modal-body"):null;this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),o.default(this._dialog).hasClass("modal-dialog-scrollable")&&i?i.scrollTop=0:this._element.scrollTop=0,n&&d.reflow(this._element),o.default(this._element).addClass(ct),this._config.focus&&this._enforceFocus();var a=o.default.Event("shown.bs.modal",{relatedTarget:t}),s=function(){e._config.focus&&e._element.focus(),e._isTransitioning=!1,o.default(e._element).trigger(a)};if(n){var l=d.getTransitionDurationFromElement(this._dialog);o.default(this._dialog).one(d.TRANSITION_END,s).emulateTransitionEnd(l)}else s()},e._enforceFocus=function(){var t=this;o.default(document).off(pt).on(pt,(function(e){document!==e.target&&t._element!==e.target&&0===o.default(t._element).has(e.target).length&&t._element.focus()}))},e._setEscapeEvent=function(){var t=this;this._isShown?o.default(this._element).on(yt,(function(e){t._config.keyboard&&27===e.which?(e.preventDefault(),t.hide()):t._config.keyboard||27!==e.which||t._triggerBackdropTransition()})):this._isShown||o.default(this._element).off(yt)},e._setResizeEvent=function(){var t=this;this._isShown?o.default(window).on(_t,(function(e){return t.handleUpdate(e)})):o.default(window).off(_t)},e._hideModal=function(){var t=this;this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._showBackdrop((function(){o.default(document.body).removeClass(ft),t._resetAdjustments(),t._resetScrollbar(),o.default(t._element).trigger(gt)}))},e._removeBackdrop=function(){this._backdrop&&(o.default(this._backdrop).remove(),this._backdrop=null)},e._showBackdrop=function(t){var e=this,n=o.default(this._element).hasClass(dt)?dt:"";if(this._isShown&&this._config.backdrop){if(this._backdrop=document.createElement("div"),this._backdrop.className="modal-backdrop",n&&this._backdrop.classList.add(n),o.default(this._backdrop).appendTo(document.body),o.default(this._element).on(vt,(function(t){e._ignoreBackdropClick?e._ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"===e._config.backdrop?e._triggerBackdropTransition():e.hide())})),n&&d.reflow(this._backdrop),o.default(this._backdrop).addClass(ct),!t)return;if(!n)return void t();var i=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,t).emulateTransitionEnd(i)}else if(!this._isShown&&this._backdrop){o.default(this._backdrop).removeClass(ct);var a=function(){e._removeBackdrop(),t&&t()};if(o.default(this._element).hasClass(dt)){var s=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a()}else t&&t()},e._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},e._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},e._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=Math.round(t.left+t.right)
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",customClass:"",sanitize:!0,sanitizeFn:null,whiteList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},Ut={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string|function)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",whiteList:"object",popperConfig:"(null|object)"},Mt={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},Wt=function(){function t(t,e){if("undefined"==typeof a.default)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var e=t.prototype;return e.enable=function(){this._isEnabled=!0},e.disable=function(){this._isEnabled=!1},e.toggleEnabled=function(){this._isEnabled=!this._isEnabled},e.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=o.default(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(o.default(this.getTipElement()).hasClass(Rt))return void this._leave(null,this);this._enter(null,this)}},e.dispose=function(){clearTimeout(this._timeout),o.default.removeData(this.element,this.constructor.DATA_KEY),o.default(this.element).off(this.constructor.EVENT_KEY),o.default(this.element).closest(".modal").off("hide.bs.modal",this._hideModalHandler),this.tip&&o.default(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},e.show=function(){var t=this;if("none"===o.default(this.element).css("display"))throw new Error("Please use show on visible elements");var e=o.default.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){o.default(this.element).trigger(e);var n=d.findShadowRoot(this.element),i=o.default.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(e.isDefaultPrevented()||!i)return;var s=this.getTipElement(),l=d.getUID(this.constructor.NAME);s.setAttribute("id",l),this.element.setAttribute("aria-describedby",l),this.setContent(),this.config.animation&&o.default(s).addClass(Lt);var r="function"==typeof this.config.placement?this.config.placement.call(this,s,this.element):this.config.placement,u=this._getAttachment(r);this.addAttachmentClass(u);var f=this._getContainer();o.default(s).data(this.constructor.DATA_KEY,this),o.default.contains(this.element.ownerDocument.documentElement,this.tip)||o.default(s).appendTo(f),o.default(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new a.default(this.element,s,this._getPopperConfig(u)),o.default(s).addClass(Rt),o.default(s).addClass(this.config.customClass),"ontouchstart"in document.documentElement&&o.default(document.body).children().on("mouseover",null,o.default.noop);var c=function(){t.config.animation&&t._fixTransition();var e=t._hoverState;t._hoverState=null,o.default(t.element).trigger(t.constructor.Event.SHOWN),e===qt&&t._leave(null,t)};if(o.default(this.tip).hasClass(Lt)){var h=d.getTransitionDurationFromElement(this.tip);o.default(this.tip).one(d.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},e.hide=function(t){var e=this,n=this.getTipElement(),i=o.default.Event(this.constructor.Event.HIDE),a=function(){e._hoverState!==xt&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),o.default(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(o.default(this.element).trigger(i),!i.isDefaultPrevented()){if(o.default(n).removeClass(Rt),"ontouchstart"in document.documentElement&&o.default(document.body).children().off("mouseover",null,o.default.noop),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,o.default(this.tip).hasClass(Lt)){var s=d.getTransitionDurationFromElement(n);o.default(n).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a();this._hoverState=""}},e.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},e.isWithContent=function(){return Boolean(this.getTitle())},e.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-tooltip-"+t)},e.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},e.setContent=function(){var t=this.getTipElement();this.setElementContent(o.default(t.querySelectorAll(".tooltip-inner")),this.getTitle()),o.default(t).removeClass("fade show")},e.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=At(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?o.default(e).parent().is(t)||t.empty().append(e):t.text(o.default(e).text())},e.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},e._getPopperConfig=function(t){var e=this;return r({},{placement:t,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:".arrow"},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}},this.config.popperConfig)},e._getOffset=function(){var t=this,e={};return"function"==typeof this.config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t.config.offset(e.offsets,t.element)),e}:e.offset=this.config.offset,e},e._getContainer=function(){return!1===this.config.container?document.body:d.isElement(this.config.container)?o.default(this.config.container):o.default(document).find(this.config.container)},e._getAttachment=function(t){return Bt[t.toUpperCase()]},e._setListeners=function(){var t=this;this.config.trigger.split(" ").forEach((function(e){if("click"===e)o.default(t.element).on(t.constructor.Event.CLICK,t.config.selector,(function(e){return t.toggle(e)}));else if("manual"!==e){var n=e===Ft?t.constructor.Event.MOUSEENTER:t.constructor.Event.FOCUSIN,i=e===Ft?t.constructor.Event.MOUSELEAVE:t.constructor.Event.FOCUSOUT;o.default(t.element).on(n,t.config.selector,(function(e){return t._enter(e)})).on(i,t.config.selector,(function(e){return t._leave(e)}))}})),this._hideModalHandler=function(){t.element&&t.hide()},o.default(this.element).closest(".modal").on("hide.bs.modal",this._hideModalHandler),this.config.selector?this.config=r({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},e._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},e._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Qt:Ft]=!0),o.default(e.getTipElement()).hasClass(Rt)||e._hoverState===xt?e._hoverState=xt:(clearTimeout(e._timeout),e._hoverState=xt,e.config.delay&&e.config.delay.show?e._timeout=setTimeout((function(){e._hoverState===xt&&e.show()}),e.config.delay.show):e.show())},e._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Qt:Ft]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=qt,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout((function(){e._hoverState===qt&&e.hide()}),e.config.delay.hide):e.hide())},e._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},e._getConfig=function(t){var e=o.default(this.element).data();return Object.keys(e).forEach((function(t){-1!==Pt.indexOf(t)&&delete e[t]})),"number"==typeof(t=r({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),d.typeCheckConfig(It,t,this.constructor.DefaultType),t.sanitize&&(t.template=At(t.template,t.whiteList,t.sanitizeFn)),t},e._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},e._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(jt);null!==e&&e.length&&t.removeClass(e.join(""))},e._handlePopperPlacementChange=function(t){this.tip=t.instance.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},e._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(o.default(t).removeClass(Lt),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(kt),a="object"==typeof e&&e;if((i||!/dispose|hide/.test(e))&&(i||(i=new t(this,a),n.data(kt,i)),"string"==typeof e)){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Ht}},{key:"NAME",get:function(){return It}},{key:"DATA_KEY",get:function(){return kt}},{key:"Event",get:function(){return Mt}},{key:"EVENT_KEY",get:function(){return".bs.tooltip"}},{key:"DefaultType",get:function(){return Ut}}]),t}();o.default.fn.tooltip=Wt._jQueryInterface,o.default.fn.tooltip.Constructor=Wt,o.default.fn.tooltip.noConflict=function(){return o.default.fn.tooltip=Ot,Wt._jQueryInterface};var Vt="bs.popover",zt=o.default.fn.popover,Kt=new RegExp("(^|\\s)bs-popover\\S+","g"),Xt=r({},Wt.Default,{placement:"right",trigger:"click",content:"",template:''}),Yt=r({},Wt.DefaultType,{content:"(string|element|function)"}),$t={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"},Jt=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),e.prototype.constructor=e,u(e,n);var a=i.prototype;return a.isWithContent=function(){return this.getTitle()||this._getContent()},a.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-popover-"+t)},a.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},a.setContent=function(){var t=o.default(this.getTipElement());this.setElementContent(t.find(".popover-header"),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(".popover-body"),e),t.removeClass("fade show")},a._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},a._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(Kt);null!==e&&e.length>0&&t.removeClass(e.join(""))},i._jQueryInterface=function(t){return this.each((function(){var e=o.default(this).data(Vt),n="object"==typeof t?t:null;if((e||!/dispose|hide/.test(t))&&(e||(e=new i(this,n),o.default(this).data(Vt,e)),"string"==typeof t)){if("undefined"==typeof e[t])throw new TypeError('No method named "'+t+'"');e[t]()}}))},l(i,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Xt}},{key:"NAME",get:function(){return"popover"}},{key:"DATA_KEY",get:function(){return Vt}},{key:"Event",get:function(){return $t}},{key:"EVENT_KEY",get:function(){return".bs.popover"}},{key:"DefaultType",get:function(){return Yt}}]),i}(Wt);o.default.fn.popover=Jt._jQueryInterface,o.default.fn.popover.Constructor=Jt,o.default.fn.popover.noConflict=function(){return o.default.fn.popover=zt,Jt._jQueryInterface};var Gt="scrollspy",Zt="bs.scrollspy",te=o.default.fn[Gt],ee="active",ne="position",ie=".nav, .list-group",oe={offset:10,method:"auto",target:""},ae={offset:"number",method:"string",target:"(string|element)"},se=function(){function t(t,e){var n=this;this._element=t,this._scrollElement="BODY"===t.tagName?window:t,this._config=this._getConfig(e),this._selector=this._config.target+" .nav-link,"+this._config.target+" .list-group-item,"+this._config.target+" .dropdown-item",this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,o.default(this._scrollElement).on("scroll.bs.scrollspy",(function(t){return n._process(t)})),this.refresh(),this._process()}var e=t.prototype;return e.refresh=function(){var t=this,e=this._scrollElement===this._scrollElement.window?"offset":ne,n="auto"===this._config.method?e:this._config.method,i=n===ne?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),[].slice.call(document.querySelectorAll(this._selector)).map((function(t){var e,a=d.getSelectorFromElement(t);if(a&&(e=document.querySelector(a)),e){var s=e.getBoundingClientRect();if(s.width||s.height)return[o.default(e)[n]().top+i,a]}return null})).filter((function(t){return t})).sort((function(t,e){return t[0]-e[0]})).forEach((function(e){t._offsets.push(e[0]),t._targets.push(e[1])}))},e.dispose=function(){o.default.removeData(this._element,Zt),o.default(this._scrollElement).off(".bs.scrollspy"),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},e._getConfig=function(t){if("string"!=typeof(t=r({},oe,"object"==typeof t&&t?t:{})).target&&d.isElement(t.target)){var e=o.default(t.target).attr("id");e||(e=d.getUID(Gt),o.default(t.target).attr("id",e)),t.target="#"+e}return d.typeCheckConfig(Gt,t,ae),t},e._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},e._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},e._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},e._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;)this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||t li > .active",ge=function(){function t(t){this._element=t}var e=t.prototype;return e.show=function(){var t=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&o.default(this._element).hasClass(ue)||o.default(this._element).hasClass("disabled"))){var e,n,i=o.default(this._element).closest(".nav, .list-group")[0],a=d.getSelectorFromElement(this._element);if(i){var s="UL"===i.nodeName||"OL"===i.nodeName?he:ce;n=(n=o.default.makeArray(o.default(i).find(s)))[n.length-1]}var l=o.default.Event("hide.bs.tab",{relatedTarget:this._element}),r=o.default.Event("show.bs.tab",{relatedTarget:n});if(n&&o.default(n).trigger(l),o.default(this._element).trigger(r),!r.isDefaultPrevented()&&!l.isDefaultPrevented()){a&&(e=document.querySelector(a)),this._activate(this._element,i);var u=function(){var e=o.default.Event("hidden.bs.tab",{relatedTarget:t._element}),i=o.default.Event("shown.bs.tab",{relatedTarget:n});o.default(n).trigger(e),o.default(t._element).trigger(i)};e?this._activate(e,e.parentNode,u):u()}}},e.dispose=function(){o.default.removeData(this._element,le),this._element=null},e._activate=function(t,e,n){var i=this,a=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?o.default(e).children(ce):o.default(e).find(he))[0],s=n&&a&&o.default(a).hasClass(fe),l=function(){return i._transitionComplete(t,a,n)};if(a&&s){var r=d.getTransitionDurationFromElement(a);o.default(a).removeClass(de).one(d.TRANSITION_END,l).emulateTransitionEnd(r)}else l()},e._transitionComplete=function(t,e,n){if(e){o.default(e).removeClass(ue);var i=o.default(e.parentNode).find("> .dropdown-menu .active")[0];i&&o.default(i).removeClass(ue),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}o.default(t).addClass(ue),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),d.reflow(t),t.classList.contains(fe)&&t.classList.add(de);var a=t.parentNode;if(a&&"LI"===a.nodeName&&(a=a.parentNode),a&&o.default(a).hasClass("dropdown-menu")){var s=o.default(t).closest(".dropdown")[0];if(s){var l=[].slice.call(s.querySelectorAll(".dropdown-toggle"));o.default(l).addClass(ue)}t.setAttribute("aria-expanded",!0)}n&&n()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(le);if(i||(i=new t(this),n.data(le,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',(function(t){t.preventDefault(),ge._jQueryInterface.call(o.default(this),"show")})),o.default.fn.tab=ge._jQueryInterface,o.default.fn.tab.Constructor=ge,o.default.fn.tab.noConflict=function(){return o.default.fn.tab=re,ge._jQueryInterface};var me="bs.toast",pe=o.default.fn.toast,_e="hide",ve="show",ye="showing",be="click.dismiss.bs.toast",Ee={animation:!0,autohide:!0,delay:500},Te={animation:"boolean",autohide:"boolean",delay:"number"},we=function(){function t(t,e){this._element=t,this._config=this._getConfig(e),this._timeout=null,this._setListeners()}var e=t.prototype;return e.show=function(){var t=this,e=o.default.Event("show.bs.toast");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){this._clearTimeout(),this._config.animation&&this._element.classList.add("fade");var n=function(){t._element.classList.remove(ye),t._element.classList.add(ve),o.default(t._element).trigger("shown.bs.toast"),t._config.autohide&&(t._timeout=setTimeout((function(){t.hide()}),t._config.delay))};if(this._element.classList.remove(_e),d.reflow(this._element),this._element.classList.add(ye),this._config.animation){var i=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,n).emulateTransitionEnd(i)}else n()}},e.hide=function(){if(this._element.classList.contains(ve)){var t=o.default.Event("hide.bs.toast");o.default(this._element).trigger(t),t.isDefaultPrevented()||this._close()}},e.dispose=function(){this._clearTimeout(),this._element.classList.contains(ve)&&this._element.classList.remove(ve),o.default(this._element).off(be),o.default.removeData(this._element,me),this._element=null,this._config=null},e._getConfig=function(t){return t=r({},Ee,o.default(this._element).data(),"object"==typeof t&&t?t:{}),d.typeCheckConfig("toast",t,this.constructor.DefaultType),t},e._setListeners=function(){var t=this;o.default(this._element).on(be,'[data-dismiss="toast"]',(function(){return t.hide()}))},e._close=function(){var t=this,e=function(){t._element.classList.add(_e),o.default(t._element).trigger("hidden.bs.toast")};if(this._element.classList.remove(ve),this._config.animation){var n=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},e._clearTimeout=function(){clearTimeout(this._timeout),this._timeout=null},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(me);if(i||(i=new t(this,"object"==typeof e&&e),n.data(me,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e](this)}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"DefaultType",get:function(){return Te}},{key:"Default",get:function(){return Ee}}]),t}();o.default.fn.toast=we._jQueryInterface,o.default.fn.toast.Constructor=we,o.default.fn.toast.noConflict=function(){return o.default.fn.toast=pe,we._jQueryInterface},t.Alert=g,t.Button=E,t.Carousel=P,t.Collapse=V,t.Dropdown=lt,t.Modal=Ct,t.Popover=Jt,t.Scrollspy=se,t.Tab=ge,t.Toast=we,t.Tooltip=Wt,t.Util=d,Object.defineProperty(t,"__esModule",{value:!0})})); +//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/code/ch4_app/ch4_final_video_collector/static/js/jquery-3.5.1.slim.min.js b/code/ch4_app/ch4_final_video_collector/static/js/jquery-3.5.1.slim.min.js new file mode 100644 index 0000000..36b4e1a --- /dev/null +++ b/code/ch4_app/ch4_final_video_collector/static/js/jquery-3.5.1.slim.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(g,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,v=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),m={},b=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},w=g.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function C(e,t,n){var r,i,o=(n=n||w).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function T(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector",E=function(e,t){return new E.fn.init(e,t)};function d(e){var t=!!e&&"length"in e&&e.length,n=T(e);return!b(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+R+")"+R+"*"),U=new RegExp(R+"|>"),V=new RegExp(W),X=new RegExp("^"+B+"$"),Q={ID:new RegExp("^#("+B+")"),CLASS:new RegExp("^\\.("+B+")"),TAG:new RegExp("^("+B+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+R+"*(even|odd|(([+-]|)(\\d*)n|)"+R+"*(?:([+-]|)"+R+"*(\\d+)|))"+R+"*\\)|)","i"),bool:new RegExp("^(?:"+I+")$","i"),needsContext:new RegExp("^"+R+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+R+"*((?:-\\d)?\\d*)"+R+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,G=/^(?:input|select|textarea|button)$/i,K=/^h\d$/i,J=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+R+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){C()},ae=xe(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{O.apply(t=P.call(d.childNodes),d.childNodes),t[d.childNodes.length].nodeType}catch(e){O={apply:t.length?function(e,t){q.apply(e,P.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,d=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==d&&9!==d&&11!==d)return n;if(!r&&(C(e),e=e||T,E)){if(11!==d&&(u=Z.exec(t)))if(i=u[1]){if(9===d){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return O.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&p.getElementsByClassName&&e.getElementsByClassName)return O.apply(n,e.getElementsByClassName(i)),n}if(p.qsa&&!k[t+" "]&&(!v||!v.test(t))&&(1!==d||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===d&&(U.test(t)||_.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&p.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=A)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+be(l[o]);c=l.join(",")}try{return O.apply(n,f.querySelectorAll(c)),n}catch(e){k(t,!0)}finally{s===A&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>x.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[A]=!0,e}function ce(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)x.attrHandle[n[r]]=t}function de(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pe(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in p=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},C=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:d;return r!=T&&9===r.nodeType&&r.documentElement&&(a=(T=r).documentElement,E=!i(T),d!=T&&(n=T.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),p.scope=ce(function(e){return a.appendChild(e).appendChild(T.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),p.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),p.getElementsByTagName=ce(function(e){return e.appendChild(T.createComment("")),!e.getElementsByTagName("*").length}),p.getElementsByClassName=J.test(T.getElementsByClassName),p.getById=ce(function(e){return a.appendChild(e).id=A,!T.getElementsByName||!T.getElementsByName(A).length}),p.getById?(x.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(x.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),x.find.TAG=p.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):p.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},x.find.CLASS=p.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(p.qsa=J.test(T.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+R+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+R+"*(?:value|"+I+")"),e.querySelectorAll("[id~="+A+"-]").length||v.push("~="),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+R+"*name"+R+"*="+R+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+A+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=T.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+R+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(p.matchesSelector=J.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){p.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",W)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=J.test(a.compareDocumentPosition),y=t||J.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!p.sortDetached&&t.compareDocumentPosition(e)===n?e==T||e.ownerDocument==d&&y(d,e)?-1:t==T||t.ownerDocument==d&&y(d,t)?1:u?H(u,e)-H(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==T?-1:t==T?1:i?-1:o?1:u?H(u,e)-H(u,t):0;if(i===o)return de(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?de(a[r],s[r]):a[r]==d?-1:s[r]==d?1:0}),T},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(C(e),p.matchesSelector&&E&&!k[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||p.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){k(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&V.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+R+")"+e+"("+R+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return b(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):"string"!=typeof n?E.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||L,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:j.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:w,!0)),k.test(r[1])&&E.isPlainObject(t))for(r in t)b(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=w.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):b(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,L=E(w);var q=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,pe=/^$|^module$|\/(?:java|ecma)script/i;le=w.createDocumentFragment().appendChild(w.createElement("div")),(ce=w.createElement("input")).setAttribute("type","radio"),ce.setAttribute("checked","checked"),ce.setAttribute("name","t"),le.appendChild(ce),m.checkClone=le.cloneNode(!0).cloneNode(!0).lastChild.checked,le.innerHTML="",m.noCloneChecked=!!le.cloneNode(!0).lastChild.defaultValue,le.innerHTML="",m.option=!!le.lastChild;var he={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ge(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&S(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var ye=/<|&#?\w+;/;function me(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),d=[],p=0,h=e.length;p\s*$/g;function Le(e,t){return S(e,"table")&&S(11!==t.nodeType?t:t.firstChild,"tr")&&E(e).children("tbody")[0]||e}function je(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n
",2===ft.childNodes.length),E.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(m.createHTMLDocument?((r=(t=w.implementation.createHTMLDocument("")).createElement("base")).href=w.location.href,t.head.appendChild(r)):t=w),o=!n&&[],(i=k.exec(e))?[t.createElement(i[1])]:(i=me([e],t,o),o&&o.length&&E(o).remove(),E.merge([],i.childNodes)));var r,i,o},E.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=E.css(e,"position"),c=E(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=E.css(e,"top"),u=E.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),b(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===E.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===E.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=E(e).offset()).top+=E.css(e,"borderTopWidth",!0),i.left+=E.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-E.css(r,"marginTop",!0),left:t.left-i.left-E.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===E.css(e,"position"))e=e.offsetParent;return e||re})}}),E.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;E.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each(["top","left"],function(e,n){E.cssHooks[n]=Fe(m.pixelPosition,function(e,t){if(t)return t=We(e,n),Ie.test(t)?E(e).position()[n]+"px":t})}),E.each({Height:"height",Width:"width"},function(a,s){E.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){E.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?E.css(e,t,i):E.style(e,t,n,i)},s,n?e:void 0,n)}})}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){E.fn[n]=function(e,t){return 0=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),ae({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=le({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f]),E=parseFloat(w['border'+f+'Width']),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},ae(n,m,$(v)),ae(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ce.FLIP:p=[n,i];break;case ce.CLOCKWISE:p=G(n);break;case ce.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u),E=!!t.flipVariationsByContent&&(w&&'start'===r&&c||w&&'end'===r&&h||!w&&'start'===r&&u||!w&&'end'===r&&g),v=y||E;(m||b||v)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),v&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=le({},e.offsets.popper,C(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport',flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=D(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.rightwindow.devicePixelRatio||!fe),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=B('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=le({},E,e.attributes),e.styles=le({},m,e.styles),e.arrowStyles=le({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return V(e.instance.popper,e.styles),j(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&V(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),V(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ge}); +//# sourceMappingURL=popper.min.js.map diff --git a/code/ch4_app/ch4_starter_video_collector/static/js/bootstrap-4.6.1.min.js b/code/ch4_app/ch4_starter_video_collector/static/js/bootstrap-4.6.1.min.js new file mode 100644 index 0000000..50720ea --- /dev/null +++ b/code/ch4_app/ch4_starter_video_collector/static/js/bootstrap-4.6.1.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.6.1 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap={},t.jQuery,t.Popper)}(this,(function(t,e,n){"use strict";function i(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var o=i(e),a=i(n);function s(t,e){for(var n=0;n=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}};d.jQueryDetection(),o.default.fn.emulateTransitionEnd=function(t){var e=this,n=!1;return o.default(this).one(d.TRANSITION_END,(function(){n=!0})),setTimeout((function(){n||d.triggerTransitionEnd(e)}),t),this},o.default.event.special[d.TRANSITION_END]={bindType:f,delegateType:f,handle:function(t){if(o.default(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}};var c="bs.alert",h=o.default.fn.alert,g=function(){function t(t){this._element=t}var e=t.prototype;return e.close=function(t){var e=this._element;t&&(e=this._getRootElement(t)),this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.dispose=function(){o.default.removeData(this._element,c),this._element=null},e._getRootElement=function(t){var e=d.getSelectorFromElement(t),n=!1;return e&&(n=document.querySelector(e)),n||(n=o.default(t).closest(".alert")[0]),n},e._triggerCloseEvent=function(t){var e=o.default.Event("close.bs.alert");return o.default(t).trigger(e),e},e._removeElement=function(t){var e=this;if(o.default(t).removeClass("show"),o.default(t).hasClass("fade")){var n=d.getTransitionDurationFromElement(t);o.default(t).one(d.TRANSITION_END,(function(n){return e._destroyElement(t,n)})).emulateTransitionEnd(n)}else this._destroyElement(t)},e._destroyElement=function(t){o.default(t).detach().trigger("closed.bs.alert").remove()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(c);i||(i=new t(this),n.data(c,i)),"close"===e&&i[e](this)}))},t._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',g._handleDismiss(new g)),o.default.fn.alert=g._jQueryInterface,o.default.fn.alert.Constructor=g,o.default.fn.alert.noConflict=function(){return o.default.fn.alert=h,g._jQueryInterface};var m="bs.button",p=o.default.fn.button,_="active",v='[data-toggle^="button"]',y='input:not([type="hidden"])',b=".btn",E=function(){function t(t){this._element=t,this.shouldAvoidTriggerChange=!1}var e=t.prototype;return e.toggle=function(){var t=!0,e=!0,n=o.default(this._element).closest('[data-toggle="buttons"]')[0];if(n){var i=this._element.querySelector(y);if(i){if("radio"===i.type)if(i.checked&&this._element.classList.contains(_))t=!1;else{var a=n.querySelector(".active");a&&o.default(a).removeClass(_)}t&&("checkbox"!==i.type&&"radio"!==i.type||(i.checked=!this._element.classList.contains(_)),this.shouldAvoidTriggerChange||o.default(i).trigger("change")),i.focus(),e=!1}}this._element.hasAttribute("disabled")||this._element.classList.contains("disabled")||(e&&this._element.setAttribute("aria-pressed",!this._element.classList.contains(_)),t&&o.default(this._element).toggleClass(_))},e.dispose=function(){o.default.removeData(this._element,m),this._element=null},t._jQueryInterface=function(e,n){return this.each((function(){var i=o.default(this),a=i.data(m);a||(a=new t(this),i.data(m,a)),a.shouldAvoidTriggerChange=n,"toggle"===e&&a[e]()}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.button.data-api",v,(function(t){var e=t.target,n=e;if(o.default(e).hasClass("btn")||(e=o.default(e).closest(b)[0]),!e||e.hasAttribute("disabled")||e.classList.contains("disabled"))t.preventDefault();else{var i=e.querySelector(y);if(i&&(i.hasAttribute("disabled")||i.classList.contains("disabled")))return void t.preventDefault();"INPUT"!==n.tagName&&"LABEL"===e.tagName||E._jQueryInterface.call(o.default(e),"toggle","INPUT"===n.tagName)}})).on("focus.bs.button.data-api blur.bs.button.data-api",v,(function(t){var e=o.default(t.target).closest(b)[0];o.default(e).toggleClass("focus",/^focus(in)?$/.test(t.type))})),o.default(window).on("load.bs.button.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-toggle="buttons"] .btn')),e=0,n=t.length;e0,this._pointerEvent=Boolean(window.PointerEvent||window.MSPointerEvent),this._addEventListeners()}var e=t.prototype;return e.next=function(){this._isSliding||this._slide(N)},e.nextWhenVisible=function(){var t=o.default(this._element);!document.hidden&&t.is(":visible")&&"hidden"!==t.css("visibility")&&this.next()},e.prev=function(){this._isSliding||this._slide(D)},e.pause=function(t){t||(this._isPaused=!0),this._element.querySelector(".carousel-item-next, .carousel-item-prev")&&(d.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},e.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},e.to=function(t){var e=this;this._activeElement=this._element.querySelector(I);var n=this._getItemIndex(this._activeElement);if(!(t>this._items.length-1||t<0))if(this._isSliding)o.default(this._element).one(A,(function(){return e.to(t)}));else{if(n===t)return this.pause(),void this.cycle();var i=t>n?N:D;this._slide(i,this._items[t])}},e.dispose=function(){o.default(this._element).off(".bs.carousel"),o.default.removeData(this._element,w),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},e._getConfig=function(t){return t=r({},k,t),d.typeCheckConfig(T,t,O),t},e._handleSwipe=function(){var t=Math.abs(this.touchDeltaX);if(!(t<=40)){var e=t/this.touchDeltaX;this.touchDeltaX=0,e>0&&this.prev(),e<0&&this.next()}},e._addEventListeners=function(){var t=this;this._config.keyboard&&o.default(this._element).on("keydown.bs.carousel",(function(e){return t._keydown(e)})),"hover"===this._config.pause&&o.default(this._element).on("mouseenter.bs.carousel",(function(e){return t.pause(e)})).on("mouseleave.bs.carousel",(function(e){return t.cycle(e)})),this._config.touch&&this._addTouchEventListeners()},e._addTouchEventListeners=function(){var t=this;if(this._touchSupported){var e=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]?t.touchStartX=e.originalEvent.clientX:t._pointerEvent||(t.touchStartX=e.originalEvent.touches[0].clientX)},n=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]&&(t.touchDeltaX=e.originalEvent.clientX-t.touchStartX),t._handleSwipe(),"hover"===t._config.pause&&(t.pause(),t.touchTimeout&&clearTimeout(t.touchTimeout),t.touchTimeout=setTimeout((function(e){return t.cycle(e)}),500+t._config.interval))};o.default(this._element.querySelectorAll(".carousel-item img")).on("dragstart.bs.carousel",(function(t){return t.preventDefault()})),this._pointerEvent?(o.default(this._element).on("pointerdown.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("pointerup.bs.carousel",(function(t){return n(t)})),this._element.classList.add("pointer-event")):(o.default(this._element).on("touchstart.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("touchmove.bs.carousel",(function(e){return function(e){t.touchDeltaX=e.originalEvent.touches&&e.originalEvent.touches.length>1?0:e.originalEvent.touches[0].clientX-t.touchStartX}(e)})),o.default(this._element).on("touchend.bs.carousel",(function(t){return n(t)})))}},e._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next()}},e._getItemIndex=function(t){return this._items=t&&t.parentNode?[].slice.call(t.parentNode.querySelectorAll(".carousel-item")):[],this._items.indexOf(t)},e._getItemByDirection=function(t,e){var n=t===N,i=t===D,o=this._getItemIndex(e),a=this._items.length-1;if((i&&0===o||n&&o===a)&&!this._config.wrap)return e;var s=(o+(t===D?-1:1))%this._items.length;return-1===s?this._items[this._items.length-1]:this._items[s]},e._triggerSlideEvent=function(t,e){var n=this._getItemIndex(t),i=this._getItemIndex(this._element.querySelector(I)),a=o.default.Event("slide.bs.carousel",{relatedTarget:t,direction:e,from:i,to:n});return o.default(this._element).trigger(a),a},e._setActiveIndicatorElement=function(t){if(this._indicatorsElement){var e=[].slice.call(this._indicatorsElement.querySelectorAll(".active"));o.default(e).removeClass(S);var n=this._indicatorsElement.children[this._getItemIndex(t)];n&&o.default(n).addClass(S)}},e._updateInterval=function(){var t=this._activeElement||this._element.querySelector(I);if(t){var e=parseInt(t.getAttribute("data-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}},e._slide=function(t,e){var n,i,a,s=this,l=this._element.querySelector(I),r=this._getItemIndex(l),u=e||l&&this._getItemByDirection(t,l),f=this._getItemIndex(u),c=Boolean(this._interval);if(t===N?(n="carousel-item-left",i="carousel-item-next",a="left"):(n="carousel-item-right",i="carousel-item-prev",a="right"),u&&o.default(u).hasClass(S))this._isSliding=!1;else if(!this._triggerSlideEvent(u,a).isDefaultPrevented()&&l&&u){this._isSliding=!0,c&&this.pause(),this._setActiveIndicatorElement(u),this._activeElement=u;var h=o.default.Event(A,{relatedTarget:u,direction:a,from:r,to:f});if(o.default(this._element).hasClass("slide")){o.default(u).addClass(i),d.reflow(u),o.default(l).addClass(n),o.default(u).addClass(n);var g=d.getTransitionDurationFromElement(l);o.default(l).one(d.TRANSITION_END,(function(){o.default(u).removeClass(n+" "+i).addClass(S),o.default(l).removeClass("active "+i+" "+n),s._isSliding=!1,setTimeout((function(){return o.default(s._element).trigger(h)}),0)})).emulateTransitionEnd(g)}else o.default(l).removeClass(S),o.default(u).addClass(S),this._isSliding=!1,o.default(this._element).trigger(h);c&&this.cycle()}},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(w),i=r({},k,o.default(this).data());"object"==typeof e&&(i=r({},i,e));var a="string"==typeof e?e:i.slide;if(n||(n=new t(this,i),o.default(this).data(w,n)),"number"==typeof e)n.to(e);else if("string"==typeof a){if("undefined"==typeof n[a])throw new TypeError('No method named "'+a+'"');n[a]()}else i.interval&&i.ride&&(n.pause(),n.cycle())}))},t._dataApiClickHandler=function(e){var n=d.getSelectorFromElement(this);if(n){var i=o.default(n)[0];if(i&&o.default(i).hasClass("carousel")){var a=r({},o.default(i).data(),o.default(this).data()),s=this.getAttribute("data-slide-to");s&&(a.interval=!1),t._jQueryInterface.call(o.default(i),a),s&&o.default(i).data(w).to(s),e.preventDefault()}}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return k}}]),t}();o.default(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",P._dataApiClickHandler),o.default(window).on("load.bs.carousel.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-ride="carousel"]')),e=0,n=t.length;e0&&(this._selector=s,this._triggerArray.push(a))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}var e=t.prototype;return e.toggle=function(){o.default(this._element).hasClass(q)?this.hide():this.show()},e.show=function(){var e,n,i=this;if(!(this._isTransitioning||o.default(this._element).hasClass(q)||(this._parent&&0===(e=[].slice.call(this._parent.querySelectorAll(".show, .collapsing")).filter((function(t){return"string"==typeof i._config.parent?t.getAttribute("data-parent")===i._config.parent:t.classList.contains(F)}))).length&&(e=null),e&&(n=o.default(e).not(this._selector).data(R))&&n._isTransitioning))){var a=o.default.Event("show.bs.collapse");if(o.default(this._element).trigger(a),!a.isDefaultPrevented()){e&&(t._jQueryInterface.call(o.default(e).not(this._selector),"hide"),n||o.default(e).data(R,null));var s=this._getDimension();o.default(this._element).removeClass(F).addClass(Q),this._element.style[s]=0,this._triggerArray.length&&o.default(this._triggerArray).removeClass(B).attr("aria-expanded",!0),this.setTransitioning(!0);var l="scroll"+(s[0].toUpperCase()+s.slice(1)),r=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,(function(){o.default(i._element).removeClass(Q).addClass("collapse show"),i._element.style[s]="",i.setTransitioning(!1),o.default(i._element).trigger("shown.bs.collapse")})).emulateTransitionEnd(r),this._element.style[s]=this._element[l]+"px"}}},e.hide=function(){var t=this;if(!this._isTransitioning&&o.default(this._element).hasClass(q)){var e=o.default.Event("hide.bs.collapse");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){var n=this._getDimension();this._element.style[n]=this._element.getBoundingClientRect()[n]+"px",d.reflow(this._element),o.default(this._element).addClass(Q).removeClass("collapse show");var i=this._triggerArray.length;if(i>0)for(var a=0;a0},e._getOffset=function(){var t=this,e={};return"function"==typeof this._config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t._config.offset(e.offsets,t._element)),e}:e.offset=this._config.offset,e},e._getPopperConfig=function(){var t={placement:this._getPlacement(),modifiers:{offset:this._getOffset(),flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}};return"static"===this._config.display&&(t.modifiers.applyStyle={enabled:!1}),r({},t,this._config.popperConfig)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(K);if(n||(n=new t(this,"object"==typeof e?e:null),o.default(this).data(K,n)),"string"==typeof e){if("undefined"==typeof n[e])throw new TypeError('No method named "'+e+'"');n[e]()}}))},t._clearMenus=function(e){if(!e||3!==e.which&&("keyup"!==e.type||9===e.which))for(var n=[].slice.call(document.querySelectorAll(it)),i=0,a=n.length;i0&&s--,40===e.which&&sdocument.documentElement.clientHeight;n||(this._element.style.overflowY="hidden"),this._element.classList.add(ht);var i=d.getTransitionDurationFromElement(this._dialog);o.default(this._element).off(d.TRANSITION_END),o.default(this._element).one(d.TRANSITION_END,(function(){t._element.classList.remove(ht),n||o.default(t._element).one(d.TRANSITION_END,(function(){t._element.style.overflowY=""})).emulateTransitionEnd(t._element,i)})).emulateTransitionEnd(i),this._element.focus()}},e._showElement=function(t){var e=this,n=o.default(this._element).hasClass(dt),i=this._dialog?this._dialog.querySelector(".modal-body"):null;this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),o.default(this._dialog).hasClass("modal-dialog-scrollable")&&i?i.scrollTop=0:this._element.scrollTop=0,n&&d.reflow(this._element),o.default(this._element).addClass(ct),this._config.focus&&this._enforceFocus();var a=o.default.Event("shown.bs.modal",{relatedTarget:t}),s=function(){e._config.focus&&e._element.focus(),e._isTransitioning=!1,o.default(e._element).trigger(a)};if(n){var l=d.getTransitionDurationFromElement(this._dialog);o.default(this._dialog).one(d.TRANSITION_END,s).emulateTransitionEnd(l)}else s()},e._enforceFocus=function(){var t=this;o.default(document).off(pt).on(pt,(function(e){document!==e.target&&t._element!==e.target&&0===o.default(t._element).has(e.target).length&&t._element.focus()}))},e._setEscapeEvent=function(){var t=this;this._isShown?o.default(this._element).on(yt,(function(e){t._config.keyboard&&27===e.which?(e.preventDefault(),t.hide()):t._config.keyboard||27!==e.which||t._triggerBackdropTransition()})):this._isShown||o.default(this._element).off(yt)},e._setResizeEvent=function(){var t=this;this._isShown?o.default(window).on(_t,(function(e){return t.handleUpdate(e)})):o.default(window).off(_t)},e._hideModal=function(){var t=this;this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._showBackdrop((function(){o.default(document.body).removeClass(ft),t._resetAdjustments(),t._resetScrollbar(),o.default(t._element).trigger(gt)}))},e._removeBackdrop=function(){this._backdrop&&(o.default(this._backdrop).remove(),this._backdrop=null)},e._showBackdrop=function(t){var e=this,n=o.default(this._element).hasClass(dt)?dt:"";if(this._isShown&&this._config.backdrop){if(this._backdrop=document.createElement("div"),this._backdrop.className="modal-backdrop",n&&this._backdrop.classList.add(n),o.default(this._backdrop).appendTo(document.body),o.default(this._element).on(vt,(function(t){e._ignoreBackdropClick?e._ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"===e._config.backdrop?e._triggerBackdropTransition():e.hide())})),n&&d.reflow(this._backdrop),o.default(this._backdrop).addClass(ct),!t)return;if(!n)return void t();var i=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,t).emulateTransitionEnd(i)}else if(!this._isShown&&this._backdrop){o.default(this._backdrop).removeClass(ct);var a=function(){e._removeBackdrop(),t&&t()};if(o.default(this._element).hasClass(dt)){var s=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a()}else t&&t()},e._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},e._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},e._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=Math.round(t.left+t.right)
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",customClass:"",sanitize:!0,sanitizeFn:null,whiteList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},Ut={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string|function)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",whiteList:"object",popperConfig:"(null|object)"},Mt={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},Wt=function(){function t(t,e){if("undefined"==typeof a.default)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var e=t.prototype;return e.enable=function(){this._isEnabled=!0},e.disable=function(){this._isEnabled=!1},e.toggleEnabled=function(){this._isEnabled=!this._isEnabled},e.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=o.default(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(o.default(this.getTipElement()).hasClass(Rt))return void this._leave(null,this);this._enter(null,this)}},e.dispose=function(){clearTimeout(this._timeout),o.default.removeData(this.element,this.constructor.DATA_KEY),o.default(this.element).off(this.constructor.EVENT_KEY),o.default(this.element).closest(".modal").off("hide.bs.modal",this._hideModalHandler),this.tip&&o.default(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},e.show=function(){var t=this;if("none"===o.default(this.element).css("display"))throw new Error("Please use show on visible elements");var e=o.default.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){o.default(this.element).trigger(e);var n=d.findShadowRoot(this.element),i=o.default.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(e.isDefaultPrevented()||!i)return;var s=this.getTipElement(),l=d.getUID(this.constructor.NAME);s.setAttribute("id",l),this.element.setAttribute("aria-describedby",l),this.setContent(),this.config.animation&&o.default(s).addClass(Lt);var r="function"==typeof this.config.placement?this.config.placement.call(this,s,this.element):this.config.placement,u=this._getAttachment(r);this.addAttachmentClass(u);var f=this._getContainer();o.default(s).data(this.constructor.DATA_KEY,this),o.default.contains(this.element.ownerDocument.documentElement,this.tip)||o.default(s).appendTo(f),o.default(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new a.default(this.element,s,this._getPopperConfig(u)),o.default(s).addClass(Rt),o.default(s).addClass(this.config.customClass),"ontouchstart"in document.documentElement&&o.default(document.body).children().on("mouseover",null,o.default.noop);var c=function(){t.config.animation&&t._fixTransition();var e=t._hoverState;t._hoverState=null,o.default(t.element).trigger(t.constructor.Event.SHOWN),e===qt&&t._leave(null,t)};if(o.default(this.tip).hasClass(Lt)){var h=d.getTransitionDurationFromElement(this.tip);o.default(this.tip).one(d.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},e.hide=function(t){var e=this,n=this.getTipElement(),i=o.default.Event(this.constructor.Event.HIDE),a=function(){e._hoverState!==xt&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),o.default(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(o.default(this.element).trigger(i),!i.isDefaultPrevented()){if(o.default(n).removeClass(Rt),"ontouchstart"in document.documentElement&&o.default(document.body).children().off("mouseover",null,o.default.noop),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,o.default(this.tip).hasClass(Lt)){var s=d.getTransitionDurationFromElement(n);o.default(n).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a();this._hoverState=""}},e.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},e.isWithContent=function(){return Boolean(this.getTitle())},e.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-tooltip-"+t)},e.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},e.setContent=function(){var t=this.getTipElement();this.setElementContent(o.default(t.querySelectorAll(".tooltip-inner")),this.getTitle()),o.default(t).removeClass("fade show")},e.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=At(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?o.default(e).parent().is(t)||t.empty().append(e):t.text(o.default(e).text())},e.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},e._getPopperConfig=function(t){var e=this;return r({},{placement:t,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:".arrow"},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}},this.config.popperConfig)},e._getOffset=function(){var t=this,e={};return"function"==typeof this.config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t.config.offset(e.offsets,t.element)),e}:e.offset=this.config.offset,e},e._getContainer=function(){return!1===this.config.container?document.body:d.isElement(this.config.container)?o.default(this.config.container):o.default(document).find(this.config.container)},e._getAttachment=function(t){return Bt[t.toUpperCase()]},e._setListeners=function(){var t=this;this.config.trigger.split(" ").forEach((function(e){if("click"===e)o.default(t.element).on(t.constructor.Event.CLICK,t.config.selector,(function(e){return t.toggle(e)}));else if("manual"!==e){var n=e===Ft?t.constructor.Event.MOUSEENTER:t.constructor.Event.FOCUSIN,i=e===Ft?t.constructor.Event.MOUSELEAVE:t.constructor.Event.FOCUSOUT;o.default(t.element).on(n,t.config.selector,(function(e){return t._enter(e)})).on(i,t.config.selector,(function(e){return t._leave(e)}))}})),this._hideModalHandler=function(){t.element&&t.hide()},o.default(this.element).closest(".modal").on("hide.bs.modal",this._hideModalHandler),this.config.selector?this.config=r({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},e._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},e._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Qt:Ft]=!0),o.default(e.getTipElement()).hasClass(Rt)||e._hoverState===xt?e._hoverState=xt:(clearTimeout(e._timeout),e._hoverState=xt,e.config.delay&&e.config.delay.show?e._timeout=setTimeout((function(){e._hoverState===xt&&e.show()}),e.config.delay.show):e.show())},e._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Qt:Ft]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=qt,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout((function(){e._hoverState===qt&&e.hide()}),e.config.delay.hide):e.hide())},e._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},e._getConfig=function(t){var e=o.default(this.element).data();return Object.keys(e).forEach((function(t){-1!==Pt.indexOf(t)&&delete e[t]})),"number"==typeof(t=r({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),d.typeCheckConfig(It,t,this.constructor.DefaultType),t.sanitize&&(t.template=At(t.template,t.whiteList,t.sanitizeFn)),t},e._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},e._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(jt);null!==e&&e.length&&t.removeClass(e.join(""))},e._handlePopperPlacementChange=function(t){this.tip=t.instance.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},e._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(o.default(t).removeClass(Lt),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(kt),a="object"==typeof e&&e;if((i||!/dispose|hide/.test(e))&&(i||(i=new t(this,a),n.data(kt,i)),"string"==typeof e)){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Ht}},{key:"NAME",get:function(){return It}},{key:"DATA_KEY",get:function(){return kt}},{key:"Event",get:function(){return Mt}},{key:"EVENT_KEY",get:function(){return".bs.tooltip"}},{key:"DefaultType",get:function(){return Ut}}]),t}();o.default.fn.tooltip=Wt._jQueryInterface,o.default.fn.tooltip.Constructor=Wt,o.default.fn.tooltip.noConflict=function(){return o.default.fn.tooltip=Ot,Wt._jQueryInterface};var Vt="bs.popover",zt=o.default.fn.popover,Kt=new RegExp("(^|\\s)bs-popover\\S+","g"),Xt=r({},Wt.Default,{placement:"right",trigger:"click",content:"",template:''}),Yt=r({},Wt.DefaultType,{content:"(string|element|function)"}),$t={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"},Jt=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),e.prototype.constructor=e,u(e,n);var a=i.prototype;return a.isWithContent=function(){return this.getTitle()||this._getContent()},a.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-popover-"+t)},a.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},a.setContent=function(){var t=o.default(this.getTipElement());this.setElementContent(t.find(".popover-header"),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(".popover-body"),e),t.removeClass("fade show")},a._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},a._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(Kt);null!==e&&e.length>0&&t.removeClass(e.join(""))},i._jQueryInterface=function(t){return this.each((function(){var e=o.default(this).data(Vt),n="object"==typeof t?t:null;if((e||!/dispose|hide/.test(t))&&(e||(e=new i(this,n),o.default(this).data(Vt,e)),"string"==typeof t)){if("undefined"==typeof e[t])throw new TypeError('No method named "'+t+'"');e[t]()}}))},l(i,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Xt}},{key:"NAME",get:function(){return"popover"}},{key:"DATA_KEY",get:function(){return Vt}},{key:"Event",get:function(){return $t}},{key:"EVENT_KEY",get:function(){return".bs.popover"}},{key:"DefaultType",get:function(){return Yt}}]),i}(Wt);o.default.fn.popover=Jt._jQueryInterface,o.default.fn.popover.Constructor=Jt,o.default.fn.popover.noConflict=function(){return o.default.fn.popover=zt,Jt._jQueryInterface};var Gt="scrollspy",Zt="bs.scrollspy",te=o.default.fn[Gt],ee="active",ne="position",ie=".nav, .list-group",oe={offset:10,method:"auto",target:""},ae={offset:"number",method:"string",target:"(string|element)"},se=function(){function t(t,e){var n=this;this._element=t,this._scrollElement="BODY"===t.tagName?window:t,this._config=this._getConfig(e),this._selector=this._config.target+" .nav-link,"+this._config.target+" .list-group-item,"+this._config.target+" .dropdown-item",this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,o.default(this._scrollElement).on("scroll.bs.scrollspy",(function(t){return n._process(t)})),this.refresh(),this._process()}var e=t.prototype;return e.refresh=function(){var t=this,e=this._scrollElement===this._scrollElement.window?"offset":ne,n="auto"===this._config.method?e:this._config.method,i=n===ne?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),[].slice.call(document.querySelectorAll(this._selector)).map((function(t){var e,a=d.getSelectorFromElement(t);if(a&&(e=document.querySelector(a)),e){var s=e.getBoundingClientRect();if(s.width||s.height)return[o.default(e)[n]().top+i,a]}return null})).filter((function(t){return t})).sort((function(t,e){return t[0]-e[0]})).forEach((function(e){t._offsets.push(e[0]),t._targets.push(e[1])}))},e.dispose=function(){o.default.removeData(this._element,Zt),o.default(this._scrollElement).off(".bs.scrollspy"),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},e._getConfig=function(t){if("string"!=typeof(t=r({},oe,"object"==typeof t&&t?t:{})).target&&d.isElement(t.target)){var e=o.default(t.target).attr("id");e||(e=d.getUID(Gt),o.default(t.target).attr("id",e)),t.target="#"+e}return d.typeCheckConfig(Gt,t,ae),t},e._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},e._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},e._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},e._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;)this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||t li > .active",ge=function(){function t(t){this._element=t}var e=t.prototype;return e.show=function(){var t=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&o.default(this._element).hasClass(ue)||o.default(this._element).hasClass("disabled"))){var e,n,i=o.default(this._element).closest(".nav, .list-group")[0],a=d.getSelectorFromElement(this._element);if(i){var s="UL"===i.nodeName||"OL"===i.nodeName?he:ce;n=(n=o.default.makeArray(o.default(i).find(s)))[n.length-1]}var l=o.default.Event("hide.bs.tab",{relatedTarget:this._element}),r=o.default.Event("show.bs.tab",{relatedTarget:n});if(n&&o.default(n).trigger(l),o.default(this._element).trigger(r),!r.isDefaultPrevented()&&!l.isDefaultPrevented()){a&&(e=document.querySelector(a)),this._activate(this._element,i);var u=function(){var e=o.default.Event("hidden.bs.tab",{relatedTarget:t._element}),i=o.default.Event("shown.bs.tab",{relatedTarget:n});o.default(n).trigger(e),o.default(t._element).trigger(i)};e?this._activate(e,e.parentNode,u):u()}}},e.dispose=function(){o.default.removeData(this._element,le),this._element=null},e._activate=function(t,e,n){var i=this,a=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?o.default(e).children(ce):o.default(e).find(he))[0],s=n&&a&&o.default(a).hasClass(fe),l=function(){return i._transitionComplete(t,a,n)};if(a&&s){var r=d.getTransitionDurationFromElement(a);o.default(a).removeClass(de).one(d.TRANSITION_END,l).emulateTransitionEnd(r)}else l()},e._transitionComplete=function(t,e,n){if(e){o.default(e).removeClass(ue);var i=o.default(e.parentNode).find("> .dropdown-menu .active")[0];i&&o.default(i).removeClass(ue),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}o.default(t).addClass(ue),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),d.reflow(t),t.classList.contains(fe)&&t.classList.add(de);var a=t.parentNode;if(a&&"LI"===a.nodeName&&(a=a.parentNode),a&&o.default(a).hasClass("dropdown-menu")){var s=o.default(t).closest(".dropdown")[0];if(s){var l=[].slice.call(s.querySelectorAll(".dropdown-toggle"));o.default(l).addClass(ue)}t.setAttribute("aria-expanded",!0)}n&&n()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(le);if(i||(i=new t(this),n.data(le,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',(function(t){t.preventDefault(),ge._jQueryInterface.call(o.default(this),"show")})),o.default.fn.tab=ge._jQueryInterface,o.default.fn.tab.Constructor=ge,o.default.fn.tab.noConflict=function(){return o.default.fn.tab=re,ge._jQueryInterface};var me="bs.toast",pe=o.default.fn.toast,_e="hide",ve="show",ye="showing",be="click.dismiss.bs.toast",Ee={animation:!0,autohide:!0,delay:500},Te={animation:"boolean",autohide:"boolean",delay:"number"},we=function(){function t(t,e){this._element=t,this._config=this._getConfig(e),this._timeout=null,this._setListeners()}var e=t.prototype;return e.show=function(){var t=this,e=o.default.Event("show.bs.toast");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){this._clearTimeout(),this._config.animation&&this._element.classList.add("fade");var n=function(){t._element.classList.remove(ye),t._element.classList.add(ve),o.default(t._element).trigger("shown.bs.toast"),t._config.autohide&&(t._timeout=setTimeout((function(){t.hide()}),t._config.delay))};if(this._element.classList.remove(_e),d.reflow(this._element),this._element.classList.add(ye),this._config.animation){var i=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,n).emulateTransitionEnd(i)}else n()}},e.hide=function(){if(this._element.classList.contains(ve)){var t=o.default.Event("hide.bs.toast");o.default(this._element).trigger(t),t.isDefaultPrevented()||this._close()}},e.dispose=function(){this._clearTimeout(),this._element.classList.contains(ve)&&this._element.classList.remove(ve),o.default(this._element).off(be),o.default.removeData(this._element,me),this._element=null,this._config=null},e._getConfig=function(t){return t=r({},Ee,o.default(this._element).data(),"object"==typeof t&&t?t:{}),d.typeCheckConfig("toast",t,this.constructor.DefaultType),t},e._setListeners=function(){var t=this;o.default(this._element).on(be,'[data-dismiss="toast"]',(function(){return t.hide()}))},e._close=function(){var t=this,e=function(){t._element.classList.add(_e),o.default(t._element).trigger("hidden.bs.toast")};if(this._element.classList.remove(ve),this._config.animation){var n=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},e._clearTimeout=function(){clearTimeout(this._timeout),this._timeout=null},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(me);if(i||(i=new t(this,"object"==typeof e&&e),n.data(me,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e](this)}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"DefaultType",get:function(){return Te}},{key:"Default",get:function(){return Ee}}]),t}();o.default.fn.toast=we._jQueryInterface,o.default.fn.toast.Constructor=we,o.default.fn.toast.noConflict=function(){return o.default.fn.toast=pe,we._jQueryInterface},t.Alert=g,t.Button=E,t.Carousel=P,t.Collapse=V,t.Dropdown=lt,t.Modal=Ct,t.Popover=Jt,t.Scrollspy=se,t.Tab=ge,t.Toast=we,t.Tooltip=Wt,t.Util=d,Object.defineProperty(t,"__esModule",{value:!0})})); +//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/code/ch4_app/ch4_starter_video_collector/static/js/jquery-3.5.1.slim.min.js b/code/ch4_app/ch4_starter_video_collector/static/js/jquery-3.5.1.slim.min.js new file mode 100644 index 0000000..36b4e1a --- /dev/null +++ b/code/ch4_app/ch4_starter_video_collector/static/js/jquery-3.5.1.slim.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(g,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,v=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),m={},b=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},w=g.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function C(e,t,n){var r,i,o=(n=n||w).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function T(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector",E=function(e,t){return new E.fn.init(e,t)};function d(e){var t=!!e&&"length"in e&&e.length,n=T(e);return!b(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+R+")"+R+"*"),U=new RegExp(R+"|>"),V=new RegExp(W),X=new RegExp("^"+B+"$"),Q={ID:new RegExp("^#("+B+")"),CLASS:new RegExp("^\\.("+B+")"),TAG:new RegExp("^("+B+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+R+"*(even|odd|(([+-]|)(\\d*)n|)"+R+"*(?:([+-]|)"+R+"*(\\d+)|))"+R+"*\\)|)","i"),bool:new RegExp("^(?:"+I+")$","i"),needsContext:new RegExp("^"+R+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+R+"*((?:-\\d)?\\d*)"+R+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,G=/^(?:input|select|textarea|button)$/i,K=/^h\d$/i,J=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+R+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){C()},ae=xe(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{O.apply(t=P.call(d.childNodes),d.childNodes),t[d.childNodes.length].nodeType}catch(e){O={apply:t.length?function(e,t){q.apply(e,P.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,d=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==d&&9!==d&&11!==d)return n;if(!r&&(C(e),e=e||T,E)){if(11!==d&&(u=Z.exec(t)))if(i=u[1]){if(9===d){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return O.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&p.getElementsByClassName&&e.getElementsByClassName)return O.apply(n,e.getElementsByClassName(i)),n}if(p.qsa&&!k[t+" "]&&(!v||!v.test(t))&&(1!==d||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===d&&(U.test(t)||_.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&p.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=A)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+be(l[o]);c=l.join(",")}try{return O.apply(n,f.querySelectorAll(c)),n}catch(e){k(t,!0)}finally{s===A&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>x.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[A]=!0,e}function ce(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)x.attrHandle[n[r]]=t}function de(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pe(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in p=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},C=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:d;return r!=T&&9===r.nodeType&&r.documentElement&&(a=(T=r).documentElement,E=!i(T),d!=T&&(n=T.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),p.scope=ce(function(e){return a.appendChild(e).appendChild(T.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),p.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),p.getElementsByTagName=ce(function(e){return e.appendChild(T.createComment("")),!e.getElementsByTagName("*").length}),p.getElementsByClassName=J.test(T.getElementsByClassName),p.getById=ce(function(e){return a.appendChild(e).id=A,!T.getElementsByName||!T.getElementsByName(A).length}),p.getById?(x.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(x.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),x.find.TAG=p.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):p.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},x.find.CLASS=p.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(p.qsa=J.test(T.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+R+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+R+"*(?:value|"+I+")"),e.querySelectorAll("[id~="+A+"-]").length||v.push("~="),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+R+"*name"+R+"*="+R+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+A+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=T.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+R+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(p.matchesSelector=J.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){p.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",W)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=J.test(a.compareDocumentPosition),y=t||J.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!p.sortDetached&&t.compareDocumentPosition(e)===n?e==T||e.ownerDocument==d&&y(d,e)?-1:t==T||t.ownerDocument==d&&y(d,t)?1:u?H(u,e)-H(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==T?-1:t==T?1:i?-1:o?1:u?H(u,e)-H(u,t):0;if(i===o)return de(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?de(a[r],s[r]):a[r]==d?-1:s[r]==d?1:0}),T},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(C(e),p.matchesSelector&&E&&!k[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||p.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){k(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&V.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+R+")"+e+"("+R+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return b(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):"string"!=typeof n?E.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||L,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:j.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:w,!0)),k.test(r[1])&&E.isPlainObject(t))for(r in t)b(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=w.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):b(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,L=E(w);var q=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,pe=/^$|^module$|\/(?:java|ecma)script/i;le=w.createDocumentFragment().appendChild(w.createElement("div")),(ce=w.createElement("input")).setAttribute("type","radio"),ce.setAttribute("checked","checked"),ce.setAttribute("name","t"),le.appendChild(ce),m.checkClone=le.cloneNode(!0).cloneNode(!0).lastChild.checked,le.innerHTML="",m.noCloneChecked=!!le.cloneNode(!0).lastChild.defaultValue,le.innerHTML="",m.option=!!le.lastChild;var he={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ge(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&S(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var ye=/<|&#?\w+;/;function me(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),d=[],p=0,h=e.length;p\s*$/g;function Le(e,t){return S(e,"table")&&S(11!==t.nodeType?t:t.firstChild,"tr")&&E(e).children("tbody")[0]||e}function je(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n
",2===ft.childNodes.length),E.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(m.createHTMLDocument?((r=(t=w.implementation.createHTMLDocument("")).createElement("base")).href=w.location.href,t.head.appendChild(r)):t=w),o=!n&&[],(i=k.exec(e))?[t.createElement(i[1])]:(i=me([e],t,o),o&&o.length&&E(o).remove(),E.merge([],i.childNodes)));var r,i,o},E.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=E.css(e,"position"),c=E(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=E.css(e,"top"),u=E.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),b(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===E.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===E.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=E(e).offset()).top+=E.css(e,"borderTopWidth",!0),i.left+=E.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-E.css(r,"marginTop",!0),left:t.left-i.left-E.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===E.css(e,"position"))e=e.offsetParent;return e||re})}}),E.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;E.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each(["top","left"],function(e,n){E.cssHooks[n]=Fe(m.pixelPosition,function(e,t){if(t)return t=We(e,n),Ie.test(t)?E(e).position()[n]+"px":t})}),E.each({Height:"height",Width:"width"},function(a,s){E.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){E.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?E.css(e,t,i):E.style(e,t,n,i)},s,n?e:void 0,n)}})}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){E.fn[n]=function(e,t){return 0=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),ae({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=le({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f]),E=parseFloat(w['border'+f+'Width']),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},ae(n,m,$(v)),ae(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ce.FLIP:p=[n,i];break;case ce.CLOCKWISE:p=G(n);break;case ce.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u),E=!!t.flipVariationsByContent&&(w&&'start'===r&&c||w&&'end'===r&&h||!w&&'start'===r&&u||!w&&'end'===r&&g),v=y||E;(m||b||v)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),v&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=le({},e.offsets.popper,C(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport',flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=D(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.rightwindow.devicePixelRatio||!fe),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=B('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=le({},E,e.attributes),e.styles=le({},m,e.styles),e.arrowStyles=le({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return V(e.instance.popper,e.styles),j(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&V(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),V(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ge}); +//# sourceMappingURL=popper.min.js.map diff --git a/code/ch5_partials/ch5_final_video_collector/static/js/bootstrap-4.6.1.min.js b/code/ch5_partials/ch5_final_video_collector/static/js/bootstrap-4.6.1.min.js new file mode 100644 index 0000000..50720ea --- /dev/null +++ b/code/ch5_partials/ch5_final_video_collector/static/js/bootstrap-4.6.1.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.6.1 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap={},t.jQuery,t.Popper)}(this,(function(t,e,n){"use strict";function i(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var o=i(e),a=i(n);function s(t,e){for(var n=0;n=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}};d.jQueryDetection(),o.default.fn.emulateTransitionEnd=function(t){var e=this,n=!1;return o.default(this).one(d.TRANSITION_END,(function(){n=!0})),setTimeout((function(){n||d.triggerTransitionEnd(e)}),t),this},o.default.event.special[d.TRANSITION_END]={bindType:f,delegateType:f,handle:function(t){if(o.default(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}};var c="bs.alert",h=o.default.fn.alert,g=function(){function t(t){this._element=t}var e=t.prototype;return e.close=function(t){var e=this._element;t&&(e=this._getRootElement(t)),this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.dispose=function(){o.default.removeData(this._element,c),this._element=null},e._getRootElement=function(t){var e=d.getSelectorFromElement(t),n=!1;return e&&(n=document.querySelector(e)),n||(n=o.default(t).closest(".alert")[0]),n},e._triggerCloseEvent=function(t){var e=o.default.Event("close.bs.alert");return o.default(t).trigger(e),e},e._removeElement=function(t){var e=this;if(o.default(t).removeClass("show"),o.default(t).hasClass("fade")){var n=d.getTransitionDurationFromElement(t);o.default(t).one(d.TRANSITION_END,(function(n){return e._destroyElement(t,n)})).emulateTransitionEnd(n)}else this._destroyElement(t)},e._destroyElement=function(t){o.default(t).detach().trigger("closed.bs.alert").remove()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(c);i||(i=new t(this),n.data(c,i)),"close"===e&&i[e](this)}))},t._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',g._handleDismiss(new g)),o.default.fn.alert=g._jQueryInterface,o.default.fn.alert.Constructor=g,o.default.fn.alert.noConflict=function(){return o.default.fn.alert=h,g._jQueryInterface};var m="bs.button",p=o.default.fn.button,_="active",v='[data-toggle^="button"]',y='input:not([type="hidden"])',b=".btn",E=function(){function t(t){this._element=t,this.shouldAvoidTriggerChange=!1}var e=t.prototype;return e.toggle=function(){var t=!0,e=!0,n=o.default(this._element).closest('[data-toggle="buttons"]')[0];if(n){var i=this._element.querySelector(y);if(i){if("radio"===i.type)if(i.checked&&this._element.classList.contains(_))t=!1;else{var a=n.querySelector(".active");a&&o.default(a).removeClass(_)}t&&("checkbox"!==i.type&&"radio"!==i.type||(i.checked=!this._element.classList.contains(_)),this.shouldAvoidTriggerChange||o.default(i).trigger("change")),i.focus(),e=!1}}this._element.hasAttribute("disabled")||this._element.classList.contains("disabled")||(e&&this._element.setAttribute("aria-pressed",!this._element.classList.contains(_)),t&&o.default(this._element).toggleClass(_))},e.dispose=function(){o.default.removeData(this._element,m),this._element=null},t._jQueryInterface=function(e,n){return this.each((function(){var i=o.default(this),a=i.data(m);a||(a=new t(this),i.data(m,a)),a.shouldAvoidTriggerChange=n,"toggle"===e&&a[e]()}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.button.data-api",v,(function(t){var e=t.target,n=e;if(o.default(e).hasClass("btn")||(e=o.default(e).closest(b)[0]),!e||e.hasAttribute("disabled")||e.classList.contains("disabled"))t.preventDefault();else{var i=e.querySelector(y);if(i&&(i.hasAttribute("disabled")||i.classList.contains("disabled")))return void t.preventDefault();"INPUT"!==n.tagName&&"LABEL"===e.tagName||E._jQueryInterface.call(o.default(e),"toggle","INPUT"===n.tagName)}})).on("focus.bs.button.data-api blur.bs.button.data-api",v,(function(t){var e=o.default(t.target).closest(b)[0];o.default(e).toggleClass("focus",/^focus(in)?$/.test(t.type))})),o.default(window).on("load.bs.button.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-toggle="buttons"] .btn')),e=0,n=t.length;e0,this._pointerEvent=Boolean(window.PointerEvent||window.MSPointerEvent),this._addEventListeners()}var e=t.prototype;return e.next=function(){this._isSliding||this._slide(N)},e.nextWhenVisible=function(){var t=o.default(this._element);!document.hidden&&t.is(":visible")&&"hidden"!==t.css("visibility")&&this.next()},e.prev=function(){this._isSliding||this._slide(D)},e.pause=function(t){t||(this._isPaused=!0),this._element.querySelector(".carousel-item-next, .carousel-item-prev")&&(d.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},e.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},e.to=function(t){var e=this;this._activeElement=this._element.querySelector(I);var n=this._getItemIndex(this._activeElement);if(!(t>this._items.length-1||t<0))if(this._isSliding)o.default(this._element).one(A,(function(){return e.to(t)}));else{if(n===t)return this.pause(),void this.cycle();var i=t>n?N:D;this._slide(i,this._items[t])}},e.dispose=function(){o.default(this._element).off(".bs.carousel"),o.default.removeData(this._element,w),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},e._getConfig=function(t){return t=r({},k,t),d.typeCheckConfig(T,t,O),t},e._handleSwipe=function(){var t=Math.abs(this.touchDeltaX);if(!(t<=40)){var e=t/this.touchDeltaX;this.touchDeltaX=0,e>0&&this.prev(),e<0&&this.next()}},e._addEventListeners=function(){var t=this;this._config.keyboard&&o.default(this._element).on("keydown.bs.carousel",(function(e){return t._keydown(e)})),"hover"===this._config.pause&&o.default(this._element).on("mouseenter.bs.carousel",(function(e){return t.pause(e)})).on("mouseleave.bs.carousel",(function(e){return t.cycle(e)})),this._config.touch&&this._addTouchEventListeners()},e._addTouchEventListeners=function(){var t=this;if(this._touchSupported){var e=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]?t.touchStartX=e.originalEvent.clientX:t._pointerEvent||(t.touchStartX=e.originalEvent.touches[0].clientX)},n=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]&&(t.touchDeltaX=e.originalEvent.clientX-t.touchStartX),t._handleSwipe(),"hover"===t._config.pause&&(t.pause(),t.touchTimeout&&clearTimeout(t.touchTimeout),t.touchTimeout=setTimeout((function(e){return t.cycle(e)}),500+t._config.interval))};o.default(this._element.querySelectorAll(".carousel-item img")).on("dragstart.bs.carousel",(function(t){return t.preventDefault()})),this._pointerEvent?(o.default(this._element).on("pointerdown.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("pointerup.bs.carousel",(function(t){return n(t)})),this._element.classList.add("pointer-event")):(o.default(this._element).on("touchstart.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("touchmove.bs.carousel",(function(e){return function(e){t.touchDeltaX=e.originalEvent.touches&&e.originalEvent.touches.length>1?0:e.originalEvent.touches[0].clientX-t.touchStartX}(e)})),o.default(this._element).on("touchend.bs.carousel",(function(t){return n(t)})))}},e._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next()}},e._getItemIndex=function(t){return this._items=t&&t.parentNode?[].slice.call(t.parentNode.querySelectorAll(".carousel-item")):[],this._items.indexOf(t)},e._getItemByDirection=function(t,e){var n=t===N,i=t===D,o=this._getItemIndex(e),a=this._items.length-1;if((i&&0===o||n&&o===a)&&!this._config.wrap)return e;var s=(o+(t===D?-1:1))%this._items.length;return-1===s?this._items[this._items.length-1]:this._items[s]},e._triggerSlideEvent=function(t,e){var n=this._getItemIndex(t),i=this._getItemIndex(this._element.querySelector(I)),a=o.default.Event("slide.bs.carousel",{relatedTarget:t,direction:e,from:i,to:n});return o.default(this._element).trigger(a),a},e._setActiveIndicatorElement=function(t){if(this._indicatorsElement){var e=[].slice.call(this._indicatorsElement.querySelectorAll(".active"));o.default(e).removeClass(S);var n=this._indicatorsElement.children[this._getItemIndex(t)];n&&o.default(n).addClass(S)}},e._updateInterval=function(){var t=this._activeElement||this._element.querySelector(I);if(t){var e=parseInt(t.getAttribute("data-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}},e._slide=function(t,e){var n,i,a,s=this,l=this._element.querySelector(I),r=this._getItemIndex(l),u=e||l&&this._getItemByDirection(t,l),f=this._getItemIndex(u),c=Boolean(this._interval);if(t===N?(n="carousel-item-left",i="carousel-item-next",a="left"):(n="carousel-item-right",i="carousel-item-prev",a="right"),u&&o.default(u).hasClass(S))this._isSliding=!1;else if(!this._triggerSlideEvent(u,a).isDefaultPrevented()&&l&&u){this._isSliding=!0,c&&this.pause(),this._setActiveIndicatorElement(u),this._activeElement=u;var h=o.default.Event(A,{relatedTarget:u,direction:a,from:r,to:f});if(o.default(this._element).hasClass("slide")){o.default(u).addClass(i),d.reflow(u),o.default(l).addClass(n),o.default(u).addClass(n);var g=d.getTransitionDurationFromElement(l);o.default(l).one(d.TRANSITION_END,(function(){o.default(u).removeClass(n+" "+i).addClass(S),o.default(l).removeClass("active "+i+" "+n),s._isSliding=!1,setTimeout((function(){return o.default(s._element).trigger(h)}),0)})).emulateTransitionEnd(g)}else o.default(l).removeClass(S),o.default(u).addClass(S),this._isSliding=!1,o.default(this._element).trigger(h);c&&this.cycle()}},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(w),i=r({},k,o.default(this).data());"object"==typeof e&&(i=r({},i,e));var a="string"==typeof e?e:i.slide;if(n||(n=new t(this,i),o.default(this).data(w,n)),"number"==typeof e)n.to(e);else if("string"==typeof a){if("undefined"==typeof n[a])throw new TypeError('No method named "'+a+'"');n[a]()}else i.interval&&i.ride&&(n.pause(),n.cycle())}))},t._dataApiClickHandler=function(e){var n=d.getSelectorFromElement(this);if(n){var i=o.default(n)[0];if(i&&o.default(i).hasClass("carousel")){var a=r({},o.default(i).data(),o.default(this).data()),s=this.getAttribute("data-slide-to");s&&(a.interval=!1),t._jQueryInterface.call(o.default(i),a),s&&o.default(i).data(w).to(s),e.preventDefault()}}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return k}}]),t}();o.default(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",P._dataApiClickHandler),o.default(window).on("load.bs.carousel.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-ride="carousel"]')),e=0,n=t.length;e0&&(this._selector=s,this._triggerArray.push(a))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}var e=t.prototype;return e.toggle=function(){o.default(this._element).hasClass(q)?this.hide():this.show()},e.show=function(){var e,n,i=this;if(!(this._isTransitioning||o.default(this._element).hasClass(q)||(this._parent&&0===(e=[].slice.call(this._parent.querySelectorAll(".show, .collapsing")).filter((function(t){return"string"==typeof i._config.parent?t.getAttribute("data-parent")===i._config.parent:t.classList.contains(F)}))).length&&(e=null),e&&(n=o.default(e).not(this._selector).data(R))&&n._isTransitioning))){var a=o.default.Event("show.bs.collapse");if(o.default(this._element).trigger(a),!a.isDefaultPrevented()){e&&(t._jQueryInterface.call(o.default(e).not(this._selector),"hide"),n||o.default(e).data(R,null));var s=this._getDimension();o.default(this._element).removeClass(F).addClass(Q),this._element.style[s]=0,this._triggerArray.length&&o.default(this._triggerArray).removeClass(B).attr("aria-expanded",!0),this.setTransitioning(!0);var l="scroll"+(s[0].toUpperCase()+s.slice(1)),r=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,(function(){o.default(i._element).removeClass(Q).addClass("collapse show"),i._element.style[s]="",i.setTransitioning(!1),o.default(i._element).trigger("shown.bs.collapse")})).emulateTransitionEnd(r),this._element.style[s]=this._element[l]+"px"}}},e.hide=function(){var t=this;if(!this._isTransitioning&&o.default(this._element).hasClass(q)){var e=o.default.Event("hide.bs.collapse");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){var n=this._getDimension();this._element.style[n]=this._element.getBoundingClientRect()[n]+"px",d.reflow(this._element),o.default(this._element).addClass(Q).removeClass("collapse show");var i=this._triggerArray.length;if(i>0)for(var a=0;a0},e._getOffset=function(){var t=this,e={};return"function"==typeof this._config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t._config.offset(e.offsets,t._element)),e}:e.offset=this._config.offset,e},e._getPopperConfig=function(){var t={placement:this._getPlacement(),modifiers:{offset:this._getOffset(),flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}};return"static"===this._config.display&&(t.modifiers.applyStyle={enabled:!1}),r({},t,this._config.popperConfig)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(K);if(n||(n=new t(this,"object"==typeof e?e:null),o.default(this).data(K,n)),"string"==typeof e){if("undefined"==typeof n[e])throw new TypeError('No method named "'+e+'"');n[e]()}}))},t._clearMenus=function(e){if(!e||3!==e.which&&("keyup"!==e.type||9===e.which))for(var n=[].slice.call(document.querySelectorAll(it)),i=0,a=n.length;i0&&s--,40===e.which&&sdocument.documentElement.clientHeight;n||(this._element.style.overflowY="hidden"),this._element.classList.add(ht);var i=d.getTransitionDurationFromElement(this._dialog);o.default(this._element).off(d.TRANSITION_END),o.default(this._element).one(d.TRANSITION_END,(function(){t._element.classList.remove(ht),n||o.default(t._element).one(d.TRANSITION_END,(function(){t._element.style.overflowY=""})).emulateTransitionEnd(t._element,i)})).emulateTransitionEnd(i),this._element.focus()}},e._showElement=function(t){var e=this,n=o.default(this._element).hasClass(dt),i=this._dialog?this._dialog.querySelector(".modal-body"):null;this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),o.default(this._dialog).hasClass("modal-dialog-scrollable")&&i?i.scrollTop=0:this._element.scrollTop=0,n&&d.reflow(this._element),o.default(this._element).addClass(ct),this._config.focus&&this._enforceFocus();var a=o.default.Event("shown.bs.modal",{relatedTarget:t}),s=function(){e._config.focus&&e._element.focus(),e._isTransitioning=!1,o.default(e._element).trigger(a)};if(n){var l=d.getTransitionDurationFromElement(this._dialog);o.default(this._dialog).one(d.TRANSITION_END,s).emulateTransitionEnd(l)}else s()},e._enforceFocus=function(){var t=this;o.default(document).off(pt).on(pt,(function(e){document!==e.target&&t._element!==e.target&&0===o.default(t._element).has(e.target).length&&t._element.focus()}))},e._setEscapeEvent=function(){var t=this;this._isShown?o.default(this._element).on(yt,(function(e){t._config.keyboard&&27===e.which?(e.preventDefault(),t.hide()):t._config.keyboard||27!==e.which||t._triggerBackdropTransition()})):this._isShown||o.default(this._element).off(yt)},e._setResizeEvent=function(){var t=this;this._isShown?o.default(window).on(_t,(function(e){return t.handleUpdate(e)})):o.default(window).off(_t)},e._hideModal=function(){var t=this;this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._showBackdrop((function(){o.default(document.body).removeClass(ft),t._resetAdjustments(),t._resetScrollbar(),o.default(t._element).trigger(gt)}))},e._removeBackdrop=function(){this._backdrop&&(o.default(this._backdrop).remove(),this._backdrop=null)},e._showBackdrop=function(t){var e=this,n=o.default(this._element).hasClass(dt)?dt:"";if(this._isShown&&this._config.backdrop){if(this._backdrop=document.createElement("div"),this._backdrop.className="modal-backdrop",n&&this._backdrop.classList.add(n),o.default(this._backdrop).appendTo(document.body),o.default(this._element).on(vt,(function(t){e._ignoreBackdropClick?e._ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"===e._config.backdrop?e._triggerBackdropTransition():e.hide())})),n&&d.reflow(this._backdrop),o.default(this._backdrop).addClass(ct),!t)return;if(!n)return void t();var i=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,t).emulateTransitionEnd(i)}else if(!this._isShown&&this._backdrop){o.default(this._backdrop).removeClass(ct);var a=function(){e._removeBackdrop(),t&&t()};if(o.default(this._element).hasClass(dt)){var s=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a()}else t&&t()},e._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},e._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},e._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=Math.round(t.left+t.right)
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",customClass:"",sanitize:!0,sanitizeFn:null,whiteList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},Ut={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string|function)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",whiteList:"object",popperConfig:"(null|object)"},Mt={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},Wt=function(){function t(t,e){if("undefined"==typeof a.default)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var e=t.prototype;return e.enable=function(){this._isEnabled=!0},e.disable=function(){this._isEnabled=!1},e.toggleEnabled=function(){this._isEnabled=!this._isEnabled},e.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=o.default(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(o.default(this.getTipElement()).hasClass(Rt))return void this._leave(null,this);this._enter(null,this)}},e.dispose=function(){clearTimeout(this._timeout),o.default.removeData(this.element,this.constructor.DATA_KEY),o.default(this.element).off(this.constructor.EVENT_KEY),o.default(this.element).closest(".modal").off("hide.bs.modal",this._hideModalHandler),this.tip&&o.default(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},e.show=function(){var t=this;if("none"===o.default(this.element).css("display"))throw new Error("Please use show on visible elements");var e=o.default.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){o.default(this.element).trigger(e);var n=d.findShadowRoot(this.element),i=o.default.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(e.isDefaultPrevented()||!i)return;var s=this.getTipElement(),l=d.getUID(this.constructor.NAME);s.setAttribute("id",l),this.element.setAttribute("aria-describedby",l),this.setContent(),this.config.animation&&o.default(s).addClass(Lt);var r="function"==typeof this.config.placement?this.config.placement.call(this,s,this.element):this.config.placement,u=this._getAttachment(r);this.addAttachmentClass(u);var f=this._getContainer();o.default(s).data(this.constructor.DATA_KEY,this),o.default.contains(this.element.ownerDocument.documentElement,this.tip)||o.default(s).appendTo(f),o.default(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new a.default(this.element,s,this._getPopperConfig(u)),o.default(s).addClass(Rt),o.default(s).addClass(this.config.customClass),"ontouchstart"in document.documentElement&&o.default(document.body).children().on("mouseover",null,o.default.noop);var c=function(){t.config.animation&&t._fixTransition();var e=t._hoverState;t._hoverState=null,o.default(t.element).trigger(t.constructor.Event.SHOWN),e===qt&&t._leave(null,t)};if(o.default(this.tip).hasClass(Lt)){var h=d.getTransitionDurationFromElement(this.tip);o.default(this.tip).one(d.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},e.hide=function(t){var e=this,n=this.getTipElement(),i=o.default.Event(this.constructor.Event.HIDE),a=function(){e._hoverState!==xt&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),o.default(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(o.default(this.element).trigger(i),!i.isDefaultPrevented()){if(o.default(n).removeClass(Rt),"ontouchstart"in document.documentElement&&o.default(document.body).children().off("mouseover",null,o.default.noop),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,o.default(this.tip).hasClass(Lt)){var s=d.getTransitionDurationFromElement(n);o.default(n).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a();this._hoverState=""}},e.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},e.isWithContent=function(){return Boolean(this.getTitle())},e.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-tooltip-"+t)},e.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},e.setContent=function(){var t=this.getTipElement();this.setElementContent(o.default(t.querySelectorAll(".tooltip-inner")),this.getTitle()),o.default(t).removeClass("fade show")},e.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=At(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?o.default(e).parent().is(t)||t.empty().append(e):t.text(o.default(e).text())},e.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},e._getPopperConfig=function(t){var e=this;return r({},{placement:t,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:".arrow"},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}},this.config.popperConfig)},e._getOffset=function(){var t=this,e={};return"function"==typeof this.config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t.config.offset(e.offsets,t.element)),e}:e.offset=this.config.offset,e},e._getContainer=function(){return!1===this.config.container?document.body:d.isElement(this.config.container)?o.default(this.config.container):o.default(document).find(this.config.container)},e._getAttachment=function(t){return Bt[t.toUpperCase()]},e._setListeners=function(){var t=this;this.config.trigger.split(" ").forEach((function(e){if("click"===e)o.default(t.element).on(t.constructor.Event.CLICK,t.config.selector,(function(e){return t.toggle(e)}));else if("manual"!==e){var n=e===Ft?t.constructor.Event.MOUSEENTER:t.constructor.Event.FOCUSIN,i=e===Ft?t.constructor.Event.MOUSELEAVE:t.constructor.Event.FOCUSOUT;o.default(t.element).on(n,t.config.selector,(function(e){return t._enter(e)})).on(i,t.config.selector,(function(e){return t._leave(e)}))}})),this._hideModalHandler=function(){t.element&&t.hide()},o.default(this.element).closest(".modal").on("hide.bs.modal",this._hideModalHandler),this.config.selector?this.config=r({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},e._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},e._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Qt:Ft]=!0),o.default(e.getTipElement()).hasClass(Rt)||e._hoverState===xt?e._hoverState=xt:(clearTimeout(e._timeout),e._hoverState=xt,e.config.delay&&e.config.delay.show?e._timeout=setTimeout((function(){e._hoverState===xt&&e.show()}),e.config.delay.show):e.show())},e._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Qt:Ft]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=qt,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout((function(){e._hoverState===qt&&e.hide()}),e.config.delay.hide):e.hide())},e._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},e._getConfig=function(t){var e=o.default(this.element).data();return Object.keys(e).forEach((function(t){-1!==Pt.indexOf(t)&&delete e[t]})),"number"==typeof(t=r({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),d.typeCheckConfig(It,t,this.constructor.DefaultType),t.sanitize&&(t.template=At(t.template,t.whiteList,t.sanitizeFn)),t},e._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},e._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(jt);null!==e&&e.length&&t.removeClass(e.join(""))},e._handlePopperPlacementChange=function(t){this.tip=t.instance.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},e._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(o.default(t).removeClass(Lt),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(kt),a="object"==typeof e&&e;if((i||!/dispose|hide/.test(e))&&(i||(i=new t(this,a),n.data(kt,i)),"string"==typeof e)){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Ht}},{key:"NAME",get:function(){return It}},{key:"DATA_KEY",get:function(){return kt}},{key:"Event",get:function(){return Mt}},{key:"EVENT_KEY",get:function(){return".bs.tooltip"}},{key:"DefaultType",get:function(){return Ut}}]),t}();o.default.fn.tooltip=Wt._jQueryInterface,o.default.fn.tooltip.Constructor=Wt,o.default.fn.tooltip.noConflict=function(){return o.default.fn.tooltip=Ot,Wt._jQueryInterface};var Vt="bs.popover",zt=o.default.fn.popover,Kt=new RegExp("(^|\\s)bs-popover\\S+","g"),Xt=r({},Wt.Default,{placement:"right",trigger:"click",content:"",template:''}),Yt=r({},Wt.DefaultType,{content:"(string|element|function)"}),$t={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"},Jt=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),e.prototype.constructor=e,u(e,n);var a=i.prototype;return a.isWithContent=function(){return this.getTitle()||this._getContent()},a.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-popover-"+t)},a.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},a.setContent=function(){var t=o.default(this.getTipElement());this.setElementContent(t.find(".popover-header"),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(".popover-body"),e),t.removeClass("fade show")},a._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},a._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(Kt);null!==e&&e.length>0&&t.removeClass(e.join(""))},i._jQueryInterface=function(t){return this.each((function(){var e=o.default(this).data(Vt),n="object"==typeof t?t:null;if((e||!/dispose|hide/.test(t))&&(e||(e=new i(this,n),o.default(this).data(Vt,e)),"string"==typeof t)){if("undefined"==typeof e[t])throw new TypeError('No method named "'+t+'"');e[t]()}}))},l(i,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Xt}},{key:"NAME",get:function(){return"popover"}},{key:"DATA_KEY",get:function(){return Vt}},{key:"Event",get:function(){return $t}},{key:"EVENT_KEY",get:function(){return".bs.popover"}},{key:"DefaultType",get:function(){return Yt}}]),i}(Wt);o.default.fn.popover=Jt._jQueryInterface,o.default.fn.popover.Constructor=Jt,o.default.fn.popover.noConflict=function(){return o.default.fn.popover=zt,Jt._jQueryInterface};var Gt="scrollspy",Zt="bs.scrollspy",te=o.default.fn[Gt],ee="active",ne="position",ie=".nav, .list-group",oe={offset:10,method:"auto",target:""},ae={offset:"number",method:"string",target:"(string|element)"},se=function(){function t(t,e){var n=this;this._element=t,this._scrollElement="BODY"===t.tagName?window:t,this._config=this._getConfig(e),this._selector=this._config.target+" .nav-link,"+this._config.target+" .list-group-item,"+this._config.target+" .dropdown-item",this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,o.default(this._scrollElement).on("scroll.bs.scrollspy",(function(t){return n._process(t)})),this.refresh(),this._process()}var e=t.prototype;return e.refresh=function(){var t=this,e=this._scrollElement===this._scrollElement.window?"offset":ne,n="auto"===this._config.method?e:this._config.method,i=n===ne?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),[].slice.call(document.querySelectorAll(this._selector)).map((function(t){var e,a=d.getSelectorFromElement(t);if(a&&(e=document.querySelector(a)),e){var s=e.getBoundingClientRect();if(s.width||s.height)return[o.default(e)[n]().top+i,a]}return null})).filter((function(t){return t})).sort((function(t,e){return t[0]-e[0]})).forEach((function(e){t._offsets.push(e[0]),t._targets.push(e[1])}))},e.dispose=function(){o.default.removeData(this._element,Zt),o.default(this._scrollElement).off(".bs.scrollspy"),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},e._getConfig=function(t){if("string"!=typeof(t=r({},oe,"object"==typeof t&&t?t:{})).target&&d.isElement(t.target)){var e=o.default(t.target).attr("id");e||(e=d.getUID(Gt),o.default(t.target).attr("id",e)),t.target="#"+e}return d.typeCheckConfig(Gt,t,ae),t},e._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},e._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},e._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},e._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;)this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||t li > .active",ge=function(){function t(t){this._element=t}var e=t.prototype;return e.show=function(){var t=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&o.default(this._element).hasClass(ue)||o.default(this._element).hasClass("disabled"))){var e,n,i=o.default(this._element).closest(".nav, .list-group")[0],a=d.getSelectorFromElement(this._element);if(i){var s="UL"===i.nodeName||"OL"===i.nodeName?he:ce;n=(n=o.default.makeArray(o.default(i).find(s)))[n.length-1]}var l=o.default.Event("hide.bs.tab",{relatedTarget:this._element}),r=o.default.Event("show.bs.tab",{relatedTarget:n});if(n&&o.default(n).trigger(l),o.default(this._element).trigger(r),!r.isDefaultPrevented()&&!l.isDefaultPrevented()){a&&(e=document.querySelector(a)),this._activate(this._element,i);var u=function(){var e=o.default.Event("hidden.bs.tab",{relatedTarget:t._element}),i=o.default.Event("shown.bs.tab",{relatedTarget:n});o.default(n).trigger(e),o.default(t._element).trigger(i)};e?this._activate(e,e.parentNode,u):u()}}},e.dispose=function(){o.default.removeData(this._element,le),this._element=null},e._activate=function(t,e,n){var i=this,a=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?o.default(e).children(ce):o.default(e).find(he))[0],s=n&&a&&o.default(a).hasClass(fe),l=function(){return i._transitionComplete(t,a,n)};if(a&&s){var r=d.getTransitionDurationFromElement(a);o.default(a).removeClass(de).one(d.TRANSITION_END,l).emulateTransitionEnd(r)}else l()},e._transitionComplete=function(t,e,n){if(e){o.default(e).removeClass(ue);var i=o.default(e.parentNode).find("> .dropdown-menu .active")[0];i&&o.default(i).removeClass(ue),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}o.default(t).addClass(ue),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),d.reflow(t),t.classList.contains(fe)&&t.classList.add(de);var a=t.parentNode;if(a&&"LI"===a.nodeName&&(a=a.parentNode),a&&o.default(a).hasClass("dropdown-menu")){var s=o.default(t).closest(".dropdown")[0];if(s){var l=[].slice.call(s.querySelectorAll(".dropdown-toggle"));o.default(l).addClass(ue)}t.setAttribute("aria-expanded",!0)}n&&n()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(le);if(i||(i=new t(this),n.data(le,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',(function(t){t.preventDefault(),ge._jQueryInterface.call(o.default(this),"show")})),o.default.fn.tab=ge._jQueryInterface,o.default.fn.tab.Constructor=ge,o.default.fn.tab.noConflict=function(){return o.default.fn.tab=re,ge._jQueryInterface};var me="bs.toast",pe=o.default.fn.toast,_e="hide",ve="show",ye="showing",be="click.dismiss.bs.toast",Ee={animation:!0,autohide:!0,delay:500},Te={animation:"boolean",autohide:"boolean",delay:"number"},we=function(){function t(t,e){this._element=t,this._config=this._getConfig(e),this._timeout=null,this._setListeners()}var e=t.prototype;return e.show=function(){var t=this,e=o.default.Event("show.bs.toast");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){this._clearTimeout(),this._config.animation&&this._element.classList.add("fade");var n=function(){t._element.classList.remove(ye),t._element.classList.add(ve),o.default(t._element).trigger("shown.bs.toast"),t._config.autohide&&(t._timeout=setTimeout((function(){t.hide()}),t._config.delay))};if(this._element.classList.remove(_e),d.reflow(this._element),this._element.classList.add(ye),this._config.animation){var i=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,n).emulateTransitionEnd(i)}else n()}},e.hide=function(){if(this._element.classList.contains(ve)){var t=o.default.Event("hide.bs.toast");o.default(this._element).trigger(t),t.isDefaultPrevented()||this._close()}},e.dispose=function(){this._clearTimeout(),this._element.classList.contains(ve)&&this._element.classList.remove(ve),o.default(this._element).off(be),o.default.removeData(this._element,me),this._element=null,this._config=null},e._getConfig=function(t){return t=r({},Ee,o.default(this._element).data(),"object"==typeof t&&t?t:{}),d.typeCheckConfig("toast",t,this.constructor.DefaultType),t},e._setListeners=function(){var t=this;o.default(this._element).on(be,'[data-dismiss="toast"]',(function(){return t.hide()}))},e._close=function(){var t=this,e=function(){t._element.classList.add(_e),o.default(t._element).trigger("hidden.bs.toast")};if(this._element.classList.remove(ve),this._config.animation){var n=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},e._clearTimeout=function(){clearTimeout(this._timeout),this._timeout=null},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(me);if(i||(i=new t(this,"object"==typeof e&&e),n.data(me,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e](this)}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"DefaultType",get:function(){return Te}},{key:"Default",get:function(){return Ee}}]),t}();o.default.fn.toast=we._jQueryInterface,o.default.fn.toast.Constructor=we,o.default.fn.toast.noConflict=function(){return o.default.fn.toast=pe,we._jQueryInterface},t.Alert=g,t.Button=E,t.Carousel=P,t.Collapse=V,t.Dropdown=lt,t.Modal=Ct,t.Popover=Jt,t.Scrollspy=se,t.Tab=ge,t.Toast=we,t.Tooltip=Wt,t.Util=d,Object.defineProperty(t,"__esModule",{value:!0})})); +//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/code/ch5_partials/ch5_final_video_collector/static/js/jquery-3.5.1.slim.min.js b/code/ch5_partials/ch5_final_video_collector/static/js/jquery-3.5.1.slim.min.js new file mode 100644 index 0000000..36b4e1a --- /dev/null +++ b/code/ch5_partials/ch5_final_video_collector/static/js/jquery-3.5.1.slim.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(g,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,v=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),m={},b=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},w=g.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function C(e,t,n){var r,i,o=(n=n||w).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function T(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector",E=function(e,t){return new E.fn.init(e,t)};function d(e){var t=!!e&&"length"in e&&e.length,n=T(e);return!b(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+R+")"+R+"*"),U=new RegExp(R+"|>"),V=new RegExp(W),X=new RegExp("^"+B+"$"),Q={ID:new RegExp("^#("+B+")"),CLASS:new RegExp("^\\.("+B+")"),TAG:new RegExp("^("+B+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+R+"*(even|odd|(([+-]|)(\\d*)n|)"+R+"*(?:([+-]|)"+R+"*(\\d+)|))"+R+"*\\)|)","i"),bool:new RegExp("^(?:"+I+")$","i"),needsContext:new RegExp("^"+R+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+R+"*((?:-\\d)?\\d*)"+R+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,G=/^(?:input|select|textarea|button)$/i,K=/^h\d$/i,J=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+R+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){C()},ae=xe(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{O.apply(t=P.call(d.childNodes),d.childNodes),t[d.childNodes.length].nodeType}catch(e){O={apply:t.length?function(e,t){q.apply(e,P.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,d=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==d&&9!==d&&11!==d)return n;if(!r&&(C(e),e=e||T,E)){if(11!==d&&(u=Z.exec(t)))if(i=u[1]){if(9===d){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return O.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&p.getElementsByClassName&&e.getElementsByClassName)return O.apply(n,e.getElementsByClassName(i)),n}if(p.qsa&&!k[t+" "]&&(!v||!v.test(t))&&(1!==d||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===d&&(U.test(t)||_.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&p.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=A)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+be(l[o]);c=l.join(",")}try{return O.apply(n,f.querySelectorAll(c)),n}catch(e){k(t,!0)}finally{s===A&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>x.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[A]=!0,e}function ce(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)x.attrHandle[n[r]]=t}function de(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pe(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in p=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},C=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:d;return r!=T&&9===r.nodeType&&r.documentElement&&(a=(T=r).documentElement,E=!i(T),d!=T&&(n=T.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),p.scope=ce(function(e){return a.appendChild(e).appendChild(T.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),p.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),p.getElementsByTagName=ce(function(e){return e.appendChild(T.createComment("")),!e.getElementsByTagName("*").length}),p.getElementsByClassName=J.test(T.getElementsByClassName),p.getById=ce(function(e){return a.appendChild(e).id=A,!T.getElementsByName||!T.getElementsByName(A).length}),p.getById?(x.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(x.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),x.find.TAG=p.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):p.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},x.find.CLASS=p.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(p.qsa=J.test(T.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+R+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+R+"*(?:value|"+I+")"),e.querySelectorAll("[id~="+A+"-]").length||v.push("~="),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+R+"*name"+R+"*="+R+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+A+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=T.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+R+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(p.matchesSelector=J.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){p.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",W)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=J.test(a.compareDocumentPosition),y=t||J.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!p.sortDetached&&t.compareDocumentPosition(e)===n?e==T||e.ownerDocument==d&&y(d,e)?-1:t==T||t.ownerDocument==d&&y(d,t)?1:u?H(u,e)-H(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==T?-1:t==T?1:i?-1:o?1:u?H(u,e)-H(u,t):0;if(i===o)return de(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?de(a[r],s[r]):a[r]==d?-1:s[r]==d?1:0}),T},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(C(e),p.matchesSelector&&E&&!k[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||p.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){k(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&V.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+R+")"+e+"("+R+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return b(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):"string"!=typeof n?E.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||L,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:j.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:w,!0)),k.test(r[1])&&E.isPlainObject(t))for(r in t)b(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=w.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):b(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,L=E(w);var q=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,pe=/^$|^module$|\/(?:java|ecma)script/i;le=w.createDocumentFragment().appendChild(w.createElement("div")),(ce=w.createElement("input")).setAttribute("type","radio"),ce.setAttribute("checked","checked"),ce.setAttribute("name","t"),le.appendChild(ce),m.checkClone=le.cloneNode(!0).cloneNode(!0).lastChild.checked,le.innerHTML="",m.noCloneChecked=!!le.cloneNode(!0).lastChild.defaultValue,le.innerHTML="",m.option=!!le.lastChild;var he={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ge(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&S(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var ye=/<|&#?\w+;/;function me(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),d=[],p=0,h=e.length;p\s*$/g;function Le(e,t){return S(e,"table")&&S(11!==t.nodeType?t:t.firstChild,"tr")&&E(e).children("tbody")[0]||e}function je(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n
",2===ft.childNodes.length),E.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(m.createHTMLDocument?((r=(t=w.implementation.createHTMLDocument("")).createElement("base")).href=w.location.href,t.head.appendChild(r)):t=w),o=!n&&[],(i=k.exec(e))?[t.createElement(i[1])]:(i=me([e],t,o),o&&o.length&&E(o).remove(),E.merge([],i.childNodes)));var r,i,o},E.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=E.css(e,"position"),c=E(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=E.css(e,"top"),u=E.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),b(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===E.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===E.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=E(e).offset()).top+=E.css(e,"borderTopWidth",!0),i.left+=E.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-E.css(r,"marginTop",!0),left:t.left-i.left-E.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===E.css(e,"position"))e=e.offsetParent;return e||re})}}),E.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;E.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each(["top","left"],function(e,n){E.cssHooks[n]=Fe(m.pixelPosition,function(e,t){if(t)return t=We(e,n),Ie.test(t)?E(e).position()[n]+"px":t})}),E.each({Height:"height",Width:"width"},function(a,s){E.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){E.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?E.css(e,t,i):E.style(e,t,n,i)},s,n?e:void 0,n)}})}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){E.fn[n]=function(e,t){return 0=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),ae({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=le({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f]),E=parseFloat(w['border'+f+'Width']),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},ae(n,m,$(v)),ae(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ce.FLIP:p=[n,i];break;case ce.CLOCKWISE:p=G(n);break;case ce.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u),E=!!t.flipVariationsByContent&&(w&&'start'===r&&c||w&&'end'===r&&h||!w&&'start'===r&&u||!w&&'end'===r&&g),v=y||E;(m||b||v)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),v&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=le({},e.offsets.popper,C(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport',flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=D(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.rightwindow.devicePixelRatio||!fe),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=B('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=le({},E,e.attributes),e.styles=le({},m,e.styles),e.arrowStyles=le({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return V(e.instance.popper,e.styles),j(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&V(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),V(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ge}); +//# sourceMappingURL=popper.min.js.map diff --git a/code/ch5_partials/ch5_starter_video_collector/static/js/bootstrap-4.6.1.min.js b/code/ch5_partials/ch5_starter_video_collector/static/js/bootstrap-4.6.1.min.js new file mode 100644 index 0000000..50720ea --- /dev/null +++ b/code/ch5_partials/ch5_starter_video_collector/static/js/bootstrap-4.6.1.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.6.1 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap={},t.jQuery,t.Popper)}(this,(function(t,e,n){"use strict";function i(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var o=i(e),a=i(n);function s(t,e){for(var n=0;n=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}};d.jQueryDetection(),o.default.fn.emulateTransitionEnd=function(t){var e=this,n=!1;return o.default(this).one(d.TRANSITION_END,(function(){n=!0})),setTimeout((function(){n||d.triggerTransitionEnd(e)}),t),this},o.default.event.special[d.TRANSITION_END]={bindType:f,delegateType:f,handle:function(t){if(o.default(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}};var c="bs.alert",h=o.default.fn.alert,g=function(){function t(t){this._element=t}var e=t.prototype;return e.close=function(t){var e=this._element;t&&(e=this._getRootElement(t)),this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.dispose=function(){o.default.removeData(this._element,c),this._element=null},e._getRootElement=function(t){var e=d.getSelectorFromElement(t),n=!1;return e&&(n=document.querySelector(e)),n||(n=o.default(t).closest(".alert")[0]),n},e._triggerCloseEvent=function(t){var e=o.default.Event("close.bs.alert");return o.default(t).trigger(e),e},e._removeElement=function(t){var e=this;if(o.default(t).removeClass("show"),o.default(t).hasClass("fade")){var n=d.getTransitionDurationFromElement(t);o.default(t).one(d.TRANSITION_END,(function(n){return e._destroyElement(t,n)})).emulateTransitionEnd(n)}else this._destroyElement(t)},e._destroyElement=function(t){o.default(t).detach().trigger("closed.bs.alert").remove()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(c);i||(i=new t(this),n.data(c,i)),"close"===e&&i[e](this)}))},t._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',g._handleDismiss(new g)),o.default.fn.alert=g._jQueryInterface,o.default.fn.alert.Constructor=g,o.default.fn.alert.noConflict=function(){return o.default.fn.alert=h,g._jQueryInterface};var m="bs.button",p=o.default.fn.button,_="active",v='[data-toggle^="button"]',y='input:not([type="hidden"])',b=".btn",E=function(){function t(t){this._element=t,this.shouldAvoidTriggerChange=!1}var e=t.prototype;return e.toggle=function(){var t=!0,e=!0,n=o.default(this._element).closest('[data-toggle="buttons"]')[0];if(n){var i=this._element.querySelector(y);if(i){if("radio"===i.type)if(i.checked&&this._element.classList.contains(_))t=!1;else{var a=n.querySelector(".active");a&&o.default(a).removeClass(_)}t&&("checkbox"!==i.type&&"radio"!==i.type||(i.checked=!this._element.classList.contains(_)),this.shouldAvoidTriggerChange||o.default(i).trigger("change")),i.focus(),e=!1}}this._element.hasAttribute("disabled")||this._element.classList.contains("disabled")||(e&&this._element.setAttribute("aria-pressed",!this._element.classList.contains(_)),t&&o.default(this._element).toggleClass(_))},e.dispose=function(){o.default.removeData(this._element,m),this._element=null},t._jQueryInterface=function(e,n){return this.each((function(){var i=o.default(this),a=i.data(m);a||(a=new t(this),i.data(m,a)),a.shouldAvoidTriggerChange=n,"toggle"===e&&a[e]()}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.button.data-api",v,(function(t){var e=t.target,n=e;if(o.default(e).hasClass("btn")||(e=o.default(e).closest(b)[0]),!e||e.hasAttribute("disabled")||e.classList.contains("disabled"))t.preventDefault();else{var i=e.querySelector(y);if(i&&(i.hasAttribute("disabled")||i.classList.contains("disabled")))return void t.preventDefault();"INPUT"!==n.tagName&&"LABEL"===e.tagName||E._jQueryInterface.call(o.default(e),"toggle","INPUT"===n.tagName)}})).on("focus.bs.button.data-api blur.bs.button.data-api",v,(function(t){var e=o.default(t.target).closest(b)[0];o.default(e).toggleClass("focus",/^focus(in)?$/.test(t.type))})),o.default(window).on("load.bs.button.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-toggle="buttons"] .btn')),e=0,n=t.length;e0,this._pointerEvent=Boolean(window.PointerEvent||window.MSPointerEvent),this._addEventListeners()}var e=t.prototype;return e.next=function(){this._isSliding||this._slide(N)},e.nextWhenVisible=function(){var t=o.default(this._element);!document.hidden&&t.is(":visible")&&"hidden"!==t.css("visibility")&&this.next()},e.prev=function(){this._isSliding||this._slide(D)},e.pause=function(t){t||(this._isPaused=!0),this._element.querySelector(".carousel-item-next, .carousel-item-prev")&&(d.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},e.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},e.to=function(t){var e=this;this._activeElement=this._element.querySelector(I);var n=this._getItemIndex(this._activeElement);if(!(t>this._items.length-1||t<0))if(this._isSliding)o.default(this._element).one(A,(function(){return e.to(t)}));else{if(n===t)return this.pause(),void this.cycle();var i=t>n?N:D;this._slide(i,this._items[t])}},e.dispose=function(){o.default(this._element).off(".bs.carousel"),o.default.removeData(this._element,w),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},e._getConfig=function(t){return t=r({},k,t),d.typeCheckConfig(T,t,O),t},e._handleSwipe=function(){var t=Math.abs(this.touchDeltaX);if(!(t<=40)){var e=t/this.touchDeltaX;this.touchDeltaX=0,e>0&&this.prev(),e<0&&this.next()}},e._addEventListeners=function(){var t=this;this._config.keyboard&&o.default(this._element).on("keydown.bs.carousel",(function(e){return t._keydown(e)})),"hover"===this._config.pause&&o.default(this._element).on("mouseenter.bs.carousel",(function(e){return t.pause(e)})).on("mouseleave.bs.carousel",(function(e){return t.cycle(e)})),this._config.touch&&this._addTouchEventListeners()},e._addTouchEventListeners=function(){var t=this;if(this._touchSupported){var e=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]?t.touchStartX=e.originalEvent.clientX:t._pointerEvent||(t.touchStartX=e.originalEvent.touches[0].clientX)},n=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]&&(t.touchDeltaX=e.originalEvent.clientX-t.touchStartX),t._handleSwipe(),"hover"===t._config.pause&&(t.pause(),t.touchTimeout&&clearTimeout(t.touchTimeout),t.touchTimeout=setTimeout((function(e){return t.cycle(e)}),500+t._config.interval))};o.default(this._element.querySelectorAll(".carousel-item img")).on("dragstart.bs.carousel",(function(t){return t.preventDefault()})),this._pointerEvent?(o.default(this._element).on("pointerdown.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("pointerup.bs.carousel",(function(t){return n(t)})),this._element.classList.add("pointer-event")):(o.default(this._element).on("touchstart.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("touchmove.bs.carousel",(function(e){return function(e){t.touchDeltaX=e.originalEvent.touches&&e.originalEvent.touches.length>1?0:e.originalEvent.touches[0].clientX-t.touchStartX}(e)})),o.default(this._element).on("touchend.bs.carousel",(function(t){return n(t)})))}},e._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next()}},e._getItemIndex=function(t){return this._items=t&&t.parentNode?[].slice.call(t.parentNode.querySelectorAll(".carousel-item")):[],this._items.indexOf(t)},e._getItemByDirection=function(t,e){var n=t===N,i=t===D,o=this._getItemIndex(e),a=this._items.length-1;if((i&&0===o||n&&o===a)&&!this._config.wrap)return e;var s=(o+(t===D?-1:1))%this._items.length;return-1===s?this._items[this._items.length-1]:this._items[s]},e._triggerSlideEvent=function(t,e){var n=this._getItemIndex(t),i=this._getItemIndex(this._element.querySelector(I)),a=o.default.Event("slide.bs.carousel",{relatedTarget:t,direction:e,from:i,to:n});return o.default(this._element).trigger(a),a},e._setActiveIndicatorElement=function(t){if(this._indicatorsElement){var e=[].slice.call(this._indicatorsElement.querySelectorAll(".active"));o.default(e).removeClass(S);var n=this._indicatorsElement.children[this._getItemIndex(t)];n&&o.default(n).addClass(S)}},e._updateInterval=function(){var t=this._activeElement||this._element.querySelector(I);if(t){var e=parseInt(t.getAttribute("data-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}},e._slide=function(t,e){var n,i,a,s=this,l=this._element.querySelector(I),r=this._getItemIndex(l),u=e||l&&this._getItemByDirection(t,l),f=this._getItemIndex(u),c=Boolean(this._interval);if(t===N?(n="carousel-item-left",i="carousel-item-next",a="left"):(n="carousel-item-right",i="carousel-item-prev",a="right"),u&&o.default(u).hasClass(S))this._isSliding=!1;else if(!this._triggerSlideEvent(u,a).isDefaultPrevented()&&l&&u){this._isSliding=!0,c&&this.pause(),this._setActiveIndicatorElement(u),this._activeElement=u;var h=o.default.Event(A,{relatedTarget:u,direction:a,from:r,to:f});if(o.default(this._element).hasClass("slide")){o.default(u).addClass(i),d.reflow(u),o.default(l).addClass(n),o.default(u).addClass(n);var g=d.getTransitionDurationFromElement(l);o.default(l).one(d.TRANSITION_END,(function(){o.default(u).removeClass(n+" "+i).addClass(S),o.default(l).removeClass("active "+i+" "+n),s._isSliding=!1,setTimeout((function(){return o.default(s._element).trigger(h)}),0)})).emulateTransitionEnd(g)}else o.default(l).removeClass(S),o.default(u).addClass(S),this._isSliding=!1,o.default(this._element).trigger(h);c&&this.cycle()}},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(w),i=r({},k,o.default(this).data());"object"==typeof e&&(i=r({},i,e));var a="string"==typeof e?e:i.slide;if(n||(n=new t(this,i),o.default(this).data(w,n)),"number"==typeof e)n.to(e);else if("string"==typeof a){if("undefined"==typeof n[a])throw new TypeError('No method named "'+a+'"');n[a]()}else i.interval&&i.ride&&(n.pause(),n.cycle())}))},t._dataApiClickHandler=function(e){var n=d.getSelectorFromElement(this);if(n){var i=o.default(n)[0];if(i&&o.default(i).hasClass("carousel")){var a=r({},o.default(i).data(),o.default(this).data()),s=this.getAttribute("data-slide-to");s&&(a.interval=!1),t._jQueryInterface.call(o.default(i),a),s&&o.default(i).data(w).to(s),e.preventDefault()}}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return k}}]),t}();o.default(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",P._dataApiClickHandler),o.default(window).on("load.bs.carousel.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-ride="carousel"]')),e=0,n=t.length;e0&&(this._selector=s,this._triggerArray.push(a))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}var e=t.prototype;return e.toggle=function(){o.default(this._element).hasClass(q)?this.hide():this.show()},e.show=function(){var e,n,i=this;if(!(this._isTransitioning||o.default(this._element).hasClass(q)||(this._parent&&0===(e=[].slice.call(this._parent.querySelectorAll(".show, .collapsing")).filter((function(t){return"string"==typeof i._config.parent?t.getAttribute("data-parent")===i._config.parent:t.classList.contains(F)}))).length&&(e=null),e&&(n=o.default(e).not(this._selector).data(R))&&n._isTransitioning))){var a=o.default.Event("show.bs.collapse");if(o.default(this._element).trigger(a),!a.isDefaultPrevented()){e&&(t._jQueryInterface.call(o.default(e).not(this._selector),"hide"),n||o.default(e).data(R,null));var s=this._getDimension();o.default(this._element).removeClass(F).addClass(Q),this._element.style[s]=0,this._triggerArray.length&&o.default(this._triggerArray).removeClass(B).attr("aria-expanded",!0),this.setTransitioning(!0);var l="scroll"+(s[0].toUpperCase()+s.slice(1)),r=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,(function(){o.default(i._element).removeClass(Q).addClass("collapse show"),i._element.style[s]="",i.setTransitioning(!1),o.default(i._element).trigger("shown.bs.collapse")})).emulateTransitionEnd(r),this._element.style[s]=this._element[l]+"px"}}},e.hide=function(){var t=this;if(!this._isTransitioning&&o.default(this._element).hasClass(q)){var e=o.default.Event("hide.bs.collapse");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){var n=this._getDimension();this._element.style[n]=this._element.getBoundingClientRect()[n]+"px",d.reflow(this._element),o.default(this._element).addClass(Q).removeClass("collapse show");var i=this._triggerArray.length;if(i>0)for(var a=0;a0},e._getOffset=function(){var t=this,e={};return"function"==typeof this._config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t._config.offset(e.offsets,t._element)),e}:e.offset=this._config.offset,e},e._getPopperConfig=function(){var t={placement:this._getPlacement(),modifiers:{offset:this._getOffset(),flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}};return"static"===this._config.display&&(t.modifiers.applyStyle={enabled:!1}),r({},t,this._config.popperConfig)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(K);if(n||(n=new t(this,"object"==typeof e?e:null),o.default(this).data(K,n)),"string"==typeof e){if("undefined"==typeof n[e])throw new TypeError('No method named "'+e+'"');n[e]()}}))},t._clearMenus=function(e){if(!e||3!==e.which&&("keyup"!==e.type||9===e.which))for(var n=[].slice.call(document.querySelectorAll(it)),i=0,a=n.length;i0&&s--,40===e.which&&sdocument.documentElement.clientHeight;n||(this._element.style.overflowY="hidden"),this._element.classList.add(ht);var i=d.getTransitionDurationFromElement(this._dialog);o.default(this._element).off(d.TRANSITION_END),o.default(this._element).one(d.TRANSITION_END,(function(){t._element.classList.remove(ht),n||o.default(t._element).one(d.TRANSITION_END,(function(){t._element.style.overflowY=""})).emulateTransitionEnd(t._element,i)})).emulateTransitionEnd(i),this._element.focus()}},e._showElement=function(t){var e=this,n=o.default(this._element).hasClass(dt),i=this._dialog?this._dialog.querySelector(".modal-body"):null;this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),o.default(this._dialog).hasClass("modal-dialog-scrollable")&&i?i.scrollTop=0:this._element.scrollTop=0,n&&d.reflow(this._element),o.default(this._element).addClass(ct),this._config.focus&&this._enforceFocus();var a=o.default.Event("shown.bs.modal",{relatedTarget:t}),s=function(){e._config.focus&&e._element.focus(),e._isTransitioning=!1,o.default(e._element).trigger(a)};if(n){var l=d.getTransitionDurationFromElement(this._dialog);o.default(this._dialog).one(d.TRANSITION_END,s).emulateTransitionEnd(l)}else s()},e._enforceFocus=function(){var t=this;o.default(document).off(pt).on(pt,(function(e){document!==e.target&&t._element!==e.target&&0===o.default(t._element).has(e.target).length&&t._element.focus()}))},e._setEscapeEvent=function(){var t=this;this._isShown?o.default(this._element).on(yt,(function(e){t._config.keyboard&&27===e.which?(e.preventDefault(),t.hide()):t._config.keyboard||27!==e.which||t._triggerBackdropTransition()})):this._isShown||o.default(this._element).off(yt)},e._setResizeEvent=function(){var t=this;this._isShown?o.default(window).on(_t,(function(e){return t.handleUpdate(e)})):o.default(window).off(_t)},e._hideModal=function(){var t=this;this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._showBackdrop((function(){o.default(document.body).removeClass(ft),t._resetAdjustments(),t._resetScrollbar(),o.default(t._element).trigger(gt)}))},e._removeBackdrop=function(){this._backdrop&&(o.default(this._backdrop).remove(),this._backdrop=null)},e._showBackdrop=function(t){var e=this,n=o.default(this._element).hasClass(dt)?dt:"";if(this._isShown&&this._config.backdrop){if(this._backdrop=document.createElement("div"),this._backdrop.className="modal-backdrop",n&&this._backdrop.classList.add(n),o.default(this._backdrop).appendTo(document.body),o.default(this._element).on(vt,(function(t){e._ignoreBackdropClick?e._ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"===e._config.backdrop?e._triggerBackdropTransition():e.hide())})),n&&d.reflow(this._backdrop),o.default(this._backdrop).addClass(ct),!t)return;if(!n)return void t();var i=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,t).emulateTransitionEnd(i)}else if(!this._isShown&&this._backdrop){o.default(this._backdrop).removeClass(ct);var a=function(){e._removeBackdrop(),t&&t()};if(o.default(this._element).hasClass(dt)){var s=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a()}else t&&t()},e._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},e._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},e._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=Math.round(t.left+t.right)
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",customClass:"",sanitize:!0,sanitizeFn:null,whiteList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},Ut={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string|function)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",whiteList:"object",popperConfig:"(null|object)"},Mt={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},Wt=function(){function t(t,e){if("undefined"==typeof a.default)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var e=t.prototype;return e.enable=function(){this._isEnabled=!0},e.disable=function(){this._isEnabled=!1},e.toggleEnabled=function(){this._isEnabled=!this._isEnabled},e.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=o.default(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(o.default(this.getTipElement()).hasClass(Rt))return void this._leave(null,this);this._enter(null,this)}},e.dispose=function(){clearTimeout(this._timeout),o.default.removeData(this.element,this.constructor.DATA_KEY),o.default(this.element).off(this.constructor.EVENT_KEY),o.default(this.element).closest(".modal").off("hide.bs.modal",this._hideModalHandler),this.tip&&o.default(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},e.show=function(){var t=this;if("none"===o.default(this.element).css("display"))throw new Error("Please use show on visible elements");var e=o.default.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){o.default(this.element).trigger(e);var n=d.findShadowRoot(this.element),i=o.default.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(e.isDefaultPrevented()||!i)return;var s=this.getTipElement(),l=d.getUID(this.constructor.NAME);s.setAttribute("id",l),this.element.setAttribute("aria-describedby",l),this.setContent(),this.config.animation&&o.default(s).addClass(Lt);var r="function"==typeof this.config.placement?this.config.placement.call(this,s,this.element):this.config.placement,u=this._getAttachment(r);this.addAttachmentClass(u);var f=this._getContainer();o.default(s).data(this.constructor.DATA_KEY,this),o.default.contains(this.element.ownerDocument.documentElement,this.tip)||o.default(s).appendTo(f),o.default(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new a.default(this.element,s,this._getPopperConfig(u)),o.default(s).addClass(Rt),o.default(s).addClass(this.config.customClass),"ontouchstart"in document.documentElement&&o.default(document.body).children().on("mouseover",null,o.default.noop);var c=function(){t.config.animation&&t._fixTransition();var e=t._hoverState;t._hoverState=null,o.default(t.element).trigger(t.constructor.Event.SHOWN),e===qt&&t._leave(null,t)};if(o.default(this.tip).hasClass(Lt)){var h=d.getTransitionDurationFromElement(this.tip);o.default(this.tip).one(d.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},e.hide=function(t){var e=this,n=this.getTipElement(),i=o.default.Event(this.constructor.Event.HIDE),a=function(){e._hoverState!==xt&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),o.default(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(o.default(this.element).trigger(i),!i.isDefaultPrevented()){if(o.default(n).removeClass(Rt),"ontouchstart"in document.documentElement&&o.default(document.body).children().off("mouseover",null,o.default.noop),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,o.default(this.tip).hasClass(Lt)){var s=d.getTransitionDurationFromElement(n);o.default(n).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a();this._hoverState=""}},e.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},e.isWithContent=function(){return Boolean(this.getTitle())},e.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-tooltip-"+t)},e.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},e.setContent=function(){var t=this.getTipElement();this.setElementContent(o.default(t.querySelectorAll(".tooltip-inner")),this.getTitle()),o.default(t).removeClass("fade show")},e.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=At(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?o.default(e).parent().is(t)||t.empty().append(e):t.text(o.default(e).text())},e.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},e._getPopperConfig=function(t){var e=this;return r({},{placement:t,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:".arrow"},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}},this.config.popperConfig)},e._getOffset=function(){var t=this,e={};return"function"==typeof this.config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t.config.offset(e.offsets,t.element)),e}:e.offset=this.config.offset,e},e._getContainer=function(){return!1===this.config.container?document.body:d.isElement(this.config.container)?o.default(this.config.container):o.default(document).find(this.config.container)},e._getAttachment=function(t){return Bt[t.toUpperCase()]},e._setListeners=function(){var t=this;this.config.trigger.split(" ").forEach((function(e){if("click"===e)o.default(t.element).on(t.constructor.Event.CLICK,t.config.selector,(function(e){return t.toggle(e)}));else if("manual"!==e){var n=e===Ft?t.constructor.Event.MOUSEENTER:t.constructor.Event.FOCUSIN,i=e===Ft?t.constructor.Event.MOUSELEAVE:t.constructor.Event.FOCUSOUT;o.default(t.element).on(n,t.config.selector,(function(e){return t._enter(e)})).on(i,t.config.selector,(function(e){return t._leave(e)}))}})),this._hideModalHandler=function(){t.element&&t.hide()},o.default(this.element).closest(".modal").on("hide.bs.modal",this._hideModalHandler),this.config.selector?this.config=r({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},e._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},e._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Qt:Ft]=!0),o.default(e.getTipElement()).hasClass(Rt)||e._hoverState===xt?e._hoverState=xt:(clearTimeout(e._timeout),e._hoverState=xt,e.config.delay&&e.config.delay.show?e._timeout=setTimeout((function(){e._hoverState===xt&&e.show()}),e.config.delay.show):e.show())},e._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Qt:Ft]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=qt,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout((function(){e._hoverState===qt&&e.hide()}),e.config.delay.hide):e.hide())},e._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},e._getConfig=function(t){var e=o.default(this.element).data();return Object.keys(e).forEach((function(t){-1!==Pt.indexOf(t)&&delete e[t]})),"number"==typeof(t=r({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),d.typeCheckConfig(It,t,this.constructor.DefaultType),t.sanitize&&(t.template=At(t.template,t.whiteList,t.sanitizeFn)),t},e._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},e._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(jt);null!==e&&e.length&&t.removeClass(e.join(""))},e._handlePopperPlacementChange=function(t){this.tip=t.instance.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},e._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(o.default(t).removeClass(Lt),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(kt),a="object"==typeof e&&e;if((i||!/dispose|hide/.test(e))&&(i||(i=new t(this,a),n.data(kt,i)),"string"==typeof e)){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Ht}},{key:"NAME",get:function(){return It}},{key:"DATA_KEY",get:function(){return kt}},{key:"Event",get:function(){return Mt}},{key:"EVENT_KEY",get:function(){return".bs.tooltip"}},{key:"DefaultType",get:function(){return Ut}}]),t}();o.default.fn.tooltip=Wt._jQueryInterface,o.default.fn.tooltip.Constructor=Wt,o.default.fn.tooltip.noConflict=function(){return o.default.fn.tooltip=Ot,Wt._jQueryInterface};var Vt="bs.popover",zt=o.default.fn.popover,Kt=new RegExp("(^|\\s)bs-popover\\S+","g"),Xt=r({},Wt.Default,{placement:"right",trigger:"click",content:"",template:''}),Yt=r({},Wt.DefaultType,{content:"(string|element|function)"}),$t={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"},Jt=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),e.prototype.constructor=e,u(e,n);var a=i.prototype;return a.isWithContent=function(){return this.getTitle()||this._getContent()},a.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-popover-"+t)},a.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},a.setContent=function(){var t=o.default(this.getTipElement());this.setElementContent(t.find(".popover-header"),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(".popover-body"),e),t.removeClass("fade show")},a._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},a._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(Kt);null!==e&&e.length>0&&t.removeClass(e.join(""))},i._jQueryInterface=function(t){return this.each((function(){var e=o.default(this).data(Vt),n="object"==typeof t?t:null;if((e||!/dispose|hide/.test(t))&&(e||(e=new i(this,n),o.default(this).data(Vt,e)),"string"==typeof t)){if("undefined"==typeof e[t])throw new TypeError('No method named "'+t+'"');e[t]()}}))},l(i,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Xt}},{key:"NAME",get:function(){return"popover"}},{key:"DATA_KEY",get:function(){return Vt}},{key:"Event",get:function(){return $t}},{key:"EVENT_KEY",get:function(){return".bs.popover"}},{key:"DefaultType",get:function(){return Yt}}]),i}(Wt);o.default.fn.popover=Jt._jQueryInterface,o.default.fn.popover.Constructor=Jt,o.default.fn.popover.noConflict=function(){return o.default.fn.popover=zt,Jt._jQueryInterface};var Gt="scrollspy",Zt="bs.scrollspy",te=o.default.fn[Gt],ee="active",ne="position",ie=".nav, .list-group",oe={offset:10,method:"auto",target:""},ae={offset:"number",method:"string",target:"(string|element)"},se=function(){function t(t,e){var n=this;this._element=t,this._scrollElement="BODY"===t.tagName?window:t,this._config=this._getConfig(e),this._selector=this._config.target+" .nav-link,"+this._config.target+" .list-group-item,"+this._config.target+" .dropdown-item",this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,o.default(this._scrollElement).on("scroll.bs.scrollspy",(function(t){return n._process(t)})),this.refresh(),this._process()}var e=t.prototype;return e.refresh=function(){var t=this,e=this._scrollElement===this._scrollElement.window?"offset":ne,n="auto"===this._config.method?e:this._config.method,i=n===ne?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),[].slice.call(document.querySelectorAll(this._selector)).map((function(t){var e,a=d.getSelectorFromElement(t);if(a&&(e=document.querySelector(a)),e){var s=e.getBoundingClientRect();if(s.width||s.height)return[o.default(e)[n]().top+i,a]}return null})).filter((function(t){return t})).sort((function(t,e){return t[0]-e[0]})).forEach((function(e){t._offsets.push(e[0]),t._targets.push(e[1])}))},e.dispose=function(){o.default.removeData(this._element,Zt),o.default(this._scrollElement).off(".bs.scrollspy"),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},e._getConfig=function(t){if("string"!=typeof(t=r({},oe,"object"==typeof t&&t?t:{})).target&&d.isElement(t.target)){var e=o.default(t.target).attr("id");e||(e=d.getUID(Gt),o.default(t.target).attr("id",e)),t.target="#"+e}return d.typeCheckConfig(Gt,t,ae),t},e._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},e._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},e._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},e._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;)this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||t li > .active",ge=function(){function t(t){this._element=t}var e=t.prototype;return e.show=function(){var t=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&o.default(this._element).hasClass(ue)||o.default(this._element).hasClass("disabled"))){var e,n,i=o.default(this._element).closest(".nav, .list-group")[0],a=d.getSelectorFromElement(this._element);if(i){var s="UL"===i.nodeName||"OL"===i.nodeName?he:ce;n=(n=o.default.makeArray(o.default(i).find(s)))[n.length-1]}var l=o.default.Event("hide.bs.tab",{relatedTarget:this._element}),r=o.default.Event("show.bs.tab",{relatedTarget:n});if(n&&o.default(n).trigger(l),o.default(this._element).trigger(r),!r.isDefaultPrevented()&&!l.isDefaultPrevented()){a&&(e=document.querySelector(a)),this._activate(this._element,i);var u=function(){var e=o.default.Event("hidden.bs.tab",{relatedTarget:t._element}),i=o.default.Event("shown.bs.tab",{relatedTarget:n});o.default(n).trigger(e),o.default(t._element).trigger(i)};e?this._activate(e,e.parentNode,u):u()}}},e.dispose=function(){o.default.removeData(this._element,le),this._element=null},e._activate=function(t,e,n){var i=this,a=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?o.default(e).children(ce):o.default(e).find(he))[0],s=n&&a&&o.default(a).hasClass(fe),l=function(){return i._transitionComplete(t,a,n)};if(a&&s){var r=d.getTransitionDurationFromElement(a);o.default(a).removeClass(de).one(d.TRANSITION_END,l).emulateTransitionEnd(r)}else l()},e._transitionComplete=function(t,e,n){if(e){o.default(e).removeClass(ue);var i=o.default(e.parentNode).find("> .dropdown-menu .active")[0];i&&o.default(i).removeClass(ue),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}o.default(t).addClass(ue),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),d.reflow(t),t.classList.contains(fe)&&t.classList.add(de);var a=t.parentNode;if(a&&"LI"===a.nodeName&&(a=a.parentNode),a&&o.default(a).hasClass("dropdown-menu")){var s=o.default(t).closest(".dropdown")[0];if(s){var l=[].slice.call(s.querySelectorAll(".dropdown-toggle"));o.default(l).addClass(ue)}t.setAttribute("aria-expanded",!0)}n&&n()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(le);if(i||(i=new t(this),n.data(le,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',(function(t){t.preventDefault(),ge._jQueryInterface.call(o.default(this),"show")})),o.default.fn.tab=ge._jQueryInterface,o.default.fn.tab.Constructor=ge,o.default.fn.tab.noConflict=function(){return o.default.fn.tab=re,ge._jQueryInterface};var me="bs.toast",pe=o.default.fn.toast,_e="hide",ve="show",ye="showing",be="click.dismiss.bs.toast",Ee={animation:!0,autohide:!0,delay:500},Te={animation:"boolean",autohide:"boolean",delay:"number"},we=function(){function t(t,e){this._element=t,this._config=this._getConfig(e),this._timeout=null,this._setListeners()}var e=t.prototype;return e.show=function(){var t=this,e=o.default.Event("show.bs.toast");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){this._clearTimeout(),this._config.animation&&this._element.classList.add("fade");var n=function(){t._element.classList.remove(ye),t._element.classList.add(ve),o.default(t._element).trigger("shown.bs.toast"),t._config.autohide&&(t._timeout=setTimeout((function(){t.hide()}),t._config.delay))};if(this._element.classList.remove(_e),d.reflow(this._element),this._element.classList.add(ye),this._config.animation){var i=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,n).emulateTransitionEnd(i)}else n()}},e.hide=function(){if(this._element.classList.contains(ve)){var t=o.default.Event("hide.bs.toast");o.default(this._element).trigger(t),t.isDefaultPrevented()||this._close()}},e.dispose=function(){this._clearTimeout(),this._element.classList.contains(ve)&&this._element.classList.remove(ve),o.default(this._element).off(be),o.default.removeData(this._element,me),this._element=null,this._config=null},e._getConfig=function(t){return t=r({},Ee,o.default(this._element).data(),"object"==typeof t&&t?t:{}),d.typeCheckConfig("toast",t,this.constructor.DefaultType),t},e._setListeners=function(){var t=this;o.default(this._element).on(be,'[data-dismiss="toast"]',(function(){return t.hide()}))},e._close=function(){var t=this,e=function(){t._element.classList.add(_e),o.default(t._element).trigger("hidden.bs.toast")};if(this._element.classList.remove(ve),this._config.animation){var n=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},e._clearTimeout=function(){clearTimeout(this._timeout),this._timeout=null},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(me);if(i||(i=new t(this,"object"==typeof e&&e),n.data(me,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e](this)}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"DefaultType",get:function(){return Te}},{key:"Default",get:function(){return Ee}}]),t}();o.default.fn.toast=we._jQueryInterface,o.default.fn.toast.Constructor=we,o.default.fn.toast.noConflict=function(){return o.default.fn.toast=pe,we._jQueryInterface},t.Alert=g,t.Button=E,t.Carousel=P,t.Collapse=V,t.Dropdown=lt,t.Modal=Ct,t.Popover=Jt,t.Scrollspy=se,t.Tab=ge,t.Toast=we,t.Tooltip=Wt,t.Util=d,Object.defineProperty(t,"__esModule",{value:!0})})); +//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/code/ch5_partials/ch5_starter_video_collector/static/js/jquery-3.5.1.slim.min.js b/code/ch5_partials/ch5_starter_video_collector/static/js/jquery-3.5.1.slim.min.js new file mode 100644 index 0000000..36b4e1a --- /dev/null +++ b/code/ch5_partials/ch5_starter_video_collector/static/js/jquery-3.5.1.slim.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(g,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,v=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),m={},b=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},w=g.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function C(e,t,n){var r,i,o=(n=n||w).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function T(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector",E=function(e,t){return new E.fn.init(e,t)};function d(e){var t=!!e&&"length"in e&&e.length,n=T(e);return!b(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+R+")"+R+"*"),U=new RegExp(R+"|>"),V=new RegExp(W),X=new RegExp("^"+B+"$"),Q={ID:new RegExp("^#("+B+")"),CLASS:new RegExp("^\\.("+B+")"),TAG:new RegExp("^("+B+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+R+"*(even|odd|(([+-]|)(\\d*)n|)"+R+"*(?:([+-]|)"+R+"*(\\d+)|))"+R+"*\\)|)","i"),bool:new RegExp("^(?:"+I+")$","i"),needsContext:new RegExp("^"+R+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+R+"*((?:-\\d)?\\d*)"+R+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,G=/^(?:input|select|textarea|button)$/i,K=/^h\d$/i,J=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+R+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){C()},ae=xe(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{O.apply(t=P.call(d.childNodes),d.childNodes),t[d.childNodes.length].nodeType}catch(e){O={apply:t.length?function(e,t){q.apply(e,P.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,d=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==d&&9!==d&&11!==d)return n;if(!r&&(C(e),e=e||T,E)){if(11!==d&&(u=Z.exec(t)))if(i=u[1]){if(9===d){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return O.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&p.getElementsByClassName&&e.getElementsByClassName)return O.apply(n,e.getElementsByClassName(i)),n}if(p.qsa&&!k[t+" "]&&(!v||!v.test(t))&&(1!==d||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===d&&(U.test(t)||_.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&p.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=A)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+be(l[o]);c=l.join(",")}try{return O.apply(n,f.querySelectorAll(c)),n}catch(e){k(t,!0)}finally{s===A&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>x.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[A]=!0,e}function ce(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)x.attrHandle[n[r]]=t}function de(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pe(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in p=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},C=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:d;return r!=T&&9===r.nodeType&&r.documentElement&&(a=(T=r).documentElement,E=!i(T),d!=T&&(n=T.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),p.scope=ce(function(e){return a.appendChild(e).appendChild(T.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),p.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),p.getElementsByTagName=ce(function(e){return e.appendChild(T.createComment("")),!e.getElementsByTagName("*").length}),p.getElementsByClassName=J.test(T.getElementsByClassName),p.getById=ce(function(e){return a.appendChild(e).id=A,!T.getElementsByName||!T.getElementsByName(A).length}),p.getById?(x.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(x.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),x.find.TAG=p.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):p.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},x.find.CLASS=p.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(p.qsa=J.test(T.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+R+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+R+"*(?:value|"+I+")"),e.querySelectorAll("[id~="+A+"-]").length||v.push("~="),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+R+"*name"+R+"*="+R+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+A+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=T.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+R+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(p.matchesSelector=J.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){p.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",W)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=J.test(a.compareDocumentPosition),y=t||J.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!p.sortDetached&&t.compareDocumentPosition(e)===n?e==T||e.ownerDocument==d&&y(d,e)?-1:t==T||t.ownerDocument==d&&y(d,t)?1:u?H(u,e)-H(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==T?-1:t==T?1:i?-1:o?1:u?H(u,e)-H(u,t):0;if(i===o)return de(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?de(a[r],s[r]):a[r]==d?-1:s[r]==d?1:0}),T},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(C(e),p.matchesSelector&&E&&!k[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||p.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){k(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&V.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+R+")"+e+"("+R+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return b(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):"string"!=typeof n?E.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||L,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:j.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:w,!0)),k.test(r[1])&&E.isPlainObject(t))for(r in t)b(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=w.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):b(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,L=E(w);var q=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,pe=/^$|^module$|\/(?:java|ecma)script/i;le=w.createDocumentFragment().appendChild(w.createElement("div")),(ce=w.createElement("input")).setAttribute("type","radio"),ce.setAttribute("checked","checked"),ce.setAttribute("name","t"),le.appendChild(ce),m.checkClone=le.cloneNode(!0).cloneNode(!0).lastChild.checked,le.innerHTML="",m.noCloneChecked=!!le.cloneNode(!0).lastChild.defaultValue,le.innerHTML="",m.option=!!le.lastChild;var he={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ge(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&S(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var ye=/<|&#?\w+;/;function me(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),d=[],p=0,h=e.length;p\s*$/g;function Le(e,t){return S(e,"table")&&S(11!==t.nodeType?t:t.firstChild,"tr")&&E(e).children("tbody")[0]||e}function je(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n
",2===ft.childNodes.length),E.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(m.createHTMLDocument?((r=(t=w.implementation.createHTMLDocument("")).createElement("base")).href=w.location.href,t.head.appendChild(r)):t=w),o=!n&&[],(i=k.exec(e))?[t.createElement(i[1])]:(i=me([e],t,o),o&&o.length&&E(o).remove(),E.merge([],i.childNodes)));var r,i,o},E.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=E.css(e,"position"),c=E(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=E.css(e,"top"),u=E.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),b(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===E.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===E.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=E(e).offset()).top+=E.css(e,"borderTopWidth",!0),i.left+=E.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-E.css(r,"marginTop",!0),left:t.left-i.left-E.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===E.css(e,"position"))e=e.offsetParent;return e||re})}}),E.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;E.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each(["top","left"],function(e,n){E.cssHooks[n]=Fe(m.pixelPosition,function(e,t){if(t)return t=We(e,n),Ie.test(t)?E(e).position()[n]+"px":t})}),E.each({Height:"height",Width:"width"},function(a,s){E.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){E.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?E.css(e,t,i):E.style(e,t,n,i)},s,n?e:void 0,n)}})}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){E.fn[n]=function(e,t){return 0=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),ae({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=le({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f]),E=parseFloat(w['border'+f+'Width']),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},ae(n,m,$(v)),ae(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ce.FLIP:p=[n,i];break;case ce.CLOCKWISE:p=G(n);break;case ce.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u),E=!!t.flipVariationsByContent&&(w&&'start'===r&&c||w&&'end'===r&&h||!w&&'start'===r&&u||!w&&'end'===r&&g),v=y||E;(m||b||v)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),v&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=le({},e.offsets.popper,C(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport',flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=D(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.rightwindow.devicePixelRatio||!fe),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=B('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=le({},E,e.attributes),e.styles=le({},m,e.styles),e.arrowStyles=le({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return V(e.instance.popper,e.styles),j(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&V(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),V(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ge}); +//# sourceMappingURL=popper.min.js.map diff --git a/code/ch6_active_search/ch6_final_video_collector/static/js/bootstrap-4.6.1.min.js b/code/ch6_active_search/ch6_final_video_collector/static/js/bootstrap-4.6.1.min.js new file mode 100644 index 0000000..50720ea --- /dev/null +++ b/code/ch6_active_search/ch6_final_video_collector/static/js/bootstrap-4.6.1.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.6.1 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap={},t.jQuery,t.Popper)}(this,(function(t,e,n){"use strict";function i(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var o=i(e),a=i(n);function s(t,e){for(var n=0;n=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}};d.jQueryDetection(),o.default.fn.emulateTransitionEnd=function(t){var e=this,n=!1;return o.default(this).one(d.TRANSITION_END,(function(){n=!0})),setTimeout((function(){n||d.triggerTransitionEnd(e)}),t),this},o.default.event.special[d.TRANSITION_END]={bindType:f,delegateType:f,handle:function(t){if(o.default(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}};var c="bs.alert",h=o.default.fn.alert,g=function(){function t(t){this._element=t}var e=t.prototype;return e.close=function(t){var e=this._element;t&&(e=this._getRootElement(t)),this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.dispose=function(){o.default.removeData(this._element,c),this._element=null},e._getRootElement=function(t){var e=d.getSelectorFromElement(t),n=!1;return e&&(n=document.querySelector(e)),n||(n=o.default(t).closest(".alert")[0]),n},e._triggerCloseEvent=function(t){var e=o.default.Event("close.bs.alert");return o.default(t).trigger(e),e},e._removeElement=function(t){var e=this;if(o.default(t).removeClass("show"),o.default(t).hasClass("fade")){var n=d.getTransitionDurationFromElement(t);o.default(t).one(d.TRANSITION_END,(function(n){return e._destroyElement(t,n)})).emulateTransitionEnd(n)}else this._destroyElement(t)},e._destroyElement=function(t){o.default(t).detach().trigger("closed.bs.alert").remove()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(c);i||(i=new t(this),n.data(c,i)),"close"===e&&i[e](this)}))},t._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',g._handleDismiss(new g)),o.default.fn.alert=g._jQueryInterface,o.default.fn.alert.Constructor=g,o.default.fn.alert.noConflict=function(){return o.default.fn.alert=h,g._jQueryInterface};var m="bs.button",p=o.default.fn.button,_="active",v='[data-toggle^="button"]',y='input:not([type="hidden"])',b=".btn",E=function(){function t(t){this._element=t,this.shouldAvoidTriggerChange=!1}var e=t.prototype;return e.toggle=function(){var t=!0,e=!0,n=o.default(this._element).closest('[data-toggle="buttons"]')[0];if(n){var i=this._element.querySelector(y);if(i){if("radio"===i.type)if(i.checked&&this._element.classList.contains(_))t=!1;else{var a=n.querySelector(".active");a&&o.default(a).removeClass(_)}t&&("checkbox"!==i.type&&"radio"!==i.type||(i.checked=!this._element.classList.contains(_)),this.shouldAvoidTriggerChange||o.default(i).trigger("change")),i.focus(),e=!1}}this._element.hasAttribute("disabled")||this._element.classList.contains("disabled")||(e&&this._element.setAttribute("aria-pressed",!this._element.classList.contains(_)),t&&o.default(this._element).toggleClass(_))},e.dispose=function(){o.default.removeData(this._element,m),this._element=null},t._jQueryInterface=function(e,n){return this.each((function(){var i=o.default(this),a=i.data(m);a||(a=new t(this),i.data(m,a)),a.shouldAvoidTriggerChange=n,"toggle"===e&&a[e]()}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.button.data-api",v,(function(t){var e=t.target,n=e;if(o.default(e).hasClass("btn")||(e=o.default(e).closest(b)[0]),!e||e.hasAttribute("disabled")||e.classList.contains("disabled"))t.preventDefault();else{var i=e.querySelector(y);if(i&&(i.hasAttribute("disabled")||i.classList.contains("disabled")))return void t.preventDefault();"INPUT"!==n.tagName&&"LABEL"===e.tagName||E._jQueryInterface.call(o.default(e),"toggle","INPUT"===n.tagName)}})).on("focus.bs.button.data-api blur.bs.button.data-api",v,(function(t){var e=o.default(t.target).closest(b)[0];o.default(e).toggleClass("focus",/^focus(in)?$/.test(t.type))})),o.default(window).on("load.bs.button.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-toggle="buttons"] .btn')),e=0,n=t.length;e0,this._pointerEvent=Boolean(window.PointerEvent||window.MSPointerEvent),this._addEventListeners()}var e=t.prototype;return e.next=function(){this._isSliding||this._slide(N)},e.nextWhenVisible=function(){var t=o.default(this._element);!document.hidden&&t.is(":visible")&&"hidden"!==t.css("visibility")&&this.next()},e.prev=function(){this._isSliding||this._slide(D)},e.pause=function(t){t||(this._isPaused=!0),this._element.querySelector(".carousel-item-next, .carousel-item-prev")&&(d.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},e.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},e.to=function(t){var e=this;this._activeElement=this._element.querySelector(I);var n=this._getItemIndex(this._activeElement);if(!(t>this._items.length-1||t<0))if(this._isSliding)o.default(this._element).one(A,(function(){return e.to(t)}));else{if(n===t)return this.pause(),void this.cycle();var i=t>n?N:D;this._slide(i,this._items[t])}},e.dispose=function(){o.default(this._element).off(".bs.carousel"),o.default.removeData(this._element,w),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},e._getConfig=function(t){return t=r({},k,t),d.typeCheckConfig(T,t,O),t},e._handleSwipe=function(){var t=Math.abs(this.touchDeltaX);if(!(t<=40)){var e=t/this.touchDeltaX;this.touchDeltaX=0,e>0&&this.prev(),e<0&&this.next()}},e._addEventListeners=function(){var t=this;this._config.keyboard&&o.default(this._element).on("keydown.bs.carousel",(function(e){return t._keydown(e)})),"hover"===this._config.pause&&o.default(this._element).on("mouseenter.bs.carousel",(function(e){return t.pause(e)})).on("mouseleave.bs.carousel",(function(e){return t.cycle(e)})),this._config.touch&&this._addTouchEventListeners()},e._addTouchEventListeners=function(){var t=this;if(this._touchSupported){var e=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]?t.touchStartX=e.originalEvent.clientX:t._pointerEvent||(t.touchStartX=e.originalEvent.touches[0].clientX)},n=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]&&(t.touchDeltaX=e.originalEvent.clientX-t.touchStartX),t._handleSwipe(),"hover"===t._config.pause&&(t.pause(),t.touchTimeout&&clearTimeout(t.touchTimeout),t.touchTimeout=setTimeout((function(e){return t.cycle(e)}),500+t._config.interval))};o.default(this._element.querySelectorAll(".carousel-item img")).on("dragstart.bs.carousel",(function(t){return t.preventDefault()})),this._pointerEvent?(o.default(this._element).on("pointerdown.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("pointerup.bs.carousel",(function(t){return n(t)})),this._element.classList.add("pointer-event")):(o.default(this._element).on("touchstart.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("touchmove.bs.carousel",(function(e){return function(e){t.touchDeltaX=e.originalEvent.touches&&e.originalEvent.touches.length>1?0:e.originalEvent.touches[0].clientX-t.touchStartX}(e)})),o.default(this._element).on("touchend.bs.carousel",(function(t){return n(t)})))}},e._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next()}},e._getItemIndex=function(t){return this._items=t&&t.parentNode?[].slice.call(t.parentNode.querySelectorAll(".carousel-item")):[],this._items.indexOf(t)},e._getItemByDirection=function(t,e){var n=t===N,i=t===D,o=this._getItemIndex(e),a=this._items.length-1;if((i&&0===o||n&&o===a)&&!this._config.wrap)return e;var s=(o+(t===D?-1:1))%this._items.length;return-1===s?this._items[this._items.length-1]:this._items[s]},e._triggerSlideEvent=function(t,e){var n=this._getItemIndex(t),i=this._getItemIndex(this._element.querySelector(I)),a=o.default.Event("slide.bs.carousel",{relatedTarget:t,direction:e,from:i,to:n});return o.default(this._element).trigger(a),a},e._setActiveIndicatorElement=function(t){if(this._indicatorsElement){var e=[].slice.call(this._indicatorsElement.querySelectorAll(".active"));o.default(e).removeClass(S);var n=this._indicatorsElement.children[this._getItemIndex(t)];n&&o.default(n).addClass(S)}},e._updateInterval=function(){var t=this._activeElement||this._element.querySelector(I);if(t){var e=parseInt(t.getAttribute("data-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}},e._slide=function(t,e){var n,i,a,s=this,l=this._element.querySelector(I),r=this._getItemIndex(l),u=e||l&&this._getItemByDirection(t,l),f=this._getItemIndex(u),c=Boolean(this._interval);if(t===N?(n="carousel-item-left",i="carousel-item-next",a="left"):(n="carousel-item-right",i="carousel-item-prev",a="right"),u&&o.default(u).hasClass(S))this._isSliding=!1;else if(!this._triggerSlideEvent(u,a).isDefaultPrevented()&&l&&u){this._isSliding=!0,c&&this.pause(),this._setActiveIndicatorElement(u),this._activeElement=u;var h=o.default.Event(A,{relatedTarget:u,direction:a,from:r,to:f});if(o.default(this._element).hasClass("slide")){o.default(u).addClass(i),d.reflow(u),o.default(l).addClass(n),o.default(u).addClass(n);var g=d.getTransitionDurationFromElement(l);o.default(l).one(d.TRANSITION_END,(function(){o.default(u).removeClass(n+" "+i).addClass(S),o.default(l).removeClass("active "+i+" "+n),s._isSliding=!1,setTimeout((function(){return o.default(s._element).trigger(h)}),0)})).emulateTransitionEnd(g)}else o.default(l).removeClass(S),o.default(u).addClass(S),this._isSliding=!1,o.default(this._element).trigger(h);c&&this.cycle()}},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(w),i=r({},k,o.default(this).data());"object"==typeof e&&(i=r({},i,e));var a="string"==typeof e?e:i.slide;if(n||(n=new t(this,i),o.default(this).data(w,n)),"number"==typeof e)n.to(e);else if("string"==typeof a){if("undefined"==typeof n[a])throw new TypeError('No method named "'+a+'"');n[a]()}else i.interval&&i.ride&&(n.pause(),n.cycle())}))},t._dataApiClickHandler=function(e){var n=d.getSelectorFromElement(this);if(n){var i=o.default(n)[0];if(i&&o.default(i).hasClass("carousel")){var a=r({},o.default(i).data(),o.default(this).data()),s=this.getAttribute("data-slide-to");s&&(a.interval=!1),t._jQueryInterface.call(o.default(i),a),s&&o.default(i).data(w).to(s),e.preventDefault()}}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return k}}]),t}();o.default(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",P._dataApiClickHandler),o.default(window).on("load.bs.carousel.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-ride="carousel"]')),e=0,n=t.length;e0&&(this._selector=s,this._triggerArray.push(a))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}var e=t.prototype;return e.toggle=function(){o.default(this._element).hasClass(q)?this.hide():this.show()},e.show=function(){var e,n,i=this;if(!(this._isTransitioning||o.default(this._element).hasClass(q)||(this._parent&&0===(e=[].slice.call(this._parent.querySelectorAll(".show, .collapsing")).filter((function(t){return"string"==typeof i._config.parent?t.getAttribute("data-parent")===i._config.parent:t.classList.contains(F)}))).length&&(e=null),e&&(n=o.default(e).not(this._selector).data(R))&&n._isTransitioning))){var a=o.default.Event("show.bs.collapse");if(o.default(this._element).trigger(a),!a.isDefaultPrevented()){e&&(t._jQueryInterface.call(o.default(e).not(this._selector),"hide"),n||o.default(e).data(R,null));var s=this._getDimension();o.default(this._element).removeClass(F).addClass(Q),this._element.style[s]=0,this._triggerArray.length&&o.default(this._triggerArray).removeClass(B).attr("aria-expanded",!0),this.setTransitioning(!0);var l="scroll"+(s[0].toUpperCase()+s.slice(1)),r=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,(function(){o.default(i._element).removeClass(Q).addClass("collapse show"),i._element.style[s]="",i.setTransitioning(!1),o.default(i._element).trigger("shown.bs.collapse")})).emulateTransitionEnd(r),this._element.style[s]=this._element[l]+"px"}}},e.hide=function(){var t=this;if(!this._isTransitioning&&o.default(this._element).hasClass(q)){var e=o.default.Event("hide.bs.collapse");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){var n=this._getDimension();this._element.style[n]=this._element.getBoundingClientRect()[n]+"px",d.reflow(this._element),o.default(this._element).addClass(Q).removeClass("collapse show");var i=this._triggerArray.length;if(i>0)for(var a=0;a0},e._getOffset=function(){var t=this,e={};return"function"==typeof this._config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t._config.offset(e.offsets,t._element)),e}:e.offset=this._config.offset,e},e._getPopperConfig=function(){var t={placement:this._getPlacement(),modifiers:{offset:this._getOffset(),flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}};return"static"===this._config.display&&(t.modifiers.applyStyle={enabled:!1}),r({},t,this._config.popperConfig)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(K);if(n||(n=new t(this,"object"==typeof e?e:null),o.default(this).data(K,n)),"string"==typeof e){if("undefined"==typeof n[e])throw new TypeError('No method named "'+e+'"');n[e]()}}))},t._clearMenus=function(e){if(!e||3!==e.which&&("keyup"!==e.type||9===e.which))for(var n=[].slice.call(document.querySelectorAll(it)),i=0,a=n.length;i0&&s--,40===e.which&&sdocument.documentElement.clientHeight;n||(this._element.style.overflowY="hidden"),this._element.classList.add(ht);var i=d.getTransitionDurationFromElement(this._dialog);o.default(this._element).off(d.TRANSITION_END),o.default(this._element).one(d.TRANSITION_END,(function(){t._element.classList.remove(ht),n||o.default(t._element).one(d.TRANSITION_END,(function(){t._element.style.overflowY=""})).emulateTransitionEnd(t._element,i)})).emulateTransitionEnd(i),this._element.focus()}},e._showElement=function(t){var e=this,n=o.default(this._element).hasClass(dt),i=this._dialog?this._dialog.querySelector(".modal-body"):null;this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),o.default(this._dialog).hasClass("modal-dialog-scrollable")&&i?i.scrollTop=0:this._element.scrollTop=0,n&&d.reflow(this._element),o.default(this._element).addClass(ct),this._config.focus&&this._enforceFocus();var a=o.default.Event("shown.bs.modal",{relatedTarget:t}),s=function(){e._config.focus&&e._element.focus(),e._isTransitioning=!1,o.default(e._element).trigger(a)};if(n){var l=d.getTransitionDurationFromElement(this._dialog);o.default(this._dialog).one(d.TRANSITION_END,s).emulateTransitionEnd(l)}else s()},e._enforceFocus=function(){var t=this;o.default(document).off(pt).on(pt,(function(e){document!==e.target&&t._element!==e.target&&0===o.default(t._element).has(e.target).length&&t._element.focus()}))},e._setEscapeEvent=function(){var t=this;this._isShown?o.default(this._element).on(yt,(function(e){t._config.keyboard&&27===e.which?(e.preventDefault(),t.hide()):t._config.keyboard||27!==e.which||t._triggerBackdropTransition()})):this._isShown||o.default(this._element).off(yt)},e._setResizeEvent=function(){var t=this;this._isShown?o.default(window).on(_t,(function(e){return t.handleUpdate(e)})):o.default(window).off(_t)},e._hideModal=function(){var t=this;this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._showBackdrop((function(){o.default(document.body).removeClass(ft),t._resetAdjustments(),t._resetScrollbar(),o.default(t._element).trigger(gt)}))},e._removeBackdrop=function(){this._backdrop&&(o.default(this._backdrop).remove(),this._backdrop=null)},e._showBackdrop=function(t){var e=this,n=o.default(this._element).hasClass(dt)?dt:"";if(this._isShown&&this._config.backdrop){if(this._backdrop=document.createElement("div"),this._backdrop.className="modal-backdrop",n&&this._backdrop.classList.add(n),o.default(this._backdrop).appendTo(document.body),o.default(this._element).on(vt,(function(t){e._ignoreBackdropClick?e._ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"===e._config.backdrop?e._triggerBackdropTransition():e.hide())})),n&&d.reflow(this._backdrop),o.default(this._backdrop).addClass(ct),!t)return;if(!n)return void t();var i=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,t).emulateTransitionEnd(i)}else if(!this._isShown&&this._backdrop){o.default(this._backdrop).removeClass(ct);var a=function(){e._removeBackdrop(),t&&t()};if(o.default(this._element).hasClass(dt)){var s=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a()}else t&&t()},e._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},e._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},e._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=Math.round(t.left+t.right)
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",customClass:"",sanitize:!0,sanitizeFn:null,whiteList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},Ut={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string|function)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",whiteList:"object",popperConfig:"(null|object)"},Mt={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},Wt=function(){function t(t,e){if("undefined"==typeof a.default)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var e=t.prototype;return e.enable=function(){this._isEnabled=!0},e.disable=function(){this._isEnabled=!1},e.toggleEnabled=function(){this._isEnabled=!this._isEnabled},e.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=o.default(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(o.default(this.getTipElement()).hasClass(Rt))return void this._leave(null,this);this._enter(null,this)}},e.dispose=function(){clearTimeout(this._timeout),o.default.removeData(this.element,this.constructor.DATA_KEY),o.default(this.element).off(this.constructor.EVENT_KEY),o.default(this.element).closest(".modal").off("hide.bs.modal",this._hideModalHandler),this.tip&&o.default(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},e.show=function(){var t=this;if("none"===o.default(this.element).css("display"))throw new Error("Please use show on visible elements");var e=o.default.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){o.default(this.element).trigger(e);var n=d.findShadowRoot(this.element),i=o.default.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(e.isDefaultPrevented()||!i)return;var s=this.getTipElement(),l=d.getUID(this.constructor.NAME);s.setAttribute("id",l),this.element.setAttribute("aria-describedby",l),this.setContent(),this.config.animation&&o.default(s).addClass(Lt);var r="function"==typeof this.config.placement?this.config.placement.call(this,s,this.element):this.config.placement,u=this._getAttachment(r);this.addAttachmentClass(u);var f=this._getContainer();o.default(s).data(this.constructor.DATA_KEY,this),o.default.contains(this.element.ownerDocument.documentElement,this.tip)||o.default(s).appendTo(f),o.default(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new a.default(this.element,s,this._getPopperConfig(u)),o.default(s).addClass(Rt),o.default(s).addClass(this.config.customClass),"ontouchstart"in document.documentElement&&o.default(document.body).children().on("mouseover",null,o.default.noop);var c=function(){t.config.animation&&t._fixTransition();var e=t._hoverState;t._hoverState=null,o.default(t.element).trigger(t.constructor.Event.SHOWN),e===qt&&t._leave(null,t)};if(o.default(this.tip).hasClass(Lt)){var h=d.getTransitionDurationFromElement(this.tip);o.default(this.tip).one(d.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},e.hide=function(t){var e=this,n=this.getTipElement(),i=o.default.Event(this.constructor.Event.HIDE),a=function(){e._hoverState!==xt&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),o.default(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(o.default(this.element).trigger(i),!i.isDefaultPrevented()){if(o.default(n).removeClass(Rt),"ontouchstart"in document.documentElement&&o.default(document.body).children().off("mouseover",null,o.default.noop),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,o.default(this.tip).hasClass(Lt)){var s=d.getTransitionDurationFromElement(n);o.default(n).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a();this._hoverState=""}},e.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},e.isWithContent=function(){return Boolean(this.getTitle())},e.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-tooltip-"+t)},e.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},e.setContent=function(){var t=this.getTipElement();this.setElementContent(o.default(t.querySelectorAll(".tooltip-inner")),this.getTitle()),o.default(t).removeClass("fade show")},e.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=At(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?o.default(e).parent().is(t)||t.empty().append(e):t.text(o.default(e).text())},e.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},e._getPopperConfig=function(t){var e=this;return r({},{placement:t,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:".arrow"},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}},this.config.popperConfig)},e._getOffset=function(){var t=this,e={};return"function"==typeof this.config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t.config.offset(e.offsets,t.element)),e}:e.offset=this.config.offset,e},e._getContainer=function(){return!1===this.config.container?document.body:d.isElement(this.config.container)?o.default(this.config.container):o.default(document).find(this.config.container)},e._getAttachment=function(t){return Bt[t.toUpperCase()]},e._setListeners=function(){var t=this;this.config.trigger.split(" ").forEach((function(e){if("click"===e)o.default(t.element).on(t.constructor.Event.CLICK,t.config.selector,(function(e){return t.toggle(e)}));else if("manual"!==e){var n=e===Ft?t.constructor.Event.MOUSEENTER:t.constructor.Event.FOCUSIN,i=e===Ft?t.constructor.Event.MOUSELEAVE:t.constructor.Event.FOCUSOUT;o.default(t.element).on(n,t.config.selector,(function(e){return t._enter(e)})).on(i,t.config.selector,(function(e){return t._leave(e)}))}})),this._hideModalHandler=function(){t.element&&t.hide()},o.default(this.element).closest(".modal").on("hide.bs.modal",this._hideModalHandler),this.config.selector?this.config=r({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},e._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},e._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Qt:Ft]=!0),o.default(e.getTipElement()).hasClass(Rt)||e._hoverState===xt?e._hoverState=xt:(clearTimeout(e._timeout),e._hoverState=xt,e.config.delay&&e.config.delay.show?e._timeout=setTimeout((function(){e._hoverState===xt&&e.show()}),e.config.delay.show):e.show())},e._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Qt:Ft]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=qt,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout((function(){e._hoverState===qt&&e.hide()}),e.config.delay.hide):e.hide())},e._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},e._getConfig=function(t){var e=o.default(this.element).data();return Object.keys(e).forEach((function(t){-1!==Pt.indexOf(t)&&delete e[t]})),"number"==typeof(t=r({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),d.typeCheckConfig(It,t,this.constructor.DefaultType),t.sanitize&&(t.template=At(t.template,t.whiteList,t.sanitizeFn)),t},e._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},e._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(jt);null!==e&&e.length&&t.removeClass(e.join(""))},e._handlePopperPlacementChange=function(t){this.tip=t.instance.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},e._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(o.default(t).removeClass(Lt),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(kt),a="object"==typeof e&&e;if((i||!/dispose|hide/.test(e))&&(i||(i=new t(this,a),n.data(kt,i)),"string"==typeof e)){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Ht}},{key:"NAME",get:function(){return It}},{key:"DATA_KEY",get:function(){return kt}},{key:"Event",get:function(){return Mt}},{key:"EVENT_KEY",get:function(){return".bs.tooltip"}},{key:"DefaultType",get:function(){return Ut}}]),t}();o.default.fn.tooltip=Wt._jQueryInterface,o.default.fn.tooltip.Constructor=Wt,o.default.fn.tooltip.noConflict=function(){return o.default.fn.tooltip=Ot,Wt._jQueryInterface};var Vt="bs.popover",zt=o.default.fn.popover,Kt=new RegExp("(^|\\s)bs-popover\\S+","g"),Xt=r({},Wt.Default,{placement:"right",trigger:"click",content:"",template:''}),Yt=r({},Wt.DefaultType,{content:"(string|element|function)"}),$t={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"},Jt=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),e.prototype.constructor=e,u(e,n);var a=i.prototype;return a.isWithContent=function(){return this.getTitle()||this._getContent()},a.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-popover-"+t)},a.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},a.setContent=function(){var t=o.default(this.getTipElement());this.setElementContent(t.find(".popover-header"),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(".popover-body"),e),t.removeClass("fade show")},a._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},a._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(Kt);null!==e&&e.length>0&&t.removeClass(e.join(""))},i._jQueryInterface=function(t){return this.each((function(){var e=o.default(this).data(Vt),n="object"==typeof t?t:null;if((e||!/dispose|hide/.test(t))&&(e||(e=new i(this,n),o.default(this).data(Vt,e)),"string"==typeof t)){if("undefined"==typeof e[t])throw new TypeError('No method named "'+t+'"');e[t]()}}))},l(i,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Xt}},{key:"NAME",get:function(){return"popover"}},{key:"DATA_KEY",get:function(){return Vt}},{key:"Event",get:function(){return $t}},{key:"EVENT_KEY",get:function(){return".bs.popover"}},{key:"DefaultType",get:function(){return Yt}}]),i}(Wt);o.default.fn.popover=Jt._jQueryInterface,o.default.fn.popover.Constructor=Jt,o.default.fn.popover.noConflict=function(){return o.default.fn.popover=zt,Jt._jQueryInterface};var Gt="scrollspy",Zt="bs.scrollspy",te=o.default.fn[Gt],ee="active",ne="position",ie=".nav, .list-group",oe={offset:10,method:"auto",target:""},ae={offset:"number",method:"string",target:"(string|element)"},se=function(){function t(t,e){var n=this;this._element=t,this._scrollElement="BODY"===t.tagName?window:t,this._config=this._getConfig(e),this._selector=this._config.target+" .nav-link,"+this._config.target+" .list-group-item,"+this._config.target+" .dropdown-item",this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,o.default(this._scrollElement).on("scroll.bs.scrollspy",(function(t){return n._process(t)})),this.refresh(),this._process()}var e=t.prototype;return e.refresh=function(){var t=this,e=this._scrollElement===this._scrollElement.window?"offset":ne,n="auto"===this._config.method?e:this._config.method,i=n===ne?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),[].slice.call(document.querySelectorAll(this._selector)).map((function(t){var e,a=d.getSelectorFromElement(t);if(a&&(e=document.querySelector(a)),e){var s=e.getBoundingClientRect();if(s.width||s.height)return[o.default(e)[n]().top+i,a]}return null})).filter((function(t){return t})).sort((function(t,e){return t[0]-e[0]})).forEach((function(e){t._offsets.push(e[0]),t._targets.push(e[1])}))},e.dispose=function(){o.default.removeData(this._element,Zt),o.default(this._scrollElement).off(".bs.scrollspy"),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},e._getConfig=function(t){if("string"!=typeof(t=r({},oe,"object"==typeof t&&t?t:{})).target&&d.isElement(t.target)){var e=o.default(t.target).attr("id");e||(e=d.getUID(Gt),o.default(t.target).attr("id",e)),t.target="#"+e}return d.typeCheckConfig(Gt,t,ae),t},e._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},e._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},e._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},e._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;)this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||t li > .active",ge=function(){function t(t){this._element=t}var e=t.prototype;return e.show=function(){var t=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&o.default(this._element).hasClass(ue)||o.default(this._element).hasClass("disabled"))){var e,n,i=o.default(this._element).closest(".nav, .list-group")[0],a=d.getSelectorFromElement(this._element);if(i){var s="UL"===i.nodeName||"OL"===i.nodeName?he:ce;n=(n=o.default.makeArray(o.default(i).find(s)))[n.length-1]}var l=o.default.Event("hide.bs.tab",{relatedTarget:this._element}),r=o.default.Event("show.bs.tab",{relatedTarget:n});if(n&&o.default(n).trigger(l),o.default(this._element).trigger(r),!r.isDefaultPrevented()&&!l.isDefaultPrevented()){a&&(e=document.querySelector(a)),this._activate(this._element,i);var u=function(){var e=o.default.Event("hidden.bs.tab",{relatedTarget:t._element}),i=o.default.Event("shown.bs.tab",{relatedTarget:n});o.default(n).trigger(e),o.default(t._element).trigger(i)};e?this._activate(e,e.parentNode,u):u()}}},e.dispose=function(){o.default.removeData(this._element,le),this._element=null},e._activate=function(t,e,n){var i=this,a=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?o.default(e).children(ce):o.default(e).find(he))[0],s=n&&a&&o.default(a).hasClass(fe),l=function(){return i._transitionComplete(t,a,n)};if(a&&s){var r=d.getTransitionDurationFromElement(a);o.default(a).removeClass(de).one(d.TRANSITION_END,l).emulateTransitionEnd(r)}else l()},e._transitionComplete=function(t,e,n){if(e){o.default(e).removeClass(ue);var i=o.default(e.parentNode).find("> .dropdown-menu .active")[0];i&&o.default(i).removeClass(ue),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}o.default(t).addClass(ue),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),d.reflow(t),t.classList.contains(fe)&&t.classList.add(de);var a=t.parentNode;if(a&&"LI"===a.nodeName&&(a=a.parentNode),a&&o.default(a).hasClass("dropdown-menu")){var s=o.default(t).closest(".dropdown")[0];if(s){var l=[].slice.call(s.querySelectorAll(".dropdown-toggle"));o.default(l).addClass(ue)}t.setAttribute("aria-expanded",!0)}n&&n()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(le);if(i||(i=new t(this),n.data(le,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',(function(t){t.preventDefault(),ge._jQueryInterface.call(o.default(this),"show")})),o.default.fn.tab=ge._jQueryInterface,o.default.fn.tab.Constructor=ge,o.default.fn.tab.noConflict=function(){return o.default.fn.tab=re,ge._jQueryInterface};var me="bs.toast",pe=o.default.fn.toast,_e="hide",ve="show",ye="showing",be="click.dismiss.bs.toast",Ee={animation:!0,autohide:!0,delay:500},Te={animation:"boolean",autohide:"boolean",delay:"number"},we=function(){function t(t,e){this._element=t,this._config=this._getConfig(e),this._timeout=null,this._setListeners()}var e=t.prototype;return e.show=function(){var t=this,e=o.default.Event("show.bs.toast");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){this._clearTimeout(),this._config.animation&&this._element.classList.add("fade");var n=function(){t._element.classList.remove(ye),t._element.classList.add(ve),o.default(t._element).trigger("shown.bs.toast"),t._config.autohide&&(t._timeout=setTimeout((function(){t.hide()}),t._config.delay))};if(this._element.classList.remove(_e),d.reflow(this._element),this._element.classList.add(ye),this._config.animation){var i=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,n).emulateTransitionEnd(i)}else n()}},e.hide=function(){if(this._element.classList.contains(ve)){var t=o.default.Event("hide.bs.toast");o.default(this._element).trigger(t),t.isDefaultPrevented()||this._close()}},e.dispose=function(){this._clearTimeout(),this._element.classList.contains(ve)&&this._element.classList.remove(ve),o.default(this._element).off(be),o.default.removeData(this._element,me),this._element=null,this._config=null},e._getConfig=function(t){return t=r({},Ee,o.default(this._element).data(),"object"==typeof t&&t?t:{}),d.typeCheckConfig("toast",t,this.constructor.DefaultType),t},e._setListeners=function(){var t=this;o.default(this._element).on(be,'[data-dismiss="toast"]',(function(){return t.hide()}))},e._close=function(){var t=this,e=function(){t._element.classList.add(_e),o.default(t._element).trigger("hidden.bs.toast")};if(this._element.classList.remove(ve),this._config.animation){var n=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},e._clearTimeout=function(){clearTimeout(this._timeout),this._timeout=null},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(me);if(i||(i=new t(this,"object"==typeof e&&e),n.data(me,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e](this)}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"DefaultType",get:function(){return Te}},{key:"Default",get:function(){return Ee}}]),t}();o.default.fn.toast=we._jQueryInterface,o.default.fn.toast.Constructor=we,o.default.fn.toast.noConflict=function(){return o.default.fn.toast=pe,we._jQueryInterface},t.Alert=g,t.Button=E,t.Carousel=P,t.Collapse=V,t.Dropdown=lt,t.Modal=Ct,t.Popover=Jt,t.Scrollspy=se,t.Tab=ge,t.Toast=we,t.Tooltip=Wt,t.Util=d,Object.defineProperty(t,"__esModule",{value:!0})})); +//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/code/ch6_active_search/ch6_final_video_collector/static/js/jquery-3.5.1.slim.min.js b/code/ch6_active_search/ch6_final_video_collector/static/js/jquery-3.5.1.slim.min.js new file mode 100644 index 0000000..36b4e1a --- /dev/null +++ b/code/ch6_active_search/ch6_final_video_collector/static/js/jquery-3.5.1.slim.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(g,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,v=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),m={},b=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},w=g.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function C(e,t,n){var r,i,o=(n=n||w).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function T(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector",E=function(e,t){return new E.fn.init(e,t)};function d(e){var t=!!e&&"length"in e&&e.length,n=T(e);return!b(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+R+")"+R+"*"),U=new RegExp(R+"|>"),V=new RegExp(W),X=new RegExp("^"+B+"$"),Q={ID:new RegExp("^#("+B+")"),CLASS:new RegExp("^\\.("+B+")"),TAG:new RegExp("^("+B+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+R+"*(even|odd|(([+-]|)(\\d*)n|)"+R+"*(?:([+-]|)"+R+"*(\\d+)|))"+R+"*\\)|)","i"),bool:new RegExp("^(?:"+I+")$","i"),needsContext:new RegExp("^"+R+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+R+"*((?:-\\d)?\\d*)"+R+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,G=/^(?:input|select|textarea|button)$/i,K=/^h\d$/i,J=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+R+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){C()},ae=xe(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{O.apply(t=P.call(d.childNodes),d.childNodes),t[d.childNodes.length].nodeType}catch(e){O={apply:t.length?function(e,t){q.apply(e,P.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,d=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==d&&9!==d&&11!==d)return n;if(!r&&(C(e),e=e||T,E)){if(11!==d&&(u=Z.exec(t)))if(i=u[1]){if(9===d){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return O.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&p.getElementsByClassName&&e.getElementsByClassName)return O.apply(n,e.getElementsByClassName(i)),n}if(p.qsa&&!k[t+" "]&&(!v||!v.test(t))&&(1!==d||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===d&&(U.test(t)||_.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&p.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=A)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+be(l[o]);c=l.join(",")}try{return O.apply(n,f.querySelectorAll(c)),n}catch(e){k(t,!0)}finally{s===A&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>x.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[A]=!0,e}function ce(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)x.attrHandle[n[r]]=t}function de(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pe(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in p=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},C=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:d;return r!=T&&9===r.nodeType&&r.documentElement&&(a=(T=r).documentElement,E=!i(T),d!=T&&(n=T.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),p.scope=ce(function(e){return a.appendChild(e).appendChild(T.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),p.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),p.getElementsByTagName=ce(function(e){return e.appendChild(T.createComment("")),!e.getElementsByTagName("*").length}),p.getElementsByClassName=J.test(T.getElementsByClassName),p.getById=ce(function(e){return a.appendChild(e).id=A,!T.getElementsByName||!T.getElementsByName(A).length}),p.getById?(x.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(x.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),x.find.TAG=p.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):p.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},x.find.CLASS=p.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(p.qsa=J.test(T.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+R+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+R+"*(?:value|"+I+")"),e.querySelectorAll("[id~="+A+"-]").length||v.push("~="),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+R+"*name"+R+"*="+R+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+A+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=T.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+R+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(p.matchesSelector=J.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){p.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",W)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=J.test(a.compareDocumentPosition),y=t||J.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!p.sortDetached&&t.compareDocumentPosition(e)===n?e==T||e.ownerDocument==d&&y(d,e)?-1:t==T||t.ownerDocument==d&&y(d,t)?1:u?H(u,e)-H(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==T?-1:t==T?1:i?-1:o?1:u?H(u,e)-H(u,t):0;if(i===o)return de(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?de(a[r],s[r]):a[r]==d?-1:s[r]==d?1:0}),T},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(C(e),p.matchesSelector&&E&&!k[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||p.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){k(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&V.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+R+")"+e+"("+R+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return b(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):"string"!=typeof n?E.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||L,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:j.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:w,!0)),k.test(r[1])&&E.isPlainObject(t))for(r in t)b(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=w.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):b(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,L=E(w);var q=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,pe=/^$|^module$|\/(?:java|ecma)script/i;le=w.createDocumentFragment().appendChild(w.createElement("div")),(ce=w.createElement("input")).setAttribute("type","radio"),ce.setAttribute("checked","checked"),ce.setAttribute("name","t"),le.appendChild(ce),m.checkClone=le.cloneNode(!0).cloneNode(!0).lastChild.checked,le.innerHTML="",m.noCloneChecked=!!le.cloneNode(!0).lastChild.defaultValue,le.innerHTML="",m.option=!!le.lastChild;var he={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ge(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&S(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var ye=/<|&#?\w+;/;function me(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),d=[],p=0,h=e.length;p\s*$/g;function Le(e,t){return S(e,"table")&&S(11!==t.nodeType?t:t.firstChild,"tr")&&E(e).children("tbody")[0]||e}function je(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n
",2===ft.childNodes.length),E.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(m.createHTMLDocument?((r=(t=w.implementation.createHTMLDocument("")).createElement("base")).href=w.location.href,t.head.appendChild(r)):t=w),o=!n&&[],(i=k.exec(e))?[t.createElement(i[1])]:(i=me([e],t,o),o&&o.length&&E(o).remove(),E.merge([],i.childNodes)));var r,i,o},E.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=E.css(e,"position"),c=E(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=E.css(e,"top"),u=E.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),b(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===E.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===E.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=E(e).offset()).top+=E.css(e,"borderTopWidth",!0),i.left+=E.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-E.css(r,"marginTop",!0),left:t.left-i.left-E.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===E.css(e,"position"))e=e.offsetParent;return e||re})}}),E.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;E.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each(["top","left"],function(e,n){E.cssHooks[n]=Fe(m.pixelPosition,function(e,t){if(t)return t=We(e,n),Ie.test(t)?E(e).position()[n]+"px":t})}),E.each({Height:"height",Width:"width"},function(a,s){E.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){E.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?E.css(e,t,i):E.style(e,t,n,i)},s,n?e:void 0,n)}})}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){E.fn[n]=function(e,t){return 0=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),ae({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=le({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f]),E=parseFloat(w['border'+f+'Width']),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},ae(n,m,$(v)),ae(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ce.FLIP:p=[n,i];break;case ce.CLOCKWISE:p=G(n);break;case ce.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u),E=!!t.flipVariationsByContent&&(w&&'start'===r&&c||w&&'end'===r&&h||!w&&'start'===r&&u||!w&&'end'===r&&g),v=y||E;(m||b||v)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),v&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=le({},e.offsets.popper,C(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport',flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=D(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.rightwindow.devicePixelRatio||!fe),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=B('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=le({},E,e.attributes),e.styles=le({},m,e.styles),e.arrowStyles=le({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return V(e.instance.popper,e.styles),j(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&V(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),V(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ge}); +//# sourceMappingURL=popper.min.js.map diff --git a/code/ch6_active_search/ch6_starter_video_collector/static/js/bootstrap-4.6.1.min.js b/code/ch6_active_search/ch6_starter_video_collector/static/js/bootstrap-4.6.1.min.js new file mode 100644 index 0000000..50720ea --- /dev/null +++ b/code/ch6_active_search/ch6_starter_video_collector/static/js/bootstrap-4.6.1.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.6.1 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap={},t.jQuery,t.Popper)}(this,(function(t,e,n){"use strict";function i(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var o=i(e),a=i(n);function s(t,e){for(var n=0;n=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}};d.jQueryDetection(),o.default.fn.emulateTransitionEnd=function(t){var e=this,n=!1;return o.default(this).one(d.TRANSITION_END,(function(){n=!0})),setTimeout((function(){n||d.triggerTransitionEnd(e)}),t),this},o.default.event.special[d.TRANSITION_END]={bindType:f,delegateType:f,handle:function(t){if(o.default(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}};var c="bs.alert",h=o.default.fn.alert,g=function(){function t(t){this._element=t}var e=t.prototype;return e.close=function(t){var e=this._element;t&&(e=this._getRootElement(t)),this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.dispose=function(){o.default.removeData(this._element,c),this._element=null},e._getRootElement=function(t){var e=d.getSelectorFromElement(t),n=!1;return e&&(n=document.querySelector(e)),n||(n=o.default(t).closest(".alert")[0]),n},e._triggerCloseEvent=function(t){var e=o.default.Event("close.bs.alert");return o.default(t).trigger(e),e},e._removeElement=function(t){var e=this;if(o.default(t).removeClass("show"),o.default(t).hasClass("fade")){var n=d.getTransitionDurationFromElement(t);o.default(t).one(d.TRANSITION_END,(function(n){return e._destroyElement(t,n)})).emulateTransitionEnd(n)}else this._destroyElement(t)},e._destroyElement=function(t){o.default(t).detach().trigger("closed.bs.alert").remove()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(c);i||(i=new t(this),n.data(c,i)),"close"===e&&i[e](this)}))},t._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',g._handleDismiss(new g)),o.default.fn.alert=g._jQueryInterface,o.default.fn.alert.Constructor=g,o.default.fn.alert.noConflict=function(){return o.default.fn.alert=h,g._jQueryInterface};var m="bs.button",p=o.default.fn.button,_="active",v='[data-toggle^="button"]',y='input:not([type="hidden"])',b=".btn",E=function(){function t(t){this._element=t,this.shouldAvoidTriggerChange=!1}var e=t.prototype;return e.toggle=function(){var t=!0,e=!0,n=o.default(this._element).closest('[data-toggle="buttons"]')[0];if(n){var i=this._element.querySelector(y);if(i){if("radio"===i.type)if(i.checked&&this._element.classList.contains(_))t=!1;else{var a=n.querySelector(".active");a&&o.default(a).removeClass(_)}t&&("checkbox"!==i.type&&"radio"!==i.type||(i.checked=!this._element.classList.contains(_)),this.shouldAvoidTriggerChange||o.default(i).trigger("change")),i.focus(),e=!1}}this._element.hasAttribute("disabled")||this._element.classList.contains("disabled")||(e&&this._element.setAttribute("aria-pressed",!this._element.classList.contains(_)),t&&o.default(this._element).toggleClass(_))},e.dispose=function(){o.default.removeData(this._element,m),this._element=null},t._jQueryInterface=function(e,n){return this.each((function(){var i=o.default(this),a=i.data(m);a||(a=new t(this),i.data(m,a)),a.shouldAvoidTriggerChange=n,"toggle"===e&&a[e]()}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.button.data-api",v,(function(t){var e=t.target,n=e;if(o.default(e).hasClass("btn")||(e=o.default(e).closest(b)[0]),!e||e.hasAttribute("disabled")||e.classList.contains("disabled"))t.preventDefault();else{var i=e.querySelector(y);if(i&&(i.hasAttribute("disabled")||i.classList.contains("disabled")))return void t.preventDefault();"INPUT"!==n.tagName&&"LABEL"===e.tagName||E._jQueryInterface.call(o.default(e),"toggle","INPUT"===n.tagName)}})).on("focus.bs.button.data-api blur.bs.button.data-api",v,(function(t){var e=o.default(t.target).closest(b)[0];o.default(e).toggleClass("focus",/^focus(in)?$/.test(t.type))})),o.default(window).on("load.bs.button.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-toggle="buttons"] .btn')),e=0,n=t.length;e0,this._pointerEvent=Boolean(window.PointerEvent||window.MSPointerEvent),this._addEventListeners()}var e=t.prototype;return e.next=function(){this._isSliding||this._slide(N)},e.nextWhenVisible=function(){var t=o.default(this._element);!document.hidden&&t.is(":visible")&&"hidden"!==t.css("visibility")&&this.next()},e.prev=function(){this._isSliding||this._slide(D)},e.pause=function(t){t||(this._isPaused=!0),this._element.querySelector(".carousel-item-next, .carousel-item-prev")&&(d.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},e.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},e.to=function(t){var e=this;this._activeElement=this._element.querySelector(I);var n=this._getItemIndex(this._activeElement);if(!(t>this._items.length-1||t<0))if(this._isSliding)o.default(this._element).one(A,(function(){return e.to(t)}));else{if(n===t)return this.pause(),void this.cycle();var i=t>n?N:D;this._slide(i,this._items[t])}},e.dispose=function(){o.default(this._element).off(".bs.carousel"),o.default.removeData(this._element,w),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},e._getConfig=function(t){return t=r({},k,t),d.typeCheckConfig(T,t,O),t},e._handleSwipe=function(){var t=Math.abs(this.touchDeltaX);if(!(t<=40)){var e=t/this.touchDeltaX;this.touchDeltaX=0,e>0&&this.prev(),e<0&&this.next()}},e._addEventListeners=function(){var t=this;this._config.keyboard&&o.default(this._element).on("keydown.bs.carousel",(function(e){return t._keydown(e)})),"hover"===this._config.pause&&o.default(this._element).on("mouseenter.bs.carousel",(function(e){return t.pause(e)})).on("mouseleave.bs.carousel",(function(e){return t.cycle(e)})),this._config.touch&&this._addTouchEventListeners()},e._addTouchEventListeners=function(){var t=this;if(this._touchSupported){var e=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]?t.touchStartX=e.originalEvent.clientX:t._pointerEvent||(t.touchStartX=e.originalEvent.touches[0].clientX)},n=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]&&(t.touchDeltaX=e.originalEvent.clientX-t.touchStartX),t._handleSwipe(),"hover"===t._config.pause&&(t.pause(),t.touchTimeout&&clearTimeout(t.touchTimeout),t.touchTimeout=setTimeout((function(e){return t.cycle(e)}),500+t._config.interval))};o.default(this._element.querySelectorAll(".carousel-item img")).on("dragstart.bs.carousel",(function(t){return t.preventDefault()})),this._pointerEvent?(o.default(this._element).on("pointerdown.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("pointerup.bs.carousel",(function(t){return n(t)})),this._element.classList.add("pointer-event")):(o.default(this._element).on("touchstart.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("touchmove.bs.carousel",(function(e){return function(e){t.touchDeltaX=e.originalEvent.touches&&e.originalEvent.touches.length>1?0:e.originalEvent.touches[0].clientX-t.touchStartX}(e)})),o.default(this._element).on("touchend.bs.carousel",(function(t){return n(t)})))}},e._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next()}},e._getItemIndex=function(t){return this._items=t&&t.parentNode?[].slice.call(t.parentNode.querySelectorAll(".carousel-item")):[],this._items.indexOf(t)},e._getItemByDirection=function(t,e){var n=t===N,i=t===D,o=this._getItemIndex(e),a=this._items.length-1;if((i&&0===o||n&&o===a)&&!this._config.wrap)return e;var s=(o+(t===D?-1:1))%this._items.length;return-1===s?this._items[this._items.length-1]:this._items[s]},e._triggerSlideEvent=function(t,e){var n=this._getItemIndex(t),i=this._getItemIndex(this._element.querySelector(I)),a=o.default.Event("slide.bs.carousel",{relatedTarget:t,direction:e,from:i,to:n});return o.default(this._element).trigger(a),a},e._setActiveIndicatorElement=function(t){if(this._indicatorsElement){var e=[].slice.call(this._indicatorsElement.querySelectorAll(".active"));o.default(e).removeClass(S);var n=this._indicatorsElement.children[this._getItemIndex(t)];n&&o.default(n).addClass(S)}},e._updateInterval=function(){var t=this._activeElement||this._element.querySelector(I);if(t){var e=parseInt(t.getAttribute("data-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}},e._slide=function(t,e){var n,i,a,s=this,l=this._element.querySelector(I),r=this._getItemIndex(l),u=e||l&&this._getItemByDirection(t,l),f=this._getItemIndex(u),c=Boolean(this._interval);if(t===N?(n="carousel-item-left",i="carousel-item-next",a="left"):(n="carousel-item-right",i="carousel-item-prev",a="right"),u&&o.default(u).hasClass(S))this._isSliding=!1;else if(!this._triggerSlideEvent(u,a).isDefaultPrevented()&&l&&u){this._isSliding=!0,c&&this.pause(),this._setActiveIndicatorElement(u),this._activeElement=u;var h=o.default.Event(A,{relatedTarget:u,direction:a,from:r,to:f});if(o.default(this._element).hasClass("slide")){o.default(u).addClass(i),d.reflow(u),o.default(l).addClass(n),o.default(u).addClass(n);var g=d.getTransitionDurationFromElement(l);o.default(l).one(d.TRANSITION_END,(function(){o.default(u).removeClass(n+" "+i).addClass(S),o.default(l).removeClass("active "+i+" "+n),s._isSliding=!1,setTimeout((function(){return o.default(s._element).trigger(h)}),0)})).emulateTransitionEnd(g)}else o.default(l).removeClass(S),o.default(u).addClass(S),this._isSliding=!1,o.default(this._element).trigger(h);c&&this.cycle()}},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(w),i=r({},k,o.default(this).data());"object"==typeof e&&(i=r({},i,e));var a="string"==typeof e?e:i.slide;if(n||(n=new t(this,i),o.default(this).data(w,n)),"number"==typeof e)n.to(e);else if("string"==typeof a){if("undefined"==typeof n[a])throw new TypeError('No method named "'+a+'"');n[a]()}else i.interval&&i.ride&&(n.pause(),n.cycle())}))},t._dataApiClickHandler=function(e){var n=d.getSelectorFromElement(this);if(n){var i=o.default(n)[0];if(i&&o.default(i).hasClass("carousel")){var a=r({},o.default(i).data(),o.default(this).data()),s=this.getAttribute("data-slide-to");s&&(a.interval=!1),t._jQueryInterface.call(o.default(i),a),s&&o.default(i).data(w).to(s),e.preventDefault()}}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return k}}]),t}();o.default(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",P._dataApiClickHandler),o.default(window).on("load.bs.carousel.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-ride="carousel"]')),e=0,n=t.length;e0&&(this._selector=s,this._triggerArray.push(a))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}var e=t.prototype;return e.toggle=function(){o.default(this._element).hasClass(q)?this.hide():this.show()},e.show=function(){var e,n,i=this;if(!(this._isTransitioning||o.default(this._element).hasClass(q)||(this._parent&&0===(e=[].slice.call(this._parent.querySelectorAll(".show, .collapsing")).filter((function(t){return"string"==typeof i._config.parent?t.getAttribute("data-parent")===i._config.parent:t.classList.contains(F)}))).length&&(e=null),e&&(n=o.default(e).not(this._selector).data(R))&&n._isTransitioning))){var a=o.default.Event("show.bs.collapse");if(o.default(this._element).trigger(a),!a.isDefaultPrevented()){e&&(t._jQueryInterface.call(o.default(e).not(this._selector),"hide"),n||o.default(e).data(R,null));var s=this._getDimension();o.default(this._element).removeClass(F).addClass(Q),this._element.style[s]=0,this._triggerArray.length&&o.default(this._triggerArray).removeClass(B).attr("aria-expanded",!0),this.setTransitioning(!0);var l="scroll"+(s[0].toUpperCase()+s.slice(1)),r=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,(function(){o.default(i._element).removeClass(Q).addClass("collapse show"),i._element.style[s]="",i.setTransitioning(!1),o.default(i._element).trigger("shown.bs.collapse")})).emulateTransitionEnd(r),this._element.style[s]=this._element[l]+"px"}}},e.hide=function(){var t=this;if(!this._isTransitioning&&o.default(this._element).hasClass(q)){var e=o.default.Event("hide.bs.collapse");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){var n=this._getDimension();this._element.style[n]=this._element.getBoundingClientRect()[n]+"px",d.reflow(this._element),o.default(this._element).addClass(Q).removeClass("collapse show");var i=this._triggerArray.length;if(i>0)for(var a=0;a0},e._getOffset=function(){var t=this,e={};return"function"==typeof this._config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t._config.offset(e.offsets,t._element)),e}:e.offset=this._config.offset,e},e._getPopperConfig=function(){var t={placement:this._getPlacement(),modifiers:{offset:this._getOffset(),flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}};return"static"===this._config.display&&(t.modifiers.applyStyle={enabled:!1}),r({},t,this._config.popperConfig)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(K);if(n||(n=new t(this,"object"==typeof e?e:null),o.default(this).data(K,n)),"string"==typeof e){if("undefined"==typeof n[e])throw new TypeError('No method named "'+e+'"');n[e]()}}))},t._clearMenus=function(e){if(!e||3!==e.which&&("keyup"!==e.type||9===e.which))for(var n=[].slice.call(document.querySelectorAll(it)),i=0,a=n.length;i0&&s--,40===e.which&&sdocument.documentElement.clientHeight;n||(this._element.style.overflowY="hidden"),this._element.classList.add(ht);var i=d.getTransitionDurationFromElement(this._dialog);o.default(this._element).off(d.TRANSITION_END),o.default(this._element).one(d.TRANSITION_END,(function(){t._element.classList.remove(ht),n||o.default(t._element).one(d.TRANSITION_END,(function(){t._element.style.overflowY=""})).emulateTransitionEnd(t._element,i)})).emulateTransitionEnd(i),this._element.focus()}},e._showElement=function(t){var e=this,n=o.default(this._element).hasClass(dt),i=this._dialog?this._dialog.querySelector(".modal-body"):null;this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),o.default(this._dialog).hasClass("modal-dialog-scrollable")&&i?i.scrollTop=0:this._element.scrollTop=0,n&&d.reflow(this._element),o.default(this._element).addClass(ct),this._config.focus&&this._enforceFocus();var a=o.default.Event("shown.bs.modal",{relatedTarget:t}),s=function(){e._config.focus&&e._element.focus(),e._isTransitioning=!1,o.default(e._element).trigger(a)};if(n){var l=d.getTransitionDurationFromElement(this._dialog);o.default(this._dialog).one(d.TRANSITION_END,s).emulateTransitionEnd(l)}else s()},e._enforceFocus=function(){var t=this;o.default(document).off(pt).on(pt,(function(e){document!==e.target&&t._element!==e.target&&0===o.default(t._element).has(e.target).length&&t._element.focus()}))},e._setEscapeEvent=function(){var t=this;this._isShown?o.default(this._element).on(yt,(function(e){t._config.keyboard&&27===e.which?(e.preventDefault(),t.hide()):t._config.keyboard||27!==e.which||t._triggerBackdropTransition()})):this._isShown||o.default(this._element).off(yt)},e._setResizeEvent=function(){var t=this;this._isShown?o.default(window).on(_t,(function(e){return t.handleUpdate(e)})):o.default(window).off(_t)},e._hideModal=function(){var t=this;this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._showBackdrop((function(){o.default(document.body).removeClass(ft),t._resetAdjustments(),t._resetScrollbar(),o.default(t._element).trigger(gt)}))},e._removeBackdrop=function(){this._backdrop&&(o.default(this._backdrop).remove(),this._backdrop=null)},e._showBackdrop=function(t){var e=this,n=o.default(this._element).hasClass(dt)?dt:"";if(this._isShown&&this._config.backdrop){if(this._backdrop=document.createElement("div"),this._backdrop.className="modal-backdrop",n&&this._backdrop.classList.add(n),o.default(this._backdrop).appendTo(document.body),o.default(this._element).on(vt,(function(t){e._ignoreBackdropClick?e._ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"===e._config.backdrop?e._triggerBackdropTransition():e.hide())})),n&&d.reflow(this._backdrop),o.default(this._backdrop).addClass(ct),!t)return;if(!n)return void t();var i=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,t).emulateTransitionEnd(i)}else if(!this._isShown&&this._backdrop){o.default(this._backdrop).removeClass(ct);var a=function(){e._removeBackdrop(),t&&t()};if(o.default(this._element).hasClass(dt)){var s=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a()}else t&&t()},e._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},e._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},e._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=Math.round(t.left+t.right)
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",customClass:"",sanitize:!0,sanitizeFn:null,whiteList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},Ut={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string|function)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",whiteList:"object",popperConfig:"(null|object)"},Mt={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},Wt=function(){function t(t,e){if("undefined"==typeof a.default)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var e=t.prototype;return e.enable=function(){this._isEnabled=!0},e.disable=function(){this._isEnabled=!1},e.toggleEnabled=function(){this._isEnabled=!this._isEnabled},e.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=o.default(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(o.default(this.getTipElement()).hasClass(Rt))return void this._leave(null,this);this._enter(null,this)}},e.dispose=function(){clearTimeout(this._timeout),o.default.removeData(this.element,this.constructor.DATA_KEY),o.default(this.element).off(this.constructor.EVENT_KEY),o.default(this.element).closest(".modal").off("hide.bs.modal",this._hideModalHandler),this.tip&&o.default(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},e.show=function(){var t=this;if("none"===o.default(this.element).css("display"))throw new Error("Please use show on visible elements");var e=o.default.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){o.default(this.element).trigger(e);var n=d.findShadowRoot(this.element),i=o.default.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(e.isDefaultPrevented()||!i)return;var s=this.getTipElement(),l=d.getUID(this.constructor.NAME);s.setAttribute("id",l),this.element.setAttribute("aria-describedby",l),this.setContent(),this.config.animation&&o.default(s).addClass(Lt);var r="function"==typeof this.config.placement?this.config.placement.call(this,s,this.element):this.config.placement,u=this._getAttachment(r);this.addAttachmentClass(u);var f=this._getContainer();o.default(s).data(this.constructor.DATA_KEY,this),o.default.contains(this.element.ownerDocument.documentElement,this.tip)||o.default(s).appendTo(f),o.default(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new a.default(this.element,s,this._getPopperConfig(u)),o.default(s).addClass(Rt),o.default(s).addClass(this.config.customClass),"ontouchstart"in document.documentElement&&o.default(document.body).children().on("mouseover",null,o.default.noop);var c=function(){t.config.animation&&t._fixTransition();var e=t._hoverState;t._hoverState=null,o.default(t.element).trigger(t.constructor.Event.SHOWN),e===qt&&t._leave(null,t)};if(o.default(this.tip).hasClass(Lt)){var h=d.getTransitionDurationFromElement(this.tip);o.default(this.tip).one(d.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},e.hide=function(t){var e=this,n=this.getTipElement(),i=o.default.Event(this.constructor.Event.HIDE),a=function(){e._hoverState!==xt&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),o.default(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(o.default(this.element).trigger(i),!i.isDefaultPrevented()){if(o.default(n).removeClass(Rt),"ontouchstart"in document.documentElement&&o.default(document.body).children().off("mouseover",null,o.default.noop),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,o.default(this.tip).hasClass(Lt)){var s=d.getTransitionDurationFromElement(n);o.default(n).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a();this._hoverState=""}},e.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},e.isWithContent=function(){return Boolean(this.getTitle())},e.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-tooltip-"+t)},e.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},e.setContent=function(){var t=this.getTipElement();this.setElementContent(o.default(t.querySelectorAll(".tooltip-inner")),this.getTitle()),o.default(t).removeClass("fade show")},e.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=At(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?o.default(e).parent().is(t)||t.empty().append(e):t.text(o.default(e).text())},e.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},e._getPopperConfig=function(t){var e=this;return r({},{placement:t,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:".arrow"},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}},this.config.popperConfig)},e._getOffset=function(){var t=this,e={};return"function"==typeof this.config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t.config.offset(e.offsets,t.element)),e}:e.offset=this.config.offset,e},e._getContainer=function(){return!1===this.config.container?document.body:d.isElement(this.config.container)?o.default(this.config.container):o.default(document).find(this.config.container)},e._getAttachment=function(t){return Bt[t.toUpperCase()]},e._setListeners=function(){var t=this;this.config.trigger.split(" ").forEach((function(e){if("click"===e)o.default(t.element).on(t.constructor.Event.CLICK,t.config.selector,(function(e){return t.toggle(e)}));else if("manual"!==e){var n=e===Ft?t.constructor.Event.MOUSEENTER:t.constructor.Event.FOCUSIN,i=e===Ft?t.constructor.Event.MOUSELEAVE:t.constructor.Event.FOCUSOUT;o.default(t.element).on(n,t.config.selector,(function(e){return t._enter(e)})).on(i,t.config.selector,(function(e){return t._leave(e)}))}})),this._hideModalHandler=function(){t.element&&t.hide()},o.default(this.element).closest(".modal").on("hide.bs.modal",this._hideModalHandler),this.config.selector?this.config=r({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},e._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},e._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Qt:Ft]=!0),o.default(e.getTipElement()).hasClass(Rt)||e._hoverState===xt?e._hoverState=xt:(clearTimeout(e._timeout),e._hoverState=xt,e.config.delay&&e.config.delay.show?e._timeout=setTimeout((function(){e._hoverState===xt&&e.show()}),e.config.delay.show):e.show())},e._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Qt:Ft]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=qt,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout((function(){e._hoverState===qt&&e.hide()}),e.config.delay.hide):e.hide())},e._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},e._getConfig=function(t){var e=o.default(this.element).data();return Object.keys(e).forEach((function(t){-1!==Pt.indexOf(t)&&delete e[t]})),"number"==typeof(t=r({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),d.typeCheckConfig(It,t,this.constructor.DefaultType),t.sanitize&&(t.template=At(t.template,t.whiteList,t.sanitizeFn)),t},e._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},e._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(jt);null!==e&&e.length&&t.removeClass(e.join(""))},e._handlePopperPlacementChange=function(t){this.tip=t.instance.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},e._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(o.default(t).removeClass(Lt),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(kt),a="object"==typeof e&&e;if((i||!/dispose|hide/.test(e))&&(i||(i=new t(this,a),n.data(kt,i)),"string"==typeof e)){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Ht}},{key:"NAME",get:function(){return It}},{key:"DATA_KEY",get:function(){return kt}},{key:"Event",get:function(){return Mt}},{key:"EVENT_KEY",get:function(){return".bs.tooltip"}},{key:"DefaultType",get:function(){return Ut}}]),t}();o.default.fn.tooltip=Wt._jQueryInterface,o.default.fn.tooltip.Constructor=Wt,o.default.fn.tooltip.noConflict=function(){return o.default.fn.tooltip=Ot,Wt._jQueryInterface};var Vt="bs.popover",zt=o.default.fn.popover,Kt=new RegExp("(^|\\s)bs-popover\\S+","g"),Xt=r({},Wt.Default,{placement:"right",trigger:"click",content:"",template:''}),Yt=r({},Wt.DefaultType,{content:"(string|element|function)"}),$t={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"},Jt=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),e.prototype.constructor=e,u(e,n);var a=i.prototype;return a.isWithContent=function(){return this.getTitle()||this._getContent()},a.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-popover-"+t)},a.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},a.setContent=function(){var t=o.default(this.getTipElement());this.setElementContent(t.find(".popover-header"),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(".popover-body"),e),t.removeClass("fade show")},a._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},a._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(Kt);null!==e&&e.length>0&&t.removeClass(e.join(""))},i._jQueryInterface=function(t){return this.each((function(){var e=o.default(this).data(Vt),n="object"==typeof t?t:null;if((e||!/dispose|hide/.test(t))&&(e||(e=new i(this,n),o.default(this).data(Vt,e)),"string"==typeof t)){if("undefined"==typeof e[t])throw new TypeError('No method named "'+t+'"');e[t]()}}))},l(i,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Xt}},{key:"NAME",get:function(){return"popover"}},{key:"DATA_KEY",get:function(){return Vt}},{key:"Event",get:function(){return $t}},{key:"EVENT_KEY",get:function(){return".bs.popover"}},{key:"DefaultType",get:function(){return Yt}}]),i}(Wt);o.default.fn.popover=Jt._jQueryInterface,o.default.fn.popover.Constructor=Jt,o.default.fn.popover.noConflict=function(){return o.default.fn.popover=zt,Jt._jQueryInterface};var Gt="scrollspy",Zt="bs.scrollspy",te=o.default.fn[Gt],ee="active",ne="position",ie=".nav, .list-group",oe={offset:10,method:"auto",target:""},ae={offset:"number",method:"string",target:"(string|element)"},se=function(){function t(t,e){var n=this;this._element=t,this._scrollElement="BODY"===t.tagName?window:t,this._config=this._getConfig(e),this._selector=this._config.target+" .nav-link,"+this._config.target+" .list-group-item,"+this._config.target+" .dropdown-item",this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,o.default(this._scrollElement).on("scroll.bs.scrollspy",(function(t){return n._process(t)})),this.refresh(),this._process()}var e=t.prototype;return e.refresh=function(){var t=this,e=this._scrollElement===this._scrollElement.window?"offset":ne,n="auto"===this._config.method?e:this._config.method,i=n===ne?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),[].slice.call(document.querySelectorAll(this._selector)).map((function(t){var e,a=d.getSelectorFromElement(t);if(a&&(e=document.querySelector(a)),e){var s=e.getBoundingClientRect();if(s.width||s.height)return[o.default(e)[n]().top+i,a]}return null})).filter((function(t){return t})).sort((function(t,e){return t[0]-e[0]})).forEach((function(e){t._offsets.push(e[0]),t._targets.push(e[1])}))},e.dispose=function(){o.default.removeData(this._element,Zt),o.default(this._scrollElement).off(".bs.scrollspy"),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},e._getConfig=function(t){if("string"!=typeof(t=r({},oe,"object"==typeof t&&t?t:{})).target&&d.isElement(t.target)){var e=o.default(t.target).attr("id");e||(e=d.getUID(Gt),o.default(t.target).attr("id",e)),t.target="#"+e}return d.typeCheckConfig(Gt,t,ae),t},e._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},e._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},e._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},e._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;)this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||t li > .active",ge=function(){function t(t){this._element=t}var e=t.prototype;return e.show=function(){var t=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&o.default(this._element).hasClass(ue)||o.default(this._element).hasClass("disabled"))){var e,n,i=o.default(this._element).closest(".nav, .list-group")[0],a=d.getSelectorFromElement(this._element);if(i){var s="UL"===i.nodeName||"OL"===i.nodeName?he:ce;n=(n=o.default.makeArray(o.default(i).find(s)))[n.length-1]}var l=o.default.Event("hide.bs.tab",{relatedTarget:this._element}),r=o.default.Event("show.bs.tab",{relatedTarget:n});if(n&&o.default(n).trigger(l),o.default(this._element).trigger(r),!r.isDefaultPrevented()&&!l.isDefaultPrevented()){a&&(e=document.querySelector(a)),this._activate(this._element,i);var u=function(){var e=o.default.Event("hidden.bs.tab",{relatedTarget:t._element}),i=o.default.Event("shown.bs.tab",{relatedTarget:n});o.default(n).trigger(e),o.default(t._element).trigger(i)};e?this._activate(e,e.parentNode,u):u()}}},e.dispose=function(){o.default.removeData(this._element,le),this._element=null},e._activate=function(t,e,n){var i=this,a=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?o.default(e).children(ce):o.default(e).find(he))[0],s=n&&a&&o.default(a).hasClass(fe),l=function(){return i._transitionComplete(t,a,n)};if(a&&s){var r=d.getTransitionDurationFromElement(a);o.default(a).removeClass(de).one(d.TRANSITION_END,l).emulateTransitionEnd(r)}else l()},e._transitionComplete=function(t,e,n){if(e){o.default(e).removeClass(ue);var i=o.default(e.parentNode).find("> .dropdown-menu .active")[0];i&&o.default(i).removeClass(ue),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}o.default(t).addClass(ue),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),d.reflow(t),t.classList.contains(fe)&&t.classList.add(de);var a=t.parentNode;if(a&&"LI"===a.nodeName&&(a=a.parentNode),a&&o.default(a).hasClass("dropdown-menu")){var s=o.default(t).closest(".dropdown")[0];if(s){var l=[].slice.call(s.querySelectorAll(".dropdown-toggle"));o.default(l).addClass(ue)}t.setAttribute("aria-expanded",!0)}n&&n()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(le);if(i||(i=new t(this),n.data(le,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',(function(t){t.preventDefault(),ge._jQueryInterface.call(o.default(this),"show")})),o.default.fn.tab=ge._jQueryInterface,o.default.fn.tab.Constructor=ge,o.default.fn.tab.noConflict=function(){return o.default.fn.tab=re,ge._jQueryInterface};var me="bs.toast",pe=o.default.fn.toast,_e="hide",ve="show",ye="showing",be="click.dismiss.bs.toast",Ee={animation:!0,autohide:!0,delay:500},Te={animation:"boolean",autohide:"boolean",delay:"number"},we=function(){function t(t,e){this._element=t,this._config=this._getConfig(e),this._timeout=null,this._setListeners()}var e=t.prototype;return e.show=function(){var t=this,e=o.default.Event("show.bs.toast");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){this._clearTimeout(),this._config.animation&&this._element.classList.add("fade");var n=function(){t._element.classList.remove(ye),t._element.classList.add(ve),o.default(t._element).trigger("shown.bs.toast"),t._config.autohide&&(t._timeout=setTimeout((function(){t.hide()}),t._config.delay))};if(this._element.classList.remove(_e),d.reflow(this._element),this._element.classList.add(ye),this._config.animation){var i=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,n).emulateTransitionEnd(i)}else n()}},e.hide=function(){if(this._element.classList.contains(ve)){var t=o.default.Event("hide.bs.toast");o.default(this._element).trigger(t),t.isDefaultPrevented()||this._close()}},e.dispose=function(){this._clearTimeout(),this._element.classList.contains(ve)&&this._element.classList.remove(ve),o.default(this._element).off(be),o.default.removeData(this._element,me),this._element=null,this._config=null},e._getConfig=function(t){return t=r({},Ee,o.default(this._element).data(),"object"==typeof t&&t?t:{}),d.typeCheckConfig("toast",t,this.constructor.DefaultType),t},e._setListeners=function(){var t=this;o.default(this._element).on(be,'[data-dismiss="toast"]',(function(){return t.hide()}))},e._close=function(){var t=this,e=function(){t._element.classList.add(_e),o.default(t._element).trigger("hidden.bs.toast")};if(this._element.classList.remove(ve),this._config.animation){var n=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},e._clearTimeout=function(){clearTimeout(this._timeout),this._timeout=null},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(me);if(i||(i=new t(this,"object"==typeof e&&e),n.data(me,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e](this)}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"DefaultType",get:function(){return Te}},{key:"Default",get:function(){return Ee}}]),t}();o.default.fn.toast=we._jQueryInterface,o.default.fn.toast.Constructor=we,o.default.fn.toast.noConflict=function(){return o.default.fn.toast=pe,we._jQueryInterface},t.Alert=g,t.Button=E,t.Carousel=P,t.Collapse=V,t.Dropdown=lt,t.Modal=Ct,t.Popover=Jt,t.Scrollspy=se,t.Tab=ge,t.Toast=we,t.Tooltip=Wt,t.Util=d,Object.defineProperty(t,"__esModule",{value:!0})})); +//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/code/ch6_active_search/ch6_starter_video_collector/static/js/jquery-3.5.1.slim.min.js b/code/ch6_active_search/ch6_starter_video_collector/static/js/jquery-3.5.1.slim.min.js new file mode 100644 index 0000000..36b4e1a --- /dev/null +++ b/code/ch6_active_search/ch6_starter_video_collector/static/js/jquery-3.5.1.slim.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(g,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,v=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),m={},b=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},w=g.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function C(e,t,n){var r,i,o=(n=n||w).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function T(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector",E=function(e,t){return new E.fn.init(e,t)};function d(e){var t=!!e&&"length"in e&&e.length,n=T(e);return!b(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+R+")"+R+"*"),U=new RegExp(R+"|>"),V=new RegExp(W),X=new RegExp("^"+B+"$"),Q={ID:new RegExp("^#("+B+")"),CLASS:new RegExp("^\\.("+B+")"),TAG:new RegExp("^("+B+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+R+"*(even|odd|(([+-]|)(\\d*)n|)"+R+"*(?:([+-]|)"+R+"*(\\d+)|))"+R+"*\\)|)","i"),bool:new RegExp("^(?:"+I+")$","i"),needsContext:new RegExp("^"+R+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+R+"*((?:-\\d)?\\d*)"+R+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,G=/^(?:input|select|textarea|button)$/i,K=/^h\d$/i,J=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+R+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){C()},ae=xe(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{O.apply(t=P.call(d.childNodes),d.childNodes),t[d.childNodes.length].nodeType}catch(e){O={apply:t.length?function(e,t){q.apply(e,P.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,d=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==d&&9!==d&&11!==d)return n;if(!r&&(C(e),e=e||T,E)){if(11!==d&&(u=Z.exec(t)))if(i=u[1]){if(9===d){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return O.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&p.getElementsByClassName&&e.getElementsByClassName)return O.apply(n,e.getElementsByClassName(i)),n}if(p.qsa&&!k[t+" "]&&(!v||!v.test(t))&&(1!==d||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===d&&(U.test(t)||_.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&p.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=A)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+be(l[o]);c=l.join(",")}try{return O.apply(n,f.querySelectorAll(c)),n}catch(e){k(t,!0)}finally{s===A&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>x.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[A]=!0,e}function ce(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)x.attrHandle[n[r]]=t}function de(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pe(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in p=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},C=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:d;return r!=T&&9===r.nodeType&&r.documentElement&&(a=(T=r).documentElement,E=!i(T),d!=T&&(n=T.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),p.scope=ce(function(e){return a.appendChild(e).appendChild(T.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),p.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),p.getElementsByTagName=ce(function(e){return e.appendChild(T.createComment("")),!e.getElementsByTagName("*").length}),p.getElementsByClassName=J.test(T.getElementsByClassName),p.getById=ce(function(e){return a.appendChild(e).id=A,!T.getElementsByName||!T.getElementsByName(A).length}),p.getById?(x.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(x.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),x.find.TAG=p.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):p.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},x.find.CLASS=p.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(p.qsa=J.test(T.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+R+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+R+"*(?:value|"+I+")"),e.querySelectorAll("[id~="+A+"-]").length||v.push("~="),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+R+"*name"+R+"*="+R+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+A+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=T.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+R+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(p.matchesSelector=J.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){p.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",W)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=J.test(a.compareDocumentPosition),y=t||J.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!p.sortDetached&&t.compareDocumentPosition(e)===n?e==T||e.ownerDocument==d&&y(d,e)?-1:t==T||t.ownerDocument==d&&y(d,t)?1:u?H(u,e)-H(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==T?-1:t==T?1:i?-1:o?1:u?H(u,e)-H(u,t):0;if(i===o)return de(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?de(a[r],s[r]):a[r]==d?-1:s[r]==d?1:0}),T},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(C(e),p.matchesSelector&&E&&!k[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||p.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){k(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&V.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+R+")"+e+"("+R+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return b(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):"string"!=typeof n?E.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||L,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:j.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:w,!0)),k.test(r[1])&&E.isPlainObject(t))for(r in t)b(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=w.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):b(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,L=E(w);var q=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,pe=/^$|^module$|\/(?:java|ecma)script/i;le=w.createDocumentFragment().appendChild(w.createElement("div")),(ce=w.createElement("input")).setAttribute("type","radio"),ce.setAttribute("checked","checked"),ce.setAttribute("name","t"),le.appendChild(ce),m.checkClone=le.cloneNode(!0).cloneNode(!0).lastChild.checked,le.innerHTML="",m.noCloneChecked=!!le.cloneNode(!0).lastChild.defaultValue,le.innerHTML="",m.option=!!le.lastChild;var he={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ge(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&S(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var ye=/<|&#?\w+;/;function me(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),d=[],p=0,h=e.length;p\s*$/g;function Le(e,t){return S(e,"table")&&S(11!==t.nodeType?t:t.firstChild,"tr")&&E(e).children("tbody")[0]||e}function je(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n
",2===ft.childNodes.length),E.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(m.createHTMLDocument?((r=(t=w.implementation.createHTMLDocument("")).createElement("base")).href=w.location.href,t.head.appendChild(r)):t=w),o=!n&&[],(i=k.exec(e))?[t.createElement(i[1])]:(i=me([e],t,o),o&&o.length&&E(o).remove(),E.merge([],i.childNodes)));var r,i,o},E.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=E.css(e,"position"),c=E(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=E.css(e,"top"),u=E.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),b(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===E.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===E.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=E(e).offset()).top+=E.css(e,"borderTopWidth",!0),i.left+=E.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-E.css(r,"marginTop",!0),left:t.left-i.left-E.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===E.css(e,"position"))e=e.offsetParent;return e||re})}}),E.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;E.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each(["top","left"],function(e,n){E.cssHooks[n]=Fe(m.pixelPosition,function(e,t){if(t)return t=We(e,n),Ie.test(t)?E(e).position()[n]+"px":t})}),E.each({Height:"height",Width:"width"},function(a,s){E.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){E.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?E.css(e,t,i):E.style(e,t,n,i)},s,n?e:void 0,n)}})}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){E.fn[n]=function(e,t){return 0=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),ae({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=le({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f]),E=parseFloat(w['border'+f+'Width']),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},ae(n,m,$(v)),ae(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ce.FLIP:p=[n,i];break;case ce.CLOCKWISE:p=G(n);break;case ce.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u),E=!!t.flipVariationsByContent&&(w&&'start'===r&&c||w&&'end'===r&&h||!w&&'start'===r&&u||!w&&'end'===r&&g),v=y||E;(m||b||v)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),v&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=le({},e.offsets.popper,C(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport',flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=D(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.rightwindow.devicePixelRatio||!fe),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=B('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=le({},E,e.attributes),e.styles=le({},m,e.styles),e.arrowStyles=le({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return V(e.instance.popper,e.styles),j(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&V(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),V(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ge}); +//# sourceMappingURL=popper.min.js.map diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/bootstrap-4.6.1.min copy.js b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/bootstrap-4.6.1.min copy.js new file mode 100644 index 0000000..50720ea --- /dev/null +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/bootstrap-4.6.1.min copy.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.6.1 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap={},t.jQuery,t.Popper)}(this,(function(t,e,n){"use strict";function i(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var o=i(e),a=i(n);function s(t,e){for(var n=0;n=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}};d.jQueryDetection(),o.default.fn.emulateTransitionEnd=function(t){var e=this,n=!1;return o.default(this).one(d.TRANSITION_END,(function(){n=!0})),setTimeout((function(){n||d.triggerTransitionEnd(e)}),t),this},o.default.event.special[d.TRANSITION_END]={bindType:f,delegateType:f,handle:function(t){if(o.default(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}};var c="bs.alert",h=o.default.fn.alert,g=function(){function t(t){this._element=t}var e=t.prototype;return e.close=function(t){var e=this._element;t&&(e=this._getRootElement(t)),this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.dispose=function(){o.default.removeData(this._element,c),this._element=null},e._getRootElement=function(t){var e=d.getSelectorFromElement(t),n=!1;return e&&(n=document.querySelector(e)),n||(n=o.default(t).closest(".alert")[0]),n},e._triggerCloseEvent=function(t){var e=o.default.Event("close.bs.alert");return o.default(t).trigger(e),e},e._removeElement=function(t){var e=this;if(o.default(t).removeClass("show"),o.default(t).hasClass("fade")){var n=d.getTransitionDurationFromElement(t);o.default(t).one(d.TRANSITION_END,(function(n){return e._destroyElement(t,n)})).emulateTransitionEnd(n)}else this._destroyElement(t)},e._destroyElement=function(t){o.default(t).detach().trigger("closed.bs.alert").remove()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(c);i||(i=new t(this),n.data(c,i)),"close"===e&&i[e](this)}))},t._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',g._handleDismiss(new g)),o.default.fn.alert=g._jQueryInterface,o.default.fn.alert.Constructor=g,o.default.fn.alert.noConflict=function(){return o.default.fn.alert=h,g._jQueryInterface};var m="bs.button",p=o.default.fn.button,_="active",v='[data-toggle^="button"]',y='input:not([type="hidden"])',b=".btn",E=function(){function t(t){this._element=t,this.shouldAvoidTriggerChange=!1}var e=t.prototype;return e.toggle=function(){var t=!0,e=!0,n=o.default(this._element).closest('[data-toggle="buttons"]')[0];if(n){var i=this._element.querySelector(y);if(i){if("radio"===i.type)if(i.checked&&this._element.classList.contains(_))t=!1;else{var a=n.querySelector(".active");a&&o.default(a).removeClass(_)}t&&("checkbox"!==i.type&&"radio"!==i.type||(i.checked=!this._element.classList.contains(_)),this.shouldAvoidTriggerChange||o.default(i).trigger("change")),i.focus(),e=!1}}this._element.hasAttribute("disabled")||this._element.classList.contains("disabled")||(e&&this._element.setAttribute("aria-pressed",!this._element.classList.contains(_)),t&&o.default(this._element).toggleClass(_))},e.dispose=function(){o.default.removeData(this._element,m),this._element=null},t._jQueryInterface=function(e,n){return this.each((function(){var i=o.default(this),a=i.data(m);a||(a=new t(this),i.data(m,a)),a.shouldAvoidTriggerChange=n,"toggle"===e&&a[e]()}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.button.data-api",v,(function(t){var e=t.target,n=e;if(o.default(e).hasClass("btn")||(e=o.default(e).closest(b)[0]),!e||e.hasAttribute("disabled")||e.classList.contains("disabled"))t.preventDefault();else{var i=e.querySelector(y);if(i&&(i.hasAttribute("disabled")||i.classList.contains("disabled")))return void t.preventDefault();"INPUT"!==n.tagName&&"LABEL"===e.tagName||E._jQueryInterface.call(o.default(e),"toggle","INPUT"===n.tagName)}})).on("focus.bs.button.data-api blur.bs.button.data-api",v,(function(t){var e=o.default(t.target).closest(b)[0];o.default(e).toggleClass("focus",/^focus(in)?$/.test(t.type))})),o.default(window).on("load.bs.button.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-toggle="buttons"] .btn')),e=0,n=t.length;e0,this._pointerEvent=Boolean(window.PointerEvent||window.MSPointerEvent),this._addEventListeners()}var e=t.prototype;return e.next=function(){this._isSliding||this._slide(N)},e.nextWhenVisible=function(){var t=o.default(this._element);!document.hidden&&t.is(":visible")&&"hidden"!==t.css("visibility")&&this.next()},e.prev=function(){this._isSliding||this._slide(D)},e.pause=function(t){t||(this._isPaused=!0),this._element.querySelector(".carousel-item-next, .carousel-item-prev")&&(d.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},e.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},e.to=function(t){var e=this;this._activeElement=this._element.querySelector(I);var n=this._getItemIndex(this._activeElement);if(!(t>this._items.length-1||t<0))if(this._isSliding)o.default(this._element).one(A,(function(){return e.to(t)}));else{if(n===t)return this.pause(),void this.cycle();var i=t>n?N:D;this._slide(i,this._items[t])}},e.dispose=function(){o.default(this._element).off(".bs.carousel"),o.default.removeData(this._element,w),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},e._getConfig=function(t){return t=r({},k,t),d.typeCheckConfig(T,t,O),t},e._handleSwipe=function(){var t=Math.abs(this.touchDeltaX);if(!(t<=40)){var e=t/this.touchDeltaX;this.touchDeltaX=0,e>0&&this.prev(),e<0&&this.next()}},e._addEventListeners=function(){var t=this;this._config.keyboard&&o.default(this._element).on("keydown.bs.carousel",(function(e){return t._keydown(e)})),"hover"===this._config.pause&&o.default(this._element).on("mouseenter.bs.carousel",(function(e){return t.pause(e)})).on("mouseleave.bs.carousel",(function(e){return t.cycle(e)})),this._config.touch&&this._addTouchEventListeners()},e._addTouchEventListeners=function(){var t=this;if(this._touchSupported){var e=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]?t.touchStartX=e.originalEvent.clientX:t._pointerEvent||(t.touchStartX=e.originalEvent.touches[0].clientX)},n=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]&&(t.touchDeltaX=e.originalEvent.clientX-t.touchStartX),t._handleSwipe(),"hover"===t._config.pause&&(t.pause(),t.touchTimeout&&clearTimeout(t.touchTimeout),t.touchTimeout=setTimeout((function(e){return t.cycle(e)}),500+t._config.interval))};o.default(this._element.querySelectorAll(".carousel-item img")).on("dragstart.bs.carousel",(function(t){return t.preventDefault()})),this._pointerEvent?(o.default(this._element).on("pointerdown.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("pointerup.bs.carousel",(function(t){return n(t)})),this._element.classList.add("pointer-event")):(o.default(this._element).on("touchstart.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("touchmove.bs.carousel",(function(e){return function(e){t.touchDeltaX=e.originalEvent.touches&&e.originalEvent.touches.length>1?0:e.originalEvent.touches[0].clientX-t.touchStartX}(e)})),o.default(this._element).on("touchend.bs.carousel",(function(t){return n(t)})))}},e._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next()}},e._getItemIndex=function(t){return this._items=t&&t.parentNode?[].slice.call(t.parentNode.querySelectorAll(".carousel-item")):[],this._items.indexOf(t)},e._getItemByDirection=function(t,e){var n=t===N,i=t===D,o=this._getItemIndex(e),a=this._items.length-1;if((i&&0===o||n&&o===a)&&!this._config.wrap)return e;var s=(o+(t===D?-1:1))%this._items.length;return-1===s?this._items[this._items.length-1]:this._items[s]},e._triggerSlideEvent=function(t,e){var n=this._getItemIndex(t),i=this._getItemIndex(this._element.querySelector(I)),a=o.default.Event("slide.bs.carousel",{relatedTarget:t,direction:e,from:i,to:n});return o.default(this._element).trigger(a),a},e._setActiveIndicatorElement=function(t){if(this._indicatorsElement){var e=[].slice.call(this._indicatorsElement.querySelectorAll(".active"));o.default(e).removeClass(S);var n=this._indicatorsElement.children[this._getItemIndex(t)];n&&o.default(n).addClass(S)}},e._updateInterval=function(){var t=this._activeElement||this._element.querySelector(I);if(t){var e=parseInt(t.getAttribute("data-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}},e._slide=function(t,e){var n,i,a,s=this,l=this._element.querySelector(I),r=this._getItemIndex(l),u=e||l&&this._getItemByDirection(t,l),f=this._getItemIndex(u),c=Boolean(this._interval);if(t===N?(n="carousel-item-left",i="carousel-item-next",a="left"):(n="carousel-item-right",i="carousel-item-prev",a="right"),u&&o.default(u).hasClass(S))this._isSliding=!1;else if(!this._triggerSlideEvent(u,a).isDefaultPrevented()&&l&&u){this._isSliding=!0,c&&this.pause(),this._setActiveIndicatorElement(u),this._activeElement=u;var h=o.default.Event(A,{relatedTarget:u,direction:a,from:r,to:f});if(o.default(this._element).hasClass("slide")){o.default(u).addClass(i),d.reflow(u),o.default(l).addClass(n),o.default(u).addClass(n);var g=d.getTransitionDurationFromElement(l);o.default(l).one(d.TRANSITION_END,(function(){o.default(u).removeClass(n+" "+i).addClass(S),o.default(l).removeClass("active "+i+" "+n),s._isSliding=!1,setTimeout((function(){return o.default(s._element).trigger(h)}),0)})).emulateTransitionEnd(g)}else o.default(l).removeClass(S),o.default(u).addClass(S),this._isSliding=!1,o.default(this._element).trigger(h);c&&this.cycle()}},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(w),i=r({},k,o.default(this).data());"object"==typeof e&&(i=r({},i,e));var a="string"==typeof e?e:i.slide;if(n||(n=new t(this,i),o.default(this).data(w,n)),"number"==typeof e)n.to(e);else if("string"==typeof a){if("undefined"==typeof n[a])throw new TypeError('No method named "'+a+'"');n[a]()}else i.interval&&i.ride&&(n.pause(),n.cycle())}))},t._dataApiClickHandler=function(e){var n=d.getSelectorFromElement(this);if(n){var i=o.default(n)[0];if(i&&o.default(i).hasClass("carousel")){var a=r({},o.default(i).data(),o.default(this).data()),s=this.getAttribute("data-slide-to");s&&(a.interval=!1),t._jQueryInterface.call(o.default(i),a),s&&o.default(i).data(w).to(s),e.preventDefault()}}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return k}}]),t}();o.default(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",P._dataApiClickHandler),o.default(window).on("load.bs.carousel.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-ride="carousel"]')),e=0,n=t.length;e0&&(this._selector=s,this._triggerArray.push(a))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}var e=t.prototype;return e.toggle=function(){o.default(this._element).hasClass(q)?this.hide():this.show()},e.show=function(){var e,n,i=this;if(!(this._isTransitioning||o.default(this._element).hasClass(q)||(this._parent&&0===(e=[].slice.call(this._parent.querySelectorAll(".show, .collapsing")).filter((function(t){return"string"==typeof i._config.parent?t.getAttribute("data-parent")===i._config.parent:t.classList.contains(F)}))).length&&(e=null),e&&(n=o.default(e).not(this._selector).data(R))&&n._isTransitioning))){var a=o.default.Event("show.bs.collapse");if(o.default(this._element).trigger(a),!a.isDefaultPrevented()){e&&(t._jQueryInterface.call(o.default(e).not(this._selector),"hide"),n||o.default(e).data(R,null));var s=this._getDimension();o.default(this._element).removeClass(F).addClass(Q),this._element.style[s]=0,this._triggerArray.length&&o.default(this._triggerArray).removeClass(B).attr("aria-expanded",!0),this.setTransitioning(!0);var l="scroll"+(s[0].toUpperCase()+s.slice(1)),r=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,(function(){o.default(i._element).removeClass(Q).addClass("collapse show"),i._element.style[s]="",i.setTransitioning(!1),o.default(i._element).trigger("shown.bs.collapse")})).emulateTransitionEnd(r),this._element.style[s]=this._element[l]+"px"}}},e.hide=function(){var t=this;if(!this._isTransitioning&&o.default(this._element).hasClass(q)){var e=o.default.Event("hide.bs.collapse");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){var n=this._getDimension();this._element.style[n]=this._element.getBoundingClientRect()[n]+"px",d.reflow(this._element),o.default(this._element).addClass(Q).removeClass("collapse show");var i=this._triggerArray.length;if(i>0)for(var a=0;a0},e._getOffset=function(){var t=this,e={};return"function"==typeof this._config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t._config.offset(e.offsets,t._element)),e}:e.offset=this._config.offset,e},e._getPopperConfig=function(){var t={placement:this._getPlacement(),modifiers:{offset:this._getOffset(),flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}};return"static"===this._config.display&&(t.modifiers.applyStyle={enabled:!1}),r({},t,this._config.popperConfig)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(K);if(n||(n=new t(this,"object"==typeof e?e:null),o.default(this).data(K,n)),"string"==typeof e){if("undefined"==typeof n[e])throw new TypeError('No method named "'+e+'"');n[e]()}}))},t._clearMenus=function(e){if(!e||3!==e.which&&("keyup"!==e.type||9===e.which))for(var n=[].slice.call(document.querySelectorAll(it)),i=0,a=n.length;i0&&s--,40===e.which&&sdocument.documentElement.clientHeight;n||(this._element.style.overflowY="hidden"),this._element.classList.add(ht);var i=d.getTransitionDurationFromElement(this._dialog);o.default(this._element).off(d.TRANSITION_END),o.default(this._element).one(d.TRANSITION_END,(function(){t._element.classList.remove(ht),n||o.default(t._element).one(d.TRANSITION_END,(function(){t._element.style.overflowY=""})).emulateTransitionEnd(t._element,i)})).emulateTransitionEnd(i),this._element.focus()}},e._showElement=function(t){var e=this,n=o.default(this._element).hasClass(dt),i=this._dialog?this._dialog.querySelector(".modal-body"):null;this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),o.default(this._dialog).hasClass("modal-dialog-scrollable")&&i?i.scrollTop=0:this._element.scrollTop=0,n&&d.reflow(this._element),o.default(this._element).addClass(ct),this._config.focus&&this._enforceFocus();var a=o.default.Event("shown.bs.modal",{relatedTarget:t}),s=function(){e._config.focus&&e._element.focus(),e._isTransitioning=!1,o.default(e._element).trigger(a)};if(n){var l=d.getTransitionDurationFromElement(this._dialog);o.default(this._dialog).one(d.TRANSITION_END,s).emulateTransitionEnd(l)}else s()},e._enforceFocus=function(){var t=this;o.default(document).off(pt).on(pt,(function(e){document!==e.target&&t._element!==e.target&&0===o.default(t._element).has(e.target).length&&t._element.focus()}))},e._setEscapeEvent=function(){var t=this;this._isShown?o.default(this._element).on(yt,(function(e){t._config.keyboard&&27===e.which?(e.preventDefault(),t.hide()):t._config.keyboard||27!==e.which||t._triggerBackdropTransition()})):this._isShown||o.default(this._element).off(yt)},e._setResizeEvent=function(){var t=this;this._isShown?o.default(window).on(_t,(function(e){return t.handleUpdate(e)})):o.default(window).off(_t)},e._hideModal=function(){var t=this;this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._showBackdrop((function(){o.default(document.body).removeClass(ft),t._resetAdjustments(),t._resetScrollbar(),o.default(t._element).trigger(gt)}))},e._removeBackdrop=function(){this._backdrop&&(o.default(this._backdrop).remove(),this._backdrop=null)},e._showBackdrop=function(t){var e=this,n=o.default(this._element).hasClass(dt)?dt:"";if(this._isShown&&this._config.backdrop){if(this._backdrop=document.createElement("div"),this._backdrop.className="modal-backdrop",n&&this._backdrop.classList.add(n),o.default(this._backdrop).appendTo(document.body),o.default(this._element).on(vt,(function(t){e._ignoreBackdropClick?e._ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"===e._config.backdrop?e._triggerBackdropTransition():e.hide())})),n&&d.reflow(this._backdrop),o.default(this._backdrop).addClass(ct),!t)return;if(!n)return void t();var i=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,t).emulateTransitionEnd(i)}else if(!this._isShown&&this._backdrop){o.default(this._backdrop).removeClass(ct);var a=function(){e._removeBackdrop(),t&&t()};if(o.default(this._element).hasClass(dt)){var s=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a()}else t&&t()},e._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},e._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},e._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=Math.round(t.left+t.right)
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",customClass:"",sanitize:!0,sanitizeFn:null,whiteList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},Ut={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string|function)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",whiteList:"object",popperConfig:"(null|object)"},Mt={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},Wt=function(){function t(t,e){if("undefined"==typeof a.default)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var e=t.prototype;return e.enable=function(){this._isEnabled=!0},e.disable=function(){this._isEnabled=!1},e.toggleEnabled=function(){this._isEnabled=!this._isEnabled},e.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=o.default(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(o.default(this.getTipElement()).hasClass(Rt))return void this._leave(null,this);this._enter(null,this)}},e.dispose=function(){clearTimeout(this._timeout),o.default.removeData(this.element,this.constructor.DATA_KEY),o.default(this.element).off(this.constructor.EVENT_KEY),o.default(this.element).closest(".modal").off("hide.bs.modal",this._hideModalHandler),this.tip&&o.default(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},e.show=function(){var t=this;if("none"===o.default(this.element).css("display"))throw new Error("Please use show on visible elements");var e=o.default.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){o.default(this.element).trigger(e);var n=d.findShadowRoot(this.element),i=o.default.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(e.isDefaultPrevented()||!i)return;var s=this.getTipElement(),l=d.getUID(this.constructor.NAME);s.setAttribute("id",l),this.element.setAttribute("aria-describedby",l),this.setContent(),this.config.animation&&o.default(s).addClass(Lt);var r="function"==typeof this.config.placement?this.config.placement.call(this,s,this.element):this.config.placement,u=this._getAttachment(r);this.addAttachmentClass(u);var f=this._getContainer();o.default(s).data(this.constructor.DATA_KEY,this),o.default.contains(this.element.ownerDocument.documentElement,this.tip)||o.default(s).appendTo(f),o.default(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new a.default(this.element,s,this._getPopperConfig(u)),o.default(s).addClass(Rt),o.default(s).addClass(this.config.customClass),"ontouchstart"in document.documentElement&&o.default(document.body).children().on("mouseover",null,o.default.noop);var c=function(){t.config.animation&&t._fixTransition();var e=t._hoverState;t._hoverState=null,o.default(t.element).trigger(t.constructor.Event.SHOWN),e===qt&&t._leave(null,t)};if(o.default(this.tip).hasClass(Lt)){var h=d.getTransitionDurationFromElement(this.tip);o.default(this.tip).one(d.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},e.hide=function(t){var e=this,n=this.getTipElement(),i=o.default.Event(this.constructor.Event.HIDE),a=function(){e._hoverState!==xt&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),o.default(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(o.default(this.element).trigger(i),!i.isDefaultPrevented()){if(o.default(n).removeClass(Rt),"ontouchstart"in document.documentElement&&o.default(document.body).children().off("mouseover",null,o.default.noop),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,o.default(this.tip).hasClass(Lt)){var s=d.getTransitionDurationFromElement(n);o.default(n).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a();this._hoverState=""}},e.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},e.isWithContent=function(){return Boolean(this.getTitle())},e.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-tooltip-"+t)},e.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},e.setContent=function(){var t=this.getTipElement();this.setElementContent(o.default(t.querySelectorAll(".tooltip-inner")),this.getTitle()),o.default(t).removeClass("fade show")},e.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=At(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?o.default(e).parent().is(t)||t.empty().append(e):t.text(o.default(e).text())},e.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},e._getPopperConfig=function(t){var e=this;return r({},{placement:t,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:".arrow"},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}},this.config.popperConfig)},e._getOffset=function(){var t=this,e={};return"function"==typeof this.config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t.config.offset(e.offsets,t.element)),e}:e.offset=this.config.offset,e},e._getContainer=function(){return!1===this.config.container?document.body:d.isElement(this.config.container)?o.default(this.config.container):o.default(document).find(this.config.container)},e._getAttachment=function(t){return Bt[t.toUpperCase()]},e._setListeners=function(){var t=this;this.config.trigger.split(" ").forEach((function(e){if("click"===e)o.default(t.element).on(t.constructor.Event.CLICK,t.config.selector,(function(e){return t.toggle(e)}));else if("manual"!==e){var n=e===Ft?t.constructor.Event.MOUSEENTER:t.constructor.Event.FOCUSIN,i=e===Ft?t.constructor.Event.MOUSELEAVE:t.constructor.Event.FOCUSOUT;o.default(t.element).on(n,t.config.selector,(function(e){return t._enter(e)})).on(i,t.config.selector,(function(e){return t._leave(e)}))}})),this._hideModalHandler=function(){t.element&&t.hide()},o.default(this.element).closest(".modal").on("hide.bs.modal",this._hideModalHandler),this.config.selector?this.config=r({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},e._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},e._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Qt:Ft]=!0),o.default(e.getTipElement()).hasClass(Rt)||e._hoverState===xt?e._hoverState=xt:(clearTimeout(e._timeout),e._hoverState=xt,e.config.delay&&e.config.delay.show?e._timeout=setTimeout((function(){e._hoverState===xt&&e.show()}),e.config.delay.show):e.show())},e._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Qt:Ft]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=qt,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout((function(){e._hoverState===qt&&e.hide()}),e.config.delay.hide):e.hide())},e._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},e._getConfig=function(t){var e=o.default(this.element).data();return Object.keys(e).forEach((function(t){-1!==Pt.indexOf(t)&&delete e[t]})),"number"==typeof(t=r({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),d.typeCheckConfig(It,t,this.constructor.DefaultType),t.sanitize&&(t.template=At(t.template,t.whiteList,t.sanitizeFn)),t},e._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},e._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(jt);null!==e&&e.length&&t.removeClass(e.join(""))},e._handlePopperPlacementChange=function(t){this.tip=t.instance.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},e._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(o.default(t).removeClass(Lt),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(kt),a="object"==typeof e&&e;if((i||!/dispose|hide/.test(e))&&(i||(i=new t(this,a),n.data(kt,i)),"string"==typeof e)){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Ht}},{key:"NAME",get:function(){return It}},{key:"DATA_KEY",get:function(){return kt}},{key:"Event",get:function(){return Mt}},{key:"EVENT_KEY",get:function(){return".bs.tooltip"}},{key:"DefaultType",get:function(){return Ut}}]),t}();o.default.fn.tooltip=Wt._jQueryInterface,o.default.fn.tooltip.Constructor=Wt,o.default.fn.tooltip.noConflict=function(){return o.default.fn.tooltip=Ot,Wt._jQueryInterface};var Vt="bs.popover",zt=o.default.fn.popover,Kt=new RegExp("(^|\\s)bs-popover\\S+","g"),Xt=r({},Wt.Default,{placement:"right",trigger:"click",content:"",template:''}),Yt=r({},Wt.DefaultType,{content:"(string|element|function)"}),$t={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"},Jt=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),e.prototype.constructor=e,u(e,n);var a=i.prototype;return a.isWithContent=function(){return this.getTitle()||this._getContent()},a.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-popover-"+t)},a.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},a.setContent=function(){var t=o.default(this.getTipElement());this.setElementContent(t.find(".popover-header"),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(".popover-body"),e),t.removeClass("fade show")},a._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},a._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(Kt);null!==e&&e.length>0&&t.removeClass(e.join(""))},i._jQueryInterface=function(t){return this.each((function(){var e=o.default(this).data(Vt),n="object"==typeof t?t:null;if((e||!/dispose|hide/.test(t))&&(e||(e=new i(this,n),o.default(this).data(Vt,e)),"string"==typeof t)){if("undefined"==typeof e[t])throw new TypeError('No method named "'+t+'"');e[t]()}}))},l(i,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Xt}},{key:"NAME",get:function(){return"popover"}},{key:"DATA_KEY",get:function(){return Vt}},{key:"Event",get:function(){return $t}},{key:"EVENT_KEY",get:function(){return".bs.popover"}},{key:"DefaultType",get:function(){return Yt}}]),i}(Wt);o.default.fn.popover=Jt._jQueryInterface,o.default.fn.popover.Constructor=Jt,o.default.fn.popover.noConflict=function(){return o.default.fn.popover=zt,Jt._jQueryInterface};var Gt="scrollspy",Zt="bs.scrollspy",te=o.default.fn[Gt],ee="active",ne="position",ie=".nav, .list-group",oe={offset:10,method:"auto",target:""},ae={offset:"number",method:"string",target:"(string|element)"},se=function(){function t(t,e){var n=this;this._element=t,this._scrollElement="BODY"===t.tagName?window:t,this._config=this._getConfig(e),this._selector=this._config.target+" .nav-link,"+this._config.target+" .list-group-item,"+this._config.target+" .dropdown-item",this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,o.default(this._scrollElement).on("scroll.bs.scrollspy",(function(t){return n._process(t)})),this.refresh(),this._process()}var e=t.prototype;return e.refresh=function(){var t=this,e=this._scrollElement===this._scrollElement.window?"offset":ne,n="auto"===this._config.method?e:this._config.method,i=n===ne?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),[].slice.call(document.querySelectorAll(this._selector)).map((function(t){var e,a=d.getSelectorFromElement(t);if(a&&(e=document.querySelector(a)),e){var s=e.getBoundingClientRect();if(s.width||s.height)return[o.default(e)[n]().top+i,a]}return null})).filter((function(t){return t})).sort((function(t,e){return t[0]-e[0]})).forEach((function(e){t._offsets.push(e[0]),t._targets.push(e[1])}))},e.dispose=function(){o.default.removeData(this._element,Zt),o.default(this._scrollElement).off(".bs.scrollspy"),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},e._getConfig=function(t){if("string"!=typeof(t=r({},oe,"object"==typeof t&&t?t:{})).target&&d.isElement(t.target)){var e=o.default(t.target).attr("id");e||(e=d.getUID(Gt),o.default(t.target).attr("id",e)),t.target="#"+e}return d.typeCheckConfig(Gt,t,ae),t},e._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},e._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},e._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},e._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;)this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||t li > .active",ge=function(){function t(t){this._element=t}var e=t.prototype;return e.show=function(){var t=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&o.default(this._element).hasClass(ue)||o.default(this._element).hasClass("disabled"))){var e,n,i=o.default(this._element).closest(".nav, .list-group")[0],a=d.getSelectorFromElement(this._element);if(i){var s="UL"===i.nodeName||"OL"===i.nodeName?he:ce;n=(n=o.default.makeArray(o.default(i).find(s)))[n.length-1]}var l=o.default.Event("hide.bs.tab",{relatedTarget:this._element}),r=o.default.Event("show.bs.tab",{relatedTarget:n});if(n&&o.default(n).trigger(l),o.default(this._element).trigger(r),!r.isDefaultPrevented()&&!l.isDefaultPrevented()){a&&(e=document.querySelector(a)),this._activate(this._element,i);var u=function(){var e=o.default.Event("hidden.bs.tab",{relatedTarget:t._element}),i=o.default.Event("shown.bs.tab",{relatedTarget:n});o.default(n).trigger(e),o.default(t._element).trigger(i)};e?this._activate(e,e.parentNode,u):u()}}},e.dispose=function(){o.default.removeData(this._element,le),this._element=null},e._activate=function(t,e,n){var i=this,a=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?o.default(e).children(ce):o.default(e).find(he))[0],s=n&&a&&o.default(a).hasClass(fe),l=function(){return i._transitionComplete(t,a,n)};if(a&&s){var r=d.getTransitionDurationFromElement(a);o.default(a).removeClass(de).one(d.TRANSITION_END,l).emulateTransitionEnd(r)}else l()},e._transitionComplete=function(t,e,n){if(e){o.default(e).removeClass(ue);var i=o.default(e.parentNode).find("> .dropdown-menu .active")[0];i&&o.default(i).removeClass(ue),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}o.default(t).addClass(ue),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),d.reflow(t),t.classList.contains(fe)&&t.classList.add(de);var a=t.parentNode;if(a&&"LI"===a.nodeName&&(a=a.parentNode),a&&o.default(a).hasClass("dropdown-menu")){var s=o.default(t).closest(".dropdown")[0];if(s){var l=[].slice.call(s.querySelectorAll(".dropdown-toggle"));o.default(l).addClass(ue)}t.setAttribute("aria-expanded",!0)}n&&n()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(le);if(i||(i=new t(this),n.data(le,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',(function(t){t.preventDefault(),ge._jQueryInterface.call(o.default(this),"show")})),o.default.fn.tab=ge._jQueryInterface,o.default.fn.tab.Constructor=ge,o.default.fn.tab.noConflict=function(){return o.default.fn.tab=re,ge._jQueryInterface};var me="bs.toast",pe=o.default.fn.toast,_e="hide",ve="show",ye="showing",be="click.dismiss.bs.toast",Ee={animation:!0,autohide:!0,delay:500},Te={animation:"boolean",autohide:"boolean",delay:"number"},we=function(){function t(t,e){this._element=t,this._config=this._getConfig(e),this._timeout=null,this._setListeners()}var e=t.prototype;return e.show=function(){var t=this,e=o.default.Event("show.bs.toast");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){this._clearTimeout(),this._config.animation&&this._element.classList.add("fade");var n=function(){t._element.classList.remove(ye),t._element.classList.add(ve),o.default(t._element).trigger("shown.bs.toast"),t._config.autohide&&(t._timeout=setTimeout((function(){t.hide()}),t._config.delay))};if(this._element.classList.remove(_e),d.reflow(this._element),this._element.classList.add(ye),this._config.animation){var i=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,n).emulateTransitionEnd(i)}else n()}},e.hide=function(){if(this._element.classList.contains(ve)){var t=o.default.Event("hide.bs.toast");o.default(this._element).trigger(t),t.isDefaultPrevented()||this._close()}},e.dispose=function(){this._clearTimeout(),this._element.classList.contains(ve)&&this._element.classList.remove(ve),o.default(this._element).off(be),o.default.removeData(this._element,me),this._element=null,this._config=null},e._getConfig=function(t){return t=r({},Ee,o.default(this._element).data(),"object"==typeof t&&t?t:{}),d.typeCheckConfig("toast",t,this.constructor.DefaultType),t},e._setListeners=function(){var t=this;o.default(this._element).on(be,'[data-dismiss="toast"]',(function(){return t.hide()}))},e._close=function(){var t=this,e=function(){t._element.classList.add(_e),o.default(t._element).trigger("hidden.bs.toast")};if(this._element.classList.remove(ve),this._config.animation){var n=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},e._clearTimeout=function(){clearTimeout(this._timeout),this._timeout=null},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(me);if(i||(i=new t(this,"object"==typeof e&&e),n.data(me,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e](this)}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"DefaultType",get:function(){return Te}},{key:"Default",get:function(){return Ee}}]),t}();o.default.fn.toast=we._jQueryInterface,o.default.fn.toast.Constructor=we,o.default.fn.toast.noConflict=function(){return o.default.fn.toast=pe,we._jQueryInterface},t.Alert=g,t.Button=E,t.Carousel=P,t.Collapse=V,t.Dropdown=lt,t.Modal=Ct,t.Popover=Jt,t.Scrollspy=se,t.Tab=ge,t.Toast=we,t.Tooltip=Wt,t.Util=d,Object.defineProperty(t,"__esModule",{value:!0})})); +//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/jquery-3.5.1.slim.min copy.js b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/jquery-3.5.1.slim.min copy.js new file mode 100644 index 0000000..36b4e1a --- /dev/null +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/jquery-3.5.1.slim.min copy.js @@ -0,0 +1,2 @@ +/*! jQuery v3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(g,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,v=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),m={},b=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},w=g.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function C(e,t,n){var r,i,o=(n=n||w).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function T(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector",E=function(e,t){return new E.fn.init(e,t)};function d(e){var t=!!e&&"length"in e&&e.length,n=T(e);return!b(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+R+")"+R+"*"),U=new RegExp(R+"|>"),V=new RegExp(W),X=new RegExp("^"+B+"$"),Q={ID:new RegExp("^#("+B+")"),CLASS:new RegExp("^\\.("+B+")"),TAG:new RegExp("^("+B+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+R+"*(even|odd|(([+-]|)(\\d*)n|)"+R+"*(?:([+-]|)"+R+"*(\\d+)|))"+R+"*\\)|)","i"),bool:new RegExp("^(?:"+I+")$","i"),needsContext:new RegExp("^"+R+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+R+"*((?:-\\d)?\\d*)"+R+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,G=/^(?:input|select|textarea|button)$/i,K=/^h\d$/i,J=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+R+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){C()},ae=xe(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{O.apply(t=P.call(d.childNodes),d.childNodes),t[d.childNodes.length].nodeType}catch(e){O={apply:t.length?function(e,t){q.apply(e,P.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,d=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==d&&9!==d&&11!==d)return n;if(!r&&(C(e),e=e||T,E)){if(11!==d&&(u=Z.exec(t)))if(i=u[1]){if(9===d){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return O.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&p.getElementsByClassName&&e.getElementsByClassName)return O.apply(n,e.getElementsByClassName(i)),n}if(p.qsa&&!k[t+" "]&&(!v||!v.test(t))&&(1!==d||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===d&&(U.test(t)||_.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&p.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=A)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+be(l[o]);c=l.join(",")}try{return O.apply(n,f.querySelectorAll(c)),n}catch(e){k(t,!0)}finally{s===A&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>x.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[A]=!0,e}function ce(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)x.attrHandle[n[r]]=t}function de(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pe(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in p=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},C=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:d;return r!=T&&9===r.nodeType&&r.documentElement&&(a=(T=r).documentElement,E=!i(T),d!=T&&(n=T.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),p.scope=ce(function(e){return a.appendChild(e).appendChild(T.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),p.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),p.getElementsByTagName=ce(function(e){return e.appendChild(T.createComment("")),!e.getElementsByTagName("*").length}),p.getElementsByClassName=J.test(T.getElementsByClassName),p.getById=ce(function(e){return a.appendChild(e).id=A,!T.getElementsByName||!T.getElementsByName(A).length}),p.getById?(x.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(x.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),x.find.TAG=p.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):p.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},x.find.CLASS=p.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(p.qsa=J.test(T.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+R+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+R+"*(?:value|"+I+")"),e.querySelectorAll("[id~="+A+"-]").length||v.push("~="),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+R+"*name"+R+"*="+R+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+A+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=T.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+R+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(p.matchesSelector=J.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){p.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",W)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=J.test(a.compareDocumentPosition),y=t||J.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!p.sortDetached&&t.compareDocumentPosition(e)===n?e==T||e.ownerDocument==d&&y(d,e)?-1:t==T||t.ownerDocument==d&&y(d,t)?1:u?H(u,e)-H(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==T?-1:t==T?1:i?-1:o?1:u?H(u,e)-H(u,t):0;if(i===o)return de(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?de(a[r],s[r]):a[r]==d?-1:s[r]==d?1:0}),T},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(C(e),p.matchesSelector&&E&&!k[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||p.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){k(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&V.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+R+")"+e+"("+R+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return b(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):"string"!=typeof n?E.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||L,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:j.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:w,!0)),k.test(r[1])&&E.isPlainObject(t))for(r in t)b(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=w.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):b(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,L=E(w);var q=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,pe=/^$|^module$|\/(?:java|ecma)script/i;le=w.createDocumentFragment().appendChild(w.createElement("div")),(ce=w.createElement("input")).setAttribute("type","radio"),ce.setAttribute("checked","checked"),ce.setAttribute("name","t"),le.appendChild(ce),m.checkClone=le.cloneNode(!0).cloneNode(!0).lastChild.checked,le.innerHTML="",m.noCloneChecked=!!le.cloneNode(!0).lastChild.defaultValue,le.innerHTML="",m.option=!!le.lastChild;var he={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ge(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&S(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var ye=/<|&#?\w+;/;function me(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),d=[],p=0,h=e.length;p\s*$/g;function Le(e,t){return S(e,"table")&&S(11!==t.nodeType?t:t.firstChild,"tr")&&E(e).children("tbody")[0]||e}function je(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n
",2===ft.childNodes.length),E.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(m.createHTMLDocument?((r=(t=w.implementation.createHTMLDocument("")).createElement("base")).href=w.location.href,t.head.appendChild(r)):t=w),o=!n&&[],(i=k.exec(e))?[t.createElement(i[1])]:(i=me([e],t,o),o&&o.length&&E(o).remove(),E.merge([],i.childNodes)));var r,i,o},E.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=E.css(e,"position"),c=E(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=E.css(e,"top"),u=E.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),b(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===E.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===E.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=E(e).offset()).top+=E.css(e,"borderTopWidth",!0),i.left+=E.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-E.css(r,"marginTop",!0),left:t.left-i.left-E.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===E.css(e,"position"))e=e.offsetParent;return e||re})}}),E.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;E.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each(["top","left"],function(e,n){E.cssHooks[n]=Fe(m.pixelPosition,function(e,t){if(t)return t=We(e,n),Ie.test(t)?E(e).position()[n]+"px":t})}),E.each({Height:"height",Width:"width"},function(a,s){E.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){E.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?E.css(e,t,i):E.style(e,t,n,i)},s,n?e:void 0,n)}})}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){E.fn[n]=function(e,t){return 0=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),ae({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=le({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f]),E=parseFloat(w['border'+f+'Width']),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},ae(n,m,$(v)),ae(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ce.FLIP:p=[n,i];break;case ce.CLOCKWISE:p=G(n);break;case ce.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u),E=!!t.flipVariationsByContent&&(w&&'start'===r&&c||w&&'end'===r&&h||!w&&'start'===r&&u||!w&&'end'===r&&g),v=y||E;(m||b||v)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),v&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=le({},e.offsets.popper,C(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport',flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=D(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.rightwindow.devicePixelRatio||!fe),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=B('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=le({},E,e.attributes),e.styles=le({},m,e.styles),e.arrowStyles=le({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return V(e.instance.popper,e.styles),j(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&V(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),V(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ge}); +//# sourceMappingURL=popper.min.js.map diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/bootstrap-4.6.1.min.js b/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/bootstrap-4.6.1.min.js new file mode 100644 index 0000000..50720ea --- /dev/null +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/bootstrap-4.6.1.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.6.1 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap={},t.jQuery,t.Popper)}(this,(function(t,e,n){"use strict";function i(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var o=i(e),a=i(n);function s(t,e){for(var n=0;n=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}};d.jQueryDetection(),o.default.fn.emulateTransitionEnd=function(t){var e=this,n=!1;return o.default(this).one(d.TRANSITION_END,(function(){n=!0})),setTimeout((function(){n||d.triggerTransitionEnd(e)}),t),this},o.default.event.special[d.TRANSITION_END]={bindType:f,delegateType:f,handle:function(t){if(o.default(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}};var c="bs.alert",h=o.default.fn.alert,g=function(){function t(t){this._element=t}var e=t.prototype;return e.close=function(t){var e=this._element;t&&(e=this._getRootElement(t)),this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.dispose=function(){o.default.removeData(this._element,c),this._element=null},e._getRootElement=function(t){var e=d.getSelectorFromElement(t),n=!1;return e&&(n=document.querySelector(e)),n||(n=o.default(t).closest(".alert")[0]),n},e._triggerCloseEvent=function(t){var e=o.default.Event("close.bs.alert");return o.default(t).trigger(e),e},e._removeElement=function(t){var e=this;if(o.default(t).removeClass("show"),o.default(t).hasClass("fade")){var n=d.getTransitionDurationFromElement(t);o.default(t).one(d.TRANSITION_END,(function(n){return e._destroyElement(t,n)})).emulateTransitionEnd(n)}else this._destroyElement(t)},e._destroyElement=function(t){o.default(t).detach().trigger("closed.bs.alert").remove()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(c);i||(i=new t(this),n.data(c,i)),"close"===e&&i[e](this)}))},t._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',g._handleDismiss(new g)),o.default.fn.alert=g._jQueryInterface,o.default.fn.alert.Constructor=g,o.default.fn.alert.noConflict=function(){return o.default.fn.alert=h,g._jQueryInterface};var m="bs.button",p=o.default.fn.button,_="active",v='[data-toggle^="button"]',y='input:not([type="hidden"])',b=".btn",E=function(){function t(t){this._element=t,this.shouldAvoidTriggerChange=!1}var e=t.prototype;return e.toggle=function(){var t=!0,e=!0,n=o.default(this._element).closest('[data-toggle="buttons"]')[0];if(n){var i=this._element.querySelector(y);if(i){if("radio"===i.type)if(i.checked&&this._element.classList.contains(_))t=!1;else{var a=n.querySelector(".active");a&&o.default(a).removeClass(_)}t&&("checkbox"!==i.type&&"radio"!==i.type||(i.checked=!this._element.classList.contains(_)),this.shouldAvoidTriggerChange||o.default(i).trigger("change")),i.focus(),e=!1}}this._element.hasAttribute("disabled")||this._element.classList.contains("disabled")||(e&&this._element.setAttribute("aria-pressed",!this._element.classList.contains(_)),t&&o.default(this._element).toggleClass(_))},e.dispose=function(){o.default.removeData(this._element,m),this._element=null},t._jQueryInterface=function(e,n){return this.each((function(){var i=o.default(this),a=i.data(m);a||(a=new t(this),i.data(m,a)),a.shouldAvoidTriggerChange=n,"toggle"===e&&a[e]()}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.button.data-api",v,(function(t){var e=t.target,n=e;if(o.default(e).hasClass("btn")||(e=o.default(e).closest(b)[0]),!e||e.hasAttribute("disabled")||e.classList.contains("disabled"))t.preventDefault();else{var i=e.querySelector(y);if(i&&(i.hasAttribute("disabled")||i.classList.contains("disabled")))return void t.preventDefault();"INPUT"!==n.tagName&&"LABEL"===e.tagName||E._jQueryInterface.call(o.default(e),"toggle","INPUT"===n.tagName)}})).on("focus.bs.button.data-api blur.bs.button.data-api",v,(function(t){var e=o.default(t.target).closest(b)[0];o.default(e).toggleClass("focus",/^focus(in)?$/.test(t.type))})),o.default(window).on("load.bs.button.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-toggle="buttons"] .btn')),e=0,n=t.length;e0,this._pointerEvent=Boolean(window.PointerEvent||window.MSPointerEvent),this._addEventListeners()}var e=t.prototype;return e.next=function(){this._isSliding||this._slide(N)},e.nextWhenVisible=function(){var t=o.default(this._element);!document.hidden&&t.is(":visible")&&"hidden"!==t.css("visibility")&&this.next()},e.prev=function(){this._isSliding||this._slide(D)},e.pause=function(t){t||(this._isPaused=!0),this._element.querySelector(".carousel-item-next, .carousel-item-prev")&&(d.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},e.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},e.to=function(t){var e=this;this._activeElement=this._element.querySelector(I);var n=this._getItemIndex(this._activeElement);if(!(t>this._items.length-1||t<0))if(this._isSliding)o.default(this._element).one(A,(function(){return e.to(t)}));else{if(n===t)return this.pause(),void this.cycle();var i=t>n?N:D;this._slide(i,this._items[t])}},e.dispose=function(){o.default(this._element).off(".bs.carousel"),o.default.removeData(this._element,w),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},e._getConfig=function(t){return t=r({},k,t),d.typeCheckConfig(T,t,O),t},e._handleSwipe=function(){var t=Math.abs(this.touchDeltaX);if(!(t<=40)){var e=t/this.touchDeltaX;this.touchDeltaX=0,e>0&&this.prev(),e<0&&this.next()}},e._addEventListeners=function(){var t=this;this._config.keyboard&&o.default(this._element).on("keydown.bs.carousel",(function(e){return t._keydown(e)})),"hover"===this._config.pause&&o.default(this._element).on("mouseenter.bs.carousel",(function(e){return t.pause(e)})).on("mouseleave.bs.carousel",(function(e){return t.cycle(e)})),this._config.touch&&this._addTouchEventListeners()},e._addTouchEventListeners=function(){var t=this;if(this._touchSupported){var e=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]?t.touchStartX=e.originalEvent.clientX:t._pointerEvent||(t.touchStartX=e.originalEvent.touches[0].clientX)},n=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]&&(t.touchDeltaX=e.originalEvent.clientX-t.touchStartX),t._handleSwipe(),"hover"===t._config.pause&&(t.pause(),t.touchTimeout&&clearTimeout(t.touchTimeout),t.touchTimeout=setTimeout((function(e){return t.cycle(e)}),500+t._config.interval))};o.default(this._element.querySelectorAll(".carousel-item img")).on("dragstart.bs.carousel",(function(t){return t.preventDefault()})),this._pointerEvent?(o.default(this._element).on("pointerdown.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("pointerup.bs.carousel",(function(t){return n(t)})),this._element.classList.add("pointer-event")):(o.default(this._element).on("touchstart.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("touchmove.bs.carousel",(function(e){return function(e){t.touchDeltaX=e.originalEvent.touches&&e.originalEvent.touches.length>1?0:e.originalEvent.touches[0].clientX-t.touchStartX}(e)})),o.default(this._element).on("touchend.bs.carousel",(function(t){return n(t)})))}},e._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next()}},e._getItemIndex=function(t){return this._items=t&&t.parentNode?[].slice.call(t.parentNode.querySelectorAll(".carousel-item")):[],this._items.indexOf(t)},e._getItemByDirection=function(t,e){var n=t===N,i=t===D,o=this._getItemIndex(e),a=this._items.length-1;if((i&&0===o||n&&o===a)&&!this._config.wrap)return e;var s=(o+(t===D?-1:1))%this._items.length;return-1===s?this._items[this._items.length-1]:this._items[s]},e._triggerSlideEvent=function(t,e){var n=this._getItemIndex(t),i=this._getItemIndex(this._element.querySelector(I)),a=o.default.Event("slide.bs.carousel",{relatedTarget:t,direction:e,from:i,to:n});return o.default(this._element).trigger(a),a},e._setActiveIndicatorElement=function(t){if(this._indicatorsElement){var e=[].slice.call(this._indicatorsElement.querySelectorAll(".active"));o.default(e).removeClass(S);var n=this._indicatorsElement.children[this._getItemIndex(t)];n&&o.default(n).addClass(S)}},e._updateInterval=function(){var t=this._activeElement||this._element.querySelector(I);if(t){var e=parseInt(t.getAttribute("data-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}},e._slide=function(t,e){var n,i,a,s=this,l=this._element.querySelector(I),r=this._getItemIndex(l),u=e||l&&this._getItemByDirection(t,l),f=this._getItemIndex(u),c=Boolean(this._interval);if(t===N?(n="carousel-item-left",i="carousel-item-next",a="left"):(n="carousel-item-right",i="carousel-item-prev",a="right"),u&&o.default(u).hasClass(S))this._isSliding=!1;else if(!this._triggerSlideEvent(u,a).isDefaultPrevented()&&l&&u){this._isSliding=!0,c&&this.pause(),this._setActiveIndicatorElement(u),this._activeElement=u;var h=o.default.Event(A,{relatedTarget:u,direction:a,from:r,to:f});if(o.default(this._element).hasClass("slide")){o.default(u).addClass(i),d.reflow(u),o.default(l).addClass(n),o.default(u).addClass(n);var g=d.getTransitionDurationFromElement(l);o.default(l).one(d.TRANSITION_END,(function(){o.default(u).removeClass(n+" "+i).addClass(S),o.default(l).removeClass("active "+i+" "+n),s._isSliding=!1,setTimeout((function(){return o.default(s._element).trigger(h)}),0)})).emulateTransitionEnd(g)}else o.default(l).removeClass(S),o.default(u).addClass(S),this._isSliding=!1,o.default(this._element).trigger(h);c&&this.cycle()}},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(w),i=r({},k,o.default(this).data());"object"==typeof e&&(i=r({},i,e));var a="string"==typeof e?e:i.slide;if(n||(n=new t(this,i),o.default(this).data(w,n)),"number"==typeof e)n.to(e);else if("string"==typeof a){if("undefined"==typeof n[a])throw new TypeError('No method named "'+a+'"');n[a]()}else i.interval&&i.ride&&(n.pause(),n.cycle())}))},t._dataApiClickHandler=function(e){var n=d.getSelectorFromElement(this);if(n){var i=o.default(n)[0];if(i&&o.default(i).hasClass("carousel")){var a=r({},o.default(i).data(),o.default(this).data()),s=this.getAttribute("data-slide-to");s&&(a.interval=!1),t._jQueryInterface.call(o.default(i),a),s&&o.default(i).data(w).to(s),e.preventDefault()}}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return k}}]),t}();o.default(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",P._dataApiClickHandler),o.default(window).on("load.bs.carousel.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-ride="carousel"]')),e=0,n=t.length;e0&&(this._selector=s,this._triggerArray.push(a))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}var e=t.prototype;return e.toggle=function(){o.default(this._element).hasClass(q)?this.hide():this.show()},e.show=function(){var e,n,i=this;if(!(this._isTransitioning||o.default(this._element).hasClass(q)||(this._parent&&0===(e=[].slice.call(this._parent.querySelectorAll(".show, .collapsing")).filter((function(t){return"string"==typeof i._config.parent?t.getAttribute("data-parent")===i._config.parent:t.classList.contains(F)}))).length&&(e=null),e&&(n=o.default(e).not(this._selector).data(R))&&n._isTransitioning))){var a=o.default.Event("show.bs.collapse");if(o.default(this._element).trigger(a),!a.isDefaultPrevented()){e&&(t._jQueryInterface.call(o.default(e).not(this._selector),"hide"),n||o.default(e).data(R,null));var s=this._getDimension();o.default(this._element).removeClass(F).addClass(Q),this._element.style[s]=0,this._triggerArray.length&&o.default(this._triggerArray).removeClass(B).attr("aria-expanded",!0),this.setTransitioning(!0);var l="scroll"+(s[0].toUpperCase()+s.slice(1)),r=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,(function(){o.default(i._element).removeClass(Q).addClass("collapse show"),i._element.style[s]="",i.setTransitioning(!1),o.default(i._element).trigger("shown.bs.collapse")})).emulateTransitionEnd(r),this._element.style[s]=this._element[l]+"px"}}},e.hide=function(){var t=this;if(!this._isTransitioning&&o.default(this._element).hasClass(q)){var e=o.default.Event("hide.bs.collapse");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){var n=this._getDimension();this._element.style[n]=this._element.getBoundingClientRect()[n]+"px",d.reflow(this._element),o.default(this._element).addClass(Q).removeClass("collapse show");var i=this._triggerArray.length;if(i>0)for(var a=0;a0},e._getOffset=function(){var t=this,e={};return"function"==typeof this._config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t._config.offset(e.offsets,t._element)),e}:e.offset=this._config.offset,e},e._getPopperConfig=function(){var t={placement:this._getPlacement(),modifiers:{offset:this._getOffset(),flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}};return"static"===this._config.display&&(t.modifiers.applyStyle={enabled:!1}),r({},t,this._config.popperConfig)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(K);if(n||(n=new t(this,"object"==typeof e?e:null),o.default(this).data(K,n)),"string"==typeof e){if("undefined"==typeof n[e])throw new TypeError('No method named "'+e+'"');n[e]()}}))},t._clearMenus=function(e){if(!e||3!==e.which&&("keyup"!==e.type||9===e.which))for(var n=[].slice.call(document.querySelectorAll(it)),i=0,a=n.length;i0&&s--,40===e.which&&sdocument.documentElement.clientHeight;n||(this._element.style.overflowY="hidden"),this._element.classList.add(ht);var i=d.getTransitionDurationFromElement(this._dialog);o.default(this._element).off(d.TRANSITION_END),o.default(this._element).one(d.TRANSITION_END,(function(){t._element.classList.remove(ht),n||o.default(t._element).one(d.TRANSITION_END,(function(){t._element.style.overflowY=""})).emulateTransitionEnd(t._element,i)})).emulateTransitionEnd(i),this._element.focus()}},e._showElement=function(t){var e=this,n=o.default(this._element).hasClass(dt),i=this._dialog?this._dialog.querySelector(".modal-body"):null;this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),o.default(this._dialog).hasClass("modal-dialog-scrollable")&&i?i.scrollTop=0:this._element.scrollTop=0,n&&d.reflow(this._element),o.default(this._element).addClass(ct),this._config.focus&&this._enforceFocus();var a=o.default.Event("shown.bs.modal",{relatedTarget:t}),s=function(){e._config.focus&&e._element.focus(),e._isTransitioning=!1,o.default(e._element).trigger(a)};if(n){var l=d.getTransitionDurationFromElement(this._dialog);o.default(this._dialog).one(d.TRANSITION_END,s).emulateTransitionEnd(l)}else s()},e._enforceFocus=function(){var t=this;o.default(document).off(pt).on(pt,(function(e){document!==e.target&&t._element!==e.target&&0===o.default(t._element).has(e.target).length&&t._element.focus()}))},e._setEscapeEvent=function(){var t=this;this._isShown?o.default(this._element).on(yt,(function(e){t._config.keyboard&&27===e.which?(e.preventDefault(),t.hide()):t._config.keyboard||27!==e.which||t._triggerBackdropTransition()})):this._isShown||o.default(this._element).off(yt)},e._setResizeEvent=function(){var t=this;this._isShown?o.default(window).on(_t,(function(e){return t.handleUpdate(e)})):o.default(window).off(_t)},e._hideModal=function(){var t=this;this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._showBackdrop((function(){o.default(document.body).removeClass(ft),t._resetAdjustments(),t._resetScrollbar(),o.default(t._element).trigger(gt)}))},e._removeBackdrop=function(){this._backdrop&&(o.default(this._backdrop).remove(),this._backdrop=null)},e._showBackdrop=function(t){var e=this,n=o.default(this._element).hasClass(dt)?dt:"";if(this._isShown&&this._config.backdrop){if(this._backdrop=document.createElement("div"),this._backdrop.className="modal-backdrop",n&&this._backdrop.classList.add(n),o.default(this._backdrop).appendTo(document.body),o.default(this._element).on(vt,(function(t){e._ignoreBackdropClick?e._ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"===e._config.backdrop?e._triggerBackdropTransition():e.hide())})),n&&d.reflow(this._backdrop),o.default(this._backdrop).addClass(ct),!t)return;if(!n)return void t();var i=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,t).emulateTransitionEnd(i)}else if(!this._isShown&&this._backdrop){o.default(this._backdrop).removeClass(ct);var a=function(){e._removeBackdrop(),t&&t()};if(o.default(this._element).hasClass(dt)){var s=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a()}else t&&t()},e._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},e._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},e._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=Math.round(t.left+t.right)
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",customClass:"",sanitize:!0,sanitizeFn:null,whiteList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},Ut={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string|function)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",whiteList:"object",popperConfig:"(null|object)"},Mt={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},Wt=function(){function t(t,e){if("undefined"==typeof a.default)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var e=t.prototype;return e.enable=function(){this._isEnabled=!0},e.disable=function(){this._isEnabled=!1},e.toggleEnabled=function(){this._isEnabled=!this._isEnabled},e.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=o.default(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(o.default(this.getTipElement()).hasClass(Rt))return void this._leave(null,this);this._enter(null,this)}},e.dispose=function(){clearTimeout(this._timeout),o.default.removeData(this.element,this.constructor.DATA_KEY),o.default(this.element).off(this.constructor.EVENT_KEY),o.default(this.element).closest(".modal").off("hide.bs.modal",this._hideModalHandler),this.tip&&o.default(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},e.show=function(){var t=this;if("none"===o.default(this.element).css("display"))throw new Error("Please use show on visible elements");var e=o.default.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){o.default(this.element).trigger(e);var n=d.findShadowRoot(this.element),i=o.default.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(e.isDefaultPrevented()||!i)return;var s=this.getTipElement(),l=d.getUID(this.constructor.NAME);s.setAttribute("id",l),this.element.setAttribute("aria-describedby",l),this.setContent(),this.config.animation&&o.default(s).addClass(Lt);var r="function"==typeof this.config.placement?this.config.placement.call(this,s,this.element):this.config.placement,u=this._getAttachment(r);this.addAttachmentClass(u);var f=this._getContainer();o.default(s).data(this.constructor.DATA_KEY,this),o.default.contains(this.element.ownerDocument.documentElement,this.tip)||o.default(s).appendTo(f),o.default(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new a.default(this.element,s,this._getPopperConfig(u)),o.default(s).addClass(Rt),o.default(s).addClass(this.config.customClass),"ontouchstart"in document.documentElement&&o.default(document.body).children().on("mouseover",null,o.default.noop);var c=function(){t.config.animation&&t._fixTransition();var e=t._hoverState;t._hoverState=null,o.default(t.element).trigger(t.constructor.Event.SHOWN),e===qt&&t._leave(null,t)};if(o.default(this.tip).hasClass(Lt)){var h=d.getTransitionDurationFromElement(this.tip);o.default(this.tip).one(d.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},e.hide=function(t){var e=this,n=this.getTipElement(),i=o.default.Event(this.constructor.Event.HIDE),a=function(){e._hoverState!==xt&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),o.default(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(o.default(this.element).trigger(i),!i.isDefaultPrevented()){if(o.default(n).removeClass(Rt),"ontouchstart"in document.documentElement&&o.default(document.body).children().off("mouseover",null,o.default.noop),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,o.default(this.tip).hasClass(Lt)){var s=d.getTransitionDurationFromElement(n);o.default(n).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a();this._hoverState=""}},e.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},e.isWithContent=function(){return Boolean(this.getTitle())},e.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-tooltip-"+t)},e.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},e.setContent=function(){var t=this.getTipElement();this.setElementContent(o.default(t.querySelectorAll(".tooltip-inner")),this.getTitle()),o.default(t).removeClass("fade show")},e.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=At(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?o.default(e).parent().is(t)||t.empty().append(e):t.text(o.default(e).text())},e.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},e._getPopperConfig=function(t){var e=this;return r({},{placement:t,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:".arrow"},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}},this.config.popperConfig)},e._getOffset=function(){var t=this,e={};return"function"==typeof this.config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t.config.offset(e.offsets,t.element)),e}:e.offset=this.config.offset,e},e._getContainer=function(){return!1===this.config.container?document.body:d.isElement(this.config.container)?o.default(this.config.container):o.default(document).find(this.config.container)},e._getAttachment=function(t){return Bt[t.toUpperCase()]},e._setListeners=function(){var t=this;this.config.trigger.split(" ").forEach((function(e){if("click"===e)o.default(t.element).on(t.constructor.Event.CLICK,t.config.selector,(function(e){return t.toggle(e)}));else if("manual"!==e){var n=e===Ft?t.constructor.Event.MOUSEENTER:t.constructor.Event.FOCUSIN,i=e===Ft?t.constructor.Event.MOUSELEAVE:t.constructor.Event.FOCUSOUT;o.default(t.element).on(n,t.config.selector,(function(e){return t._enter(e)})).on(i,t.config.selector,(function(e){return t._leave(e)}))}})),this._hideModalHandler=function(){t.element&&t.hide()},o.default(this.element).closest(".modal").on("hide.bs.modal",this._hideModalHandler),this.config.selector?this.config=r({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},e._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},e._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Qt:Ft]=!0),o.default(e.getTipElement()).hasClass(Rt)||e._hoverState===xt?e._hoverState=xt:(clearTimeout(e._timeout),e._hoverState=xt,e.config.delay&&e.config.delay.show?e._timeout=setTimeout((function(){e._hoverState===xt&&e.show()}),e.config.delay.show):e.show())},e._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Qt:Ft]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=qt,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout((function(){e._hoverState===qt&&e.hide()}),e.config.delay.hide):e.hide())},e._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},e._getConfig=function(t){var e=o.default(this.element).data();return Object.keys(e).forEach((function(t){-1!==Pt.indexOf(t)&&delete e[t]})),"number"==typeof(t=r({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),d.typeCheckConfig(It,t,this.constructor.DefaultType),t.sanitize&&(t.template=At(t.template,t.whiteList,t.sanitizeFn)),t},e._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},e._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(jt);null!==e&&e.length&&t.removeClass(e.join(""))},e._handlePopperPlacementChange=function(t){this.tip=t.instance.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},e._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(o.default(t).removeClass(Lt),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(kt),a="object"==typeof e&&e;if((i||!/dispose|hide/.test(e))&&(i||(i=new t(this,a),n.data(kt,i)),"string"==typeof e)){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Ht}},{key:"NAME",get:function(){return It}},{key:"DATA_KEY",get:function(){return kt}},{key:"Event",get:function(){return Mt}},{key:"EVENT_KEY",get:function(){return".bs.tooltip"}},{key:"DefaultType",get:function(){return Ut}}]),t}();o.default.fn.tooltip=Wt._jQueryInterface,o.default.fn.tooltip.Constructor=Wt,o.default.fn.tooltip.noConflict=function(){return o.default.fn.tooltip=Ot,Wt._jQueryInterface};var Vt="bs.popover",zt=o.default.fn.popover,Kt=new RegExp("(^|\\s)bs-popover\\S+","g"),Xt=r({},Wt.Default,{placement:"right",trigger:"click",content:"",template:''}),Yt=r({},Wt.DefaultType,{content:"(string|element|function)"}),$t={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"},Jt=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),e.prototype.constructor=e,u(e,n);var a=i.prototype;return a.isWithContent=function(){return this.getTitle()||this._getContent()},a.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-popover-"+t)},a.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},a.setContent=function(){var t=o.default(this.getTipElement());this.setElementContent(t.find(".popover-header"),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(".popover-body"),e),t.removeClass("fade show")},a._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},a._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(Kt);null!==e&&e.length>0&&t.removeClass(e.join(""))},i._jQueryInterface=function(t){return this.each((function(){var e=o.default(this).data(Vt),n="object"==typeof t?t:null;if((e||!/dispose|hide/.test(t))&&(e||(e=new i(this,n),o.default(this).data(Vt,e)),"string"==typeof t)){if("undefined"==typeof e[t])throw new TypeError('No method named "'+t+'"');e[t]()}}))},l(i,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Xt}},{key:"NAME",get:function(){return"popover"}},{key:"DATA_KEY",get:function(){return Vt}},{key:"Event",get:function(){return $t}},{key:"EVENT_KEY",get:function(){return".bs.popover"}},{key:"DefaultType",get:function(){return Yt}}]),i}(Wt);o.default.fn.popover=Jt._jQueryInterface,o.default.fn.popover.Constructor=Jt,o.default.fn.popover.noConflict=function(){return o.default.fn.popover=zt,Jt._jQueryInterface};var Gt="scrollspy",Zt="bs.scrollspy",te=o.default.fn[Gt],ee="active",ne="position",ie=".nav, .list-group",oe={offset:10,method:"auto",target:""},ae={offset:"number",method:"string",target:"(string|element)"},se=function(){function t(t,e){var n=this;this._element=t,this._scrollElement="BODY"===t.tagName?window:t,this._config=this._getConfig(e),this._selector=this._config.target+" .nav-link,"+this._config.target+" .list-group-item,"+this._config.target+" .dropdown-item",this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,o.default(this._scrollElement).on("scroll.bs.scrollspy",(function(t){return n._process(t)})),this.refresh(),this._process()}var e=t.prototype;return e.refresh=function(){var t=this,e=this._scrollElement===this._scrollElement.window?"offset":ne,n="auto"===this._config.method?e:this._config.method,i=n===ne?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),[].slice.call(document.querySelectorAll(this._selector)).map((function(t){var e,a=d.getSelectorFromElement(t);if(a&&(e=document.querySelector(a)),e){var s=e.getBoundingClientRect();if(s.width||s.height)return[o.default(e)[n]().top+i,a]}return null})).filter((function(t){return t})).sort((function(t,e){return t[0]-e[0]})).forEach((function(e){t._offsets.push(e[0]),t._targets.push(e[1])}))},e.dispose=function(){o.default.removeData(this._element,Zt),o.default(this._scrollElement).off(".bs.scrollspy"),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},e._getConfig=function(t){if("string"!=typeof(t=r({},oe,"object"==typeof t&&t?t:{})).target&&d.isElement(t.target)){var e=o.default(t.target).attr("id");e||(e=d.getUID(Gt),o.default(t.target).attr("id",e)),t.target="#"+e}return d.typeCheckConfig(Gt,t,ae),t},e._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},e._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},e._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},e._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;)this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||t li > .active",ge=function(){function t(t){this._element=t}var e=t.prototype;return e.show=function(){var t=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&o.default(this._element).hasClass(ue)||o.default(this._element).hasClass("disabled"))){var e,n,i=o.default(this._element).closest(".nav, .list-group")[0],a=d.getSelectorFromElement(this._element);if(i){var s="UL"===i.nodeName||"OL"===i.nodeName?he:ce;n=(n=o.default.makeArray(o.default(i).find(s)))[n.length-1]}var l=o.default.Event("hide.bs.tab",{relatedTarget:this._element}),r=o.default.Event("show.bs.tab",{relatedTarget:n});if(n&&o.default(n).trigger(l),o.default(this._element).trigger(r),!r.isDefaultPrevented()&&!l.isDefaultPrevented()){a&&(e=document.querySelector(a)),this._activate(this._element,i);var u=function(){var e=o.default.Event("hidden.bs.tab",{relatedTarget:t._element}),i=o.default.Event("shown.bs.tab",{relatedTarget:n});o.default(n).trigger(e),o.default(t._element).trigger(i)};e?this._activate(e,e.parentNode,u):u()}}},e.dispose=function(){o.default.removeData(this._element,le),this._element=null},e._activate=function(t,e,n){var i=this,a=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?o.default(e).children(ce):o.default(e).find(he))[0],s=n&&a&&o.default(a).hasClass(fe),l=function(){return i._transitionComplete(t,a,n)};if(a&&s){var r=d.getTransitionDurationFromElement(a);o.default(a).removeClass(de).one(d.TRANSITION_END,l).emulateTransitionEnd(r)}else l()},e._transitionComplete=function(t,e,n){if(e){o.default(e).removeClass(ue);var i=o.default(e.parentNode).find("> .dropdown-menu .active")[0];i&&o.default(i).removeClass(ue),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}o.default(t).addClass(ue),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),d.reflow(t),t.classList.contains(fe)&&t.classList.add(de);var a=t.parentNode;if(a&&"LI"===a.nodeName&&(a=a.parentNode),a&&o.default(a).hasClass("dropdown-menu")){var s=o.default(t).closest(".dropdown")[0];if(s){var l=[].slice.call(s.querySelectorAll(".dropdown-toggle"));o.default(l).addClass(ue)}t.setAttribute("aria-expanded",!0)}n&&n()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(le);if(i||(i=new t(this),n.data(le,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',(function(t){t.preventDefault(),ge._jQueryInterface.call(o.default(this),"show")})),o.default.fn.tab=ge._jQueryInterface,o.default.fn.tab.Constructor=ge,o.default.fn.tab.noConflict=function(){return o.default.fn.tab=re,ge._jQueryInterface};var me="bs.toast",pe=o.default.fn.toast,_e="hide",ve="show",ye="showing",be="click.dismiss.bs.toast",Ee={animation:!0,autohide:!0,delay:500},Te={animation:"boolean",autohide:"boolean",delay:"number"},we=function(){function t(t,e){this._element=t,this._config=this._getConfig(e),this._timeout=null,this._setListeners()}var e=t.prototype;return e.show=function(){var t=this,e=o.default.Event("show.bs.toast");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){this._clearTimeout(),this._config.animation&&this._element.classList.add("fade");var n=function(){t._element.classList.remove(ye),t._element.classList.add(ve),o.default(t._element).trigger("shown.bs.toast"),t._config.autohide&&(t._timeout=setTimeout((function(){t.hide()}),t._config.delay))};if(this._element.classList.remove(_e),d.reflow(this._element),this._element.classList.add(ye),this._config.animation){var i=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,n).emulateTransitionEnd(i)}else n()}},e.hide=function(){if(this._element.classList.contains(ve)){var t=o.default.Event("hide.bs.toast");o.default(this._element).trigger(t),t.isDefaultPrevented()||this._close()}},e.dispose=function(){this._clearTimeout(),this._element.classList.contains(ve)&&this._element.classList.remove(ve),o.default(this._element).off(be),o.default.removeData(this._element,me),this._element=null,this._config=null},e._getConfig=function(t){return t=r({},Ee,o.default(this._element).data(),"object"==typeof t&&t?t:{}),d.typeCheckConfig("toast",t,this.constructor.DefaultType),t},e._setListeners=function(){var t=this;o.default(this._element).on(be,'[data-dismiss="toast"]',(function(){return t.hide()}))},e._close=function(){var t=this,e=function(){t._element.classList.add(_e),o.default(t._element).trigger("hidden.bs.toast")};if(this._element.classList.remove(ve),this._config.animation){var n=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},e._clearTimeout=function(){clearTimeout(this._timeout),this._timeout=null},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(me);if(i||(i=new t(this,"object"==typeof e&&e),n.data(me,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e](this)}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"DefaultType",get:function(){return Te}},{key:"Default",get:function(){return Ee}}]),t}();o.default.fn.toast=we._jQueryInterface,o.default.fn.toast.Constructor=we,o.default.fn.toast.noConflict=function(){return o.default.fn.toast=pe,we._jQueryInterface},t.Alert=g,t.Button=E,t.Carousel=P,t.Collapse=V,t.Dropdown=lt,t.Modal=Ct,t.Popover=Jt,t.Scrollspy=se,t.Tab=ge,t.Toast=we,t.Tooltip=Wt,t.Util=d,Object.defineProperty(t,"__esModule",{value:!0})})); +//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/jquery-3.5.1.slim.min.js b/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/jquery-3.5.1.slim.min.js new file mode 100644 index 0000000..36b4e1a --- /dev/null +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/jquery-3.5.1.slim.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(g,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,v=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),m={},b=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},w=g.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function C(e,t,n){var r,i,o=(n=n||w).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function T(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector",E=function(e,t){return new E.fn.init(e,t)};function d(e){var t=!!e&&"length"in e&&e.length,n=T(e);return!b(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+R+")"+R+"*"),U=new RegExp(R+"|>"),V=new RegExp(W),X=new RegExp("^"+B+"$"),Q={ID:new RegExp("^#("+B+")"),CLASS:new RegExp("^\\.("+B+")"),TAG:new RegExp("^("+B+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+R+"*(even|odd|(([+-]|)(\\d*)n|)"+R+"*(?:([+-]|)"+R+"*(\\d+)|))"+R+"*\\)|)","i"),bool:new RegExp("^(?:"+I+")$","i"),needsContext:new RegExp("^"+R+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+R+"*((?:-\\d)?\\d*)"+R+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,G=/^(?:input|select|textarea|button)$/i,K=/^h\d$/i,J=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+R+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){C()},ae=xe(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{O.apply(t=P.call(d.childNodes),d.childNodes),t[d.childNodes.length].nodeType}catch(e){O={apply:t.length?function(e,t){q.apply(e,P.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,d=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==d&&9!==d&&11!==d)return n;if(!r&&(C(e),e=e||T,E)){if(11!==d&&(u=Z.exec(t)))if(i=u[1]){if(9===d){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return O.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&p.getElementsByClassName&&e.getElementsByClassName)return O.apply(n,e.getElementsByClassName(i)),n}if(p.qsa&&!k[t+" "]&&(!v||!v.test(t))&&(1!==d||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===d&&(U.test(t)||_.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&p.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=A)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+be(l[o]);c=l.join(",")}try{return O.apply(n,f.querySelectorAll(c)),n}catch(e){k(t,!0)}finally{s===A&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>x.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[A]=!0,e}function ce(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)x.attrHandle[n[r]]=t}function de(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pe(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in p=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},C=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:d;return r!=T&&9===r.nodeType&&r.documentElement&&(a=(T=r).documentElement,E=!i(T),d!=T&&(n=T.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),p.scope=ce(function(e){return a.appendChild(e).appendChild(T.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),p.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),p.getElementsByTagName=ce(function(e){return e.appendChild(T.createComment("")),!e.getElementsByTagName("*").length}),p.getElementsByClassName=J.test(T.getElementsByClassName),p.getById=ce(function(e){return a.appendChild(e).id=A,!T.getElementsByName||!T.getElementsByName(A).length}),p.getById?(x.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(x.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),x.find.TAG=p.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):p.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},x.find.CLASS=p.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(p.qsa=J.test(T.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+R+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+R+"*(?:value|"+I+")"),e.querySelectorAll("[id~="+A+"-]").length||v.push("~="),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+R+"*name"+R+"*="+R+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+A+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=T.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+R+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(p.matchesSelector=J.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){p.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",W)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=J.test(a.compareDocumentPosition),y=t||J.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!p.sortDetached&&t.compareDocumentPosition(e)===n?e==T||e.ownerDocument==d&&y(d,e)?-1:t==T||t.ownerDocument==d&&y(d,t)?1:u?H(u,e)-H(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==T?-1:t==T?1:i?-1:o?1:u?H(u,e)-H(u,t):0;if(i===o)return de(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?de(a[r],s[r]):a[r]==d?-1:s[r]==d?1:0}),T},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(C(e),p.matchesSelector&&E&&!k[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||p.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){k(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&V.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+R+")"+e+"("+R+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return b(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):"string"!=typeof n?E.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||L,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:j.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:w,!0)),k.test(r[1])&&E.isPlainObject(t))for(r in t)b(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=w.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):b(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,L=E(w);var q=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,pe=/^$|^module$|\/(?:java|ecma)script/i;le=w.createDocumentFragment().appendChild(w.createElement("div")),(ce=w.createElement("input")).setAttribute("type","radio"),ce.setAttribute("checked","checked"),ce.setAttribute("name","t"),le.appendChild(ce),m.checkClone=le.cloneNode(!0).cloneNode(!0).lastChild.checked,le.innerHTML="",m.noCloneChecked=!!le.cloneNode(!0).lastChild.defaultValue,le.innerHTML="",m.option=!!le.lastChild;var he={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ge(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&S(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var ye=/<|&#?\w+;/;function me(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),d=[],p=0,h=e.length;p\s*$/g;function Le(e,t){return S(e,"table")&&S(11!==t.nodeType?t:t.firstChild,"tr")&&E(e).children("tbody")[0]||e}function je(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n
",2===ft.childNodes.length),E.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(m.createHTMLDocument?((r=(t=w.implementation.createHTMLDocument("")).createElement("base")).href=w.location.href,t.head.appendChild(r)):t=w),o=!n&&[],(i=k.exec(e))?[t.createElement(i[1])]:(i=me([e],t,o),o&&o.length&&E(o).remove(),E.merge([],i.childNodes)));var r,i,o},E.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=E.css(e,"position"),c=E(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=E.css(e,"top"),u=E.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),b(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===E.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===E.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=E(e).offset()).top+=E.css(e,"borderTopWidth",!0),i.left+=E.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-E.css(r,"marginTop",!0),left:t.left-i.left-E.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===E.css(e,"position"))e=e.offsetParent;return e||re})}}),E.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;E.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each(["top","left"],function(e,n){E.cssHooks[n]=Fe(m.pixelPosition,function(e,t){if(t)return t=We(e,n),Ie.test(t)?E(e).position()[n]+"px":t})}),E.each({Height:"height",Width:"width"},function(a,s){E.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){E.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?E.css(e,t,i):E.style(e,t,n,i)},s,n?e:void 0,n)}})}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){E.fn[n]=function(e,t){return 0=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),ae({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=le({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f]),E=parseFloat(w['border'+f+'Width']),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},ae(n,m,$(v)),ae(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ce.FLIP:p=[n,i];break;case ce.CLOCKWISE:p=G(n);break;case ce.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u),E=!!t.flipVariationsByContent&&(w&&'start'===r&&c||w&&'end'===r&&h||!w&&'start'===r&&u||!w&&'end'===r&&g),v=y||E;(m||b||v)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),v&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=le({},e.offsets.popper,C(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport',flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=D(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.rightwindow.devicePixelRatio||!fe),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=B('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=le({},E,e.attributes),e.styles=le({},m,e.styles),e.arrowStyles=le({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return V(e.instance.popper,e.styles),j(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&V(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),V(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ge}); +//# sourceMappingURL=popper.min.js.map diff --git a/code/starter_video_collector/static/js/bootstrap-4.6.1.min.js b/code/starter_video_collector/static/js/bootstrap-4.6.1.min.js new file mode 100644 index 0000000..50720ea --- /dev/null +++ b/code/starter_video_collector/static/js/bootstrap-4.6.1.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.6.1 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap={},t.jQuery,t.Popper)}(this,(function(t,e,n){"use strict";function i(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var o=i(e),a=i(n);function s(t,e){for(var n=0;n=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}};d.jQueryDetection(),o.default.fn.emulateTransitionEnd=function(t){var e=this,n=!1;return o.default(this).one(d.TRANSITION_END,(function(){n=!0})),setTimeout((function(){n||d.triggerTransitionEnd(e)}),t),this},o.default.event.special[d.TRANSITION_END]={bindType:f,delegateType:f,handle:function(t){if(o.default(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}};var c="bs.alert",h=o.default.fn.alert,g=function(){function t(t){this._element=t}var e=t.prototype;return e.close=function(t){var e=this._element;t&&(e=this._getRootElement(t)),this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.dispose=function(){o.default.removeData(this._element,c),this._element=null},e._getRootElement=function(t){var e=d.getSelectorFromElement(t),n=!1;return e&&(n=document.querySelector(e)),n||(n=o.default(t).closest(".alert")[0]),n},e._triggerCloseEvent=function(t){var e=o.default.Event("close.bs.alert");return o.default(t).trigger(e),e},e._removeElement=function(t){var e=this;if(o.default(t).removeClass("show"),o.default(t).hasClass("fade")){var n=d.getTransitionDurationFromElement(t);o.default(t).one(d.TRANSITION_END,(function(n){return e._destroyElement(t,n)})).emulateTransitionEnd(n)}else this._destroyElement(t)},e._destroyElement=function(t){o.default(t).detach().trigger("closed.bs.alert").remove()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(c);i||(i=new t(this),n.data(c,i)),"close"===e&&i[e](this)}))},t._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',g._handleDismiss(new g)),o.default.fn.alert=g._jQueryInterface,o.default.fn.alert.Constructor=g,o.default.fn.alert.noConflict=function(){return o.default.fn.alert=h,g._jQueryInterface};var m="bs.button",p=o.default.fn.button,_="active",v='[data-toggle^="button"]',y='input:not([type="hidden"])',b=".btn",E=function(){function t(t){this._element=t,this.shouldAvoidTriggerChange=!1}var e=t.prototype;return e.toggle=function(){var t=!0,e=!0,n=o.default(this._element).closest('[data-toggle="buttons"]')[0];if(n){var i=this._element.querySelector(y);if(i){if("radio"===i.type)if(i.checked&&this._element.classList.contains(_))t=!1;else{var a=n.querySelector(".active");a&&o.default(a).removeClass(_)}t&&("checkbox"!==i.type&&"radio"!==i.type||(i.checked=!this._element.classList.contains(_)),this.shouldAvoidTriggerChange||o.default(i).trigger("change")),i.focus(),e=!1}}this._element.hasAttribute("disabled")||this._element.classList.contains("disabled")||(e&&this._element.setAttribute("aria-pressed",!this._element.classList.contains(_)),t&&o.default(this._element).toggleClass(_))},e.dispose=function(){o.default.removeData(this._element,m),this._element=null},t._jQueryInterface=function(e,n){return this.each((function(){var i=o.default(this),a=i.data(m);a||(a=new t(this),i.data(m,a)),a.shouldAvoidTriggerChange=n,"toggle"===e&&a[e]()}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.button.data-api",v,(function(t){var e=t.target,n=e;if(o.default(e).hasClass("btn")||(e=o.default(e).closest(b)[0]),!e||e.hasAttribute("disabled")||e.classList.contains("disabled"))t.preventDefault();else{var i=e.querySelector(y);if(i&&(i.hasAttribute("disabled")||i.classList.contains("disabled")))return void t.preventDefault();"INPUT"!==n.tagName&&"LABEL"===e.tagName||E._jQueryInterface.call(o.default(e),"toggle","INPUT"===n.tagName)}})).on("focus.bs.button.data-api blur.bs.button.data-api",v,(function(t){var e=o.default(t.target).closest(b)[0];o.default(e).toggleClass("focus",/^focus(in)?$/.test(t.type))})),o.default(window).on("load.bs.button.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-toggle="buttons"] .btn')),e=0,n=t.length;e0,this._pointerEvent=Boolean(window.PointerEvent||window.MSPointerEvent),this._addEventListeners()}var e=t.prototype;return e.next=function(){this._isSliding||this._slide(N)},e.nextWhenVisible=function(){var t=o.default(this._element);!document.hidden&&t.is(":visible")&&"hidden"!==t.css("visibility")&&this.next()},e.prev=function(){this._isSliding||this._slide(D)},e.pause=function(t){t||(this._isPaused=!0),this._element.querySelector(".carousel-item-next, .carousel-item-prev")&&(d.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},e.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},e.to=function(t){var e=this;this._activeElement=this._element.querySelector(I);var n=this._getItemIndex(this._activeElement);if(!(t>this._items.length-1||t<0))if(this._isSliding)o.default(this._element).one(A,(function(){return e.to(t)}));else{if(n===t)return this.pause(),void this.cycle();var i=t>n?N:D;this._slide(i,this._items[t])}},e.dispose=function(){o.default(this._element).off(".bs.carousel"),o.default.removeData(this._element,w),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},e._getConfig=function(t){return t=r({},k,t),d.typeCheckConfig(T,t,O),t},e._handleSwipe=function(){var t=Math.abs(this.touchDeltaX);if(!(t<=40)){var e=t/this.touchDeltaX;this.touchDeltaX=0,e>0&&this.prev(),e<0&&this.next()}},e._addEventListeners=function(){var t=this;this._config.keyboard&&o.default(this._element).on("keydown.bs.carousel",(function(e){return t._keydown(e)})),"hover"===this._config.pause&&o.default(this._element).on("mouseenter.bs.carousel",(function(e){return t.pause(e)})).on("mouseleave.bs.carousel",(function(e){return t.cycle(e)})),this._config.touch&&this._addTouchEventListeners()},e._addTouchEventListeners=function(){var t=this;if(this._touchSupported){var e=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]?t.touchStartX=e.originalEvent.clientX:t._pointerEvent||(t.touchStartX=e.originalEvent.touches[0].clientX)},n=function(e){t._pointerEvent&&j[e.originalEvent.pointerType.toUpperCase()]&&(t.touchDeltaX=e.originalEvent.clientX-t.touchStartX),t._handleSwipe(),"hover"===t._config.pause&&(t.pause(),t.touchTimeout&&clearTimeout(t.touchTimeout),t.touchTimeout=setTimeout((function(e){return t.cycle(e)}),500+t._config.interval))};o.default(this._element.querySelectorAll(".carousel-item img")).on("dragstart.bs.carousel",(function(t){return t.preventDefault()})),this._pointerEvent?(o.default(this._element).on("pointerdown.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("pointerup.bs.carousel",(function(t){return n(t)})),this._element.classList.add("pointer-event")):(o.default(this._element).on("touchstart.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("touchmove.bs.carousel",(function(e){return function(e){t.touchDeltaX=e.originalEvent.touches&&e.originalEvent.touches.length>1?0:e.originalEvent.touches[0].clientX-t.touchStartX}(e)})),o.default(this._element).on("touchend.bs.carousel",(function(t){return n(t)})))}},e._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next()}},e._getItemIndex=function(t){return this._items=t&&t.parentNode?[].slice.call(t.parentNode.querySelectorAll(".carousel-item")):[],this._items.indexOf(t)},e._getItemByDirection=function(t,e){var n=t===N,i=t===D,o=this._getItemIndex(e),a=this._items.length-1;if((i&&0===o||n&&o===a)&&!this._config.wrap)return e;var s=(o+(t===D?-1:1))%this._items.length;return-1===s?this._items[this._items.length-1]:this._items[s]},e._triggerSlideEvent=function(t,e){var n=this._getItemIndex(t),i=this._getItemIndex(this._element.querySelector(I)),a=o.default.Event("slide.bs.carousel",{relatedTarget:t,direction:e,from:i,to:n});return o.default(this._element).trigger(a),a},e._setActiveIndicatorElement=function(t){if(this._indicatorsElement){var e=[].slice.call(this._indicatorsElement.querySelectorAll(".active"));o.default(e).removeClass(S);var n=this._indicatorsElement.children[this._getItemIndex(t)];n&&o.default(n).addClass(S)}},e._updateInterval=function(){var t=this._activeElement||this._element.querySelector(I);if(t){var e=parseInt(t.getAttribute("data-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}},e._slide=function(t,e){var n,i,a,s=this,l=this._element.querySelector(I),r=this._getItemIndex(l),u=e||l&&this._getItemByDirection(t,l),f=this._getItemIndex(u),c=Boolean(this._interval);if(t===N?(n="carousel-item-left",i="carousel-item-next",a="left"):(n="carousel-item-right",i="carousel-item-prev",a="right"),u&&o.default(u).hasClass(S))this._isSliding=!1;else if(!this._triggerSlideEvent(u,a).isDefaultPrevented()&&l&&u){this._isSliding=!0,c&&this.pause(),this._setActiveIndicatorElement(u),this._activeElement=u;var h=o.default.Event(A,{relatedTarget:u,direction:a,from:r,to:f});if(o.default(this._element).hasClass("slide")){o.default(u).addClass(i),d.reflow(u),o.default(l).addClass(n),o.default(u).addClass(n);var g=d.getTransitionDurationFromElement(l);o.default(l).one(d.TRANSITION_END,(function(){o.default(u).removeClass(n+" "+i).addClass(S),o.default(l).removeClass("active "+i+" "+n),s._isSliding=!1,setTimeout((function(){return o.default(s._element).trigger(h)}),0)})).emulateTransitionEnd(g)}else o.default(l).removeClass(S),o.default(u).addClass(S),this._isSliding=!1,o.default(this._element).trigger(h);c&&this.cycle()}},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(w),i=r({},k,o.default(this).data());"object"==typeof e&&(i=r({},i,e));var a="string"==typeof e?e:i.slide;if(n||(n=new t(this,i),o.default(this).data(w,n)),"number"==typeof e)n.to(e);else if("string"==typeof a){if("undefined"==typeof n[a])throw new TypeError('No method named "'+a+'"');n[a]()}else i.interval&&i.ride&&(n.pause(),n.cycle())}))},t._dataApiClickHandler=function(e){var n=d.getSelectorFromElement(this);if(n){var i=o.default(n)[0];if(i&&o.default(i).hasClass("carousel")){var a=r({},o.default(i).data(),o.default(this).data()),s=this.getAttribute("data-slide-to");s&&(a.interval=!1),t._jQueryInterface.call(o.default(i),a),s&&o.default(i).data(w).to(s),e.preventDefault()}}},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return k}}]),t}();o.default(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",P._dataApiClickHandler),o.default(window).on("load.bs.carousel.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-ride="carousel"]')),e=0,n=t.length;e0&&(this._selector=s,this._triggerArray.push(a))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}var e=t.prototype;return e.toggle=function(){o.default(this._element).hasClass(q)?this.hide():this.show()},e.show=function(){var e,n,i=this;if(!(this._isTransitioning||o.default(this._element).hasClass(q)||(this._parent&&0===(e=[].slice.call(this._parent.querySelectorAll(".show, .collapsing")).filter((function(t){return"string"==typeof i._config.parent?t.getAttribute("data-parent")===i._config.parent:t.classList.contains(F)}))).length&&(e=null),e&&(n=o.default(e).not(this._selector).data(R))&&n._isTransitioning))){var a=o.default.Event("show.bs.collapse");if(o.default(this._element).trigger(a),!a.isDefaultPrevented()){e&&(t._jQueryInterface.call(o.default(e).not(this._selector),"hide"),n||o.default(e).data(R,null));var s=this._getDimension();o.default(this._element).removeClass(F).addClass(Q),this._element.style[s]=0,this._triggerArray.length&&o.default(this._triggerArray).removeClass(B).attr("aria-expanded",!0),this.setTransitioning(!0);var l="scroll"+(s[0].toUpperCase()+s.slice(1)),r=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,(function(){o.default(i._element).removeClass(Q).addClass("collapse show"),i._element.style[s]="",i.setTransitioning(!1),o.default(i._element).trigger("shown.bs.collapse")})).emulateTransitionEnd(r),this._element.style[s]=this._element[l]+"px"}}},e.hide=function(){var t=this;if(!this._isTransitioning&&o.default(this._element).hasClass(q)){var e=o.default.Event("hide.bs.collapse");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){var n=this._getDimension();this._element.style[n]=this._element.getBoundingClientRect()[n]+"px",d.reflow(this._element),o.default(this._element).addClass(Q).removeClass("collapse show");var i=this._triggerArray.length;if(i>0)for(var a=0;a0},e._getOffset=function(){var t=this,e={};return"function"==typeof this._config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t._config.offset(e.offsets,t._element)),e}:e.offset=this._config.offset,e},e._getPopperConfig=function(){var t={placement:this._getPlacement(),modifiers:{offset:this._getOffset(),flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}};return"static"===this._config.display&&(t.modifiers.applyStyle={enabled:!1}),r({},t,this._config.popperConfig)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data(K);if(n||(n=new t(this,"object"==typeof e?e:null),o.default(this).data(K,n)),"string"==typeof e){if("undefined"==typeof n[e])throw new TypeError('No method named "'+e+'"');n[e]()}}))},t._clearMenus=function(e){if(!e||3!==e.which&&("keyup"!==e.type||9===e.which))for(var n=[].slice.call(document.querySelectorAll(it)),i=0,a=n.length;i0&&s--,40===e.which&&sdocument.documentElement.clientHeight;n||(this._element.style.overflowY="hidden"),this._element.classList.add(ht);var i=d.getTransitionDurationFromElement(this._dialog);o.default(this._element).off(d.TRANSITION_END),o.default(this._element).one(d.TRANSITION_END,(function(){t._element.classList.remove(ht),n||o.default(t._element).one(d.TRANSITION_END,(function(){t._element.style.overflowY=""})).emulateTransitionEnd(t._element,i)})).emulateTransitionEnd(i),this._element.focus()}},e._showElement=function(t){var e=this,n=o.default(this._element).hasClass(dt),i=this._dialog?this._dialog.querySelector(".modal-body"):null;this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),o.default(this._dialog).hasClass("modal-dialog-scrollable")&&i?i.scrollTop=0:this._element.scrollTop=0,n&&d.reflow(this._element),o.default(this._element).addClass(ct),this._config.focus&&this._enforceFocus();var a=o.default.Event("shown.bs.modal",{relatedTarget:t}),s=function(){e._config.focus&&e._element.focus(),e._isTransitioning=!1,o.default(e._element).trigger(a)};if(n){var l=d.getTransitionDurationFromElement(this._dialog);o.default(this._dialog).one(d.TRANSITION_END,s).emulateTransitionEnd(l)}else s()},e._enforceFocus=function(){var t=this;o.default(document).off(pt).on(pt,(function(e){document!==e.target&&t._element!==e.target&&0===o.default(t._element).has(e.target).length&&t._element.focus()}))},e._setEscapeEvent=function(){var t=this;this._isShown?o.default(this._element).on(yt,(function(e){t._config.keyboard&&27===e.which?(e.preventDefault(),t.hide()):t._config.keyboard||27!==e.which||t._triggerBackdropTransition()})):this._isShown||o.default(this._element).off(yt)},e._setResizeEvent=function(){var t=this;this._isShown?o.default(window).on(_t,(function(e){return t.handleUpdate(e)})):o.default(window).off(_t)},e._hideModal=function(){var t=this;this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._showBackdrop((function(){o.default(document.body).removeClass(ft),t._resetAdjustments(),t._resetScrollbar(),o.default(t._element).trigger(gt)}))},e._removeBackdrop=function(){this._backdrop&&(o.default(this._backdrop).remove(),this._backdrop=null)},e._showBackdrop=function(t){var e=this,n=o.default(this._element).hasClass(dt)?dt:"";if(this._isShown&&this._config.backdrop){if(this._backdrop=document.createElement("div"),this._backdrop.className="modal-backdrop",n&&this._backdrop.classList.add(n),o.default(this._backdrop).appendTo(document.body),o.default(this._element).on(vt,(function(t){e._ignoreBackdropClick?e._ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"===e._config.backdrop?e._triggerBackdropTransition():e.hide())})),n&&d.reflow(this._backdrop),o.default(this._backdrop).addClass(ct),!t)return;if(!n)return void t();var i=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,t).emulateTransitionEnd(i)}else if(!this._isShown&&this._backdrop){o.default(this._backdrop).removeClass(ct);var a=function(){e._removeBackdrop(),t&&t()};if(o.default(this._element).hasClass(dt)){var s=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a()}else t&&t()},e._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},e._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},e._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=Math.round(t.left+t.right)
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",customClass:"",sanitize:!0,sanitizeFn:null,whiteList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},Ut={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string|function)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",whiteList:"object",popperConfig:"(null|object)"},Mt={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},Wt=function(){function t(t,e){if("undefined"==typeof a.default)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var e=t.prototype;return e.enable=function(){this._isEnabled=!0},e.disable=function(){this._isEnabled=!1},e.toggleEnabled=function(){this._isEnabled=!this._isEnabled},e.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=o.default(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(o.default(this.getTipElement()).hasClass(Rt))return void this._leave(null,this);this._enter(null,this)}},e.dispose=function(){clearTimeout(this._timeout),o.default.removeData(this.element,this.constructor.DATA_KEY),o.default(this.element).off(this.constructor.EVENT_KEY),o.default(this.element).closest(".modal").off("hide.bs.modal",this._hideModalHandler),this.tip&&o.default(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},e.show=function(){var t=this;if("none"===o.default(this.element).css("display"))throw new Error("Please use show on visible elements");var e=o.default.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){o.default(this.element).trigger(e);var n=d.findShadowRoot(this.element),i=o.default.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(e.isDefaultPrevented()||!i)return;var s=this.getTipElement(),l=d.getUID(this.constructor.NAME);s.setAttribute("id",l),this.element.setAttribute("aria-describedby",l),this.setContent(),this.config.animation&&o.default(s).addClass(Lt);var r="function"==typeof this.config.placement?this.config.placement.call(this,s,this.element):this.config.placement,u=this._getAttachment(r);this.addAttachmentClass(u);var f=this._getContainer();o.default(s).data(this.constructor.DATA_KEY,this),o.default.contains(this.element.ownerDocument.documentElement,this.tip)||o.default(s).appendTo(f),o.default(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new a.default(this.element,s,this._getPopperConfig(u)),o.default(s).addClass(Rt),o.default(s).addClass(this.config.customClass),"ontouchstart"in document.documentElement&&o.default(document.body).children().on("mouseover",null,o.default.noop);var c=function(){t.config.animation&&t._fixTransition();var e=t._hoverState;t._hoverState=null,o.default(t.element).trigger(t.constructor.Event.SHOWN),e===qt&&t._leave(null,t)};if(o.default(this.tip).hasClass(Lt)){var h=d.getTransitionDurationFromElement(this.tip);o.default(this.tip).one(d.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},e.hide=function(t){var e=this,n=this.getTipElement(),i=o.default.Event(this.constructor.Event.HIDE),a=function(){e._hoverState!==xt&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),o.default(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(o.default(this.element).trigger(i),!i.isDefaultPrevented()){if(o.default(n).removeClass(Rt),"ontouchstart"in document.documentElement&&o.default(document.body).children().off("mouseover",null,o.default.noop),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,o.default(this.tip).hasClass(Lt)){var s=d.getTransitionDurationFromElement(n);o.default(n).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a();this._hoverState=""}},e.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},e.isWithContent=function(){return Boolean(this.getTitle())},e.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-tooltip-"+t)},e.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},e.setContent=function(){var t=this.getTipElement();this.setElementContent(o.default(t.querySelectorAll(".tooltip-inner")),this.getTitle()),o.default(t).removeClass("fade show")},e.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=At(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?o.default(e).parent().is(t)||t.empty().append(e):t.text(o.default(e).text())},e.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},e._getPopperConfig=function(t){var e=this;return r({},{placement:t,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:".arrow"},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}},this.config.popperConfig)},e._getOffset=function(){var t=this,e={};return"function"==typeof this.config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t.config.offset(e.offsets,t.element)),e}:e.offset=this.config.offset,e},e._getContainer=function(){return!1===this.config.container?document.body:d.isElement(this.config.container)?o.default(this.config.container):o.default(document).find(this.config.container)},e._getAttachment=function(t){return Bt[t.toUpperCase()]},e._setListeners=function(){var t=this;this.config.trigger.split(" ").forEach((function(e){if("click"===e)o.default(t.element).on(t.constructor.Event.CLICK,t.config.selector,(function(e){return t.toggle(e)}));else if("manual"!==e){var n=e===Ft?t.constructor.Event.MOUSEENTER:t.constructor.Event.FOCUSIN,i=e===Ft?t.constructor.Event.MOUSELEAVE:t.constructor.Event.FOCUSOUT;o.default(t.element).on(n,t.config.selector,(function(e){return t._enter(e)})).on(i,t.config.selector,(function(e){return t._leave(e)}))}})),this._hideModalHandler=function(){t.element&&t.hide()},o.default(this.element).closest(".modal").on("hide.bs.modal",this._hideModalHandler),this.config.selector?this.config=r({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},e._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},e._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Qt:Ft]=!0),o.default(e.getTipElement()).hasClass(Rt)||e._hoverState===xt?e._hoverState=xt:(clearTimeout(e._timeout),e._hoverState=xt,e.config.delay&&e.config.delay.show?e._timeout=setTimeout((function(){e._hoverState===xt&&e.show()}),e.config.delay.show):e.show())},e._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Qt:Ft]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=qt,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout((function(){e._hoverState===qt&&e.hide()}),e.config.delay.hide):e.hide())},e._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},e._getConfig=function(t){var e=o.default(this.element).data();return Object.keys(e).forEach((function(t){-1!==Pt.indexOf(t)&&delete e[t]})),"number"==typeof(t=r({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),d.typeCheckConfig(It,t,this.constructor.DefaultType),t.sanitize&&(t.template=At(t.template,t.whiteList,t.sanitizeFn)),t},e._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},e._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(jt);null!==e&&e.length&&t.removeClass(e.join(""))},e._handlePopperPlacementChange=function(t){this.tip=t.instance.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},e._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(o.default(t).removeClass(Lt),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(kt),a="object"==typeof e&&e;if((i||!/dispose|hide/.test(e))&&(i||(i=new t(this,a),n.data(kt,i)),"string"==typeof e)){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Ht}},{key:"NAME",get:function(){return It}},{key:"DATA_KEY",get:function(){return kt}},{key:"Event",get:function(){return Mt}},{key:"EVENT_KEY",get:function(){return".bs.tooltip"}},{key:"DefaultType",get:function(){return Ut}}]),t}();o.default.fn.tooltip=Wt._jQueryInterface,o.default.fn.tooltip.Constructor=Wt,o.default.fn.tooltip.noConflict=function(){return o.default.fn.tooltip=Ot,Wt._jQueryInterface};var Vt="bs.popover",zt=o.default.fn.popover,Kt=new RegExp("(^|\\s)bs-popover\\S+","g"),Xt=r({},Wt.Default,{placement:"right",trigger:"click",content:"",template:''}),Yt=r({},Wt.DefaultType,{content:"(string|element|function)"}),$t={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"},Jt=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),e.prototype.constructor=e,u(e,n);var a=i.prototype;return a.isWithContent=function(){return this.getTitle()||this._getContent()},a.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-popover-"+t)},a.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},a.setContent=function(){var t=o.default(this.getTipElement());this.setElementContent(t.find(".popover-header"),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(".popover-body"),e),t.removeClass("fade show")},a._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},a._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(Kt);null!==e&&e.length>0&&t.removeClass(e.join(""))},i._jQueryInterface=function(t){return this.each((function(){var e=o.default(this).data(Vt),n="object"==typeof t?t:null;if((e||!/dispose|hide/.test(t))&&(e||(e=new i(this,n),o.default(this).data(Vt,e)),"string"==typeof t)){if("undefined"==typeof e[t])throw new TypeError('No method named "'+t+'"');e[t]()}}))},l(i,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return Xt}},{key:"NAME",get:function(){return"popover"}},{key:"DATA_KEY",get:function(){return Vt}},{key:"Event",get:function(){return $t}},{key:"EVENT_KEY",get:function(){return".bs.popover"}},{key:"DefaultType",get:function(){return Yt}}]),i}(Wt);o.default.fn.popover=Jt._jQueryInterface,o.default.fn.popover.Constructor=Jt,o.default.fn.popover.noConflict=function(){return o.default.fn.popover=zt,Jt._jQueryInterface};var Gt="scrollspy",Zt="bs.scrollspy",te=o.default.fn[Gt],ee="active",ne="position",ie=".nav, .list-group",oe={offset:10,method:"auto",target:""},ae={offset:"number",method:"string",target:"(string|element)"},se=function(){function t(t,e){var n=this;this._element=t,this._scrollElement="BODY"===t.tagName?window:t,this._config=this._getConfig(e),this._selector=this._config.target+" .nav-link,"+this._config.target+" .list-group-item,"+this._config.target+" .dropdown-item",this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,o.default(this._scrollElement).on("scroll.bs.scrollspy",(function(t){return n._process(t)})),this.refresh(),this._process()}var e=t.prototype;return e.refresh=function(){var t=this,e=this._scrollElement===this._scrollElement.window?"offset":ne,n="auto"===this._config.method?e:this._config.method,i=n===ne?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),[].slice.call(document.querySelectorAll(this._selector)).map((function(t){var e,a=d.getSelectorFromElement(t);if(a&&(e=document.querySelector(a)),e){var s=e.getBoundingClientRect();if(s.width||s.height)return[o.default(e)[n]().top+i,a]}return null})).filter((function(t){return t})).sort((function(t,e){return t[0]-e[0]})).forEach((function(e){t._offsets.push(e[0]),t._targets.push(e[1])}))},e.dispose=function(){o.default.removeData(this._element,Zt),o.default(this._scrollElement).off(".bs.scrollspy"),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},e._getConfig=function(t){if("string"!=typeof(t=r({},oe,"object"==typeof t&&t?t:{})).target&&d.isElement(t.target)){var e=o.default(t.target).attr("id");e||(e=d.getUID(Gt),o.default(t.target).attr("id",e)),t.target="#"+e}return d.typeCheckConfig(Gt,t,ae),t},e._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},e._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},e._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},e._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;)this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||t li > .active",ge=function(){function t(t){this._element=t}var e=t.prototype;return e.show=function(){var t=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&o.default(this._element).hasClass(ue)||o.default(this._element).hasClass("disabled"))){var e,n,i=o.default(this._element).closest(".nav, .list-group")[0],a=d.getSelectorFromElement(this._element);if(i){var s="UL"===i.nodeName||"OL"===i.nodeName?he:ce;n=(n=o.default.makeArray(o.default(i).find(s)))[n.length-1]}var l=o.default.Event("hide.bs.tab",{relatedTarget:this._element}),r=o.default.Event("show.bs.tab",{relatedTarget:n});if(n&&o.default(n).trigger(l),o.default(this._element).trigger(r),!r.isDefaultPrevented()&&!l.isDefaultPrevented()){a&&(e=document.querySelector(a)),this._activate(this._element,i);var u=function(){var e=o.default.Event("hidden.bs.tab",{relatedTarget:t._element}),i=o.default.Event("shown.bs.tab",{relatedTarget:n});o.default(n).trigger(e),o.default(t._element).trigger(i)};e?this._activate(e,e.parentNode,u):u()}}},e.dispose=function(){o.default.removeData(this._element,le),this._element=null},e._activate=function(t,e,n){var i=this,a=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?o.default(e).children(ce):o.default(e).find(he))[0],s=n&&a&&o.default(a).hasClass(fe),l=function(){return i._transitionComplete(t,a,n)};if(a&&s){var r=d.getTransitionDurationFromElement(a);o.default(a).removeClass(de).one(d.TRANSITION_END,l).emulateTransitionEnd(r)}else l()},e._transitionComplete=function(t,e,n){if(e){o.default(e).removeClass(ue);var i=o.default(e.parentNode).find("> .dropdown-menu .active")[0];i&&o.default(i).removeClass(ue),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}o.default(t).addClass(ue),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),d.reflow(t),t.classList.contains(fe)&&t.classList.add(de);var a=t.parentNode;if(a&&"LI"===a.nodeName&&(a=a.parentNode),a&&o.default(a).hasClass("dropdown-menu")){var s=o.default(t).closest(".dropdown")[0];if(s){var l=[].slice.call(s.querySelectorAll(".dropdown-toggle"));o.default(l).addClass(ue)}t.setAttribute("aria-expanded",!0)}n&&n()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(le);if(i||(i=new t(this),n.data(le,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',(function(t){t.preventDefault(),ge._jQueryInterface.call(o.default(this),"show")})),o.default.fn.tab=ge._jQueryInterface,o.default.fn.tab.Constructor=ge,o.default.fn.tab.noConflict=function(){return o.default.fn.tab=re,ge._jQueryInterface};var me="bs.toast",pe=o.default.fn.toast,_e="hide",ve="show",ye="showing",be="click.dismiss.bs.toast",Ee={animation:!0,autohide:!0,delay:500},Te={animation:"boolean",autohide:"boolean",delay:"number"},we=function(){function t(t,e){this._element=t,this._config=this._getConfig(e),this._timeout=null,this._setListeners()}var e=t.prototype;return e.show=function(){var t=this,e=o.default.Event("show.bs.toast");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){this._clearTimeout(),this._config.animation&&this._element.classList.add("fade");var n=function(){t._element.classList.remove(ye),t._element.classList.add(ve),o.default(t._element).trigger("shown.bs.toast"),t._config.autohide&&(t._timeout=setTimeout((function(){t.hide()}),t._config.delay))};if(this._element.classList.remove(_e),d.reflow(this._element),this._element.classList.add(ye),this._config.animation){var i=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,n).emulateTransitionEnd(i)}else n()}},e.hide=function(){if(this._element.classList.contains(ve)){var t=o.default.Event("hide.bs.toast");o.default(this._element).trigger(t),t.isDefaultPrevented()||this._close()}},e.dispose=function(){this._clearTimeout(),this._element.classList.contains(ve)&&this._element.classList.remove(ve),o.default(this._element).off(be),o.default.removeData(this._element,me),this._element=null,this._config=null},e._getConfig=function(t){return t=r({},Ee,o.default(this._element).data(),"object"==typeof t&&t?t:{}),d.typeCheckConfig("toast",t,this.constructor.DefaultType),t},e._setListeners=function(){var t=this;o.default(this._element).on(be,'[data-dismiss="toast"]',(function(){return t.hide()}))},e._close=function(){var t=this,e=function(){t._element.classList.add(_e),o.default(t._element).trigger("hidden.bs.toast")};if(this._element.classList.remove(ve),this._config.animation){var n=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},e._clearTimeout=function(){clearTimeout(this._timeout),this._timeout=null},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data(me);if(i||(i=new t(this,"object"==typeof e&&e),n.data(me,i)),"string"==typeof e){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e](this)}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"DefaultType",get:function(){return Te}},{key:"Default",get:function(){return Ee}}]),t}();o.default.fn.toast=we._jQueryInterface,o.default.fn.toast.Constructor=we,o.default.fn.toast.noConflict=function(){return o.default.fn.toast=pe,we._jQueryInterface},t.Alert=g,t.Button=E,t.Carousel=P,t.Collapse=V,t.Dropdown=lt,t.Modal=Ct,t.Popover=Jt,t.Scrollspy=se,t.Tab=ge,t.Toast=we,t.Tooltip=Wt,t.Util=d,Object.defineProperty(t,"__esModule",{value:!0})})); +//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/code/starter_video_collector/static/js/jquery-3.5.1.slim.min.js b/code/starter_video_collector/static/js/jquery-3.5.1.slim.min.js new file mode 100644 index 0000000..36b4e1a --- /dev/null +++ b/code/starter_video_collector/static/js/jquery-3.5.1.slim.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(g,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,v=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),m={},b=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},w=g.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function C(e,t,n){var r,i,o=(n=n||w).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function T(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector",E=function(e,t){return new E.fn.init(e,t)};function d(e){var t=!!e&&"length"in e&&e.length,n=T(e);return!b(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+R+")"+R+"*"),U=new RegExp(R+"|>"),V=new RegExp(W),X=new RegExp("^"+B+"$"),Q={ID:new RegExp("^#("+B+")"),CLASS:new RegExp("^\\.("+B+")"),TAG:new RegExp("^("+B+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+R+"*(even|odd|(([+-]|)(\\d*)n|)"+R+"*(?:([+-]|)"+R+"*(\\d+)|))"+R+"*\\)|)","i"),bool:new RegExp("^(?:"+I+")$","i"),needsContext:new RegExp("^"+R+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+R+"*((?:-\\d)?\\d*)"+R+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,G=/^(?:input|select|textarea|button)$/i,K=/^h\d$/i,J=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+R+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){C()},ae=xe(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{O.apply(t=P.call(d.childNodes),d.childNodes),t[d.childNodes.length].nodeType}catch(e){O={apply:t.length?function(e,t){q.apply(e,P.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,d=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==d&&9!==d&&11!==d)return n;if(!r&&(C(e),e=e||T,E)){if(11!==d&&(u=Z.exec(t)))if(i=u[1]){if(9===d){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return O.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&p.getElementsByClassName&&e.getElementsByClassName)return O.apply(n,e.getElementsByClassName(i)),n}if(p.qsa&&!k[t+" "]&&(!v||!v.test(t))&&(1!==d||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===d&&(U.test(t)||_.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&p.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=A)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+be(l[o]);c=l.join(",")}try{return O.apply(n,f.querySelectorAll(c)),n}catch(e){k(t,!0)}finally{s===A&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>x.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[A]=!0,e}function ce(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)x.attrHandle[n[r]]=t}function de(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pe(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in p=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},C=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:d;return r!=T&&9===r.nodeType&&r.documentElement&&(a=(T=r).documentElement,E=!i(T),d!=T&&(n=T.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),p.scope=ce(function(e){return a.appendChild(e).appendChild(T.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),p.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),p.getElementsByTagName=ce(function(e){return e.appendChild(T.createComment("")),!e.getElementsByTagName("*").length}),p.getElementsByClassName=J.test(T.getElementsByClassName),p.getById=ce(function(e){return a.appendChild(e).id=A,!T.getElementsByName||!T.getElementsByName(A).length}),p.getById?(x.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(x.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),x.find.TAG=p.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):p.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},x.find.CLASS=p.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(p.qsa=J.test(T.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+R+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+R+"*(?:value|"+I+")"),e.querySelectorAll("[id~="+A+"-]").length||v.push("~="),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+R+"*name"+R+"*="+R+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+A+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=T.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+R+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(p.matchesSelector=J.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){p.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",W)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=J.test(a.compareDocumentPosition),y=t||J.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!p.sortDetached&&t.compareDocumentPosition(e)===n?e==T||e.ownerDocument==d&&y(d,e)?-1:t==T||t.ownerDocument==d&&y(d,t)?1:u?H(u,e)-H(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==T?-1:t==T?1:i?-1:o?1:u?H(u,e)-H(u,t):0;if(i===o)return de(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?de(a[r],s[r]):a[r]==d?-1:s[r]==d?1:0}),T},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(C(e),p.matchesSelector&&E&&!k[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||p.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){k(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&V.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+R+")"+e+"("+R+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return b(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):"string"!=typeof n?E.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||L,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:j.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:w,!0)),k.test(r[1])&&E.isPlainObject(t))for(r in t)b(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=w.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):b(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,L=E(w);var q=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,pe=/^$|^module$|\/(?:java|ecma)script/i;le=w.createDocumentFragment().appendChild(w.createElement("div")),(ce=w.createElement("input")).setAttribute("type","radio"),ce.setAttribute("checked","checked"),ce.setAttribute("name","t"),le.appendChild(ce),m.checkClone=le.cloneNode(!0).cloneNode(!0).lastChild.checked,le.innerHTML="",m.noCloneChecked=!!le.cloneNode(!0).lastChild.defaultValue,le.innerHTML="",m.option=!!le.lastChild;var he={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ge(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&S(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var ye=/<|&#?\w+;/;function me(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),d=[],p=0,h=e.length;p\s*$/g;function Le(e,t){return S(e,"table")&&S(11!==t.nodeType?t:t.firstChild,"tr")&&E(e).children("tbody")[0]||e}function je(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n
",2===ft.childNodes.length),E.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(m.createHTMLDocument?((r=(t=w.implementation.createHTMLDocument("")).createElement("base")).href=w.location.href,t.head.appendChild(r)):t=w),o=!n&&[],(i=k.exec(e))?[t.createElement(i[1])]:(i=me([e],t,o),o&&o.length&&E(o).remove(),E.merge([],i.childNodes)));var r,i,o},E.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=E.css(e,"position"),c=E(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=E.css(e,"top"),u=E.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),b(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===E.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===E.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=E(e).offset()).top+=E.css(e,"borderTopWidth",!0),i.left+=E.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-E.css(r,"marginTop",!0),left:t.left-i.left-E.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===E.css(e,"position"))e=e.offsetParent;return e||re})}}),E.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;E.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each(["top","left"],function(e,n){E.cssHooks[n]=Fe(m.pixelPosition,function(e,t){if(t)return t=We(e,n),Ie.test(t)?E(e).position()[n]+"px":t})}),E.each({Height:"height",Width:"width"},function(a,s){E.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){E.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?E.css(e,t,i):E.style(e,t,n,i)},s,n?e:void 0,n)}})}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){E.fn[n]=function(e,t){return 0=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),ae({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=le({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f]),E=parseFloat(w['border'+f+'Width']),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},ae(n,m,$(v)),ae(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ce.FLIP:p=[n,i];break;case ce.CLOCKWISE:p=G(n);break;case ce.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u),E=!!t.flipVariationsByContent&&(w&&'start'===r&&c||w&&'end'===r&&h||!w&&'start'===r&&u||!w&&'end'===r&&g),v=y||E;(m||b||v)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),v&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=le({},e.offsets.popper,C(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport',flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=D(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.rightwindow.devicePixelRatio||!fe),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=B('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=le({},E,e.attributes),e.styles=le({},m,e.styles),e.arrowStyles=le({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return V(e.instance.popper,e.styles),j(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&V(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),V(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ge}); +//# sourceMappingURL=popper.min.js.map From ffebc055cc2388aa154a5a3c6acc87bcc8c66c23 Mon Sep 17 00:00:00 2001 From: Michael Kennedy Date: Fri, 3 Dec 2021 17:26:42 -0800 Subject: [PATCH 03/21] Add the jQuery/Bootstrap JS needed for responsive nav bars in Bootstrap. --- .../ch4_final_video_collector/templates/shared/_layout.html | 4 ++++ .../templates/shared/_layout.html | 5 +++++ .../ch5_final_video_collector/templates/shared/_layout.html | 4 ++++ .../templates/shared/_layout.html | 4 ++++ .../ch6_final_video_collector/templates/shared/_layout.html | 4 ++++ .../templates/shared/_layout.html | 4 ++++ .../templates/shared/_layout.html | 4 ++++ code/starter_video_collector/templates/shared/_layout.html | 4 ++++ 8 files changed, 33 insertions(+) diff --git a/code/ch4_app/ch4_final_video_collector/templates/shared/_layout.html b/code/ch4_app/ch4_final_video_collector/templates/shared/_layout.html index 0ee82ef..b4738bb 100644 --- a/code/ch4_app/ch4_final_video_collector/templates/shared/_layout.html +++ b/code/ch4_app/ch4_final_video_collector/templates/shared/_layout.html @@ -53,6 +53,10 @@ + + + + {% block additional_js %}{% endblock %} diff --git a/code/ch4_app/ch4_starter_video_collector/templates/shared/_layout.html b/code/ch4_app/ch4_starter_video_collector/templates/shared/_layout.html index f36d523..ca521bd 100644 --- a/code/ch4_app/ch4_starter_video_collector/templates/shared/_layout.html +++ b/code/ch4_app/ch4_starter_video_collector/templates/shared/_layout.html @@ -51,6 +51,11 @@ + + + + + {% block additional_js %}{% endblock %} diff --git a/code/ch5_partials/ch5_final_video_collector/templates/shared/_layout.html b/code/ch5_partials/ch5_final_video_collector/templates/shared/_layout.html index 0ee82ef..b4738bb 100644 --- a/code/ch5_partials/ch5_final_video_collector/templates/shared/_layout.html +++ b/code/ch5_partials/ch5_final_video_collector/templates/shared/_layout.html @@ -53,6 +53,10 @@ + + + + {% block additional_js %}{% endblock %} diff --git a/code/ch5_partials/ch5_starter_video_collector/templates/shared/_layout.html b/code/ch5_partials/ch5_starter_video_collector/templates/shared/_layout.html index 0ee82ef..b4738bb 100644 --- a/code/ch5_partials/ch5_starter_video_collector/templates/shared/_layout.html +++ b/code/ch5_partials/ch5_starter_video_collector/templates/shared/_layout.html @@ -53,6 +53,10 @@ + + + + {% block additional_js %}{% endblock %} diff --git a/code/ch6_active_search/ch6_final_video_collector/templates/shared/_layout.html b/code/ch6_active_search/ch6_final_video_collector/templates/shared/_layout.html index fccc4a6..a13399e 100644 --- a/code/ch6_active_search/ch6_final_video_collector/templates/shared/_layout.html +++ b/code/ch6_active_search/ch6_final_video_collector/templates/shared/_layout.html @@ -54,6 +54,10 @@ + + + + {% block additional_js %}{% endblock %} diff --git a/code/ch6_active_search/ch6_starter_video_collector/templates/shared/_layout.html b/code/ch6_active_search/ch6_starter_video_collector/templates/shared/_layout.html index 0ee82ef..b4738bb 100644 --- a/code/ch6_active_search/ch6_starter_video_collector/templates/shared/_layout.html +++ b/code/ch6_active_search/ch6_starter_video_collector/templates/shared/_layout.html @@ -53,6 +53,10 @@ + + + + {% block additional_js %}{% endblock %} diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/templates/shared/_layout.html b/code/ch7_infinite_scroll/ch7_starter_video_collector/templates/shared/_layout.html index fccc4a6..a13399e 100644 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/templates/shared/_layout.html +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/templates/shared/_layout.html @@ -54,6 +54,10 @@ + + + + {% block additional_js %}{% endblock %} diff --git a/code/starter_video_collector/templates/shared/_layout.html b/code/starter_video_collector/templates/shared/_layout.html index f36d523..b9c6357 100644 --- a/code/starter_video_collector/templates/shared/_layout.html +++ b/code/starter_video_collector/templates/shared/_layout.html @@ -50,6 +50,10 @@ + + + + {% block additional_js %}{% endblock %} From 9d9abbff7e7143136e05adf21ab25f5fee2612ea Mon Sep 17 00:00:00 2001 From: Michael Kennedy Date: Tue, 25 Jan 2022 14:13:10 -0800 Subject: [PATCH 04/21] Convert these string formats to f-strings --- .../ch4_final_video_collector/infrastructure/view_modifiers.py | 2 +- .../infrastructure/view_modifiers.py | 2 +- .../ch5_final_video_collector/infrastructure/view_modifiers.py | 2 +- .../infrastructure/view_modifiers.py | 2 +- .../ch6_final_video_collector/infrastructure/view_modifiers.py | 2 +- .../infrastructure/view_modifiers.py | 2 +- .../ch7_final_video_collector/infrastructure/view_modifiers.py | 2 +- .../infrastructure/view_modifiers.py | 2 +- code/starter_video_collector/infrastructure/view_modifiers.py | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/code/ch4_app/ch4_final_video_collector/infrastructure/view_modifiers.py b/code/ch4_app/ch4_final_video_collector/infrastructure/view_modifiers.py index 2067462..063f7d6 100644 --- a/code/ch4_app/ch4_final_video_collector/infrastructure/view_modifiers.py +++ b/code/ch4_app/ch4_final_video_collector/infrastructure/view_modifiers.py @@ -25,7 +25,7 @@ def view_method(*args, **kwargs): if template_file and not isinstance(response_val, dict): raise Exception( - "Invalid return type {}, we expected a dict as the return value.".format(type(response_val))) + f"Invalid return type {type(response_val)}, we expected a dict as the return value.") if template_file: response_val = flask.render_template(template_file, **response_val) diff --git a/code/ch4_app/ch4_starter_video_collector/infrastructure/view_modifiers.py b/code/ch4_app/ch4_starter_video_collector/infrastructure/view_modifiers.py index 2067462..063f7d6 100644 --- a/code/ch4_app/ch4_starter_video_collector/infrastructure/view_modifiers.py +++ b/code/ch4_app/ch4_starter_video_collector/infrastructure/view_modifiers.py @@ -25,7 +25,7 @@ def view_method(*args, **kwargs): if template_file and not isinstance(response_val, dict): raise Exception( - "Invalid return type {}, we expected a dict as the return value.".format(type(response_val))) + f"Invalid return type {type(response_val)}, we expected a dict as the return value.") if template_file: response_val = flask.render_template(template_file, **response_val) diff --git a/code/ch5_partials/ch5_final_video_collector/infrastructure/view_modifiers.py b/code/ch5_partials/ch5_final_video_collector/infrastructure/view_modifiers.py index 2067462..063f7d6 100644 --- a/code/ch5_partials/ch5_final_video_collector/infrastructure/view_modifiers.py +++ b/code/ch5_partials/ch5_final_video_collector/infrastructure/view_modifiers.py @@ -25,7 +25,7 @@ def view_method(*args, **kwargs): if template_file and not isinstance(response_val, dict): raise Exception( - "Invalid return type {}, we expected a dict as the return value.".format(type(response_val))) + f"Invalid return type {type(response_val)}, we expected a dict as the return value.") if template_file: response_val = flask.render_template(template_file, **response_val) diff --git a/code/ch5_partials/ch5_starter_video_collector/infrastructure/view_modifiers.py b/code/ch5_partials/ch5_starter_video_collector/infrastructure/view_modifiers.py index 2067462..063f7d6 100644 --- a/code/ch5_partials/ch5_starter_video_collector/infrastructure/view_modifiers.py +++ b/code/ch5_partials/ch5_starter_video_collector/infrastructure/view_modifiers.py @@ -25,7 +25,7 @@ def view_method(*args, **kwargs): if template_file and not isinstance(response_val, dict): raise Exception( - "Invalid return type {}, we expected a dict as the return value.".format(type(response_val))) + f"Invalid return type {type(response_val)}, we expected a dict as the return value.") if template_file: response_val = flask.render_template(template_file, **response_val) diff --git a/code/ch6_active_search/ch6_final_video_collector/infrastructure/view_modifiers.py b/code/ch6_active_search/ch6_final_video_collector/infrastructure/view_modifiers.py index 2067462..063f7d6 100644 --- a/code/ch6_active_search/ch6_final_video_collector/infrastructure/view_modifiers.py +++ b/code/ch6_active_search/ch6_final_video_collector/infrastructure/view_modifiers.py @@ -25,7 +25,7 @@ def view_method(*args, **kwargs): if template_file and not isinstance(response_val, dict): raise Exception( - "Invalid return type {}, we expected a dict as the return value.".format(type(response_val))) + f"Invalid return type {type(response_val)}, we expected a dict as the return value.") if template_file: response_val = flask.render_template(template_file, **response_val) diff --git a/code/ch6_active_search/ch6_starter_video_collector/infrastructure/view_modifiers.py b/code/ch6_active_search/ch6_starter_video_collector/infrastructure/view_modifiers.py index 2067462..063f7d6 100644 --- a/code/ch6_active_search/ch6_starter_video_collector/infrastructure/view_modifiers.py +++ b/code/ch6_active_search/ch6_starter_video_collector/infrastructure/view_modifiers.py @@ -25,7 +25,7 @@ def view_method(*args, **kwargs): if template_file and not isinstance(response_val, dict): raise Exception( - "Invalid return type {}, we expected a dict as the return value.".format(type(response_val))) + f"Invalid return type {type(response_val)}, we expected a dict as the return value.") if template_file: response_val = flask.render_template(template_file, **response_val) diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/infrastructure/view_modifiers.py b/code/ch7_infinite_scroll/ch7_final_video_collector/infrastructure/view_modifiers.py index 2067462..063f7d6 100644 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/infrastructure/view_modifiers.py +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/infrastructure/view_modifiers.py @@ -25,7 +25,7 @@ def view_method(*args, **kwargs): if template_file and not isinstance(response_val, dict): raise Exception( - "Invalid return type {}, we expected a dict as the return value.".format(type(response_val))) + f"Invalid return type {type(response_val)}, we expected a dict as the return value.") if template_file: response_val = flask.render_template(template_file, **response_val) diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/infrastructure/view_modifiers.py b/code/ch7_infinite_scroll/ch7_starter_video_collector/infrastructure/view_modifiers.py index 2067462..063f7d6 100644 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/infrastructure/view_modifiers.py +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/infrastructure/view_modifiers.py @@ -25,7 +25,7 @@ def view_method(*args, **kwargs): if template_file and not isinstance(response_val, dict): raise Exception( - "Invalid return type {}, we expected a dict as the return value.".format(type(response_val))) + f"Invalid return type {type(response_val)}, we expected a dict as the return value.") if template_file: response_val = flask.render_template(template_file, **response_val) diff --git a/code/starter_video_collector/infrastructure/view_modifiers.py b/code/starter_video_collector/infrastructure/view_modifiers.py index 2067462..063f7d6 100644 --- a/code/starter_video_collector/infrastructure/view_modifiers.py +++ b/code/starter_video_collector/infrastructure/view_modifiers.py @@ -25,7 +25,7 @@ def view_method(*args, **kwargs): if template_file and not isinstance(response_val, dict): raise Exception( - "Invalid return type {}, we expected a dict as the return value.".format(type(response_val))) + f"Invalid return type {type(response_val)}, we expected a dict as the return value.") if template_file: response_val = flask.render_template(template_file, **response_val) From 06fffd646d81694bdd089aa5183e452e770ab04c Mon Sep 17 00:00:00 2001 From: Michael Kennedy Date: Wed, 23 Mar 2022 08:07:54 -0700 Subject: [PATCH 05/21] Upgrade htmx.js from 1.5 to 1.7. --- .../static/js/htmx.js | 1180 ++++++++++++----- .../static/js/htmx.min.js | 2 +- .../static/js/htmx.js | 1180 ++++++++++++----- .../static/js/htmx.min.js | 2 +- .../static/js/htmx.js | 1180 ++++++++++++----- .../static/js/htmx.min.js | 2 +- .../static/js/htmx.js | 1180 ++++++++++++----- .../static/js/htmx.min.js | 2 +- .../static/js/htmx.js | 1180 ++++++++++++----- .../static/js/htmx.min.js | 2 +- .../static/js/htmx.js | 1180 ++++++++++++----- .../static/js/htmx.min.js | 2 +- .../static/js/htmx.js | 1180 ++++++++++++----- .../static/js/htmx.min.js | 2 +- .../static/js/htmx.js | 1180 ++++++++++++----- .../static/js/htmx.min.js | 2 +- .../starter_video_collector/static/js/htmx.js | 1180 ++++++++++++----- .../static/js/htmx.min.js | 2 +- 18 files changed, 7803 insertions(+), 2835 deletions(-) diff --git a/code/ch4_app/ch4_final_video_collector/static/js/htmx.js b/code/ch4_app/ch4_final_video_collector/static/js/htmx.js index e38f6ed..27e57bc 100644 --- a/code/ch4_app/ch4_final_video_collector/static/js/htmx.js +++ b/code/ch4_app/ch4_final_video_collector/static/js/htmx.js @@ -1,7 +1,9 @@ //AMD insanity (function (root, factory) { + //@ts-ignore if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. + //@ts-ignore define([], factory); } else { // Browser globals @@ -12,6 +14,8 @@ return (function () { 'use strict'; // Public API + //** @type {import("./htmx").HtmxApi} */ + // TODO: list all methods in public API var htmx = { onLoad: onLoadHelper, process: processNode, @@ -35,7 +39,6 @@ return (function () { removeExtension : removeExtension, logAll : logAll, logger : null, - useTemplateFragments: false, config : { historyEnabled:true, historyCacheSize:10, @@ -46,13 +49,19 @@ return (function () { includeIndicatorStyles:true, indicatorClass:'htmx-indicator', requestClass:'htmx-request', + addedClass:'htmx-added', settlingClass:'htmx-settling', swappingClass:'htmx-swapping', allowEval:true, + inlineScriptNonce:'', attributesToSettle:["class", "style", "width", "height"], withCredentials:false, + timeout:0, wsReconnectDelay: 'full-jitter', disableSelector: "[hx-disable], [data-hx-disable]", + useTemplateFragments: false, + scrollBehavior: 'smooth', + defaultFocusScroll: false, }, parseInterval:parseInterval, _:internalEval, @@ -61,9 +70,36 @@ return (function () { }, createWebSocket: function(url){ return new WebSocket(url, []); - } + }, + version: "1.7.0" }; + /** @type {import("./htmx").HtmxInternalApi} */ + var internalAPI = { + bodyContains: bodyContains, + filterValues: filterValues, + hasAttribute: hasAttribute, + getAttributeValue: getAttributeValue, + getClosestMatch: getClosestMatch, + getExpressionVars: getExpressionVars, + getHeaders: getHeaders, + getInputValues: getInputValues, + getInternalData: getInternalData, + getSwapSpecification: getSwapSpecification, + getTriggerSpecs: getTriggerSpecs, + getTarget: getTarget, + makeFragment: makeFragment, + mergeObjects: mergeObjects, + makeSettleInfo: makeSettleInfo, + oobSwap: oobSwap, + selectAndSwap: selectAndSwap, + settleImmediately: settleImmediately, + shouldCancel: shouldCancel, + triggerEvent: triggerEvent, + triggerErrorEvent: triggerErrorEvent, + withExtensions: withExtensions, + } + var VERBS = ['get', 'post', 'put', 'delete', 'patch']; var VERB_SELECTOR = VERBS.map(function(verb){ return "[hx-" + verb + "], [data-hx-" + verb + "]" @@ -73,19 +109,24 @@ return (function () { // Utilities //==================================================================== - function parseInterval(str) { - if (str == undefined) { - return undefined - } - if (str.slice(-2) == "ms") { - return parseFloat(str.slice(0,-2)) || undefined - } - if (str.slice(-1) == "s") { - return (parseFloat(str.slice(0,-1)) * 1000) || undefined - } - return parseFloat(str) || undefined + function parseInterval(str) { + if (str == undefined) { + return undefined + } + if (str.slice(-2) == "ms") { + return parseFloat(str.slice(0,-2)) || undefined + } + if (str.slice(-1) == "s") { + return (parseFloat(str.slice(0,-1)) * 1000) || undefined + } + return parseFloat(str) || undefined } + /** + * @param {HTMLElement} elt + * @param {string} name + * @returns {(string | null)} + */ function getRawAttribute(elt, name) { return elt.getAttribute && elt.getAttribute(name); } @@ -96,18 +137,36 @@ return (function () { elt.hasAttribute("data-" + qualifiedName)); } + /** + * + * @param {HTMLElement} elt + * @param {string} qualifiedName + * @returns {(string | null)} + */ function getAttributeValue(elt, qualifiedName) { return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); } + /** + * @param {HTMLElement} elt + * @returns {HTMLElement | null} + */ function parentElt(elt) { return elt.parentElement; } + /** + * @returns {Document} + */ function getDocument() { return document; } + /** + * @param {HTMLElement} elt + * @param {(e:HTMLElement) => boolean} condition + * @returns {HTMLElement | null} + */ function getClosestMatch(elt, condition) { if (condition(elt)) { return elt; @@ -118,22 +177,47 @@ return (function () { } } + function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ + var attributeValue = getAttributeValue(ancestor, attributeName); + var disinherit = getAttributeValue(ancestor, "hx-disinherit"); + if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) { + return "unset"; + } else { + return attributeValue + } + } + + /** + * @param {HTMLElement} elt + * @param {string} attributeName + * @returns {string | null} + */ function getClosestAttributeValue(elt, attributeName) { var closestAttr = null; getClosestMatch(elt, function (e) { - return closestAttr = getAttributeValue(e, attributeName); + return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName); }); - return closestAttr; + if (closestAttr !== "unset") { + return closestAttr; + } } + /** + * @param {HTMLElement} elt + * @param {string} selector + * @returns {boolean} + */ function matches(elt, selector) { + // @ts-ignore: non-standard properties for browser compatability // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || - elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector - || elt.webkitMatchesSelector || elt.oMatchesSelector; + var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; return matchesFunction && matchesFunction.call(elt, selector); } + /** + * @param {string} str + * @returns {string} + */ function getStartTag(str) { var tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i var match = tagMatcher.exec( str ); @@ -144,23 +228,40 @@ return (function () { } } + /** + * + * @param {string} resp + * @param {number} depth + * @returns {Element} + */ function parseHTML(resp, depth) { var parser = new DOMParser(); var responseDoc = parser.parseFromString(resp, "text/html"); + + /** @type {Element} */ var responseNode = responseDoc.body; while (depth > 0) { depth--; + // @ts-ignore responseNode = responseNode.firstChild; } if (responseNode == null) { + // @ts-ignore responseNode = getDocument().createDocumentFragment(); } return responseNode; } + /** + * + * @param {string} resp + * @returns {Element} + */ function makeFragment(resp) { if (htmx.config.useTemplateFragments) { var documentFragment = parseHTML("", 0); + // @ts-ignore type mismatch between DocumentFragment and Element. + // TODO: Are these close enough for htmx to use interchangably? return documentFragment.querySelector('template').content; } else { var startTag = getStartTag(resp); @@ -186,24 +287,45 @@ return (function () { } } + /** + * @param {Function} func + */ function maybeCall(func){ if(func) { func(); } } + /** + * @param {any} o + * @param {string} type + * @returns + */ function isType(o, type) { return Object.prototype.toString.call(o) === "[object " + type + "]"; } + /** + * @param {*} o + * @returns {o is Function} + */ function isFunction(o) { return isType(o, "Function"); } + /** + * @param {*} o + * @returns {o is Object} + */ function isRawObject(o) { return isType(o, "Object"); } + /** + * getInternalData retrieves "private" data stored by htmx within an element + * @param {HTMLElement} elt + * @returns {*} + */ function getInternalData(elt) { var dataProp = 'htmx-internal-data'; var data = elt[dataProp]; @@ -213,6 +335,11 @@ return (function () { return data; } + /** + * toArray converts an ArrayLike object into a real array. + * @param {ArrayLike} arr + * @returns {any[]} + */ function toArray(arr) { var returnArr = []; if (arr) { @@ -238,14 +365,25 @@ return (function () { return elemTop < window.innerHeight && elemBottom >= 0; } - function bodyContains(elt) { - return getDocument().body.contains(elt); - } + function bodyContains(elt) { + if (elt.getRootNode() instanceof ShadowRoot) { + return getDocument().body.contains(elt.getRootNode().host); + } else { + return getDocument().body.contains(elt); + } + } function splitOnWhitespace(trigger) { return trigger.trim().split(/\s+/); } + /** + * mergeObjects takes all of the keys from + * obj2 and duplicates them into obj1 + * @param {Object} obj1 + * @param {Object} obj2 + * @returns {Object} + */ function mergeObjects(obj1, obj2) { for (var key in obj2) { if (obj2.hasOwnProperty(key)) { @@ -319,7 +457,7 @@ return (function () { if (delay) { setTimeout(function(){addClassToElement(elt, clazz);}, delay) } else { - elt.classList.add(clazz); + elt.classList && elt.classList.add(clazz); } } @@ -328,7 +466,13 @@ return (function () { if (delay) { setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) } else { - elt.classList.remove(clazz); + if (elt.classList) { + elt.classList.remove(clazz); + // if there are no classes left, remove the class attribute + if (elt.classList.length === 0) { + elt.removeAttribute("class"); + } + } } } @@ -360,17 +504,25 @@ return (function () { } function querySelectorAllExt(elt, selector) { - if (selector.indexOf("closest ") === 0) { + if (selector.indexOf("closest ") === 0) { return [closest(elt, selector.substr(8))]; } else if (selector.indexOf("find ") === 0) { return [find(elt, selector.substr(5))]; + } else if (selector === 'document') { + return [document]; + } else if (selector === 'window') { + return [window]; } else { return getDocument().querySelectorAll(selector); } } function querySelectorExt(eltOrSelector, selector) { - return querySelectorAllExt(eltOrSelector, selector)[0] + if (selector) { + return querySelectorAllExt(eltOrSelector, selector)[0]; + } else { + return querySelectorAllExt(getDocument().body, eltOrSelector)[0]; + } } function resolveTarget(arg2) { @@ -418,13 +570,36 @@ return (function () { //==================================================================== // Node processing //==================================================================== + + var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors + function findAttributeTargets(elt, attrName) { + var attrTarget = getClosestAttributeValue(elt, attrName); + if (attrTarget) { + if (attrTarget === "this") { + return [findThisElement(elt, attrName)]; + } else { + var result = querySelectorAllExt(elt, attrTarget); + if (result.length === 0) { + logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!"); + return [DUMMY_ELT] + } else { + return result; + } + } + } + } + + function findThisElement(elt, attribute){ + return getClosestMatch(elt, function (elt) { + return getAttributeValue(elt, attribute) != null; + }) + } function getTarget(elt) { - var explicitTarget = getClosestMatch(elt, function(e){return getAttributeValue(e,"hx-target") !== null}); - if (explicitTarget) { - var targetStr = getAttributeValue(explicitTarget, "hx-target"); + var targetStr = getClosestAttributeValue(elt, "hx-target"); + if (targetStr) { if (targetStr === "this") { - return explicitTarget; + return findThisElement(elt,'hx-target'); } else { return querySelectorExt(elt, targetStr) } @@ -476,6 +651,13 @@ return (function () { return swapStyle === "outerHTML"; } + /** + * + * @param {string} oobValue + * @param {HTMLElement} oobElement + * @param {*} settleInfo + * @returns + */ function oobSwap(oobValue, oobElement, settleInfo) { var selector = "#" + oobElement.id; var swapStyle = "outerHTML"; @@ -488,18 +670,35 @@ return (function () { swapStyle = oobValue; } - var target = getDocument().querySelector(selector); - if (target) { - var fragment; - fragment = getDocument().createDocumentFragment(); - fragment.appendChild(oobElement); // pulls the child out of the existing fragment - if (!isInlineSwap(swapStyle, target)) { - fragment = oobElement; // if this is not an inline swap, we use the content of the node, not the node itself - } - swap(swapStyle, target, target, fragment, settleInfo); + var targets = getDocument().querySelectorAll(selector); + if (targets) { + forEach( + targets, + function (target) { + var fragment; + var oobElementClone = oobElement.cloneNode(true); + fragment = getDocument().createDocumentFragment(); + fragment.appendChild(oobElementClone); + if (!isInlineSwap(swapStyle, target)) { + fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself + } + + var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment }; + if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return; + + target = beforeSwapDetails.target; // allow re-targeting + if (beforeSwapDetails['shouldSwap']){ + swap(swapStyle, target, target, fragment, settleInfo); + } + forEach(settleInfo.elts, function (elt) { + triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails); + }); + } + ); + oobElement.parentNode.removeChild(oobElement); } else { oobElement.parentNode.removeChild(oobElement); - triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}) + triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}); } return oobValue; } @@ -540,6 +739,7 @@ return (function () { function makeAjaxLoadTask(child) { return function () { + removeClassFromElement(child, htmx.config.addedClass); processNode(child); processScripts(child); processFocus(child) @@ -559,6 +759,7 @@ return (function () { handleAttributes(parentNode, fragment, settleInfo); while(fragment.childNodes.length > 0){ var child = fragment.firstChild; + addClassToElement(child, htmx.config.addedClass); parentNode.insertBefore(child, insertBefore); if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { settleInfo.tasks.push(makeAjaxLoadTask(child)); @@ -574,6 +775,9 @@ return (function () { if (internalData.sseEventSource) { internalData.sseEventSource.close(); } + + triggerEvent(element, "htmx:beforeCleanupElement") + if (internalData.listenerInfos) { forEach(internalData.listenerInfos, function(info) { if (element !== info.on) { @@ -590,12 +794,14 @@ return (function () { if (target.tagName === "BODY") { return swapInnerHTML(target, fragment, settleInfo); } else { + // @type {HTMLElement} + var newElt var eltBeforeNewContent = target.previousSibling; insertNodesBefore(parentElt(target), target, fragment, settleInfo); if (eltBeforeNewContent == null) { - var newElt = parentElt(target).firstChild; + newElt = parentElt(target).firstChild; } else { - var newElt = eltBeforeNewContent.nextSibling; + newElt = eltBeforeNewContent.nextSibling; } getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later settleInfo.elts = [] // clear existing elements @@ -625,6 +831,10 @@ return (function () { function swapAfterEnd(target, fragment, settleInfo) { return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo); } + function swapDelete(target, fragment, settleInfo) { + cleanUpElement(target); + return parentElt(target).removeChild(target); + } function swapInnerHTML(target, fragment, settleInfo) { var firstChild = target.firstChild; @@ -670,6 +880,9 @@ return (function () { case "afterend": swapAfterEnd(target, fragment, settleInfo); return; + case "delete": + swapDelete(target, fragment, settleInfo); + return; default: var extensions = getExtensions(elt); for (var i = 0; i < extensions.length; i++) { @@ -692,32 +905,27 @@ return (function () { logError(e); } } - swapInnerHTML(target, fragment, settleInfo); + if (swapStyle === "innerHTML") { + swapInnerHTML(target, fragment, settleInfo); + } else { + swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo); + } } } - var TITLE_FINDER = /([\s\S]+?)<\/title>/im; function findTitle(content) { - if(content.indexOf('<title>') > -1 && - (content.indexOf('<svg>') == -1 || - content.indexOf('<title>') < content.indexOf('<svg>'))) { - var result = TITLE_FINDER.exec(content); + if (content.indexOf('<title') > -1) { + var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, ''); + var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im); + if (result) { - return result[1]; + return result[2]; } } } function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) { - var title = findTitle(responseText); - if(title) { - var titleElt = find("title"); - if(titleElt) { - titleElt.innerHTML = title; - } else { - window.document.title = title; - } - } + settleInfo.title = findTitle(responseText); var fragment = makeFragment(responseText); if (fragment) { handleOutOfBandSwaps(fragment, settleInfo); @@ -840,6 +1048,11 @@ return (function () { } var INPUT_SELECTOR = 'input, textarea, select'; + + /** + * @param {HTMLElement} elt + * @returns {import("./htmx").HtmxTriggerSpecification[]} + */ function getTriggerSpecs(elt) { var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); var triggerSpecs = []; @@ -853,7 +1066,12 @@ return (function () { if (trigger === "every") { var every = {trigger: 'every'}; consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, WHITESPACE)); + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); + consumeUntil(tokens, NOT_WHITESPACE); + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + every.eventFilter = eventFilter; + } triggerSpecs.push(every); } else if (trigger.indexOf("sse:") === 0) { triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); @@ -877,7 +1095,17 @@ return (function () { triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); } else if (token === "from" && tokens[0] === ":") { tokens.shift(); - triggerSpec.from = consumeUntil(tokens, WHITESPACE_OR_COMMA); + var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); + if (from_arg === "closest" || from_arg === "find") { + tokens.shift(); + from_arg += + " " + + consumeUntil( + tokens, + WHITESPACE_OR_COMMA + ); + } + triggerSpec.from = from_arg; } else if (token === "target" && tokens[0] === ":") { tokens.shift(); triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA); @@ -919,14 +1147,16 @@ return (function () { getInternalData(elt).cancelled = true; } - function processPolling(elt, verb, path, interval) { + function processPolling(elt, verb, path, spec) { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - issueAjaxRequest(verb, path, elt); - processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), interval); + if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { + issueAjaxRequest(verb, path, elt); + } + processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), spec); } - }, interval); + }, spec.pollInterval); } function isLocalLink(elt) { @@ -936,7 +1166,7 @@ return (function () { } function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt)) || elt.tagName === "FORM") { + if ((elt.tagName === "A" && isLocalLink(elt) && elt.target === "") || elt.tagName === "FORM") { nodeData.boosted = true; var verb, path; if (elt.tagName === "A") { @@ -957,11 +1187,26 @@ return (function () { } } - function shouldCancel(elt) { - return elt.tagName === "FORM" || - (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) || - (elt.tagName === "A" && elt.href && (elt.getAttribute('href') === '#' || - elt.getAttribute('href').indexOf("#") !== 0)); + /** + * + * @param {Event} evt + * @param {HTMLElement} elt + * @returns + */ + function shouldCancel(evt, elt) { + if (evt.type === "submit" || evt.type === "click") { + if (elt.tagName === "FORM") { + return true; + } + if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { + return true; + } + if (elt.tagName === "A" && elt.href && + (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) { + return true; + } + } + return false; } function ignoreBoostedAnchorCtrlClick(elt, evt) { @@ -982,86 +1227,90 @@ return (function () { } function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { - var eltToListenOn = elt; + var eltsToListenOn; if (triggerSpec.from) { - eltToListenOn = find(triggerSpec.from); + eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); + } else { + eltsToListenOn = [elt]; } - var eventListener = function (evt) { - if (!bodyContains(elt)) { - eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); - return; - } - if (ignoreBoostedAnchorCtrlClick(elt, evt)) { - return; - } - if(explicitCancel || shouldCancel(elt)){ - evt.preventDefault(); - } - if (maybeFilterEvent(triggerSpec, evt)) { - return; - } - var eventData = getInternalData(evt); - eventData.triggerSpec = triggerSpec; - if (eventData.handledFor == null) { - eventData.handledFor = []; - } - var elementData = getInternalData(elt); - if (eventData.handledFor.indexOf(elt) < 0) { - eventData.handledFor.push(elt); - if (triggerSpec.consume) { - evt.stopPropagation(); - } - if (triggerSpec.target && evt.target) { - if (!matches(evt.target, triggerSpec.target)) { - return; - } - } - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } + forEach(eltsToListenOn, function (eltToListenOn) { + var eventListener = function (evt) { + if (!bodyContains(elt)) { + eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); + return; } - if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { - return; - } else { - elementData.lastValue = elt.value; - } + if (ignoreBoostedAnchorCtrlClick(elt, evt)) { + return; } - if (elementData.delayed) { - clearTimeout(elementData.delayed); + if (explicitCancel || shouldCancel(evt, elt)) { + evt.preventDefault(); } - if (elementData.throttle) { + if (maybeFilterEvent(triggerSpec, evt)) { return; } + var eventData = getInternalData(evt); + eventData.triggerSpec = triggerSpec; + if (eventData.handledFor == null) { + eventData.handledFor = []; + } + var elementData = getInternalData(elt); + if (eventData.handledFor.indexOf(elt) < 0) { + eventData.handledFor.push(elt); + if (triggerSpec.consume) { + evt.stopPropagation(); + } + if (triggerSpec.target && evt.target) { + if (!matches(evt.target, triggerSpec.target)) { + return; + } + } + 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); + } + if (elementData.throttle) { + return; + } - if (triggerSpec.throttle) { - if(!elementData.throttle) { + if (triggerSpec.throttle) { + if (!elementData.throttle) { + issueAjaxRequest(verb, path, elt, evt); + elementData.throttle = setTimeout(function () { + elementData.throttle = null; + }, triggerSpec.throttle); + } + } else if (triggerSpec.delay) { + elementData.delayed = setTimeout(function () { + issueAjaxRequest(verb, path, elt, evt); + }, triggerSpec.delay); + } else { issueAjaxRequest(verb, path, elt, evt); - elementData.throttle = setTimeout(function(){ - elementData.throttle = null; - }, triggerSpec.throttle); } - } else if (triggerSpec.delay) { - elementData.delayed = setTimeout(function(){ - issueAjaxRequest(verb, path, elt, evt); - }, triggerSpec.delay); - } else { - issueAjaxRequest(verb, path, elt, evt); } - } - }; - if (nodeData.listenerInfos == null) { - nodeData.listenerInfos = []; - } - nodeData.listenerInfos.push({ - trigger: triggerSpec.trigger, - listener: eventListener, - on: eltToListenOn + }; + if (nodeData.listenerInfos == null) { + nodeData.listenerInfos = []; + } + nodeData.listenerInfos.push({ + trigger: triggerSpec.trigger, + listener: eventListener, + on: eltToListenOn + }) + eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); }) - eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); } var windowIsScrolling = false // used by initScrollHandler @@ -1084,9 +1333,9 @@ return (function () { } function maybeReveal(elt) { - var nodeData = getInternalData(elt); - if (!nodeData.revealed && isScrolledIntoView(elt)) { - nodeData.revealed = true; + if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { + elt.setAttribute('data-hx-revealed', 'true'); + var nodeData = getInternalData(elt); if (nodeData.initialized) { issueAjaxRequest(nodeData.verb, nodeData.path, elt); } else { @@ -1099,6 +1348,10 @@ return (function () { } } + //==================================================================== + // Web Sockets + //==================================================================== + function processWebSocketInfo(elt, nodeData, info) { var values = splitOnWhitespace(info); for (var i = 0; i < values.length; i++) { @@ -1132,7 +1385,7 @@ return (function () { }; socket.onclose = function (e) { - if ([1006, 1012, 1013].includes(e.code)) { // Abnormal Closure/Service Restart/Try Again Later + if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later var delay = getWebSocketReconnectDelay(retryCount); setTimeout(function() { ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout @@ -1193,7 +1446,7 @@ return (function () { return; } webSocket.send(JSON.stringify(filteredParameters)); - if(shouldCancel(elt)){ + if(shouldCancel(evt, elt)){ evt.preventDefault(); } }); @@ -1205,6 +1458,7 @@ return (function () { function getWebSocketReconnectDelay(retryCount) { var delay = htmx.config.wsReconnectDelay; if (typeof delay === 'function') { + // @ts-ignore return delay(retryCount); } if (delay === 'full-jitter') { @@ -1340,7 +1594,7 @@ return (function () { } else if (triggerSpec.trigger === "intersect") { var observerOptions = {}; if (triggerSpec.root) { - observerOptions.root = querySelectorExt(triggerSpec.root) + observerOptions.root = querySelectorExt(elt, triggerSpec.root) } if (triggerSpec.threshold) { observerOptions.threshold = parseFloat(triggerSpec.threshold); @@ -1360,7 +1614,7 @@ return (function () { loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); } else if (triggerSpec.pollInterval) { nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec.pollInterval); + processPolling(elt, verb, path, triggerSpec); } else { addEventListener(elt, verb, path, nodeData, triggerSpec); } @@ -1371,14 +1625,24 @@ return (function () { } function evalScript(script) { - if (script.type === "text/javascript" || script.type === "") { + if (script.type === "text/javascript" || script.type === "module" || script.type === "") { + var newScript = getDocument().createElement("script"); + forEach(script.attributes, function (attr) { + newScript.setAttribute(attr.name, attr.value); + }); + newScript.textContent = script.textContent; + newScript.async = false; + if (htmx.config.inlineScriptNonce) { + newScript.nonce = htmx.config.inlineScriptNonce; + } + var parent = script.parentElement; + try { - maybeEval(script, function () { - // wtf - https://stackoverflow.com/questions/9107240/1-evalthis-vs-evalthis-in-javascript - (1, eval)(script.innerText); - }); + parent.insertBefore(newScript, script); } catch (e) { logError(e); + } finally { + parent.removeChild(script); } } } @@ -1392,21 +1656,41 @@ return (function () { }); } - function isBoosted() { + function hasChanceOfBeingBoosted() { return document.querySelector("[hx-boost], [data-hx-boost]"); } function findElementsToProcess(elt) { if (elt.querySelectorAll) { - var boostedElts = isBoosted() ? ", a, form" : ""; + var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws]"); + " [data-hx-ws], [hx-ext], [hx-data-ext]"); return results; } else { return []; } } + function initButtonTracking(form){ + var maybeSetLastButtonClicked = function(evt){ + if (matches(evt.target, "button, input[type='submit']")) { + var internalData = getInternalData(form); + internalData.lastButtonClicked = evt.target; + } + }; + + // need to handle both click and focus in: + // focusin - in case someone tabs in to a button and hits the space bar + // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + + form.addEventListener('click', maybeSetLastButtonClicked) + form.addEventListener('focusin', maybeSetLastButtonClicked) + form.addEventListener('focusout', function(evt){ + var internalData = getInternalData(form); + internalData.lastButtonClicked = null; + }) + } + function initNode(elt) { if (elt.closest && elt.closest(htmx.config.disableSelector)) { return; @@ -1427,6 +1711,10 @@ return (function () { boostElement(elt, nodeData, triggerSpecs); } + if (elt.tagName === "FORM") { + initButtonTracking(elt); + } + var sseInfo = getAttributeValue(elt, 'hx-sse'); if (sseInfo) { processSSEInfo(elt, nodeData, sseInfo); @@ -1473,6 +1761,15 @@ return (function () { return eventName === "htmx:afterProcessNode" } + /** + * `withExtensions` locates all active extensions for a provided element, then + * executes the provided function using each of the active extensions. It should + * be called internally at every extendable execution point in htmx. + * + * @param {HTMLElement} elt + * @param {(extension:import("./htmx").HtmxExtension) => void} toDo + * @returns void + */ function withExtensions(elt, toDo) { forEach(getExtensions(elt), function(extension){ try { @@ -1520,7 +1817,7 @@ return (function () { //==================================================================== // History Support //==================================================================== - var currentPathForHistory = null; + var currentPathForHistory = location.pathname+location.search; function getHistoryElement() { var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]'); @@ -1569,7 +1866,7 @@ return (function () { return clone.innerHTML; } - function saveHistory() { + function saveCurrentPageToHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); @@ -1598,9 +1895,11 @@ return (function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); var fragment = makeFragment(this.response); + // @ts-ignore fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; var historyElement = getHistoryElement(); var settleInfo = makeSettleInfo(historyElement); + // @ts-ignore swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); currentPathForHistory = path; @@ -1613,7 +1912,7 @@ return (function () { } function restoreHistory(path) { - saveHistory(); + saveCurrentPageToHistory(); path = path || location.pathname+location.search; var cached = getCachedHistory(path); if (cached) { @@ -1628,6 +1927,8 @@ return (function () { triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); } else { if (htmx.config.refreshOnHistoryMiss) { + + // @ts-ignore: optional parameter in reload() function throws error window.location.reload(true); } else { loadHistoryFromServer(path); @@ -1647,10 +1948,8 @@ return (function () { } function addRequestIndicatorClasses(elt) { - var indicator = getClosestAttributeValue(elt, 'hx-indicator'); - if (indicator) { - var indicators = querySelectorAllExt(elt, indicator); - } else { + var indicators = findAttributeTargets(elt, 'hx-indicator'); + if (indicators == null) { indicators = [elt]; } forEach(indicators, function (ic) { @@ -1753,14 +2052,22 @@ return (function () { } } + /** + * @param {HTMLElement} elt + * @param {string} verb + */ function getInputValues(elt, verb) { var processed = []; var values = {}; var formValues = {}; var errors = []; + var internalData = getInternalData(elt); - // only validate when form is directly submitted and novalidate is not set + // only validate when form is directly submitted and novalidate or formnovalidate are not set var validate = matches(elt, 'form') && elt.noValidate !== true; + if (internalData.lastButtonClicked) { + validate = validate && internalData.lastButtonClicked.formNoValidate !== true; + } // for a non-GET include the closest form if (verb !== 'get') { @@ -1770,21 +2077,26 @@ return (function () { // include the element itself processInputValue(processed, values, errors, elt, validate); - // include any explicit includes - var includes = getClosestAttributeValue(elt, "hx-include"); - if (includes) { - var nodes = querySelectorAllExt(elt, includes); - forEach(nodes, function(node) { - processInputValue(processed, values, errors, node, validate); - // if a non-form is included, include any input values within it - if (!matches(node, 'form')) { - forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { - processInputValue(processed, values, errors, descendant, validate); - }) - } - }); + // if a button or submit was clicked last, include its value + if (internalData.lastButtonClicked) { + var name = getRawAttribute(internalData.lastButtonClicked,"name"); + if (name) { + values[name] = internalData.lastButtonClicked.value; + } } + // include any explicit includes + var includes = findAttributeTargets(elt, "hx-include"); + forEach(includes, function(node) { + processInputValue(processed, values, errors, node, validate); + // if a non-form is included, include any input values within it + if (!matches(node, 'form')) { + forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { + processInputValue(processed, values, errors, descendant, validate); + }) + } + }); + // form values take precedence, overriding the regular values values = mergeObjects(values, formValues); @@ -1795,7 +2107,11 @@ return (function () { if (returnStr !== "") { returnStr += "&"; } - returnStr += encodeURIComponent(name) + "=" + encodeURIComponent(realValue); + if (String(realValue) === "[object Object]") { + realValue = JSON.stringify(realValue); + } + var s = encodeURIComponent(realValue); + returnStr += encodeURIComponent(name) + "=" + s; return returnStr; } @@ -1837,6 +2153,12 @@ return (function () { // Ajax //==================================================================== + /** + * @param {HTMLElement} elt + * @param {HTMLElement} target + * @param {string} prompt + * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification + */ function getHeaders(elt, target, prompt) { var headers = { "HX-Request" : "true", @@ -1849,9 +2171,20 @@ return (function () { if (prompt !== undefined) { headers["HX-Prompt"] = prompt; } + if (getInternalData(elt).boosted) { + headers["HX-Boosted"] = "true"; + } return headers; } + /** + * filterValues takes an object containing form input values + * and returns a new object that only contains keys that are + * specified by the closest "hx-params" attribute + * @param {Object} inputValues + * @param {HTMLElement} elt + * @returns {Object} + */ function filterValues(inputValues, elt) { var paramsValue = getClosestAttributeValue(elt, "hx-params"); if (paramsValue) { @@ -1882,8 +2215,14 @@ return (function () { return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0 } - function getSwapSpecification(elt) { - var swapInfo = getClosestAttributeValue(elt, "hx-swap"); + /** + * + * @param {HTMLElement} elt + * @param {string} swapInfoOverride + * @returns {import("./htmx").HtmxSwapSpecification} + */ + function getSwapSpecification(elt, swapInfoOverride) { + var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap"); var swapSpec = { "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, "swapDelay" : htmx.config.defaultSwapDelay, @@ -1905,10 +2244,24 @@ return (function () { swapSpec["settleDelay"] = parseInterval(modifier.substr(7)); } if (modifier.indexOf("scroll:") === 0) { - swapSpec["scroll"] = modifier.substr(7); + var scrollSpec = modifier.substr(7); + var splitSpec = scrollSpec.split(":"); + var scrollVal = splitSpec.pop(); + var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; + swapSpec["scroll"] = scrollVal; + swapSpec["scrollTarget"] = selectorVal; } if (modifier.indexOf("show:") === 0) { - swapSpec["show"] = modifier.substr(5); + var showSpec = modifier.substr(5); + var splitSpec = showSpec.split(":"); + var showVal = splitSpec.pop(); + var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; + swapSpec["show"] = showVal; + swapSpec["showTarget"] = selectorVal; + } + if (modifier.indexOf("focus-scroll:") === 0) { + var focusScrollVal = modifier.substr("focus-scroll:".length); + swapSpec["focusScroll"] = focusScrollVal == "true"; } } } @@ -1926,7 +2279,8 @@ return (function () { if (encodedParameters != null) { return encodedParameters; } else { - if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data") { + if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || + (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) { return makeFormData(filteredParameters); } else { return urlEncode(filteredParameters); @@ -1934,6 +2288,11 @@ return (function () { } } + /** + * + * @param {Element} target + * @returns {import("./htmx").HtmxSettleInfo} + */ function makeSettleInfo(target) { return {tasks: [], elts: [target]}; } @@ -1942,23 +2301,46 @@ return (function () { var first = content[0]; var last = content[content.length - 1]; if (swapSpec.scroll) { - if (swapSpec.scroll === "top" && first) { - first.scrollTop = 0; + var target = null; + if (swapSpec.scrollTarget) { + target = querySelectorExt(first, swapSpec.scrollTarget); + } + if (swapSpec.scroll === "top" && (first || target)) { + target = target || first; + target.scrollTop = 0; } - if (swapSpec.scroll === "bottom" && last) { - last.scrollTop = last.scrollHeight; + if (swapSpec.scroll === "bottom" && (last || target)) { + target = target || last; + target.scrollTop = target.scrollHeight; } } if (swapSpec.show) { - if (swapSpec.show === "top" && first) { - first.scrollIntoView(true); + var target = null; + if (swapSpec.showTarget) { + var targetStr = swapSpec.showTarget; + if (swapSpec.showTarget === "window") { + targetStr = "body"; + } + target = querySelectorExt(first, targetStr); + } + if (swapSpec.show === "top" && (first || target)) { + target = target || first; + target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior}); } - if (swapSpec.show === "bottom" && last) { - last.scrollIntoView(false); + if (swapSpec.show === "bottom" && (last || target)) { + target = target || last; + target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior}); } } } + /** + * @param {HTMLElement} elt + * @param {string} attr + * @param {boolean=} evalAsDefault + * @param {Object=} values + * @returns {Object} + */ function getValuesForElement(elt, attr, evalAsDefault, values) { if (values == null) { values = {}; @@ -1973,6 +2355,9 @@ return (function () { if (str.indexOf("javascript:") === 0) { str = str.substr(11); evaluateValue = true; + } else if (str.indexOf("js:") === 0) { + str = str.substr(3); + evaluateValue = true; } if (str.indexOf('{') !== 0) { str = "{" + str + "}"; @@ -2003,14 +2388,28 @@ return (function () { } } + /** + * @param {HTMLElement} elt + * @param {*} expressionVars + * @returns + */ function getHXVarsForElement(elt, expressionVars) { return getValuesForElement(elt, "hx-vars", true, expressionVars); } + /** + * @param {HTMLElement} elt + * @param {*} expressionVars + * @returns + */ function getHXValsForElement(elt, expressionVars) { return getValuesForElement(elt, "hx-vals", false, expressionVars); } + /** + * @param {HTMLElement} elt + * @returns {Object} + */ function getExpressionVars(elt) { return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)); } @@ -2044,10 +2443,12 @@ return (function () { } function ajaxHelper(verb, path, context) { + verb = verb.toLowerCase(); if (context) { if (context instanceof Element || isType(context, 'String')) { return issueAjaxRequest(verb, path, null, null, { - targetOverride: resolveTarget(context) + targetOverride: resolveTarget(context), + returnPromise: true }); } else { return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, @@ -2055,11 +2456,15 @@ return (function () { handler : context.handler, headers : context.headers, values : context.values, - targetOverride: resolveTarget(context.target) + targetOverride: resolveTarget(context.target), + swapOverride: context.swap, + returnPromise: true }); } } else { - return issueAjaxRequest(verb, path); + return issueAjaxRequest(verb, path, null, null, { + returnPromise: true + }); } } @@ -2076,7 +2481,7 @@ return (function () { var resolve = null; var reject = null; etc = etc != null ? etc : {}; - if(typeof Promise !== "undefined"){ + if(etc.returnPromise && typeof Promise !== "undefined"){ var promise = new Promise(function (_resolve, _reject) { resolve = _resolve; reject = _reject; @@ -2091,40 +2496,85 @@ return (function () { return; // do not issue requests for elements removed from the DOM } var target = etc.targetOverride || getTarget(elt); - if (target == null) { + if (target == null || target == DUMMY_ELT) { triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); return; } + + var syncElt = elt; var eltData = getInternalData(elt); - if (eltData.requestInFlight) { - var queueStrategy = 'last'; - var eventData = getInternalData(event); - if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { - queueStrategy = eventData.triggerSpec.queue; - } - if (eltData.queuedRequests == null) { - eltData.queuedRequests = []; - } - if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); - } else if (queueStrategy === "all") { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); - } else if (queueStrategy === "last") { - eltData.queuedRequests = []; // dump existing queue - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); + var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); + var queueStrategy = null; + var abortable = false; + if (syncStrategy) { + var syncStrings = syncStrategy.split(":"); + var selector = syncStrings[0].trim(); + if (selector === "this") { + syncElt = findThisElement(elt, 'hx-sync'); + } else { + syncElt = querySelectorExt(elt, selector); + } + // default to the drop strategy + syncStrategy = (syncStrings[1] || 'drop').trim(); + eltData = getInternalData(syncElt); + if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { + return; + } else if (syncStrategy === "abort") { + if (eltData.xhr) { + return; + } else { + abortable = true; + } + } else if (syncStrategy === "replace") { + triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue + } else if (syncStrategy.indexOf("queue") === 0) { + var queueStrArray = syncStrategy.split(" "); + queueStrategy = (queueStrArray[1] || "last").trim(); } - return; - } else { - eltData.requestInFlight = true; } + + if (eltData.xhr) { + if (eltData.abortable) { + triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue + } else { + if(queueStrategy == null){ + if (event) { + var eventData = getInternalData(event); + if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { + queueStrategy = eventData.triggerSpec.queue; + } + } + if (queueStrategy == null) { + queueStrategy = "last"; + } + } + if (eltData.queuedRequests == null) { + eltData.queuedRequests = []; + } + if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } else if (queueStrategy === "all") { + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } else if (queueStrategy === "last") { + eltData.queuedRequests = []; // dump existing queue + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } + return; + } + } + + var xhr = new XMLHttpRequest(); + eltData.xhr = xhr; + eltData.abortable = abortable; var endRequestLock = function(){ - eltData.requestInFlight = false + eltData.xhr = null; + eltData.abortable = false; if (eltData.queuedRequests != null && eltData.queuedRequests.length > 0) { var queuedRequest = eltData.queuedRequests.shift(); @@ -2152,11 +2602,10 @@ return (function () { } } - var xhr = new XMLHttpRequest(); var headers = getHeaders(elt, target, promptResponse); if (etc.headers) { - headers = mergeObjects(headers, etc.values); + headers = mergeObjects(headers, etc.headers); } var results = getInputValues(elt, verb); var errors = results.errors; @@ -2169,7 +2618,7 @@ return (function () { var filteredParameters = filterValues(allParameters, elt); if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null) { - headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; + headers['Content-Type'] = 'application/x-www-form-urlencoded'; } // behavior of anchors w/ empty href is to use the current URL @@ -2177,6 +2626,8 @@ return (function () { path = getDocument().location.href; } + var requestAttrValues = getValuesForElement(elt, 'hx-request'); + var requestConfig = { parameters: filteredParameters, unfilteredParameters: allParameters, @@ -2184,6 +2635,8 @@ return (function () { target:target, verb:verb, errors:errors, + withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, + timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, path:path, triggeringEvent:event }; @@ -2231,17 +2684,22 @@ return (function () { } xhr.overrideMimeType("text/html"); - xhr.withCredentials = htmx.config.withCredentials; + xhr.withCredentials = requestConfig.withCredentials; + xhr.timeout = requestConfig.timeout; // request headers - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - var headerValue = headers[header]; - safelySetHeaderValue(xhr, header, headerValue); + if (requestAttrValues.noHeaders) { + // ignore all headers + } else { + for (var header in headers) { + if (headers.hasOwnProperty(header)) { + var headerValue = headers[header]; + safelySetHeaderValue(xhr, header, headerValue); + } } } - var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, pathInfo:{ + var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, etc:etc, pathInfo:{ path:path, finalPath:finalPathForGet, anchor:anchor } }; @@ -2289,6 +2747,13 @@ return (function () { maybeCall(reject); endRequestLock(); } + xhr.ontimeout = function() { + removeRequestIndicatorClasses(indicators); + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); + triggerErrorEvent(elt, 'htmx:timeout', responseInfo); + maybeCall(reject); + endRequestLock(); + } if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){ maybeCall(resolve); endRequestLock() @@ -2315,6 +2780,7 @@ return (function () { function handleAjaxResponse(elt, responseInfo) { var xhr = responseInfo.xhr; var target = responseInfo.target; + var etc = responseInfo.etc; if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; @@ -2338,123 +2804,162 @@ return (function () { } } - var shouldSaveHistory = shouldPush(elt) || pushedUrl; + if (hasHeader(xhr,/HX-Retarget:/i)) { + responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget")); + } - if (xhr.status >= 200 && xhr.status < 400) { + /** @type {boolean} */ + var shouldSaveHistory + if (pushedUrl == "false") { + shouldSaveHistory = false + } else { + shouldSaveHistory = shouldPush(elt) || pushedUrl; + } + + // by default htmx only swaps on 200 return codes and does not swap + // on 204 'No Content' + // this can be ovverriden by responding to the htmx:beforeSwap event and + // overriding the detail.shouldSwap property + var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; + var serverResponse = xhr.response; + var isError = xhr.status >= 400; + var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo); + if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; + + target = beforeSwapDetails.target; // allow re-targeting + serverResponse = beforeSwapDetails.serverResponse; // allow updating content + isError = beforeSwapDetails.isError; // allow updating error + + responseInfo.failed = isError; // Make failed property available to response events + responseInfo.successful = !isError; // Make successful property available to response events + + if (beforeSwapDetails.shouldSwap) { if (xhr.status === 286) { cancelPolling(elt); } - // don't process 'No Content' - if (xhr.status !== 204) { - if (!triggerEvent(target, 'htmx:beforeSwap', responseInfo)) return; - var serverResponse = xhr.response; - withExtensions(elt, function(extension){ - serverResponse = extension.transformResponse(serverResponse, xhr, elt); - }); + withExtensions(elt, function (extension) { + serverResponse = extension.transformResponse(serverResponse, xhr, elt); + }); - // Save current page - if (shouldSaveHistory) { - saveHistory(); - } + // Save current page + if (shouldSaveHistory) { + saveCurrentPageToHistory(); + } + + var swapOverride = etc.swapOverride; + var swapSpec = getSwapSpecification(elt, swapOverride); - var swapSpec = getSwapSpecification(elt); + target.classList.add(htmx.config.swappingClass); + var doSwap = function () { + try { - target.classList.add(htmx.config.swappingClass); - var doSwap = function () { + var activeElt = document.activeElement; + var selectionInfo = {}; try { + selectionInfo = { + elt: activeElt, + // @ts-ignore + start: activeElt ? activeElt.selectionStart : null, + // @ts-ignore + end: activeElt ? activeElt.selectionEnd : null + }; + } catch (e) { + // safari issue - see https://github.com/microsoft/playwright/issues/5894 + } - var activeElt = document.activeElement; - var selectionInfo = {}; - try { - selectionInfo = { - elt: activeElt, - start: activeElt ? activeElt.selectionStart : null, - end: activeElt ? activeElt.selectionEnd : null - }; - } catch (e) { - // safari issue - see https://github.com/microsoft/playwright/issues/5894 + var settleInfo = makeSettleInfo(target); + selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + + if (selectionInfo.elt && + !bodyContains(selectionInfo.elt) && + selectionInfo.elt.id) { + var newActiveElt = document.getElementById(selectionInfo.elt.id); + var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; + if (newActiveElt) { + // @ts-ignore + if (selectionInfo.start && newActiveElt.setSelectionRange) { + // @ts-ignore + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + } + newActiveElt.focus(focusOptions); } + } - var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + target.classList.remove(htmx.config.swappingClass); + forEach(settleInfo.elts, function (elt) { + if (elt.classList) { + elt.classList.add(htmx.config.settlingClass); + } + triggerEvent(elt, 'htmx:afterSwap', responseInfo); + }); + if (responseInfo.pathInfo.anchor) { + location.hash = responseInfo.pathInfo.anchor; + } - if (selectionInfo.elt && - !bodyContains(selectionInfo.elt) && - selectionInfo.elt.id) { - var newActiveElt = document.getElementById(selectionInfo.elt.id); - if (newActiveElt) { - if (selectionInfo.start && newActiveElt.setSelectionRange) { - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); - } - newActiveElt.focus(); - } + if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { + var finalElt = elt; + if (!bodyContains(elt)) { + finalElt = getDocument().body; } + handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); + } - target.classList.remove(htmx.config.swappingClass); + var doSettle = function () { + forEach(settleInfo.tasks, function (task) { + task.call(); + }); forEach(settleInfo.elts, function (elt) { if (elt.classList) { - elt.classList.add(htmx.config.settlingClass); + elt.classList.remove(htmx.config.settlingClass); } - triggerEvent(elt, 'htmx:afterSwap', responseInfo); + triggerEvent(elt, 'htmx:afterSettle', responseInfo); }); - if (responseInfo.pathInfo.anchor) { - location.hash = responseInfo.pathInfo.anchor; + // push URL and save new page + if (shouldSaveHistory) { + var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; + pushUrlIntoHistory(pathToPush); + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: pathToPush}); } - if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; + if(settleInfo.title) { + var titleElt = find("title"); + if(titleElt) { + titleElt.innerHTML = settleInfo.title; + } else { + window.document.title = settleInfo.title; } - handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); } - var doSettle = function(){ - forEach(settleInfo.tasks, function (task) { - task.call(); - }); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.remove(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSettle', responseInfo); - }); - // push URL and save new page - if (shouldSaveHistory) { - var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; - pushUrlIntoHistory(pathToPush); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path:pathToPush}); - } - updateScrollState(settleInfo.elts, swapSpec); + updateScrollState(settleInfo.elts, swapSpec); - if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); + if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { + var finalElt = elt; + if (!bodyContains(elt)) { + finalElt = getDocument().body; } + handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'htmx:swapError', responseInfo); - throw e; } - }; - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); + if (swapSpec.settleDelay > 0) { + setTimeout(doSettle, swapSpec.settleDelay) + } else { + doSettle(); + } + } catch (e) { + triggerErrorEvent(elt, 'htmx:swapError', responseInfo); + throw e; } + }; + + if (swapSpec.swapDelay > 0) { + setTimeout(doSwap, swapSpec.swapDelay) + } else { + doSwap(); } - } else { + } + if (isError) { triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.path}, responseInfo)); } } @@ -2462,9 +2967,17 @@ return (function () { //==================================================================== // Extensions API //==================================================================== + + /** @type {Object<string, import("./htmx").HtmxExtension>} */ var extensions = {}; + + /** + * extensionBase defines the default functions for all extensions. + * @returns {import("./htmx").HtmxExtension} + */ function extensionBase() { return { + init: function(api) {return null;}, onEvent : function(name, evt) {return true;}, transformResponse : function(text, xhr, elt) {return text;}, isInlineSwap : function(swapStyle) {return false;}, @@ -2473,15 +2986,37 @@ return (function () { } } + /** + * defineExtension initializes the extension and adds it to the htmx registry + * + * @param {string} name + * @param {import("./htmx").HtmxExtension} extension + */ function defineExtension(name, extension) { + if(extension.init) { + extension.init(internalAPI) + } extensions[name] = mergeObjects(extensionBase(), extension); } + /** + * removeExtension removes an extension from the htmx registry + * + * @param {string} name + */ function removeExtension(name) { delete extensions[name]; } - function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + /** + * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element + * + * @param {HTMLElement} elt + * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn + * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore + */ + function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + if (elt == undefined) { return extensionsToReturn; } @@ -2536,6 +3071,7 @@ return (function () { function getMetaConfig() { var element = getDocument().querySelector('meta[name="htmx-config"]'); if (element) { + // @ts-ignore return parseJSON(element.content); } else { return null; @@ -2555,9 +3091,25 @@ return (function () { insertIndicatorStyles(); var body = getDocument().body; processNode(body); + var restoredElts = getDocument().querySelectorAll( + "[hx-trigger='restored'],[data-hx-trigger='restored']" + ); + body.addEventListener("htmx:abort", function (evt) { + var target = evt.target; + var internalData = getInternalData(target); + if (internalData && internalData.xhr) { + internalData.xhr.abort(); + } + }); window.onpopstate = function (event) { if (event.state && event.state.htmx) { restoreHistory(); + forEach(restoredElts, function(elt){ + triggerEvent(elt, 'htmx:restored', { + 'document': getDocument(), + 'triggerEvent': triggerEvent + }); + }); } }; setTimeout(function () { diff --git a/code/ch4_app/ch4_final_video_collector/static/js/htmx.min.js b/code/ch4_app/ch4_final_video_collector/static/js/htmx.min.js index 57f33b2..998414c 100644 --- a/code/ch4_app/ch4_final_video_collector/static/js/htmx.min.js +++ b/code/ch4_app/ch4_final_video_collector/static/js/htmx.min.js @@ -1 +1 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var k={onLoad:t,process:rt,on:I,off:M,trigger:lt,ajax:$t,find:w,findAll:S,closest:L,values:function(e,t){var r=Lt(e,t||"post");return r.values},remove:E,addClass:q,removeClass:R,toggleClass:C,takeClass:O,defineExtension:Qt,removeExtension:er,logAll:b,logger:null,useTemplateFragments:false,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,attributesToSettle:["class","style","width","height"],withCredentials:false,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]"},parseInterval:f,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])}};var r=["get","post","put","delete","patch"];var n=r.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function f(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function l(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function D(e,t){return l(e,t)||l(e,"data-"+t)}function c(e){return e.parentElement}function F(){return document}function h(e,t){if(t(e)){return e}else if(c(e)){return h(c(e),t)}else{return null}}function X(e,t){var r=null;h(e,function(e){return r=D(e,t)});return r}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function i(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 o(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=F().createDocumentFragment()}return i}function u(e){if(k.config.useTemplateFragments){var t=o("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=i(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return o("<table>"+e+"</table>",1);case"col":return o("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return o("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return o("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return o("<div>"+e+"</div>",1);default:return o(e,0)}}}function P(e){if(e){e()}}function a(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function v(e){return a(e,"Function")}function g(e){return a(e,"Object")}function U(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function p(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function j(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function m(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function z(e){return F().body.contains(e)}function y(e){return e.trim().split(/\s+/)}function V(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function x(e){try{return JSON.parse(e)}catch(e){ut(e);return null}}function e(e){return Ut(F().body,function(){return eval(e)})}function t(t){var e=k.on("htmx:load",function(e){t(e.detail.elt)});return e}function b(){k.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function w(e,t){if(t){return e.querySelector(t)}else{return w(F(),e)}}function S(e,t){if(t){return e.querySelectorAll(t)}else{return S(F(),e)}}function E(e,t){e=H(e);if(t){setTimeout(function(){E(e)},t)}else{e.parentElement.removeChild(e)}}function q(e,t,r){e=H(e);if(r){setTimeout(function(){q(e,t)},r)}else{e.classList.add(t)}}function R(e,t,r){e=H(e);if(r){setTimeout(function(){R(e,t)},r)}else{e.classList.remove(t)}}function C(e,t){e=H(e);e.classList.toggle(t)}function O(e,t){e=H(e);j(e.parentElement.children,function(e){R(e,t)});q(e,t)}function L(e,t){e=H(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&c(e))}}function A(e,t){if(t.indexOf("closest ")===0){return[L(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[w(e,t.substr(5))]}else{return F().querySelectorAll(t)}}function T(e,t){return A(e,t)[0]}function H(e){if(a(e,"String")){return w(e)}else{return e}}function N(e,t,r){if(v(t)){return{target:F().body,event:e,listener:t}}else{return{target:H(e),event:t,listener:r}}}function I(t,r,n){rr(function(){var e=N(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=v(r);return e?r:n}function M(t,r,n){rr(function(){var e=N(t,r,n);e.target.removeEventListener(e.event,e.listener)});return v(r)?r:n}function _(e){var t=h(e,function(e){return D(e,"hx-target")!==null});if(t){var r=D(t,"hx-target");if(r==="this"){return t}else{return T(e,r)}}else{var n=U(e);if(n.boosted){return F().body}else{return e}}}function B(e){var t=k.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function W(t,r){j(t.attributes,function(e){if(!r.hasAttribute(e.name)&&B(e.name)){t.removeAttribute(e.name)}});j(r.attributes,function(e){if(B(e.name)){t.setAttribute(e.name,e.value)}})}function $(e,t){var r=tr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){ut(e)}}return e==="outerHTML"}function J(e,t,r){var n="#"+t.id;var i="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){i=e.substr(0,e.indexOf(":"));n=e.substr(e.indexOf(":")+1,e.length)}else{i=e}var o=F().querySelector(n);if(o){var a;a=F().createDocumentFragment();a.appendChild(t);if(!$(i,o)){a=t}le(i,o,o,a,r)}else{t.parentNode.removeChild(t);ot(F().body,"htmx:oobErrorNoTarget",{content:t})}return e}function Z(e,r){j(S(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=D(e,"hx-swap-oob");if(t!=null){J(t,e,r)}})}function G(e){j(S(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=D(e,"id");var r=F().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function K(n,e,i){j(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();W(e,t);i.tasks.push(function(){W(e,r)})}}})}function Y(e){return function(){rt(e);Ye(e);Q(e);lt(e,"htmx:load")}}function Q(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ee(e,t,r,n){K(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Y(i))}}}function te(t){var e=U(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}if(e.listenerInfos){j(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){j(t.children,function(e){te(e)})}}function re(e,t,r){if(e.tagName==="BODY"){return se(e,t,r)}else{var n=e.previousSibling;ee(c(e),e,t,r);if(n==null){var i=c(e).firstChild}else{var i=n.nextSibling}U(e).replacedWith=i;r.elts=[];while(i&&i!==e){if(i.nodeType===Node.ELEMENT_NODE){r.elts.push(i)}i=i.nextElementSibling}te(e);c(e).removeChild(e)}}function ne(e,t,r){return ee(e,e.firstChild,t,r)}function ie(e,t,r){return ee(c(e),e,t,r)}function oe(e,t,r){return ee(e,null,t,r)}function ae(e,t,r){return ee(c(e),e.nextSibling,t,r)}function se(e,t,r){var n=e.firstChild;ee(e,n,t,r);if(n){while(n.nextSibling){te(n.nextSibling);e.removeChild(n.nextSibling)}te(n);e.removeChild(n)}}function ue(e,t){var r=X(e,"hx-select");if(r){var n=F().createDocumentFragment();j(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function le(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":re(r,n,i);return;case"afterbegin":ne(r,n,i);return;case"beforebegin":ie(r,n,i);return;case"beforeend":oe(r,n,i);return;case"afterend":ae(r,n,i);return;default:var o=tr(t);for(var a=0;a<o.length;a++){var s=o[a];try{var u=s.handleSwap(e,r,n,i);if(u){if(typeof u.length!=="undefined"){for(var l=0;l<u.length;l++){var f=u[l];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Y(f))}}}return}}catch(e){ut(e)}}se(r,n,i)}}var fe=/<title>([\s\S]+?)<\/title>/im;function ce(e){if(e.indexOf("<title>")>-1&&(e.indexOf("<svg>")==-1||e.indexOf("<title>")<e.indexOf("<svg>"))){var t=fe.exec(e);if(t){return t[1]}}}function he(e,t,r,n,i){var o=ce(n);if(o){var a=w("title");if(a){a.innerHTML=o}else{window.document.title=o}}var s=u(n);if(s){Z(s,i);s=ue(r,s);G(s);return le(e,r,t,s,i)}}function de(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=x(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!g(a)){a={value:a}}lt(r,o,a)}}}else{lt(r,n,[])}}var ve=/\s/;var ge=/[\s,]/;var pe=/[_$a-zA-Z]/;var me=/[_$a-zA-Z0-9]/;var ye=['"',"'","/"];var xe=/[^\s]/;function be(e){var t=[];var r=0;while(r<e.length){if(pe.exec(e.charAt(r))){var n=r;while(me.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(ye.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function we(e,t,r){return pe.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function Se(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Ut(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){ot(F().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(we(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function Ee(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var qe="input, textarea, select";function Re(e){var t=D(e,"hx-trigger");var r=[];if(t){var n=be(t);do{Ee(n,xe);var i=n.length;var o=Ee(n,/[,\[\s]/);if(o!==""){if(o==="every"){var a={trigger:"every"};Ee(n,xe);a.pollInterval=f(Ee(n,ve));r.push(a)}else if(o.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:o.substr(4)})}else{var s={trigger:o};var u=Se(e,n,"event");if(u){s.eventFilter=u}while(n.length>0&&n[0]!==","){Ee(n,xe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=f(Ee(n,ge))}else if(l==="from"&&n[0]===":"){n.shift();s.from=Ee(n,ge)}else if(l==="target"&&n[0]===":"){n.shift();s.target=Ee(n,ge)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=f(Ee(n,ge))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=Ee(n,ge)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=Ee(n,ge)}else{ot(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===i){ot(e,"htmx:syntax:error",{token:n.shift()})}Ee(n,xe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,qe)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ce(e){U(e).cancelled=true}function Oe(e,t,r,n){var i=U(e);i.timeout=setTimeout(function(){if(z(e)&&i.cancelled!==true){Zt(t,r,e);Oe(e,t,D(e,"hx-"+t),n)}},n)}function Le(e){return location.hostname===e.hostname&&l(e,"href")&&l(e,"href").indexOf("#")!==0}function Ae(t,r,e){if(t.tagName==="A"&&Le(t)||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=l(t,"href");r.pushURL=true}else{var o=l(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=l(t,"action")}e.forEach(function(e){Ie(t,n,i,r,e,true)})}}function Te(e){return e.tagName==="FORM"||d(e,'input[type="submit"], button')&&L(e,"form")!==null||e.tagName==="A"&&e.href&&(e.getAttribute("href")==="#"||e.getAttribute("href").indexOf("#")!==0)}function He(e,t){return U(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function Ne(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){ot(F().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Ie(n,i,o,e,a,s){var u=n;if(a.from){u=w(a.from)}var l=function(e){if(!z(n)){u.removeEventListener(a.trigger,l);return}if(He(n,e)){return}if(s||Te(n)){e.preventDefault()}if(Ne(a,e)){return}var t=U(e);t.triggerSpec=a;if(t.handledFor==null){t.handledFor=[]}var r=U(n);if(t.handledFor.indexOf(n)<0){t.handledFor.push(n);if(a.consume){e.stopPropagation()}if(a.target&&e.target){if(!d(e.target,a.target)){return}}if(a.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(a.changed){if(r.lastValue===n.value){return}else{r.lastValue=n.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(a.throttle){if(!r.throttle){Zt(i,o,n,e);r.throttle=setTimeout(function(){r.throttle=null},a.throttle)}}else if(a.delay){r.delayed=setTimeout(function(){Zt(i,o,n,e)},a.delay)}else{Zt(i,o,n,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:a.trigger,listener:l,on:u});u.addEventListener(a.trigger,l)}var Me=false;var ke=null;function De(){if(!ke){ke=function(){Me=true};window.addEventListener("scroll",ke);setInterval(function(){if(Me){Me=false;j(F().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){Fe(e)})}},200)}}function Fe(e){var t=U(e);if(!t.revealed&&m(e)){t.revealed=true;if(t.initialized){Zt(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Zt(t.verb,t.path,e)},{once:true})}}}function Xe(e,t,r){var n=y(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Pe(e,o[1],0)}if(o[0]==="send"){je(e)}}}function Pe(s,r,n){if(!z(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=k.createWebSocket(r);t.onerror=function(e){ot(s,"htmx:wsError",{error:e,socket:t});Ue(s)};t.onclose=function(e){if([1006,1012,1013].includes(e.code)){var t=ze(n);setTimeout(function(){Pe(s,r,n+1)},t)}};t.onopen=function(e){n=0};U(s).webSocket=t;t.addEventListener("message",function(e){if(Ue(s)){return}var t=e.data;st(s,function(e){t=e.transformResponse(t,null,s)});var r=Ft(s);var n=u(t);var i=p(n.children);for(var o=0;o<i.length;o++){var a=i[o];J(D(a,"hx-swap-oob")||"true",a,r)}mt(r.tasks)})}function Ue(e){if(!z(e)){U(e).webSocket.close();return true}}function je(l){var f=h(l,function(e){return U(e).webSocket!=null});if(f){l.addEventListener(Re(l)[0].trigger,function(e){var t=U(f).webSocket;var r=Nt(l,f);var n=Lt(l,"post");var i=n.errors;var o=n.values;var a=Vt(l);var s=V(o,a);var u=It(s,l);u["HEADERS"]=r;if(i&&i.length>0){lt(l,"htmx:validation:halted",i);return}t.send(JSON.stringify(u));if(Te(l)){e.preventDefault()}})}else{ot(l,"htmx:noWebSocketSourceError")}}function ze(e){var t=k.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}ut('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ve(e,t,r){var n=y(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){_e(e,o[1])}if(o[0]==="swap"){Be(e,o[1])}}}function _e(t,e){var r=k.createEventSource(e);r.onerror=function(e){ot(t,"htmx:sseError",{error:e,source:r});$e(t)};U(t).sseEventSource=r}function Be(o,a){var s=h(o,Je);if(s){var u=U(s).sseEventSource;var l=function(e){if($e(s)){u.removeEventListener(a,l);return}var t=e.data;st(o,function(e){t=e.transformResponse(t,null,o)});var r=kt(o);var n=_(o);var i=Ft(o);he(r.swapStyle,o,n,t,i);mt(i.tasks);lt(o,"htmx:sseMessage",e)};U(o).sseListener=l;u.addEventListener(a,l)}else{ot(o,"htmx:noSSESourceError")}}function We(e,t,r,n){var i=h(e,Je);if(i){var o=U(i).sseEventSource;var a=function(){if(!$e(i)){if(z(e)){Zt(t,r,e)}else{o.removeEventListener(n,a)}}};U(e).sseListener=a;o.addEventListener(n,a)}else{ot(e,"htmx:noSSESourceError")}}function $e(e){if(!z(e)){U(e).sseEventSource.close();return true}}function Je(e){return U(e).sseEventSource!=null}function Ze(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Zt(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function Ge(o,a,e){var t=false;j(r,function(n){if(s(o,"hx-"+n)){var i=D(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){We(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){De();Fe(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=T(e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){lt(o,"intersect");break}}},t);r.observe(o);Ie(o,n,i,a,e)}else if(e.trigger==="load"){Ze(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Oe(o,n,i,e.pollInterval)}else{Ie(o,n,i,a,e)}})}});return t}function Ke(e){if(e.type==="text/javascript"||e.type===""){try{Ut(e,function(){(1,eval)(e.innerText)})}catch(e){ut(e)}}}function Ye(e){if(d(e,"script")){Ke(e)}j(S(e,"script"),function(e){Ke(e)})}function Qe(){return document.querySelector("[hx-boost], [data-hx-boost]")}function et(e){if(e.querySelectorAll){var t=Qe()?", a, form":"";var r=e.querySelectorAll(n+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws]");return r}else{return[]}}function tt(e){if(e.closest&&e.closest(k.config.disableSelector)){return}var t=U(e);if(!t.initialized){t.initialized=true;lt(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=Re(e);var n=Ge(e,t,r);if(!n&&X(e,"hx-boost")==="true"){Ae(e,t,r)}var i=D(e,"hx-sse");if(i){Ve(e,t,i)}var o=D(e,"hx-ws");if(o){Xe(e,t,o)}lt(e,"htmx:afterProcessNode")}}function rt(e){e=H(e);tt(e);j(et(e),function(e){tt(e)})}function nt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function it(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=F().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function ot(e,t,r){lt(e,t,V({error:t},r))}function at(e){return e==="htmx:afterProcessNode"}function st(e,t){j(tr(e),function(e){try{t(e)}catch(e){ut(e)}})}function ut(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function lt(e,t,r){e=H(e);if(r==null){r={}}r["elt"]=e;var n=it(t,r);if(k.logger&&!at(t)){k.logger(e,t,r)}if(r.error){ut(r.error);lt(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=nt(t);if(i&&o!==t){var a=it(o,n.detail);i=i&&e.dispatchEvent(a)}st(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var ft=null;function ct(){var e=F().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||F().body}function ht(e,t,r,n){var i=x(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>k.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ot(F().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function dt(e){var t=x(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function vt(e){var t=k.config.requestClass;var r=e.cloneNode(true);j(S(r,"."+t),function(e){R(e,t)});return r.innerHTML}function gt(){var e=ct();var t=ft||location.pathname+location.search;lt(F().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(k.config.historyEnabled)history.replaceState({htmx:true},F().title,window.location.href);ht(t,vt(e),F().title,window.scrollY)}function pt(e){if(k.config.historyEnabled)history.pushState({htmx:true},"",e);ft=e}function mt(e){j(e,function(e){e.call()})}function yt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};lt(F().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){lt(F().body,"htmx:historyCacheMissLoad",i);var e=u(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=ct();var r=Ft(t);se(t,e,r);mt(r.tasks);ft=n;lt(F().body,"htmx:historyRestore",{path:n})}else{ot(F().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function xt(e){gt();e=e||location.pathname+location.search;var t=dt(e);if(t){var r=u(t.content);var n=ct();var i=Ft(n);se(n,r,i);mt(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);ft=e;lt(F().body,"htmx:historyRestore",{path:e})}else{if(k.config.refreshOnHistoryMiss){window.location.reload(true)}else{yt(e)}}}function bt(e){var t=X(e,"hx-push-url");return t&&t!=="false"||U(e).boosted&&U(e).pushURL}function wt(e){var t=X(e,"hx-push-url");return t==="true"||t==="false"?null:t}function St(e){var t=X(e,"hx-indicator");if(t){var r=A(e,t)}else{r=[e]}j(r,function(e){e.classList["add"].call(e.classList,k.config.requestClass)});return r}function Et(e){j(e,function(e){e.classList["remove"].call(e.classList,k.config.requestClass)})}function qt(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Rt(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 Ct(t,r,n,e,i){if(e==null||qt(t,e)){return}else{t.push(e)}if(Rt(e)){var o=l(e,"name");var a=e.value;if(e.multiple){a=p(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=p(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){Ot(e,n)}}if(d(e,"form")){var u=e.elements;j(u,function(e){Ct(t,r,n,e,i)})}}function Ot(e,t){if(e.willValidate){lt(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});lt(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Lt(e,t){var r=[];var n={};var i={};var o=[];var a=d(e,"form")&&e.noValidate!==true;if(t!=="get"){Ct(r,i,o,L(e,"form"),a)}Ct(r,n,o,e,a);var s=X(e,"hx-include");if(s){var u=A(e,s);j(u,function(e){Ct(r,n,o,e,a);if(!d(e,"form")){j(e.querySelectorAll(qe),function(e){Ct(r,n,o,e,a)})}})}n=V(n,i);return{errors:o,values:n}}function At(e,t,r){if(e!==""){e+="&"}e+=encodeURIComponent(t)+"="+encodeURIComponent(r);return e}function Tt(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){j(n,function(e){t=At(t,r,e)})}else{t=At(t,r,n)}}}return t}function Ht(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){j(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Nt(e,t,r){var n={"HX-Request":"true","HX-Trigger":l(e,"id"),"HX-Trigger-Name":l(e,"name"),"HX-Target":D(t,"id"),"HX-Current-URL":F().location.href};Pt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}return n}function It(t,e){var r=X(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){j(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};j(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Mt(e){return l(e,"href")&&l(e,"href").indexOf("#")>=0}function kt(e){var t=X(e,"hx-swap");var r={swapStyle:U(e).boosted?"innerHTML":k.config.defaultSwapStyle,swapDelay:k.config.defaultSwapDelay,settleDelay:k.config.defaultSettleDelay};if(U(e).boosted&&!Mt(e)){r["show"]="top"}if(t){var n=y(t);if(n.length>0){r["swapStyle"]=n[0];for(var i=1;i<n.length;i++){var o=n[i];if(o.indexOf("swap:")===0){r["swapDelay"]=f(o.substr(5))}if(o.indexOf("settle:")===0){r["settleDelay"]=f(o.substr(7))}if(o.indexOf("scroll:")===0){r["scroll"]=o.substr(7)}if(o.indexOf("show:")===0){r["show"]=o.substr(5)}}}}return r}function Dt(t,r,n){var i=null;st(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(X(r,"hx-encoding")==="multipart/form-data"){return Ht(n)}else{return Tt(n)}}}function Ft(e){return{tasks:[],elts:[e]}}function Xt(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){if(t.scroll==="top"&&r){r.scrollTop=0}if(t.scroll==="bottom"&&n){n.scrollTop=n.scrollHeight}}if(t.show){if(t.show==="top"&&r){r.scrollIntoView(true)}if(t.show==="bottom"&&n){n.scrollIntoView(false)}}}function Pt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=D(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Ut(e,function(){return Function("return ("+o+")")()},{})}else{s=x(o)}for(var u in s){if(s.hasOwnProperty(u)){if(n[u]==null){n[u]=s[u]}}}}return Pt(c(e),t,r,n)}function Ut(e,t,r){if(k.config.allowEval){return t()}else{ot(e,"htmx:evalDisallowedError");return r}}function jt(e,t){return Pt(e,"hx-vars",true,t)}function zt(e,t){return Pt(e,"hx-vals",false,t)}function Vt(e){return V(jt(e),zt(e))}function _t(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Bt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ot(F().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Wt(e,t){return e.getAllResponseHeaders().match(t)}function $t(e,t,r){if(r){if(r instanceof Element||a(r,"String")){return Zt(e,t,null,null,{targetOverride:H(r)})}else{return Zt(e,t,H(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:H(r.target)})}}else{return Zt(e,t)}}function Jt(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Zt(e,t,n,r,i){var o=null;var a=null;i=i!=null?i:{};if(typeof Promise!=="undefined"){var s=new Promise(function(e,t){o=e;a=t})}if(n==null){n=F().body}var u=i.handler||Gt;if(!z(n)){return}var l=i.targetOverride||_(n);if(l==null){ot(n,"htmx:targetError",{target:D(n,"hx-target")});return}var f=U(n);if(f.requestInFlight){var c="last";var h=U(r);if(h&&h.triggerSpec&&h.triggerSpec.queue){c=h.triggerSpec.queue}if(f.queuedRequests==null){f.queuedRequests=[]}if(c==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){Zt(e,t,n,r)})}else if(c==="all"){f.queuedRequests.push(function(){Zt(e,t,n,r)})}else if(c==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){Zt(e,t,n,r)})}return}else{f.requestInFlight=true}var d=function(){f.requestInFlight=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var v=X(n,"hx-prompt");if(v){var g=prompt(v);if(g===null||!lt(n,"htmx:prompt",{prompt:g,target:l})){P(o);d();return s}}var p=X(n,"hx-confirm");if(p){if(!confirm(p)){P(o);d();return s}}var m=new XMLHttpRequest;var y=Nt(n,l,g);if(i.headers){y=V(y,i.values)}var x=Lt(n,e);var b=x.errors;var w=x.values;if(i.values){w=V(w,i.values)}var S=Vt(n);var E=V(w,S);var q=It(E,n);if(e!=="get"&&X(n,"hx-encoding")==null){y["Content-Type"]="application/x-www-form-urlencoded; charset=UTF-8"}if(t==null||t===""){t=F().location.href}var R={parameters:q,unfilteredParameters:E,headers:y,target:l,verb:e,errors:b,path:t,triggeringEvent:r};if(!lt(n,"htmx:configRequest",R)){P(o);d();return s}t=R.path;e=R.verb;y=R.headers;q=R.parameters;b=R.errors;if(b&&b.length>0){lt(n,"htmx:validation:halted",R);P(o);d();return s}var C=t.split("#");var O=C[0];var L=C[1];if(e==="get"){var A=O;var T=Object.keys(q).length!==0;if(T){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=Tt(q);if(L){A+="#"+L}}m.open("GET",A,true)}else{m.open(e.toUpperCase(),t,true)}m.overrideMimeType("text/html");m.withCredentials=k.config.withCredentials;for(var H in y){if(y.hasOwnProperty(H)){var N=y[H];_t(m,H,N)}}var I={xhr:m,target:l,requestConfig:R,pathInfo:{path:t,finalPath:A,anchor:L}};m.onload=function(){try{var e=Jt(n);u(n,I);Et(M);lt(n,"htmx:afterRequest",I);lt(n,"htmx:afterOnLoad",I);if(!z(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(z(r)){t=r}}if(t){lt(t,"htmx:afterRequest",I);lt(t,"htmx:afterOnLoad",I)}}P(o);d()}catch(e){ot(n,"htmx:onLoadError",V({error:e},I));throw e}};m.onerror=function(){Et(M);ot(n,"htmx:afterRequest",I);ot(n,"htmx:sendError",I);P(a);d()};m.onabort=function(){Et(M);ot(n,"htmx:afterRequest",I);ot(n,"htmx:sendAbort",I);P(a);d()};if(!lt(n,"htmx:beforeRequest",I)){P(o);d();return s}var M=St(n);j(["loadstart","loadend","progress","abort"],function(t){j([m,m.upload],function(e){e.addEventListener(t,function(e){lt(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});lt(n,"htmx:beforeSend",I);m.send(e==="get"?null:Dt(m,n,q));return s}function Gt(a,s){var u=s.xhr;var l=s.target;if(!lt(a,"htmx:beforeOnLoad",s))return;if(Wt(u,/HX-Trigger:/i)){de(u,"HX-Trigger",a)}if(Wt(u,/HX-Push:/i)){var f=u.getResponseHeader("HX-Push")}if(Wt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Wt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}var c=bt(a)||f;if(u.status>=200&&u.status<400){if(u.status===286){Ce(a)}if(u.status!==204){if(!lt(l,"htmx:beforeSwap",s))return;var h=u.response;st(a,function(e){h=e.transformResponse(h,u,a)});if(c){gt()}var d=kt(a);l.classList.add(k.config.swappingClass);var e=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r=Ft(l);he(d.swapStyle,l,a,h,r);if(t.elt&&!z(t.elt)&&t.elt.id){var n=document.getElementById(t.elt.id);if(n){if(t.start&&n.setSelectionRange){n.setSelectionRange(t.start,t.end)}n.focus()}}l.classList.remove(k.config.swappingClass);j(r.elts,function(e){if(e.classList){e.classList.add(k.config.settlingClass)}lt(e,"htmx:afterSwap",s)});if(s.pathInfo.anchor){location.hash=s.pathInfo.anchor}if(Wt(u,/HX-Trigger-After-Swap:/i)){var i=a;if(!z(a)){i=F().body}de(u,"HX-Trigger-After-Swap",i)}var o=function(){j(r.tasks,function(e){e.call()});j(r.elts,function(e){if(e.classList){e.classList.remove(k.config.settlingClass)}lt(e,"htmx:afterSettle",s)});if(c){var e=f||wt(a)||Bt(u)||s.pathInfo.finalPath||s.pathInfo.path;pt(e);lt(F().body,"htmx:pushedIntoHistory",{path:e})}Xt(r.elts,d);if(Wt(u,/HX-Trigger-After-Settle:/i)){var t=a;if(!z(a)){t=F().body}de(u,"HX-Trigger-After-Settle",t)}};if(d.settleDelay>0){setTimeout(o,d.settleDelay)}else{o()}}catch(e){ot(a,"htmx:swapError",s);throw e}};if(d.swapDelay>0){setTimeout(e,d.swapDelay)}else{e()}}}else{ot(a,"htmx:responseError",V({error:"Response Status Error Code "+u.status+" from "+s.pathInfo.path},s))}}var Kt={};function Yt(){return{onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Qt(e,t){Kt[e]=V(Yt(),t)}function er(e){delete Kt[e]}function tr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=D(e,"hx-ext");if(t){j(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Kt[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return tr(c(e),r,n)}function rr(e){if(F().readyState!=="loading"){e()}else{F().addEventListener("DOMContentLoaded",e)}}function nr(){if(k.config.includeIndicatorStyles!==false){F().head.insertAdjacentHTML("beforeend","<style> ."+k.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+k.config.requestClass+" ."+k.config.indicatorClass+"{opacity:1} ."+k.config.requestClass+"."+k.config.indicatorClass+"{opacity:1} </style>")}}function ir(){var e=F().querySelector('meta[name="htmx-config"]');if(e){return x(e.content)}else{return null}}function or(){var e=ir();if(e){k.config=V(k.config,e)}}rr(function(){or();nr();var e=F().body;rt(e);window.onpopstate=function(e){if(e.state&&e.state.htmx){xt()}};setTimeout(function(){lt(e,"htmx:load",{})},0)});return k}()}); \ No newline at end of file +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(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 l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=k(e);e.classList.toggle(t)}function T(e,t){e=k(e);W(e.parentElement.children,function(e){q(e,t)});L(e,t)}function H(e,t){e=k(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function N(e,t){if(t.indexOf("closest ")===0){return[H(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[C(e,t.substr(5))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return z().querySelectorAll(t)}}function ee(e,t){if(t){return N(e,t)[0]}else{return N(z().body,e)[0]}}function k(e){if(p(e,"String")){return C(e)}else{return e}}function I(e,t,r){if(m(t)){return{target:z().body,event:e,listener:t}}else{return{target:k(e),event:t,listener:r}}}function M(t,r,n){lr(function(){var e=I(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function D(t,r,n){lr(function(){var e=I(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var te=z().createElement("output");function F(e,t){var r=G(e,t);if(r){if(r==="this"){return[re(e,t)]}else{var n=N(e,r);if(n.length===0){pt('The selector "'+r+'" on '+t+" returned no matches!");return[te]}else{return n}}}}function re(e,t){return h(e,function(e){return V(e,t)!=null})}function ne(e){var t=G(e,"hx-target");if(t){if(t==="this"){return re(e,"hx-target")}else{return ee(e,t)}}else{var r=_(e);if(r.boosted){return z().body}else{return e}}}function P(e){var t=U.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function X(t,r){W(t.attributes,function(e){if(!r.hasAttribute(e.name)&&P(e.name)){t.removeAttribute(e.name)}});W(r.attributes,function(e){if(P(e.name)){t.setAttribute(e.name,e.value)}})}function j(e,t){var r=sr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){pt(e)}}return e==="outerHTML"}function B(e,i,o){var t="#"+i.id;var a="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){a=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{a=e}var r=z().querySelectorAll(t);if(r){W(r,function(e){var t;var r=i.cloneNode(true);t=z().createDocumentFragment();t.appendChild(r);if(!j(a,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ye(a,e,e,t,o)}W(o.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(z().body,"htmx:oobErrorNoTarget",{content:i})}return e}function ie(e,r){W(R(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=V(e,"hx-swap-oob");if(t!=null){B(t,e,r)}})}function oe(e){W(R(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=V(e,"id");var r=z().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function ae(n,e,i){W(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();X(e,t);i.tasks.push(function(){X(e,r)})}}})}function se(e){return function(){q(e,U.config.addedClass);ct(e);at(e);le(e);$(e,"htmx:load")}}function le(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ue(e,t,r,n){ae(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(se(i))}}}function fe(t){var e=_(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){W(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){W(t.children,function(e){fe(e)})}}function ce(e,t,r){if(e.tagName==="BODY"){return me(e,t,r)}else{var n;var i=e.previousSibling;ue(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}_(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}fe(e);u(e).removeChild(e)}}function he(e,t,r){return ue(e,e.firstChild,t,r)}function de(e,t,r){return ue(u(e),e,t,r)}function ve(e,t,r){return ue(e,null,t,r)}function ge(e,t,r){return ue(u(e),e.nextSibling,t,r)}function pe(e,t,r){fe(e);return u(e).removeChild(e)}function me(e,t,r){var n=e.firstChild;ue(e,n,t,r);if(n){while(n.nextSibling){fe(n.nextSibling);e.removeChild(n.nextSibling)}fe(n);e.removeChild(n)}}function xe(e,t){var r=G(e,"hx-select");if(r){var n=z().createDocumentFragment();W(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function ye(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":ce(r,n,i);return;case"afterbegin":he(r,n,i);return;case"beforebegin":de(r,n,i);return;case"beforeend":ve(r,n,i);return;case"afterend":ge(r,n,i);return;case"delete":pe(r,n,i);return;default:var o=sr(t);for(var a=0;a<o.length;a++){var f=o[a];try{var s=f.handleSwap(e,r,n,i);if(s){if(typeof s.length!=="undefined"){for(var l=0;l<s.length;l++){var u=s[l];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){i.tasks.push(se(u))}}}return}}catch(e){pt(e)}}if(e==="innerHTML"){me(r,n,i)}else{ye(U.config.defaultSwapStyle,t,r,n,i)}}}function be(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function we(e,t,r,n,i){i.title=be(n);var o=g(n);if(o){ie(o,i);o=xe(r,o);oe(o);return ye(e,r,t,o,i)}}function Se(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!x(a)){a={value:a}}$(r,o,a)}}}else{$(r,n,[])}}var Ee=/\s/;var Ce=/[\s,]/;var Re=/[_$a-zA-Z]/;var Oe=/[_$a-zA-Z0-9]/;var Le=['"',"'","/"];var qe=/[^\s]/;function Ae(e){var t=[];var r=0;while(r<e.length){if(Re.exec(e.charAt(r))){var n=r;while(Oe.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Le.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function Te(e,t,r){return Re.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function He(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Jt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(z().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(Te(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var Ne="input, textarea, select";function ke(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=Ae(t);do{c(n,qe);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var o={trigger:"every"};c(n,qe);o.pollInterval=v(c(n,/[,\[\s]/));c(n,qe);var a=He(e,n,"event");if(a){o.eventFilter=a}r.push(o)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var a=He(e,n,"event");if(a){s.eventFilter=a}while(n.length>0&&n[0]!==","){c(n,qe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Ce))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Ce);if(u==="closest"||u==="find"){n.shift();u+=" "+c(n,Ce)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Ce)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Ce))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Ce)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Ce)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,qe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,Ne)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ie(e){_(e).cancelled=true}function Me(e,t,r,n){var i=_(e);i.timeout=setTimeout(function(){if(Y(e)&&i.cancelled!==true){if(!je(n,dt("hx:poll:trigger",{triggerSpec:n,target:e}))){Z(t,r,e)}Me(e,t,V(e,"hx-"+t),n)}},n.pollInterval)}function De(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&De(t)&&t.target===""||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href");r.pushURL=true}else{var o=f(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=f(t,"action")}e.forEach(function(e){Be(t,n,i,r,e,true)})}}function Pe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&H(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Xe(e,t){return _(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function je(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(z().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Be(o,a,s,e,l,u){var t;if(l.from){t=N(o,l.from)}else{t=[o]}W(t,function(n){var i=function(e){if(!Y(o)){n.removeEventListener(l.trigger,i);return}if(Xe(o,e)){return}if(u||Pe(e,o)){e.preventDefault()}if(je(l,e)){return}var t=_(e);t.triggerSpec=l;if(t.handledFor==null){t.handledFor=[]}var r=_(o);if(t.handledFor.indexOf(o)<0){t.handledFor.push(o);if(l.consume){e.stopPropagation()}if(l.target&&e.target){if(!d(e.target,l.target)){return}}if(l.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(l.changed){if(r.lastValue===o.value){return}else{r.lastValue=o.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(l.throttle){if(!r.throttle){Z(a,s,o,e);r.throttle=setTimeout(function(){r.throttle=null},l.throttle)}}else if(l.delay){r.delayed=setTimeout(function(){Z(a,s,o,e)},l.delay)}else{Z(a,s,o,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:l.trigger,listener:i,on:n});n.addEventListener(l.trigger,i)})}var Ue=false;var Ve=null;function ze(){if(!Ve){Ve=function(){Ue=true};window.addEventListener("scroll",Ve);setInterval(function(){if(Ue){Ue=false;W(z().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){_e(e)})}},200)}}function _e(e){if(!s(e,"data-hx-revealed")&&b(e)){e.setAttribute("data-hx-revealed","true");var t=_(e);if(t.initialized){Z(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Z(t.verb,t.path,e)},{once:true})}}}function We(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Je(e,o[1],0)}if(o[0]==="send"){Ze(e)}}}function Je(s,r,n){if(!Y(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=U.createWebSocket(r);t.onerror=function(e){J(s,"htmx:wsError",{error:e,socket:t});$e(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=Ge(n);setTimeout(function(){Je(s,r,n+1)},t)}};t.onopen=function(e){n=0};_(s).webSocket=t;t.addEventListener("message",function(e){if($e(s)){return}var t=e.data;gt(s,function(e){t=e.transformResponse(t,null,s)});var r=zt(s);var n=g(t);var i=y(n.children);for(var o=0;o<i.length;o++){var a=i[o];B(V(a,"hx-swap-oob")||"true",a,r)}Ct(r.tasks)})}function $e(e){if(!Y(e)){_(e).webSocket.close();return true}}function Ze(u){var f=h(u,function(e){return _(e).webSocket!=null});if(f){u.addEventListener(ke(u)[0].trigger,function(e){var t=_(f).webSocket;var r=Xt(u,f);var n=Mt(u,"post");var i=n.errors;var o=n.values;var a=Gt(u);var s=Q(o,a);var l=jt(s,u);l["HEADERS"]=r;if(i&&i.length>0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Pe(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ge(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}pt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ke(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Ye(e,o[1])}if(o[0]==="swap"){Qe(e,o[1])}}}function Ye(t,e){var r=U.createEventSource(e);r.onerror=function(e){J(t,"htmx:sseError",{error:e,source:r});tt(t)};_(t).sseEventSource=r}function Qe(o,a){var s=h(o,rt);if(s){var l=_(s).sseEventSource;var u=function(e){if(tt(s)){l.removeEventListener(a,u);return}var t=e.data;gt(o,function(e){t=e.transformResponse(t,null,o)});var r=Ut(o);var n=ne(o);var i=zt(o);we(r.swapStyle,o,n,t,i);Ct(i.tasks);$(o,"htmx:sseMessage",e)};_(o).sseListener=u;l.addEventListener(a,u)}else{J(o,"htmx:noSSESourceError")}}function et(e,t,r,n){var i=h(e,rt);if(i){var o=_(i).sseEventSource;var a=function(){if(!tt(i)){if(Y(e)){Z(t,r,e)}else{o.removeEventListener(n,a)}}};_(e).sseListener=a;o.addEventListener(n,a)}else{J(e,"htmx:noSSESourceError")}}function tt(e){if(!Y(e)){_(e).sseEventSource.close();return true}}function rt(e){return _(e).sseEventSource!=null}function nt(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Z(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function it(o,a,e){var t=false;W(n,function(n){if(s(o,"hx-"+n)){var i=V(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){et(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){ze();_e(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=ee(o,e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){$(o,"intersect");break}}},t);r.observe(o);Be(o,n,i,a,e)}else if(e.trigger==="load"){nt(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Me(o,n,i,e)}else{Be(o,n,i,a,e)}})}});return t}function ot(e){if(e.type==="text/javascript"||e.type==="module"||e.type===""){var t=z().createElement("script");W(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(U.config.inlineScriptNonce){t.nonce=U.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){pt(e)}finally{r.removeChild(e)}}}function at(e){if(d(e,"script")){ot(e)}W(R(e,"script"),function(e){ot(e)})}function st(){return document.querySelector("[hx-boost], [data-hx-boost]")}function lt(e){if(e.querySelectorAll){var t=st()?", a, form":"";var r=e.querySelectorAll(i+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [hx-data-ext]");return r}else{return[]}}function ut(r){var e=function(e){if(d(e.target,"button, input[type='submit']")){var t=_(r);t.lastButtonClicked=e.target}};r.addEventListener("click",e);r.addEventListener("focusin",e);r.addEventListener("focusout",function(e){var t=_(r);t.lastButtonClicked=null})}function ft(e){if(e.closest&&e.closest(U.config.disableSelector)){return}var t=_(e);if(!t.initialized){t.initialized=true;$(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=ke(e);var n=it(e,t,r);if(!n&&G(e,"hx-boost")==="true"){Fe(e,t,r)}if(e.tagName==="FORM"){ut(e)}var i=V(e,"hx-sse");if(i){Ke(e,t,i)}var o=V(e,"hx-ws");if(o){We(e,t,o)}$(e,"htmx:afterProcessNode")}}function ct(e){e=k(e);ft(e);W(lt(e),function(e){ft(e)})}function ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function dt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=z().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function J(e,t,r){$(e,t,Q({error:t},r))}function vt(e){return e==="htmx:afterProcessNode"}function gt(e,t){W(sr(e),function(e){try{t(e)}catch(e){pt(e)}})}function pt(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function $(e,t,r){e=k(e);if(r==null){r={}}r["elt"]=e;var n=dt(t,r);if(U.logger&&!vt(t)){U.logger(e,t,r)}if(r.error){pt(r.error);$(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=ht(t);if(i&&o!==t){var a=dt(o,n.detail);i=i&&e.dispatchEvent(a)}gt(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var mt=location.pathname+location.search;function xt(){var e=z().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||z().body}function yt(e,t,r,n){var i=S(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>U.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(z().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function bt(e){var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function wt(e){var t=U.config.requestClass;var r=e.cloneNode(true);W(R(r,"."+t),function(e){q(e,t)});return r.innerHTML}function St(){var e=xt();var t=mt||location.pathname+location.search;$(z().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(U.config.historyEnabled)history.replaceState({htmx:true},z().title,window.location.href);yt(t,wt(e),z().title,window.scrollY)}function Et(e){if(U.config.historyEnabled)history.pushState({htmx:true},"",e);mt=e}function Ct(e){W(e,function(e){e.call()})}function Rt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};$(z().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){$(z().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=xt();var r=zt(t);me(t,e,r);Ct(r.tasks);mt=n;$(z().body,"htmx:historyRestore",{path:n})}else{J(z().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Ot(e){St();e=e||location.pathname+location.search;var t=bt(e);if(t){var r=g(t.content);var n=xt();var i=zt(n);me(n,r,i);Ct(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);mt=e;$(z().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Rt(e)}}}function Lt(e){var t=G(e,"hx-push-url");return t&&t!=="false"||_(e).boosted&&_(e).pushURL}function qt(e){var t=G(e,"hx-push-url");return t==="true"||t==="false"?null:t}function At(e){var t=F(e,"hx-indicator");if(t==null){t=[e]}W(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Tt(e){W(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function Ht(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Nt(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 kt(t,r,n,e,i){if(e==null||Ht(t,e)){return}else{t.push(e)}if(Nt(e)){var o=f(e,"name");var a=e.value;if(e.multiple){a=y(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=y(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){It(e,n)}}if(d(e,"form")){var l=e.elements;W(l,function(e){kt(t,r,n,e,i)})}}function It(e,t){if(e.willValidate){$(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});$(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Mt(e,t){var r=[];var n={};var i={};var o=[];var a=_(e);var s=d(e,"form")&&e.noValidate!==true;if(a.lastButtonClicked){s=s&&a.lastButtonClicked.formNoValidate!==true}if(t!=="get"){kt(r,i,o,H(e,"form"),s)}kt(r,n,o,e,s);if(a.lastButtonClicked){var l=f(a.lastButtonClicked,"name");if(l){n[l]=a.lastButtonClicked.value}}var u=F(e,"hx-include");W(u,function(e){kt(r,n,o,e,s);if(!d(e,"form")){W(e.querySelectorAll(Ne),function(e){kt(r,n,o,e,s)})}});n=Q(n,i);return{errors:o,values:n}}function Dt(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function Ft(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=Dt(t,r,e)})}else{t=Dt(t,r,n)}}}return t}function Pt(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){W(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Xt(e,t,r){var n={"HX-Request":"true","HX-Trigger":f(e,"id"),"HX-Trigger-Name":f(e,"name"),"HX-Target":V(t,"id"),"HX-Current-URL":z().location.href};Wt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(_(e).boosted){n["HX-Boosted"]="true"}return n}function jt(t,e){var r=G(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){W(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};W(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Bt(e){return f(e,"href")&&f(e,"href").indexOf("#")>=0}function Ut(e,t){var r=t?t:G(e,"hx-swap");var n={swapStyle:_(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(_(e).boosted&&!Bt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var o=1;o<i.length;o++){var a=i[o];if(a.indexOf("swap:")===0){n["swapDelay"]=v(a.substr(5))}if(a.indexOf("settle:")===0){n["settleDelay"]=v(a.substr(7))}if(a.indexOf("scroll:")===0){var s=a.substr(7);var l=s.split(":");var f=l.pop();var u=l.length>0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(a.indexOf("show:")===0){var c=a.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(a.indexOf("focus-scroll:")===0){var d=a.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function Vt(t,r,n){var i=null;gt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(G(r,"hx-encoding")==="multipart/form-data"||d(r,"form")&&f(r,"enctype")==="multipart/form-data"){return Pt(n)}else{return Ft(n)}}}function zt(e){return{tasks:[],elts:[e]}}function _t(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ee(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var o=t.showTarget;if(t.showTarget==="window"){o="body"}i=ee(r,o)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function Wt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}else if(o.indexOf("js:")===0){o=o.substr(3);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Jt(e,function(){return Function("return ("+o+")")()},{})}else{s=S(o)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Wt(u(e),t,r,n)}function Jt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function $t(e,t){return Wt(e,"hx-vars",true,t)}function Zt(e,t){return Wt(e,"hx-vals",false,t)}function Gt(e){return Q($t(e),Zt(e))}function Kt(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Yt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(z().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Qt(e,t){return e.getAllResponseHeaders().match(t)}function er(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return Z(e,t,null,null,{targetOverride:k(r),returnPromise:true})}else{return Z(e,t,k(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:k(r.target),swapOverride:r.swap,returnPromise:true})}}else{return Z(e,t,null,null,{returnPromise:true})}}function tr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Z(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=z().body}var v=r.handler||rr;if(!Y(n)){return}var g=r.targetOverride||ne(n);if(g==null||g==te){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=_(n);var o=G(n,"hx-sync");var m=null;var x=false;if(o){var y=o.split(":");var b=y[0].trim();if(b==="this"){p=re(n,"hx-sync")}else{p=ee(n,b)}o=(y[1]||"drop").trim();i=_(p);if(o==="drop"&&i.xhr&&i.abortable!==true){return}else if(o==="abort"){if(i.xhr){return}else{x=true}}else if(o==="replace"){$(p,"htmx:abort")}else if(o.indexOf("queue")===0){var w=o.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=_(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){Z(e,t,n,f,r)})}return}}var a=new XMLHttpRequest;i.xhr=a;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=G(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){K(c);s();return d}}var R=G(n,"hx-confirm");if(R){if(!confirm(R)){K(c);s();return d}}var O=Xt(n,g,C);if(r.headers){O=Q(O,r.headers)}var L=Mt(n,e);var q=L.errors;var A=L.values;if(r.values){A=Q(A,r.values)}var T=Gt(n);var H=Q(A,T);var N=jt(H,n);if(e!=="get"&&G(n,"hx-encoding")==null){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=z().location.href}var k=Wt(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:q,withCredentials:r.credentials||k.credentials||U.config.withCredentials,timeout:r.timeout||k.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){K(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;q=l.errors;if(q&&q.length>0){$(n,"htmx:validation:halted",l);K(c);s();return d}var I=t.split("#");var M=I[0];var D=I[1];if(e==="get"){var F=M;var P=Object.keys(N).length!==0;if(P){if(F.indexOf("?")<0){F+="?"}else{F+="&"}F+=Ft(N);if(D){F+="#"+D}}a.open("GET",F,true)}else{a.open(e.toUpperCase(),t,true)}a.overrideMimeType("text/html");a.withCredentials=l.withCredentials;a.timeout=l.timeout;if(k.noHeaders){}else{for(var X in O){if(O.hasOwnProperty(X)){var j=O[X];Kt(a,X,j)}}}var u={xhr:a,target:g,requestConfig:l,etc:r,pathInfo:{path:t,finalPath:F,anchor:D}};a.onload=function(){try{var e=tr(n);v(n,u);Tt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!Y(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(Y(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}K(c);s()}catch(e){J(n,"htmx:onLoadError",Q({error:e},u));throw e}};a.onerror=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);K(h);s()};a.onabort=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);K(h);s()};a.ontimeout=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);K(h);s()};if(!$(n,"htmx:beforeRequest",u)){K(c);s();return d}var B=At(n);W(["loadstart","loadend","progress","abort"],function(t){W([a,a.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);a.send(e==="get"?null:Vt(a,n,N));return d}function rr(s,l){var u=l.xhr;var f=l.target;var r=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(Qt(u,/HX-Trigger:/i)){Se(u,"HX-Trigger",s)}if(Qt(u,/HX-Push:/i)){var c=u.getResponseHeader("HX-Push")}if(Qt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Qt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(Qt(u,/HX-Retarget:/i)){l.target=z().querySelector(u.getResponseHeader("HX-Retarget"))}var h;if(c=="false"){h=false}else{h=Lt(s)||c}var n=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var e=u.status>=400;var t=Q({shouldSwap:n,serverResponse:d,isError:e},l);if(!$(f,"htmx:beforeSwap",t))return;f=t.target;d=t.serverResponse;e=t.isError;l.failed=e;l.successful=!e;if(t.shouldSwap){if(u.status===286){Ie(s)}gt(s,function(e){d=e.transformResponse(d,u,s)});if(h){St()}var i=r.swapOverride;var v=Ut(s,i);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=zt(f);we(v.swapStyle,f,s,d,n);if(t.elt&&!Y(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);W(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(l.pathInfo.anchor){location.hash=l.pathInfo.anchor}if(Qt(u,/HX-Trigger-After-Swap:/i)){var o=s;if(!Y(s)){o=z().body}Se(u,"HX-Trigger-After-Swap",o)}var a=function(){W(n.tasks,function(e){e.call()});W(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h){var e=c||qt(s)||Yt(u)||l.pathInfo.finalPath||l.pathInfo.path;Et(e);$(z().body,"htmx:pushedIntoHistory",{path:e})}if(n.title){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}_t(n.elts,v);if(Qt(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!Y(s)){r=z().body}Se(u,"HX-Trigger-After-Settle",r)}};if(v.settleDelay>0){setTimeout(a,v.settleDelay)}else{a()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(v.swapDelay>0){setTimeout(o,v.swapDelay)}else{o()}}if(e){J(s,"htmx:responseError",Q({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var nr={};function ir(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function or(e,t){if(t.init){t.init(r)}nr[e]=Q(ir(),t)}function ar(e){delete nr[e]}function sr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){W(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=nr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return sr(u(e),r,n)}function lr(e){if(z().readyState!=="loading"){e()}else{z().addEventListener("DOMContentLoaded",e)}}function ur(){if(U.config.includeIndicatorStyles!==false){z().head.insertAdjacentHTML("beforeend","<style> ."+U.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+U.config.requestClass+" ."+U.config.indicatorClass+"{opacity:1} ."+U.config.requestClass+"."+U.config.indicatorClass+"{opacity:1} </style>")}}function fr(){var e=z().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function cr(){var e=fr();if(e){U.config=Q(U.config,e)}}lr(function(){cr();ur();var e=z().body;ct(e);var t=z().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=_(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){Ot();W(t,function(e){$(e,"htmx:restored",{document:z(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file diff --git a/code/ch4_app/ch4_starter_video_collector/static/js/htmx.js b/code/ch4_app/ch4_starter_video_collector/static/js/htmx.js index e38f6ed..27e57bc 100644 --- a/code/ch4_app/ch4_starter_video_collector/static/js/htmx.js +++ b/code/ch4_app/ch4_starter_video_collector/static/js/htmx.js @@ -1,7 +1,9 @@ //AMD insanity (function (root, factory) { + //@ts-ignore if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. + //@ts-ignore define([], factory); } else { // Browser globals @@ -12,6 +14,8 @@ return (function () { 'use strict'; // Public API + //** @type {import("./htmx").HtmxApi} */ + // TODO: list all methods in public API var htmx = { onLoad: onLoadHelper, process: processNode, @@ -35,7 +39,6 @@ return (function () { removeExtension : removeExtension, logAll : logAll, logger : null, - useTemplateFragments: false, config : { historyEnabled:true, historyCacheSize:10, @@ -46,13 +49,19 @@ return (function () { includeIndicatorStyles:true, indicatorClass:'htmx-indicator', requestClass:'htmx-request', + addedClass:'htmx-added', settlingClass:'htmx-settling', swappingClass:'htmx-swapping', allowEval:true, + inlineScriptNonce:'', attributesToSettle:["class", "style", "width", "height"], withCredentials:false, + timeout:0, wsReconnectDelay: 'full-jitter', disableSelector: "[hx-disable], [data-hx-disable]", + useTemplateFragments: false, + scrollBehavior: 'smooth', + defaultFocusScroll: false, }, parseInterval:parseInterval, _:internalEval, @@ -61,9 +70,36 @@ return (function () { }, createWebSocket: function(url){ return new WebSocket(url, []); - } + }, + version: "1.7.0" }; + /** @type {import("./htmx").HtmxInternalApi} */ + var internalAPI = { + bodyContains: bodyContains, + filterValues: filterValues, + hasAttribute: hasAttribute, + getAttributeValue: getAttributeValue, + getClosestMatch: getClosestMatch, + getExpressionVars: getExpressionVars, + getHeaders: getHeaders, + getInputValues: getInputValues, + getInternalData: getInternalData, + getSwapSpecification: getSwapSpecification, + getTriggerSpecs: getTriggerSpecs, + getTarget: getTarget, + makeFragment: makeFragment, + mergeObjects: mergeObjects, + makeSettleInfo: makeSettleInfo, + oobSwap: oobSwap, + selectAndSwap: selectAndSwap, + settleImmediately: settleImmediately, + shouldCancel: shouldCancel, + triggerEvent: triggerEvent, + triggerErrorEvent: triggerErrorEvent, + withExtensions: withExtensions, + } + var VERBS = ['get', 'post', 'put', 'delete', 'patch']; var VERB_SELECTOR = VERBS.map(function(verb){ return "[hx-" + verb + "], [data-hx-" + verb + "]" @@ -73,19 +109,24 @@ return (function () { // Utilities //==================================================================== - function parseInterval(str) { - if (str == undefined) { - return undefined - } - if (str.slice(-2) == "ms") { - return parseFloat(str.slice(0,-2)) || undefined - } - if (str.slice(-1) == "s") { - return (parseFloat(str.slice(0,-1)) * 1000) || undefined - } - return parseFloat(str) || undefined + function parseInterval(str) { + if (str == undefined) { + return undefined + } + if (str.slice(-2) == "ms") { + return parseFloat(str.slice(0,-2)) || undefined + } + if (str.slice(-1) == "s") { + return (parseFloat(str.slice(0,-1)) * 1000) || undefined + } + return parseFloat(str) || undefined } + /** + * @param {HTMLElement} elt + * @param {string} name + * @returns {(string | null)} + */ function getRawAttribute(elt, name) { return elt.getAttribute && elt.getAttribute(name); } @@ -96,18 +137,36 @@ return (function () { elt.hasAttribute("data-" + qualifiedName)); } + /** + * + * @param {HTMLElement} elt + * @param {string} qualifiedName + * @returns {(string | null)} + */ function getAttributeValue(elt, qualifiedName) { return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); } + /** + * @param {HTMLElement} elt + * @returns {HTMLElement | null} + */ function parentElt(elt) { return elt.parentElement; } + /** + * @returns {Document} + */ function getDocument() { return document; } + /** + * @param {HTMLElement} elt + * @param {(e:HTMLElement) => boolean} condition + * @returns {HTMLElement | null} + */ function getClosestMatch(elt, condition) { if (condition(elt)) { return elt; @@ -118,22 +177,47 @@ return (function () { } } + function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ + var attributeValue = getAttributeValue(ancestor, attributeName); + var disinherit = getAttributeValue(ancestor, "hx-disinherit"); + if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) { + return "unset"; + } else { + return attributeValue + } + } + + /** + * @param {HTMLElement} elt + * @param {string} attributeName + * @returns {string | null} + */ function getClosestAttributeValue(elt, attributeName) { var closestAttr = null; getClosestMatch(elt, function (e) { - return closestAttr = getAttributeValue(e, attributeName); + return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName); }); - return closestAttr; + if (closestAttr !== "unset") { + return closestAttr; + } } + /** + * @param {HTMLElement} elt + * @param {string} selector + * @returns {boolean} + */ function matches(elt, selector) { + // @ts-ignore: non-standard properties for browser compatability // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || - elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector - || elt.webkitMatchesSelector || elt.oMatchesSelector; + var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; return matchesFunction && matchesFunction.call(elt, selector); } + /** + * @param {string} str + * @returns {string} + */ function getStartTag(str) { var tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i var match = tagMatcher.exec( str ); @@ -144,23 +228,40 @@ return (function () { } } + /** + * + * @param {string} resp + * @param {number} depth + * @returns {Element} + */ function parseHTML(resp, depth) { var parser = new DOMParser(); var responseDoc = parser.parseFromString(resp, "text/html"); + + /** @type {Element} */ var responseNode = responseDoc.body; while (depth > 0) { depth--; + // @ts-ignore responseNode = responseNode.firstChild; } if (responseNode == null) { + // @ts-ignore responseNode = getDocument().createDocumentFragment(); } return responseNode; } + /** + * + * @param {string} resp + * @returns {Element} + */ function makeFragment(resp) { if (htmx.config.useTemplateFragments) { var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0); + // @ts-ignore type mismatch between DocumentFragment and Element. + // TODO: Are these close enough for htmx to use interchangably? return documentFragment.querySelector('template').content; } else { var startTag = getStartTag(resp); @@ -186,24 +287,45 @@ return (function () { } } + /** + * @param {Function} func + */ function maybeCall(func){ if(func) { func(); } } + /** + * @param {any} o + * @param {string} type + * @returns + */ function isType(o, type) { return Object.prototype.toString.call(o) === "[object " + type + "]"; } + /** + * @param {*} o + * @returns {o is Function} + */ function isFunction(o) { return isType(o, "Function"); } + /** + * @param {*} o + * @returns {o is Object} + */ function isRawObject(o) { return isType(o, "Object"); } + /** + * getInternalData retrieves "private" data stored by htmx within an element + * @param {HTMLElement} elt + * @returns {*} + */ function getInternalData(elt) { var dataProp = 'htmx-internal-data'; var data = elt[dataProp]; @@ -213,6 +335,11 @@ return (function () { return data; } + /** + * toArray converts an ArrayLike object into a real array. + * @param {ArrayLike} arr + * @returns {any[]} + */ function toArray(arr) { var returnArr = []; if (arr) { @@ -238,14 +365,25 @@ return (function () { return elemTop < window.innerHeight && elemBottom >= 0; } - function bodyContains(elt) { - return getDocument().body.contains(elt); - } + function bodyContains(elt) { + if (elt.getRootNode() instanceof ShadowRoot) { + return getDocument().body.contains(elt.getRootNode().host); + } else { + return getDocument().body.contains(elt); + } + } function splitOnWhitespace(trigger) { return trigger.trim().split(/\s+/); } + /** + * mergeObjects takes all of the keys from + * obj2 and duplicates them into obj1 + * @param {Object} obj1 + * @param {Object} obj2 + * @returns {Object} + */ function mergeObjects(obj1, obj2) { for (var key in obj2) { if (obj2.hasOwnProperty(key)) { @@ -319,7 +457,7 @@ return (function () { if (delay) { setTimeout(function(){addClassToElement(elt, clazz);}, delay) } else { - elt.classList.add(clazz); + elt.classList && elt.classList.add(clazz); } } @@ -328,7 +466,13 @@ return (function () { if (delay) { setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) } else { - elt.classList.remove(clazz); + if (elt.classList) { + elt.classList.remove(clazz); + // if there are no classes left, remove the class attribute + if (elt.classList.length === 0) { + elt.removeAttribute("class"); + } + } } } @@ -360,17 +504,25 @@ return (function () { } function querySelectorAllExt(elt, selector) { - if (selector.indexOf("closest ") === 0) { + if (selector.indexOf("closest ") === 0) { return [closest(elt, selector.substr(8))]; } else if (selector.indexOf("find ") === 0) { return [find(elt, selector.substr(5))]; + } else if (selector === 'document') { + return [document]; + } else if (selector === 'window') { + return [window]; } else { return getDocument().querySelectorAll(selector); } } function querySelectorExt(eltOrSelector, selector) { - return querySelectorAllExt(eltOrSelector, selector)[0] + if (selector) { + return querySelectorAllExt(eltOrSelector, selector)[0]; + } else { + return querySelectorAllExt(getDocument().body, eltOrSelector)[0]; + } } function resolveTarget(arg2) { @@ -418,13 +570,36 @@ return (function () { //==================================================================== // Node processing //==================================================================== + + var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors + function findAttributeTargets(elt, attrName) { + var attrTarget = getClosestAttributeValue(elt, attrName); + if (attrTarget) { + if (attrTarget === "this") { + return [findThisElement(elt, attrName)]; + } else { + var result = querySelectorAllExt(elt, attrTarget); + if (result.length === 0) { + logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!"); + return [DUMMY_ELT] + } else { + return result; + } + } + } + } + + function findThisElement(elt, attribute){ + return getClosestMatch(elt, function (elt) { + return getAttributeValue(elt, attribute) != null; + }) + } function getTarget(elt) { - var explicitTarget = getClosestMatch(elt, function(e){return getAttributeValue(e,"hx-target") !== null}); - if (explicitTarget) { - var targetStr = getAttributeValue(explicitTarget, "hx-target"); + var targetStr = getClosestAttributeValue(elt, "hx-target"); + if (targetStr) { if (targetStr === "this") { - return explicitTarget; + return findThisElement(elt,'hx-target'); } else { return querySelectorExt(elt, targetStr) } @@ -476,6 +651,13 @@ return (function () { return swapStyle === "outerHTML"; } + /** + * + * @param {string} oobValue + * @param {HTMLElement} oobElement + * @param {*} settleInfo + * @returns + */ function oobSwap(oobValue, oobElement, settleInfo) { var selector = "#" + oobElement.id; var swapStyle = "outerHTML"; @@ -488,18 +670,35 @@ return (function () { swapStyle = oobValue; } - var target = getDocument().querySelector(selector); - if (target) { - var fragment; - fragment = getDocument().createDocumentFragment(); - fragment.appendChild(oobElement); // pulls the child out of the existing fragment - if (!isInlineSwap(swapStyle, target)) { - fragment = oobElement; // if this is not an inline swap, we use the content of the node, not the node itself - } - swap(swapStyle, target, target, fragment, settleInfo); + var targets = getDocument().querySelectorAll(selector); + if (targets) { + forEach( + targets, + function (target) { + var fragment; + var oobElementClone = oobElement.cloneNode(true); + fragment = getDocument().createDocumentFragment(); + fragment.appendChild(oobElementClone); + if (!isInlineSwap(swapStyle, target)) { + fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself + } + + var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment }; + if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return; + + target = beforeSwapDetails.target; // allow re-targeting + if (beforeSwapDetails['shouldSwap']){ + swap(swapStyle, target, target, fragment, settleInfo); + } + forEach(settleInfo.elts, function (elt) { + triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails); + }); + } + ); + oobElement.parentNode.removeChild(oobElement); } else { oobElement.parentNode.removeChild(oobElement); - triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}) + triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}); } return oobValue; } @@ -540,6 +739,7 @@ return (function () { function makeAjaxLoadTask(child) { return function () { + removeClassFromElement(child, htmx.config.addedClass); processNode(child); processScripts(child); processFocus(child) @@ -559,6 +759,7 @@ return (function () { handleAttributes(parentNode, fragment, settleInfo); while(fragment.childNodes.length > 0){ var child = fragment.firstChild; + addClassToElement(child, htmx.config.addedClass); parentNode.insertBefore(child, insertBefore); if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { settleInfo.tasks.push(makeAjaxLoadTask(child)); @@ -574,6 +775,9 @@ return (function () { if (internalData.sseEventSource) { internalData.sseEventSource.close(); } + + triggerEvent(element, "htmx:beforeCleanupElement") + if (internalData.listenerInfos) { forEach(internalData.listenerInfos, function(info) { if (element !== info.on) { @@ -590,12 +794,14 @@ return (function () { if (target.tagName === "BODY") { return swapInnerHTML(target, fragment, settleInfo); } else { + // @type {HTMLElement} + var newElt var eltBeforeNewContent = target.previousSibling; insertNodesBefore(parentElt(target), target, fragment, settleInfo); if (eltBeforeNewContent == null) { - var newElt = parentElt(target).firstChild; + newElt = parentElt(target).firstChild; } else { - var newElt = eltBeforeNewContent.nextSibling; + newElt = eltBeforeNewContent.nextSibling; } getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later settleInfo.elts = [] // clear existing elements @@ -625,6 +831,10 @@ return (function () { function swapAfterEnd(target, fragment, settleInfo) { return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo); } + function swapDelete(target, fragment, settleInfo) { + cleanUpElement(target); + return parentElt(target).removeChild(target); + } function swapInnerHTML(target, fragment, settleInfo) { var firstChild = target.firstChild; @@ -670,6 +880,9 @@ return (function () { case "afterend": swapAfterEnd(target, fragment, settleInfo); return; + case "delete": + swapDelete(target, fragment, settleInfo); + return; default: var extensions = getExtensions(elt); for (var i = 0; i < extensions.length; i++) { @@ -692,32 +905,27 @@ return (function () { logError(e); } } - swapInnerHTML(target, fragment, settleInfo); + if (swapStyle === "innerHTML") { + swapInnerHTML(target, fragment, settleInfo); + } else { + swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo); + } } } - var TITLE_FINDER = /<title>([\s\S]+?)<\/title>/im; function findTitle(content) { - if(content.indexOf('<title>') > -1 && - (content.indexOf('<svg>') == -1 || - content.indexOf('<title>') < content.indexOf('<svg>'))) { - var result = TITLE_FINDER.exec(content); + if (content.indexOf('<title') > -1) { + var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, ''); + var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im); + if (result) { - return result[1]; + return result[2]; } } } function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) { - var title = findTitle(responseText); - if(title) { - var titleElt = find("title"); - if(titleElt) { - titleElt.innerHTML = title; - } else { - window.document.title = title; - } - } + settleInfo.title = findTitle(responseText); var fragment = makeFragment(responseText); if (fragment) { handleOutOfBandSwaps(fragment, settleInfo); @@ -840,6 +1048,11 @@ return (function () { } var INPUT_SELECTOR = 'input, textarea, select'; + + /** + * @param {HTMLElement} elt + * @returns {import("./htmx").HtmxTriggerSpecification[]} + */ function getTriggerSpecs(elt) { var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); var triggerSpecs = []; @@ -853,7 +1066,12 @@ return (function () { if (trigger === "every") { var every = {trigger: 'every'}; consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, WHITESPACE)); + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); + consumeUntil(tokens, NOT_WHITESPACE); + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + every.eventFilter = eventFilter; + } triggerSpecs.push(every); } else if (trigger.indexOf("sse:") === 0) { triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); @@ -877,7 +1095,17 @@ return (function () { triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); } else if (token === "from" && tokens[0] === ":") { tokens.shift(); - triggerSpec.from = consumeUntil(tokens, WHITESPACE_OR_COMMA); + var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); + if (from_arg === "closest" || from_arg === "find") { + tokens.shift(); + from_arg += + " " + + consumeUntil( + tokens, + WHITESPACE_OR_COMMA + ); + } + triggerSpec.from = from_arg; } else if (token === "target" && tokens[0] === ":") { tokens.shift(); triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA); @@ -919,14 +1147,16 @@ return (function () { getInternalData(elt).cancelled = true; } - function processPolling(elt, verb, path, interval) { + function processPolling(elt, verb, path, spec) { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - issueAjaxRequest(verb, path, elt); - processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), interval); + if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { + issueAjaxRequest(verb, path, elt); + } + processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), spec); } - }, interval); + }, spec.pollInterval); } function isLocalLink(elt) { @@ -936,7 +1166,7 @@ return (function () { } function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt)) || elt.tagName === "FORM") { + if ((elt.tagName === "A" && isLocalLink(elt) && elt.target === "") || elt.tagName === "FORM") { nodeData.boosted = true; var verb, path; if (elt.tagName === "A") { @@ -957,11 +1187,26 @@ return (function () { } } - function shouldCancel(elt) { - return elt.tagName === "FORM" || - (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) || - (elt.tagName === "A" && elt.href && (elt.getAttribute('href') === '#' || - elt.getAttribute('href').indexOf("#") !== 0)); + /** + * + * @param {Event} evt + * @param {HTMLElement} elt + * @returns + */ + function shouldCancel(evt, elt) { + if (evt.type === "submit" || evt.type === "click") { + if (elt.tagName === "FORM") { + return true; + } + if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { + return true; + } + if (elt.tagName === "A" && elt.href && + (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) { + return true; + } + } + return false; } function ignoreBoostedAnchorCtrlClick(elt, evt) { @@ -982,86 +1227,90 @@ return (function () { } function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { - var eltToListenOn = elt; + var eltsToListenOn; if (triggerSpec.from) { - eltToListenOn = find(triggerSpec.from); + eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); + } else { + eltsToListenOn = [elt]; } - var eventListener = function (evt) { - if (!bodyContains(elt)) { - eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); - return; - } - if (ignoreBoostedAnchorCtrlClick(elt, evt)) { - return; - } - if(explicitCancel || shouldCancel(elt)){ - evt.preventDefault(); - } - if (maybeFilterEvent(triggerSpec, evt)) { - return; - } - var eventData = getInternalData(evt); - eventData.triggerSpec = triggerSpec; - if (eventData.handledFor == null) { - eventData.handledFor = []; - } - var elementData = getInternalData(elt); - if (eventData.handledFor.indexOf(elt) < 0) { - eventData.handledFor.push(elt); - if (triggerSpec.consume) { - evt.stopPropagation(); - } - if (triggerSpec.target && evt.target) { - if (!matches(evt.target, triggerSpec.target)) { - return; - } - } - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } + forEach(eltsToListenOn, function (eltToListenOn) { + var eventListener = function (evt) { + if (!bodyContains(elt)) { + eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); + return; } - if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { - return; - } else { - elementData.lastValue = elt.value; - } + if (ignoreBoostedAnchorCtrlClick(elt, evt)) { + return; } - if (elementData.delayed) { - clearTimeout(elementData.delayed); + if (explicitCancel || shouldCancel(evt, elt)) { + evt.preventDefault(); } - if (elementData.throttle) { + if (maybeFilterEvent(triggerSpec, evt)) { return; } + var eventData = getInternalData(evt); + eventData.triggerSpec = triggerSpec; + if (eventData.handledFor == null) { + eventData.handledFor = []; + } + var elementData = getInternalData(elt); + if (eventData.handledFor.indexOf(elt) < 0) { + eventData.handledFor.push(elt); + if (triggerSpec.consume) { + evt.stopPropagation(); + } + if (triggerSpec.target && evt.target) { + if (!matches(evt.target, triggerSpec.target)) { + return; + } + } + 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); + } + if (elementData.throttle) { + return; + } - if (triggerSpec.throttle) { - if(!elementData.throttle) { + if (triggerSpec.throttle) { + if (!elementData.throttle) { + issueAjaxRequest(verb, path, elt, evt); + elementData.throttle = setTimeout(function () { + elementData.throttle = null; + }, triggerSpec.throttle); + } + } else if (triggerSpec.delay) { + elementData.delayed = setTimeout(function () { + issueAjaxRequest(verb, path, elt, evt); + }, triggerSpec.delay); + } else { issueAjaxRequest(verb, path, elt, evt); - elementData.throttle = setTimeout(function(){ - elementData.throttle = null; - }, triggerSpec.throttle); } - } else if (triggerSpec.delay) { - elementData.delayed = setTimeout(function(){ - issueAjaxRequest(verb, path, elt, evt); - }, triggerSpec.delay); - } else { - issueAjaxRequest(verb, path, elt, evt); } - } - }; - if (nodeData.listenerInfos == null) { - nodeData.listenerInfos = []; - } - nodeData.listenerInfos.push({ - trigger: triggerSpec.trigger, - listener: eventListener, - on: eltToListenOn + }; + if (nodeData.listenerInfos == null) { + nodeData.listenerInfos = []; + } + nodeData.listenerInfos.push({ + trigger: triggerSpec.trigger, + listener: eventListener, + on: eltToListenOn + }) + eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); }) - eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); } var windowIsScrolling = false // used by initScrollHandler @@ -1084,9 +1333,9 @@ return (function () { } function maybeReveal(elt) { - var nodeData = getInternalData(elt); - if (!nodeData.revealed && isScrolledIntoView(elt)) { - nodeData.revealed = true; + if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { + elt.setAttribute('data-hx-revealed', 'true'); + var nodeData = getInternalData(elt); if (nodeData.initialized) { issueAjaxRequest(nodeData.verb, nodeData.path, elt); } else { @@ -1099,6 +1348,10 @@ return (function () { } } + //==================================================================== + // Web Sockets + //==================================================================== + function processWebSocketInfo(elt, nodeData, info) { var values = splitOnWhitespace(info); for (var i = 0; i < values.length; i++) { @@ -1132,7 +1385,7 @@ return (function () { }; socket.onclose = function (e) { - if ([1006, 1012, 1013].includes(e.code)) { // Abnormal Closure/Service Restart/Try Again Later + if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later var delay = getWebSocketReconnectDelay(retryCount); setTimeout(function() { ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout @@ -1193,7 +1446,7 @@ return (function () { return; } webSocket.send(JSON.stringify(filteredParameters)); - if(shouldCancel(elt)){ + if(shouldCancel(evt, elt)){ evt.preventDefault(); } }); @@ -1205,6 +1458,7 @@ return (function () { function getWebSocketReconnectDelay(retryCount) { var delay = htmx.config.wsReconnectDelay; if (typeof delay === 'function') { + // @ts-ignore return delay(retryCount); } if (delay === 'full-jitter') { @@ -1340,7 +1594,7 @@ return (function () { } else if (triggerSpec.trigger === "intersect") { var observerOptions = {}; if (triggerSpec.root) { - observerOptions.root = querySelectorExt(triggerSpec.root) + observerOptions.root = querySelectorExt(elt, triggerSpec.root) } if (triggerSpec.threshold) { observerOptions.threshold = parseFloat(triggerSpec.threshold); @@ -1360,7 +1614,7 @@ return (function () { loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); } else if (triggerSpec.pollInterval) { nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec.pollInterval); + processPolling(elt, verb, path, triggerSpec); } else { addEventListener(elt, verb, path, nodeData, triggerSpec); } @@ -1371,14 +1625,24 @@ return (function () { } function evalScript(script) { - if (script.type === "text/javascript" || script.type === "") { + if (script.type === "text/javascript" || script.type === "module" || script.type === "") { + var newScript = getDocument().createElement("script"); + forEach(script.attributes, function (attr) { + newScript.setAttribute(attr.name, attr.value); + }); + newScript.textContent = script.textContent; + newScript.async = false; + if (htmx.config.inlineScriptNonce) { + newScript.nonce = htmx.config.inlineScriptNonce; + } + var parent = script.parentElement; + try { - maybeEval(script, function () { - // wtf - https://stackoverflow.com/questions/9107240/1-evalthis-vs-evalthis-in-javascript - (1, eval)(script.innerText); - }); + parent.insertBefore(newScript, script); } catch (e) { logError(e); + } finally { + parent.removeChild(script); } } } @@ -1392,21 +1656,41 @@ return (function () { }); } - function isBoosted() { + function hasChanceOfBeingBoosted() { return document.querySelector("[hx-boost], [data-hx-boost]"); } function findElementsToProcess(elt) { if (elt.querySelectorAll) { - var boostedElts = isBoosted() ? ", a, form" : ""; + var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws]"); + " [data-hx-ws], [hx-ext], [hx-data-ext]"); return results; } else { return []; } } + function initButtonTracking(form){ + var maybeSetLastButtonClicked = function(evt){ + if (matches(evt.target, "button, input[type='submit']")) { + var internalData = getInternalData(form); + internalData.lastButtonClicked = evt.target; + } + }; + + // need to handle both click and focus in: + // focusin - in case someone tabs in to a button and hits the space bar + // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + + form.addEventListener('click', maybeSetLastButtonClicked) + form.addEventListener('focusin', maybeSetLastButtonClicked) + form.addEventListener('focusout', function(evt){ + var internalData = getInternalData(form); + internalData.lastButtonClicked = null; + }) + } + function initNode(elt) { if (elt.closest && elt.closest(htmx.config.disableSelector)) { return; @@ -1427,6 +1711,10 @@ return (function () { boostElement(elt, nodeData, triggerSpecs); } + if (elt.tagName === "FORM") { + initButtonTracking(elt); + } + var sseInfo = getAttributeValue(elt, 'hx-sse'); if (sseInfo) { processSSEInfo(elt, nodeData, sseInfo); @@ -1473,6 +1761,15 @@ return (function () { return eventName === "htmx:afterProcessNode" } + /** + * `withExtensions` locates all active extensions for a provided element, then + * executes the provided function using each of the active extensions. It should + * be called internally at every extendable execution point in htmx. + * + * @param {HTMLElement} elt + * @param {(extension:import("./htmx").HtmxExtension) => void} toDo + * @returns void + */ function withExtensions(elt, toDo) { forEach(getExtensions(elt), function(extension){ try { @@ -1520,7 +1817,7 @@ return (function () { //==================================================================== // History Support //==================================================================== - var currentPathForHistory = null; + var currentPathForHistory = location.pathname+location.search; function getHistoryElement() { var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]'); @@ -1569,7 +1866,7 @@ return (function () { return clone.innerHTML; } - function saveHistory() { + function saveCurrentPageToHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); @@ -1598,9 +1895,11 @@ return (function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); var fragment = makeFragment(this.response); + // @ts-ignore fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; var historyElement = getHistoryElement(); var settleInfo = makeSettleInfo(historyElement); + // @ts-ignore swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); currentPathForHistory = path; @@ -1613,7 +1912,7 @@ return (function () { } function restoreHistory(path) { - saveHistory(); + saveCurrentPageToHistory(); path = path || location.pathname+location.search; var cached = getCachedHistory(path); if (cached) { @@ -1628,6 +1927,8 @@ return (function () { triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); } else { if (htmx.config.refreshOnHistoryMiss) { + + // @ts-ignore: optional parameter in reload() function throws error window.location.reload(true); } else { loadHistoryFromServer(path); @@ -1647,10 +1948,8 @@ return (function () { } function addRequestIndicatorClasses(elt) { - var indicator = getClosestAttributeValue(elt, 'hx-indicator'); - if (indicator) { - var indicators = querySelectorAllExt(elt, indicator); - } else { + var indicators = findAttributeTargets(elt, 'hx-indicator'); + if (indicators == null) { indicators = [elt]; } forEach(indicators, function (ic) { @@ -1753,14 +2052,22 @@ return (function () { } } + /** + * @param {HTMLElement} elt + * @param {string} verb + */ function getInputValues(elt, verb) { var processed = []; var values = {}; var formValues = {}; var errors = []; + var internalData = getInternalData(elt); - // only validate when form is directly submitted and novalidate is not set + // only validate when form is directly submitted and novalidate or formnovalidate are not set var validate = matches(elt, 'form') && elt.noValidate !== true; + if (internalData.lastButtonClicked) { + validate = validate && internalData.lastButtonClicked.formNoValidate !== true; + } // for a non-GET include the closest form if (verb !== 'get') { @@ -1770,21 +2077,26 @@ return (function () { // include the element itself processInputValue(processed, values, errors, elt, validate); - // include any explicit includes - var includes = getClosestAttributeValue(elt, "hx-include"); - if (includes) { - var nodes = querySelectorAllExt(elt, includes); - forEach(nodes, function(node) { - processInputValue(processed, values, errors, node, validate); - // if a non-form is included, include any input values within it - if (!matches(node, 'form')) { - forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { - processInputValue(processed, values, errors, descendant, validate); - }) - } - }); + // if a button or submit was clicked last, include its value + if (internalData.lastButtonClicked) { + var name = getRawAttribute(internalData.lastButtonClicked,"name"); + if (name) { + values[name] = internalData.lastButtonClicked.value; + } } + // include any explicit includes + var includes = findAttributeTargets(elt, "hx-include"); + forEach(includes, function(node) { + processInputValue(processed, values, errors, node, validate); + // if a non-form is included, include any input values within it + if (!matches(node, 'form')) { + forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { + processInputValue(processed, values, errors, descendant, validate); + }) + } + }); + // form values take precedence, overriding the regular values values = mergeObjects(values, formValues); @@ -1795,7 +2107,11 @@ return (function () { if (returnStr !== "") { returnStr += "&"; } - returnStr += encodeURIComponent(name) + "=" + encodeURIComponent(realValue); + if (String(realValue) === "[object Object]") { + realValue = JSON.stringify(realValue); + } + var s = encodeURIComponent(realValue); + returnStr += encodeURIComponent(name) + "=" + s; return returnStr; } @@ -1837,6 +2153,12 @@ return (function () { // Ajax //==================================================================== + /** + * @param {HTMLElement} elt + * @param {HTMLElement} target + * @param {string} prompt + * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification + */ function getHeaders(elt, target, prompt) { var headers = { "HX-Request" : "true", @@ -1849,9 +2171,20 @@ return (function () { if (prompt !== undefined) { headers["HX-Prompt"] = prompt; } + if (getInternalData(elt).boosted) { + headers["HX-Boosted"] = "true"; + } return headers; } + /** + * filterValues takes an object containing form input values + * and returns a new object that only contains keys that are + * specified by the closest "hx-params" attribute + * @param {Object} inputValues + * @param {HTMLElement} elt + * @returns {Object} + */ function filterValues(inputValues, elt) { var paramsValue = getClosestAttributeValue(elt, "hx-params"); if (paramsValue) { @@ -1882,8 +2215,14 @@ return (function () { return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0 } - function getSwapSpecification(elt) { - var swapInfo = getClosestAttributeValue(elt, "hx-swap"); + /** + * + * @param {HTMLElement} elt + * @param {string} swapInfoOverride + * @returns {import("./htmx").HtmxSwapSpecification} + */ + function getSwapSpecification(elt, swapInfoOverride) { + var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap"); var swapSpec = { "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, "swapDelay" : htmx.config.defaultSwapDelay, @@ -1905,10 +2244,24 @@ return (function () { swapSpec["settleDelay"] = parseInterval(modifier.substr(7)); } if (modifier.indexOf("scroll:") === 0) { - swapSpec["scroll"] = modifier.substr(7); + var scrollSpec = modifier.substr(7); + var splitSpec = scrollSpec.split(":"); + var scrollVal = splitSpec.pop(); + var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; + swapSpec["scroll"] = scrollVal; + swapSpec["scrollTarget"] = selectorVal; } if (modifier.indexOf("show:") === 0) { - swapSpec["show"] = modifier.substr(5); + var showSpec = modifier.substr(5); + var splitSpec = showSpec.split(":"); + var showVal = splitSpec.pop(); + var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; + swapSpec["show"] = showVal; + swapSpec["showTarget"] = selectorVal; + } + if (modifier.indexOf("focus-scroll:") === 0) { + var focusScrollVal = modifier.substr("focus-scroll:".length); + swapSpec["focusScroll"] = focusScrollVal == "true"; } } } @@ -1926,7 +2279,8 @@ return (function () { if (encodedParameters != null) { return encodedParameters; } else { - if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data") { + if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || + (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) { return makeFormData(filteredParameters); } else { return urlEncode(filteredParameters); @@ -1934,6 +2288,11 @@ return (function () { } } + /** + * + * @param {Element} target + * @returns {import("./htmx").HtmxSettleInfo} + */ function makeSettleInfo(target) { return {tasks: [], elts: [target]}; } @@ -1942,23 +2301,46 @@ return (function () { var first = content[0]; var last = content[content.length - 1]; if (swapSpec.scroll) { - if (swapSpec.scroll === "top" && first) { - first.scrollTop = 0; + var target = null; + if (swapSpec.scrollTarget) { + target = querySelectorExt(first, swapSpec.scrollTarget); + } + if (swapSpec.scroll === "top" && (first || target)) { + target = target || first; + target.scrollTop = 0; } - if (swapSpec.scroll === "bottom" && last) { - last.scrollTop = last.scrollHeight; + if (swapSpec.scroll === "bottom" && (last || target)) { + target = target || last; + target.scrollTop = target.scrollHeight; } } if (swapSpec.show) { - if (swapSpec.show === "top" && first) { - first.scrollIntoView(true); + var target = null; + if (swapSpec.showTarget) { + var targetStr = swapSpec.showTarget; + if (swapSpec.showTarget === "window") { + targetStr = "body"; + } + target = querySelectorExt(first, targetStr); + } + if (swapSpec.show === "top" && (first || target)) { + target = target || first; + target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior}); } - if (swapSpec.show === "bottom" && last) { - last.scrollIntoView(false); + if (swapSpec.show === "bottom" && (last || target)) { + target = target || last; + target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior}); } } } + /** + * @param {HTMLElement} elt + * @param {string} attr + * @param {boolean=} evalAsDefault + * @param {Object=} values + * @returns {Object} + */ function getValuesForElement(elt, attr, evalAsDefault, values) { if (values == null) { values = {}; @@ -1973,6 +2355,9 @@ return (function () { if (str.indexOf("javascript:") === 0) { str = str.substr(11); evaluateValue = true; + } else if (str.indexOf("js:") === 0) { + str = str.substr(3); + evaluateValue = true; } if (str.indexOf('{') !== 0) { str = "{" + str + "}"; @@ -2003,14 +2388,28 @@ return (function () { } } + /** + * @param {HTMLElement} elt + * @param {*} expressionVars + * @returns + */ function getHXVarsForElement(elt, expressionVars) { return getValuesForElement(elt, "hx-vars", true, expressionVars); } + /** + * @param {HTMLElement} elt + * @param {*} expressionVars + * @returns + */ function getHXValsForElement(elt, expressionVars) { return getValuesForElement(elt, "hx-vals", false, expressionVars); } + /** + * @param {HTMLElement} elt + * @returns {Object} + */ function getExpressionVars(elt) { return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)); } @@ -2044,10 +2443,12 @@ return (function () { } function ajaxHelper(verb, path, context) { + verb = verb.toLowerCase(); if (context) { if (context instanceof Element || isType(context, 'String')) { return issueAjaxRequest(verb, path, null, null, { - targetOverride: resolveTarget(context) + targetOverride: resolveTarget(context), + returnPromise: true }); } else { return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, @@ -2055,11 +2456,15 @@ return (function () { handler : context.handler, headers : context.headers, values : context.values, - targetOverride: resolveTarget(context.target) + targetOverride: resolveTarget(context.target), + swapOverride: context.swap, + returnPromise: true }); } } else { - return issueAjaxRequest(verb, path); + return issueAjaxRequest(verb, path, null, null, { + returnPromise: true + }); } } @@ -2076,7 +2481,7 @@ return (function () { var resolve = null; var reject = null; etc = etc != null ? etc : {}; - if(typeof Promise !== "undefined"){ + if(etc.returnPromise && typeof Promise !== "undefined"){ var promise = new Promise(function (_resolve, _reject) { resolve = _resolve; reject = _reject; @@ -2091,40 +2496,85 @@ return (function () { return; // do not issue requests for elements removed from the DOM } var target = etc.targetOverride || getTarget(elt); - if (target == null) { + if (target == null || target == DUMMY_ELT) { triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); return; } + + var syncElt = elt; var eltData = getInternalData(elt); - if (eltData.requestInFlight) { - var queueStrategy = 'last'; - var eventData = getInternalData(event); - if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { - queueStrategy = eventData.triggerSpec.queue; - } - if (eltData.queuedRequests == null) { - eltData.queuedRequests = []; - } - if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); - } else if (queueStrategy === "all") { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); - } else if (queueStrategy === "last") { - eltData.queuedRequests = []; // dump existing queue - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); + var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); + var queueStrategy = null; + var abortable = false; + if (syncStrategy) { + var syncStrings = syncStrategy.split(":"); + var selector = syncStrings[0].trim(); + if (selector === "this") { + syncElt = findThisElement(elt, 'hx-sync'); + } else { + syncElt = querySelectorExt(elt, selector); + } + // default to the drop strategy + syncStrategy = (syncStrings[1] || 'drop').trim(); + eltData = getInternalData(syncElt); + if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { + return; + } else if (syncStrategy === "abort") { + if (eltData.xhr) { + return; + } else { + abortable = true; + } + } else if (syncStrategy === "replace") { + triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue + } else if (syncStrategy.indexOf("queue") === 0) { + var queueStrArray = syncStrategy.split(" "); + queueStrategy = (queueStrArray[1] || "last").trim(); } - return; - } else { - eltData.requestInFlight = true; } + + if (eltData.xhr) { + if (eltData.abortable) { + triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue + } else { + if(queueStrategy == null){ + if (event) { + var eventData = getInternalData(event); + if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { + queueStrategy = eventData.triggerSpec.queue; + } + } + if (queueStrategy == null) { + queueStrategy = "last"; + } + } + if (eltData.queuedRequests == null) { + eltData.queuedRequests = []; + } + if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } else if (queueStrategy === "all") { + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } else if (queueStrategy === "last") { + eltData.queuedRequests = []; // dump existing queue + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } + return; + } + } + + var xhr = new XMLHttpRequest(); + eltData.xhr = xhr; + eltData.abortable = abortable; var endRequestLock = function(){ - eltData.requestInFlight = false + eltData.xhr = null; + eltData.abortable = false; if (eltData.queuedRequests != null && eltData.queuedRequests.length > 0) { var queuedRequest = eltData.queuedRequests.shift(); @@ -2152,11 +2602,10 @@ return (function () { } } - var xhr = new XMLHttpRequest(); var headers = getHeaders(elt, target, promptResponse); if (etc.headers) { - headers = mergeObjects(headers, etc.values); + headers = mergeObjects(headers, etc.headers); } var results = getInputValues(elt, verb); var errors = results.errors; @@ -2169,7 +2618,7 @@ return (function () { var filteredParameters = filterValues(allParameters, elt); if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null) { - headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; + headers['Content-Type'] = 'application/x-www-form-urlencoded'; } // behavior of anchors w/ empty href is to use the current URL @@ -2177,6 +2626,8 @@ return (function () { path = getDocument().location.href; } + var requestAttrValues = getValuesForElement(elt, 'hx-request'); + var requestConfig = { parameters: filteredParameters, unfilteredParameters: allParameters, @@ -2184,6 +2635,8 @@ return (function () { target:target, verb:verb, errors:errors, + withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, + timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, path:path, triggeringEvent:event }; @@ -2231,17 +2684,22 @@ return (function () { } xhr.overrideMimeType("text/html"); - xhr.withCredentials = htmx.config.withCredentials; + xhr.withCredentials = requestConfig.withCredentials; + xhr.timeout = requestConfig.timeout; // request headers - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - var headerValue = headers[header]; - safelySetHeaderValue(xhr, header, headerValue); + if (requestAttrValues.noHeaders) { + // ignore all headers + } else { + for (var header in headers) { + if (headers.hasOwnProperty(header)) { + var headerValue = headers[header]; + safelySetHeaderValue(xhr, header, headerValue); + } } } - var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, pathInfo:{ + var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, etc:etc, pathInfo:{ path:path, finalPath:finalPathForGet, anchor:anchor } }; @@ -2289,6 +2747,13 @@ return (function () { maybeCall(reject); endRequestLock(); } + xhr.ontimeout = function() { + removeRequestIndicatorClasses(indicators); + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); + triggerErrorEvent(elt, 'htmx:timeout', responseInfo); + maybeCall(reject); + endRequestLock(); + } if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){ maybeCall(resolve); endRequestLock() @@ -2315,6 +2780,7 @@ return (function () { function handleAjaxResponse(elt, responseInfo) { var xhr = responseInfo.xhr; var target = responseInfo.target; + var etc = responseInfo.etc; if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; @@ -2338,123 +2804,162 @@ return (function () { } } - var shouldSaveHistory = shouldPush(elt) || pushedUrl; + if (hasHeader(xhr,/HX-Retarget:/i)) { + responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget")); + } - if (xhr.status >= 200 && xhr.status < 400) { + /** @type {boolean} */ + var shouldSaveHistory + if (pushedUrl == "false") { + shouldSaveHistory = false + } else { + shouldSaveHistory = shouldPush(elt) || pushedUrl; + } + + // by default htmx only swaps on 200 return codes and does not swap + // on 204 'No Content' + // this can be ovverriden by responding to the htmx:beforeSwap event and + // overriding the detail.shouldSwap property + var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; + var serverResponse = xhr.response; + var isError = xhr.status >= 400; + var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo); + if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; + + target = beforeSwapDetails.target; // allow re-targeting + serverResponse = beforeSwapDetails.serverResponse; // allow updating content + isError = beforeSwapDetails.isError; // allow updating error + + responseInfo.failed = isError; // Make failed property available to response events + responseInfo.successful = !isError; // Make successful property available to response events + + if (beforeSwapDetails.shouldSwap) { if (xhr.status === 286) { cancelPolling(elt); } - // don't process 'No Content' - if (xhr.status !== 204) { - if (!triggerEvent(target, 'htmx:beforeSwap', responseInfo)) return; - var serverResponse = xhr.response; - withExtensions(elt, function(extension){ - serverResponse = extension.transformResponse(serverResponse, xhr, elt); - }); + withExtensions(elt, function (extension) { + serverResponse = extension.transformResponse(serverResponse, xhr, elt); + }); - // Save current page - if (shouldSaveHistory) { - saveHistory(); - } + // Save current page + if (shouldSaveHistory) { + saveCurrentPageToHistory(); + } + + var swapOverride = etc.swapOverride; + var swapSpec = getSwapSpecification(elt, swapOverride); - var swapSpec = getSwapSpecification(elt); + target.classList.add(htmx.config.swappingClass); + var doSwap = function () { + try { - target.classList.add(htmx.config.swappingClass); - var doSwap = function () { + var activeElt = document.activeElement; + var selectionInfo = {}; try { + selectionInfo = { + elt: activeElt, + // @ts-ignore + start: activeElt ? activeElt.selectionStart : null, + // @ts-ignore + end: activeElt ? activeElt.selectionEnd : null + }; + } catch (e) { + // safari issue - see https://github.com/microsoft/playwright/issues/5894 + } - var activeElt = document.activeElement; - var selectionInfo = {}; - try { - selectionInfo = { - elt: activeElt, - start: activeElt ? activeElt.selectionStart : null, - end: activeElt ? activeElt.selectionEnd : null - }; - } catch (e) { - // safari issue - see https://github.com/microsoft/playwright/issues/5894 + var settleInfo = makeSettleInfo(target); + selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + + if (selectionInfo.elt && + !bodyContains(selectionInfo.elt) && + selectionInfo.elt.id) { + var newActiveElt = document.getElementById(selectionInfo.elt.id); + var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; + if (newActiveElt) { + // @ts-ignore + if (selectionInfo.start && newActiveElt.setSelectionRange) { + // @ts-ignore + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + } + newActiveElt.focus(focusOptions); } + } - var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + target.classList.remove(htmx.config.swappingClass); + forEach(settleInfo.elts, function (elt) { + if (elt.classList) { + elt.classList.add(htmx.config.settlingClass); + } + triggerEvent(elt, 'htmx:afterSwap', responseInfo); + }); + if (responseInfo.pathInfo.anchor) { + location.hash = responseInfo.pathInfo.anchor; + } - if (selectionInfo.elt && - !bodyContains(selectionInfo.elt) && - selectionInfo.elt.id) { - var newActiveElt = document.getElementById(selectionInfo.elt.id); - if (newActiveElt) { - if (selectionInfo.start && newActiveElt.setSelectionRange) { - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); - } - newActiveElt.focus(); - } + if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { + var finalElt = elt; + if (!bodyContains(elt)) { + finalElt = getDocument().body; } + handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); + } - target.classList.remove(htmx.config.swappingClass); + var doSettle = function () { + forEach(settleInfo.tasks, function (task) { + task.call(); + }); forEach(settleInfo.elts, function (elt) { if (elt.classList) { - elt.classList.add(htmx.config.settlingClass); + elt.classList.remove(htmx.config.settlingClass); } - triggerEvent(elt, 'htmx:afterSwap', responseInfo); + triggerEvent(elt, 'htmx:afterSettle', responseInfo); }); - if (responseInfo.pathInfo.anchor) { - location.hash = responseInfo.pathInfo.anchor; + // push URL and save new page + if (shouldSaveHistory) { + var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; + pushUrlIntoHistory(pathToPush); + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: pathToPush}); } - if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; + if(settleInfo.title) { + var titleElt = find("title"); + if(titleElt) { + titleElt.innerHTML = settleInfo.title; + } else { + window.document.title = settleInfo.title; } - handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); } - var doSettle = function(){ - forEach(settleInfo.tasks, function (task) { - task.call(); - }); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.remove(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSettle', responseInfo); - }); - // push URL and save new page - if (shouldSaveHistory) { - var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; - pushUrlIntoHistory(pathToPush); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path:pathToPush}); - } - updateScrollState(settleInfo.elts, swapSpec); + updateScrollState(settleInfo.elts, swapSpec); - if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); + if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { + var finalElt = elt; + if (!bodyContains(elt)) { + finalElt = getDocument().body; } + handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'htmx:swapError', responseInfo); - throw e; } - }; - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); + if (swapSpec.settleDelay > 0) { + setTimeout(doSettle, swapSpec.settleDelay) + } else { + doSettle(); + } + } catch (e) { + triggerErrorEvent(elt, 'htmx:swapError', responseInfo); + throw e; } + }; + + if (swapSpec.swapDelay > 0) { + setTimeout(doSwap, swapSpec.swapDelay) + } else { + doSwap(); } - } else { + } + if (isError) { triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.path}, responseInfo)); } } @@ -2462,9 +2967,17 @@ return (function () { //==================================================================== // Extensions API //==================================================================== + + /** @type {Object<string, import("./htmx").HtmxExtension>} */ var extensions = {}; + + /** + * extensionBase defines the default functions for all extensions. + * @returns {import("./htmx").HtmxExtension} + */ function extensionBase() { return { + init: function(api) {return null;}, onEvent : function(name, evt) {return true;}, transformResponse : function(text, xhr, elt) {return text;}, isInlineSwap : function(swapStyle) {return false;}, @@ -2473,15 +2986,37 @@ return (function () { } } + /** + * defineExtension initializes the extension and adds it to the htmx registry + * + * @param {string} name + * @param {import("./htmx").HtmxExtension} extension + */ function defineExtension(name, extension) { + if(extension.init) { + extension.init(internalAPI) + } extensions[name] = mergeObjects(extensionBase(), extension); } + /** + * removeExtension removes an extension from the htmx registry + * + * @param {string} name + */ function removeExtension(name) { delete extensions[name]; } - function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + /** + * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element + * + * @param {HTMLElement} elt + * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn + * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore + */ + function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + if (elt == undefined) { return extensionsToReturn; } @@ -2536,6 +3071,7 @@ return (function () { function getMetaConfig() { var element = getDocument().querySelector('meta[name="htmx-config"]'); if (element) { + // @ts-ignore return parseJSON(element.content); } else { return null; @@ -2555,9 +3091,25 @@ return (function () { insertIndicatorStyles(); var body = getDocument().body; processNode(body); + var restoredElts = getDocument().querySelectorAll( + "[hx-trigger='restored'],[data-hx-trigger='restored']" + ); + body.addEventListener("htmx:abort", function (evt) { + var target = evt.target; + var internalData = getInternalData(target); + if (internalData && internalData.xhr) { + internalData.xhr.abort(); + } + }); window.onpopstate = function (event) { if (event.state && event.state.htmx) { restoreHistory(); + forEach(restoredElts, function(elt){ + triggerEvent(elt, 'htmx:restored', { + 'document': getDocument(), + 'triggerEvent': triggerEvent + }); + }); } }; setTimeout(function () { diff --git a/code/ch4_app/ch4_starter_video_collector/static/js/htmx.min.js b/code/ch4_app/ch4_starter_video_collector/static/js/htmx.min.js index 57f33b2..998414c 100644 --- a/code/ch4_app/ch4_starter_video_collector/static/js/htmx.min.js +++ b/code/ch4_app/ch4_starter_video_collector/static/js/htmx.min.js @@ -1 +1 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var k={onLoad:t,process:rt,on:I,off:M,trigger:lt,ajax:$t,find:w,findAll:S,closest:L,values:function(e,t){var r=Lt(e,t||"post");return r.values},remove:E,addClass:q,removeClass:R,toggleClass:C,takeClass:O,defineExtension:Qt,removeExtension:er,logAll:b,logger:null,useTemplateFragments:false,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,attributesToSettle:["class","style","width","height"],withCredentials:false,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]"},parseInterval:f,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])}};var r=["get","post","put","delete","patch"];var n=r.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function f(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function l(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function D(e,t){return l(e,t)||l(e,"data-"+t)}function c(e){return e.parentElement}function F(){return document}function h(e,t){if(t(e)){return e}else if(c(e)){return h(c(e),t)}else{return null}}function X(e,t){var r=null;h(e,function(e){return r=D(e,t)});return r}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function i(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 o(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=F().createDocumentFragment()}return i}function u(e){if(k.config.useTemplateFragments){var t=o("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=i(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return o("<table>"+e+"</table>",1);case"col":return o("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return o("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return o("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return o("<div>"+e+"</div>",1);default:return o(e,0)}}}function P(e){if(e){e()}}function a(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function v(e){return a(e,"Function")}function g(e){return a(e,"Object")}function U(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function p(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function j(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function m(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function z(e){return F().body.contains(e)}function y(e){return e.trim().split(/\s+/)}function V(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function x(e){try{return JSON.parse(e)}catch(e){ut(e);return null}}function e(e){return Ut(F().body,function(){return eval(e)})}function t(t){var e=k.on("htmx:load",function(e){t(e.detail.elt)});return e}function b(){k.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function w(e,t){if(t){return e.querySelector(t)}else{return w(F(),e)}}function S(e,t){if(t){return e.querySelectorAll(t)}else{return S(F(),e)}}function E(e,t){e=H(e);if(t){setTimeout(function(){E(e)},t)}else{e.parentElement.removeChild(e)}}function q(e,t,r){e=H(e);if(r){setTimeout(function(){q(e,t)},r)}else{e.classList.add(t)}}function R(e,t,r){e=H(e);if(r){setTimeout(function(){R(e,t)},r)}else{e.classList.remove(t)}}function C(e,t){e=H(e);e.classList.toggle(t)}function O(e,t){e=H(e);j(e.parentElement.children,function(e){R(e,t)});q(e,t)}function L(e,t){e=H(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&c(e))}}function A(e,t){if(t.indexOf("closest ")===0){return[L(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[w(e,t.substr(5))]}else{return F().querySelectorAll(t)}}function T(e,t){return A(e,t)[0]}function H(e){if(a(e,"String")){return w(e)}else{return e}}function N(e,t,r){if(v(t)){return{target:F().body,event:e,listener:t}}else{return{target:H(e),event:t,listener:r}}}function I(t,r,n){rr(function(){var e=N(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=v(r);return e?r:n}function M(t,r,n){rr(function(){var e=N(t,r,n);e.target.removeEventListener(e.event,e.listener)});return v(r)?r:n}function _(e){var t=h(e,function(e){return D(e,"hx-target")!==null});if(t){var r=D(t,"hx-target");if(r==="this"){return t}else{return T(e,r)}}else{var n=U(e);if(n.boosted){return F().body}else{return e}}}function B(e){var t=k.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function W(t,r){j(t.attributes,function(e){if(!r.hasAttribute(e.name)&&B(e.name)){t.removeAttribute(e.name)}});j(r.attributes,function(e){if(B(e.name)){t.setAttribute(e.name,e.value)}})}function $(e,t){var r=tr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){ut(e)}}return e==="outerHTML"}function J(e,t,r){var n="#"+t.id;var i="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){i=e.substr(0,e.indexOf(":"));n=e.substr(e.indexOf(":")+1,e.length)}else{i=e}var o=F().querySelector(n);if(o){var a;a=F().createDocumentFragment();a.appendChild(t);if(!$(i,o)){a=t}le(i,o,o,a,r)}else{t.parentNode.removeChild(t);ot(F().body,"htmx:oobErrorNoTarget",{content:t})}return e}function Z(e,r){j(S(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=D(e,"hx-swap-oob");if(t!=null){J(t,e,r)}})}function G(e){j(S(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=D(e,"id");var r=F().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function K(n,e,i){j(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();W(e,t);i.tasks.push(function(){W(e,r)})}}})}function Y(e){return function(){rt(e);Ye(e);Q(e);lt(e,"htmx:load")}}function Q(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ee(e,t,r,n){K(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Y(i))}}}function te(t){var e=U(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}if(e.listenerInfos){j(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){j(t.children,function(e){te(e)})}}function re(e,t,r){if(e.tagName==="BODY"){return se(e,t,r)}else{var n=e.previousSibling;ee(c(e),e,t,r);if(n==null){var i=c(e).firstChild}else{var i=n.nextSibling}U(e).replacedWith=i;r.elts=[];while(i&&i!==e){if(i.nodeType===Node.ELEMENT_NODE){r.elts.push(i)}i=i.nextElementSibling}te(e);c(e).removeChild(e)}}function ne(e,t,r){return ee(e,e.firstChild,t,r)}function ie(e,t,r){return ee(c(e),e,t,r)}function oe(e,t,r){return ee(e,null,t,r)}function ae(e,t,r){return ee(c(e),e.nextSibling,t,r)}function se(e,t,r){var n=e.firstChild;ee(e,n,t,r);if(n){while(n.nextSibling){te(n.nextSibling);e.removeChild(n.nextSibling)}te(n);e.removeChild(n)}}function ue(e,t){var r=X(e,"hx-select");if(r){var n=F().createDocumentFragment();j(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function le(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":re(r,n,i);return;case"afterbegin":ne(r,n,i);return;case"beforebegin":ie(r,n,i);return;case"beforeend":oe(r,n,i);return;case"afterend":ae(r,n,i);return;default:var o=tr(t);for(var a=0;a<o.length;a++){var s=o[a];try{var u=s.handleSwap(e,r,n,i);if(u){if(typeof u.length!=="undefined"){for(var l=0;l<u.length;l++){var f=u[l];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Y(f))}}}return}}catch(e){ut(e)}}se(r,n,i)}}var fe=/<title>([\s\S]+?)<\/title>/im;function ce(e){if(e.indexOf("<title>")>-1&&(e.indexOf("<svg>")==-1||e.indexOf("<title>")<e.indexOf("<svg>"))){var t=fe.exec(e);if(t){return t[1]}}}function he(e,t,r,n,i){var o=ce(n);if(o){var a=w("title");if(a){a.innerHTML=o}else{window.document.title=o}}var s=u(n);if(s){Z(s,i);s=ue(r,s);G(s);return le(e,r,t,s,i)}}function de(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=x(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!g(a)){a={value:a}}lt(r,o,a)}}}else{lt(r,n,[])}}var ve=/\s/;var ge=/[\s,]/;var pe=/[_$a-zA-Z]/;var me=/[_$a-zA-Z0-9]/;var ye=['"',"'","/"];var xe=/[^\s]/;function be(e){var t=[];var r=0;while(r<e.length){if(pe.exec(e.charAt(r))){var n=r;while(me.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(ye.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function we(e,t,r){return pe.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function Se(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Ut(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){ot(F().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(we(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function Ee(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var qe="input, textarea, select";function Re(e){var t=D(e,"hx-trigger");var r=[];if(t){var n=be(t);do{Ee(n,xe);var i=n.length;var o=Ee(n,/[,\[\s]/);if(o!==""){if(o==="every"){var a={trigger:"every"};Ee(n,xe);a.pollInterval=f(Ee(n,ve));r.push(a)}else if(o.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:o.substr(4)})}else{var s={trigger:o};var u=Se(e,n,"event");if(u){s.eventFilter=u}while(n.length>0&&n[0]!==","){Ee(n,xe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=f(Ee(n,ge))}else if(l==="from"&&n[0]===":"){n.shift();s.from=Ee(n,ge)}else if(l==="target"&&n[0]===":"){n.shift();s.target=Ee(n,ge)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=f(Ee(n,ge))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=Ee(n,ge)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=Ee(n,ge)}else{ot(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===i){ot(e,"htmx:syntax:error",{token:n.shift()})}Ee(n,xe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,qe)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ce(e){U(e).cancelled=true}function Oe(e,t,r,n){var i=U(e);i.timeout=setTimeout(function(){if(z(e)&&i.cancelled!==true){Zt(t,r,e);Oe(e,t,D(e,"hx-"+t),n)}},n)}function Le(e){return location.hostname===e.hostname&&l(e,"href")&&l(e,"href").indexOf("#")!==0}function Ae(t,r,e){if(t.tagName==="A"&&Le(t)||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=l(t,"href");r.pushURL=true}else{var o=l(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=l(t,"action")}e.forEach(function(e){Ie(t,n,i,r,e,true)})}}function Te(e){return e.tagName==="FORM"||d(e,'input[type="submit"], button')&&L(e,"form")!==null||e.tagName==="A"&&e.href&&(e.getAttribute("href")==="#"||e.getAttribute("href").indexOf("#")!==0)}function He(e,t){return U(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function Ne(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){ot(F().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Ie(n,i,o,e,a,s){var u=n;if(a.from){u=w(a.from)}var l=function(e){if(!z(n)){u.removeEventListener(a.trigger,l);return}if(He(n,e)){return}if(s||Te(n)){e.preventDefault()}if(Ne(a,e)){return}var t=U(e);t.triggerSpec=a;if(t.handledFor==null){t.handledFor=[]}var r=U(n);if(t.handledFor.indexOf(n)<0){t.handledFor.push(n);if(a.consume){e.stopPropagation()}if(a.target&&e.target){if(!d(e.target,a.target)){return}}if(a.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(a.changed){if(r.lastValue===n.value){return}else{r.lastValue=n.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(a.throttle){if(!r.throttle){Zt(i,o,n,e);r.throttle=setTimeout(function(){r.throttle=null},a.throttle)}}else if(a.delay){r.delayed=setTimeout(function(){Zt(i,o,n,e)},a.delay)}else{Zt(i,o,n,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:a.trigger,listener:l,on:u});u.addEventListener(a.trigger,l)}var Me=false;var ke=null;function De(){if(!ke){ke=function(){Me=true};window.addEventListener("scroll",ke);setInterval(function(){if(Me){Me=false;j(F().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){Fe(e)})}},200)}}function Fe(e){var t=U(e);if(!t.revealed&&m(e)){t.revealed=true;if(t.initialized){Zt(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Zt(t.verb,t.path,e)},{once:true})}}}function Xe(e,t,r){var n=y(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Pe(e,o[1],0)}if(o[0]==="send"){je(e)}}}function Pe(s,r,n){if(!z(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=k.createWebSocket(r);t.onerror=function(e){ot(s,"htmx:wsError",{error:e,socket:t});Ue(s)};t.onclose=function(e){if([1006,1012,1013].includes(e.code)){var t=ze(n);setTimeout(function(){Pe(s,r,n+1)},t)}};t.onopen=function(e){n=0};U(s).webSocket=t;t.addEventListener("message",function(e){if(Ue(s)){return}var t=e.data;st(s,function(e){t=e.transformResponse(t,null,s)});var r=Ft(s);var n=u(t);var i=p(n.children);for(var o=0;o<i.length;o++){var a=i[o];J(D(a,"hx-swap-oob")||"true",a,r)}mt(r.tasks)})}function Ue(e){if(!z(e)){U(e).webSocket.close();return true}}function je(l){var f=h(l,function(e){return U(e).webSocket!=null});if(f){l.addEventListener(Re(l)[0].trigger,function(e){var t=U(f).webSocket;var r=Nt(l,f);var n=Lt(l,"post");var i=n.errors;var o=n.values;var a=Vt(l);var s=V(o,a);var u=It(s,l);u["HEADERS"]=r;if(i&&i.length>0){lt(l,"htmx:validation:halted",i);return}t.send(JSON.stringify(u));if(Te(l)){e.preventDefault()}})}else{ot(l,"htmx:noWebSocketSourceError")}}function ze(e){var t=k.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}ut('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ve(e,t,r){var n=y(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){_e(e,o[1])}if(o[0]==="swap"){Be(e,o[1])}}}function _e(t,e){var r=k.createEventSource(e);r.onerror=function(e){ot(t,"htmx:sseError",{error:e,source:r});$e(t)};U(t).sseEventSource=r}function Be(o,a){var s=h(o,Je);if(s){var u=U(s).sseEventSource;var l=function(e){if($e(s)){u.removeEventListener(a,l);return}var t=e.data;st(o,function(e){t=e.transformResponse(t,null,o)});var r=kt(o);var n=_(o);var i=Ft(o);he(r.swapStyle,o,n,t,i);mt(i.tasks);lt(o,"htmx:sseMessage",e)};U(o).sseListener=l;u.addEventListener(a,l)}else{ot(o,"htmx:noSSESourceError")}}function We(e,t,r,n){var i=h(e,Je);if(i){var o=U(i).sseEventSource;var a=function(){if(!$e(i)){if(z(e)){Zt(t,r,e)}else{o.removeEventListener(n,a)}}};U(e).sseListener=a;o.addEventListener(n,a)}else{ot(e,"htmx:noSSESourceError")}}function $e(e){if(!z(e)){U(e).sseEventSource.close();return true}}function Je(e){return U(e).sseEventSource!=null}function Ze(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Zt(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function Ge(o,a,e){var t=false;j(r,function(n){if(s(o,"hx-"+n)){var i=D(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){We(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){De();Fe(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=T(e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){lt(o,"intersect");break}}},t);r.observe(o);Ie(o,n,i,a,e)}else if(e.trigger==="load"){Ze(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Oe(o,n,i,e.pollInterval)}else{Ie(o,n,i,a,e)}})}});return t}function Ke(e){if(e.type==="text/javascript"||e.type===""){try{Ut(e,function(){(1,eval)(e.innerText)})}catch(e){ut(e)}}}function Ye(e){if(d(e,"script")){Ke(e)}j(S(e,"script"),function(e){Ke(e)})}function Qe(){return document.querySelector("[hx-boost], [data-hx-boost]")}function et(e){if(e.querySelectorAll){var t=Qe()?", a, form":"";var r=e.querySelectorAll(n+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws]");return r}else{return[]}}function tt(e){if(e.closest&&e.closest(k.config.disableSelector)){return}var t=U(e);if(!t.initialized){t.initialized=true;lt(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=Re(e);var n=Ge(e,t,r);if(!n&&X(e,"hx-boost")==="true"){Ae(e,t,r)}var i=D(e,"hx-sse");if(i){Ve(e,t,i)}var o=D(e,"hx-ws");if(o){Xe(e,t,o)}lt(e,"htmx:afterProcessNode")}}function rt(e){e=H(e);tt(e);j(et(e),function(e){tt(e)})}function nt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function it(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=F().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function ot(e,t,r){lt(e,t,V({error:t},r))}function at(e){return e==="htmx:afterProcessNode"}function st(e,t){j(tr(e),function(e){try{t(e)}catch(e){ut(e)}})}function ut(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function lt(e,t,r){e=H(e);if(r==null){r={}}r["elt"]=e;var n=it(t,r);if(k.logger&&!at(t)){k.logger(e,t,r)}if(r.error){ut(r.error);lt(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=nt(t);if(i&&o!==t){var a=it(o,n.detail);i=i&&e.dispatchEvent(a)}st(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var ft=null;function ct(){var e=F().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||F().body}function ht(e,t,r,n){var i=x(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>k.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ot(F().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function dt(e){var t=x(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function vt(e){var t=k.config.requestClass;var r=e.cloneNode(true);j(S(r,"."+t),function(e){R(e,t)});return r.innerHTML}function gt(){var e=ct();var t=ft||location.pathname+location.search;lt(F().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(k.config.historyEnabled)history.replaceState({htmx:true},F().title,window.location.href);ht(t,vt(e),F().title,window.scrollY)}function pt(e){if(k.config.historyEnabled)history.pushState({htmx:true},"",e);ft=e}function mt(e){j(e,function(e){e.call()})}function yt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};lt(F().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){lt(F().body,"htmx:historyCacheMissLoad",i);var e=u(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=ct();var r=Ft(t);se(t,e,r);mt(r.tasks);ft=n;lt(F().body,"htmx:historyRestore",{path:n})}else{ot(F().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function xt(e){gt();e=e||location.pathname+location.search;var t=dt(e);if(t){var r=u(t.content);var n=ct();var i=Ft(n);se(n,r,i);mt(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);ft=e;lt(F().body,"htmx:historyRestore",{path:e})}else{if(k.config.refreshOnHistoryMiss){window.location.reload(true)}else{yt(e)}}}function bt(e){var t=X(e,"hx-push-url");return t&&t!=="false"||U(e).boosted&&U(e).pushURL}function wt(e){var t=X(e,"hx-push-url");return t==="true"||t==="false"?null:t}function St(e){var t=X(e,"hx-indicator");if(t){var r=A(e,t)}else{r=[e]}j(r,function(e){e.classList["add"].call(e.classList,k.config.requestClass)});return r}function Et(e){j(e,function(e){e.classList["remove"].call(e.classList,k.config.requestClass)})}function qt(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Rt(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 Ct(t,r,n,e,i){if(e==null||qt(t,e)){return}else{t.push(e)}if(Rt(e)){var o=l(e,"name");var a=e.value;if(e.multiple){a=p(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=p(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){Ot(e,n)}}if(d(e,"form")){var u=e.elements;j(u,function(e){Ct(t,r,n,e,i)})}}function Ot(e,t){if(e.willValidate){lt(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});lt(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Lt(e,t){var r=[];var n={};var i={};var o=[];var a=d(e,"form")&&e.noValidate!==true;if(t!=="get"){Ct(r,i,o,L(e,"form"),a)}Ct(r,n,o,e,a);var s=X(e,"hx-include");if(s){var u=A(e,s);j(u,function(e){Ct(r,n,o,e,a);if(!d(e,"form")){j(e.querySelectorAll(qe),function(e){Ct(r,n,o,e,a)})}})}n=V(n,i);return{errors:o,values:n}}function At(e,t,r){if(e!==""){e+="&"}e+=encodeURIComponent(t)+"="+encodeURIComponent(r);return e}function Tt(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){j(n,function(e){t=At(t,r,e)})}else{t=At(t,r,n)}}}return t}function Ht(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){j(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Nt(e,t,r){var n={"HX-Request":"true","HX-Trigger":l(e,"id"),"HX-Trigger-Name":l(e,"name"),"HX-Target":D(t,"id"),"HX-Current-URL":F().location.href};Pt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}return n}function It(t,e){var r=X(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){j(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};j(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Mt(e){return l(e,"href")&&l(e,"href").indexOf("#")>=0}function kt(e){var t=X(e,"hx-swap");var r={swapStyle:U(e).boosted?"innerHTML":k.config.defaultSwapStyle,swapDelay:k.config.defaultSwapDelay,settleDelay:k.config.defaultSettleDelay};if(U(e).boosted&&!Mt(e)){r["show"]="top"}if(t){var n=y(t);if(n.length>0){r["swapStyle"]=n[0];for(var i=1;i<n.length;i++){var o=n[i];if(o.indexOf("swap:")===0){r["swapDelay"]=f(o.substr(5))}if(o.indexOf("settle:")===0){r["settleDelay"]=f(o.substr(7))}if(o.indexOf("scroll:")===0){r["scroll"]=o.substr(7)}if(o.indexOf("show:")===0){r["show"]=o.substr(5)}}}}return r}function Dt(t,r,n){var i=null;st(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(X(r,"hx-encoding")==="multipart/form-data"){return Ht(n)}else{return Tt(n)}}}function Ft(e){return{tasks:[],elts:[e]}}function Xt(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){if(t.scroll==="top"&&r){r.scrollTop=0}if(t.scroll==="bottom"&&n){n.scrollTop=n.scrollHeight}}if(t.show){if(t.show==="top"&&r){r.scrollIntoView(true)}if(t.show==="bottom"&&n){n.scrollIntoView(false)}}}function Pt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=D(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Ut(e,function(){return Function("return ("+o+")")()},{})}else{s=x(o)}for(var u in s){if(s.hasOwnProperty(u)){if(n[u]==null){n[u]=s[u]}}}}return Pt(c(e),t,r,n)}function Ut(e,t,r){if(k.config.allowEval){return t()}else{ot(e,"htmx:evalDisallowedError");return r}}function jt(e,t){return Pt(e,"hx-vars",true,t)}function zt(e,t){return Pt(e,"hx-vals",false,t)}function Vt(e){return V(jt(e),zt(e))}function _t(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Bt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ot(F().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Wt(e,t){return e.getAllResponseHeaders().match(t)}function $t(e,t,r){if(r){if(r instanceof Element||a(r,"String")){return Zt(e,t,null,null,{targetOverride:H(r)})}else{return Zt(e,t,H(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:H(r.target)})}}else{return Zt(e,t)}}function Jt(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Zt(e,t,n,r,i){var o=null;var a=null;i=i!=null?i:{};if(typeof Promise!=="undefined"){var s=new Promise(function(e,t){o=e;a=t})}if(n==null){n=F().body}var u=i.handler||Gt;if(!z(n)){return}var l=i.targetOverride||_(n);if(l==null){ot(n,"htmx:targetError",{target:D(n,"hx-target")});return}var f=U(n);if(f.requestInFlight){var c="last";var h=U(r);if(h&&h.triggerSpec&&h.triggerSpec.queue){c=h.triggerSpec.queue}if(f.queuedRequests==null){f.queuedRequests=[]}if(c==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){Zt(e,t,n,r)})}else if(c==="all"){f.queuedRequests.push(function(){Zt(e,t,n,r)})}else if(c==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){Zt(e,t,n,r)})}return}else{f.requestInFlight=true}var d=function(){f.requestInFlight=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var v=X(n,"hx-prompt");if(v){var g=prompt(v);if(g===null||!lt(n,"htmx:prompt",{prompt:g,target:l})){P(o);d();return s}}var p=X(n,"hx-confirm");if(p){if(!confirm(p)){P(o);d();return s}}var m=new XMLHttpRequest;var y=Nt(n,l,g);if(i.headers){y=V(y,i.values)}var x=Lt(n,e);var b=x.errors;var w=x.values;if(i.values){w=V(w,i.values)}var S=Vt(n);var E=V(w,S);var q=It(E,n);if(e!=="get"&&X(n,"hx-encoding")==null){y["Content-Type"]="application/x-www-form-urlencoded; charset=UTF-8"}if(t==null||t===""){t=F().location.href}var R={parameters:q,unfilteredParameters:E,headers:y,target:l,verb:e,errors:b,path:t,triggeringEvent:r};if(!lt(n,"htmx:configRequest",R)){P(o);d();return s}t=R.path;e=R.verb;y=R.headers;q=R.parameters;b=R.errors;if(b&&b.length>0){lt(n,"htmx:validation:halted",R);P(o);d();return s}var C=t.split("#");var O=C[0];var L=C[1];if(e==="get"){var A=O;var T=Object.keys(q).length!==0;if(T){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=Tt(q);if(L){A+="#"+L}}m.open("GET",A,true)}else{m.open(e.toUpperCase(),t,true)}m.overrideMimeType("text/html");m.withCredentials=k.config.withCredentials;for(var H in y){if(y.hasOwnProperty(H)){var N=y[H];_t(m,H,N)}}var I={xhr:m,target:l,requestConfig:R,pathInfo:{path:t,finalPath:A,anchor:L}};m.onload=function(){try{var e=Jt(n);u(n,I);Et(M);lt(n,"htmx:afterRequest",I);lt(n,"htmx:afterOnLoad",I);if(!z(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(z(r)){t=r}}if(t){lt(t,"htmx:afterRequest",I);lt(t,"htmx:afterOnLoad",I)}}P(o);d()}catch(e){ot(n,"htmx:onLoadError",V({error:e},I));throw e}};m.onerror=function(){Et(M);ot(n,"htmx:afterRequest",I);ot(n,"htmx:sendError",I);P(a);d()};m.onabort=function(){Et(M);ot(n,"htmx:afterRequest",I);ot(n,"htmx:sendAbort",I);P(a);d()};if(!lt(n,"htmx:beforeRequest",I)){P(o);d();return s}var M=St(n);j(["loadstart","loadend","progress","abort"],function(t){j([m,m.upload],function(e){e.addEventListener(t,function(e){lt(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});lt(n,"htmx:beforeSend",I);m.send(e==="get"?null:Dt(m,n,q));return s}function Gt(a,s){var u=s.xhr;var l=s.target;if(!lt(a,"htmx:beforeOnLoad",s))return;if(Wt(u,/HX-Trigger:/i)){de(u,"HX-Trigger",a)}if(Wt(u,/HX-Push:/i)){var f=u.getResponseHeader("HX-Push")}if(Wt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Wt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}var c=bt(a)||f;if(u.status>=200&&u.status<400){if(u.status===286){Ce(a)}if(u.status!==204){if(!lt(l,"htmx:beforeSwap",s))return;var h=u.response;st(a,function(e){h=e.transformResponse(h,u,a)});if(c){gt()}var d=kt(a);l.classList.add(k.config.swappingClass);var e=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r=Ft(l);he(d.swapStyle,l,a,h,r);if(t.elt&&!z(t.elt)&&t.elt.id){var n=document.getElementById(t.elt.id);if(n){if(t.start&&n.setSelectionRange){n.setSelectionRange(t.start,t.end)}n.focus()}}l.classList.remove(k.config.swappingClass);j(r.elts,function(e){if(e.classList){e.classList.add(k.config.settlingClass)}lt(e,"htmx:afterSwap",s)});if(s.pathInfo.anchor){location.hash=s.pathInfo.anchor}if(Wt(u,/HX-Trigger-After-Swap:/i)){var i=a;if(!z(a)){i=F().body}de(u,"HX-Trigger-After-Swap",i)}var o=function(){j(r.tasks,function(e){e.call()});j(r.elts,function(e){if(e.classList){e.classList.remove(k.config.settlingClass)}lt(e,"htmx:afterSettle",s)});if(c){var e=f||wt(a)||Bt(u)||s.pathInfo.finalPath||s.pathInfo.path;pt(e);lt(F().body,"htmx:pushedIntoHistory",{path:e})}Xt(r.elts,d);if(Wt(u,/HX-Trigger-After-Settle:/i)){var t=a;if(!z(a)){t=F().body}de(u,"HX-Trigger-After-Settle",t)}};if(d.settleDelay>0){setTimeout(o,d.settleDelay)}else{o()}}catch(e){ot(a,"htmx:swapError",s);throw e}};if(d.swapDelay>0){setTimeout(e,d.swapDelay)}else{e()}}}else{ot(a,"htmx:responseError",V({error:"Response Status Error Code "+u.status+" from "+s.pathInfo.path},s))}}var Kt={};function Yt(){return{onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Qt(e,t){Kt[e]=V(Yt(),t)}function er(e){delete Kt[e]}function tr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=D(e,"hx-ext");if(t){j(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Kt[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return tr(c(e),r,n)}function rr(e){if(F().readyState!=="loading"){e()}else{F().addEventListener("DOMContentLoaded",e)}}function nr(){if(k.config.includeIndicatorStyles!==false){F().head.insertAdjacentHTML("beforeend","<style> ."+k.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+k.config.requestClass+" ."+k.config.indicatorClass+"{opacity:1} ."+k.config.requestClass+"."+k.config.indicatorClass+"{opacity:1} </style>")}}function ir(){var e=F().querySelector('meta[name="htmx-config"]');if(e){return x(e.content)}else{return null}}function or(){var e=ir();if(e){k.config=V(k.config,e)}}rr(function(){or();nr();var e=F().body;rt(e);window.onpopstate=function(e){if(e.state&&e.state.htmx){xt()}};setTimeout(function(){lt(e,"htmx:load",{})},0)});return k}()}); \ No newline at end of file +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(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 l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=k(e);e.classList.toggle(t)}function T(e,t){e=k(e);W(e.parentElement.children,function(e){q(e,t)});L(e,t)}function H(e,t){e=k(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function N(e,t){if(t.indexOf("closest ")===0){return[H(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[C(e,t.substr(5))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return z().querySelectorAll(t)}}function ee(e,t){if(t){return N(e,t)[0]}else{return N(z().body,e)[0]}}function k(e){if(p(e,"String")){return C(e)}else{return e}}function I(e,t,r){if(m(t)){return{target:z().body,event:e,listener:t}}else{return{target:k(e),event:t,listener:r}}}function M(t,r,n){lr(function(){var e=I(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function D(t,r,n){lr(function(){var e=I(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var te=z().createElement("output");function F(e,t){var r=G(e,t);if(r){if(r==="this"){return[re(e,t)]}else{var n=N(e,r);if(n.length===0){pt('The selector "'+r+'" on '+t+" returned no matches!");return[te]}else{return n}}}}function re(e,t){return h(e,function(e){return V(e,t)!=null})}function ne(e){var t=G(e,"hx-target");if(t){if(t==="this"){return re(e,"hx-target")}else{return ee(e,t)}}else{var r=_(e);if(r.boosted){return z().body}else{return e}}}function P(e){var t=U.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function X(t,r){W(t.attributes,function(e){if(!r.hasAttribute(e.name)&&P(e.name)){t.removeAttribute(e.name)}});W(r.attributes,function(e){if(P(e.name)){t.setAttribute(e.name,e.value)}})}function j(e,t){var r=sr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){pt(e)}}return e==="outerHTML"}function B(e,i,o){var t="#"+i.id;var a="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){a=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{a=e}var r=z().querySelectorAll(t);if(r){W(r,function(e){var t;var r=i.cloneNode(true);t=z().createDocumentFragment();t.appendChild(r);if(!j(a,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ye(a,e,e,t,o)}W(o.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(z().body,"htmx:oobErrorNoTarget",{content:i})}return e}function ie(e,r){W(R(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=V(e,"hx-swap-oob");if(t!=null){B(t,e,r)}})}function oe(e){W(R(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=V(e,"id");var r=z().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function ae(n,e,i){W(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();X(e,t);i.tasks.push(function(){X(e,r)})}}})}function se(e){return function(){q(e,U.config.addedClass);ct(e);at(e);le(e);$(e,"htmx:load")}}function le(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ue(e,t,r,n){ae(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(se(i))}}}function fe(t){var e=_(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){W(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){W(t.children,function(e){fe(e)})}}function ce(e,t,r){if(e.tagName==="BODY"){return me(e,t,r)}else{var n;var i=e.previousSibling;ue(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}_(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}fe(e);u(e).removeChild(e)}}function he(e,t,r){return ue(e,e.firstChild,t,r)}function de(e,t,r){return ue(u(e),e,t,r)}function ve(e,t,r){return ue(e,null,t,r)}function ge(e,t,r){return ue(u(e),e.nextSibling,t,r)}function pe(e,t,r){fe(e);return u(e).removeChild(e)}function me(e,t,r){var n=e.firstChild;ue(e,n,t,r);if(n){while(n.nextSibling){fe(n.nextSibling);e.removeChild(n.nextSibling)}fe(n);e.removeChild(n)}}function xe(e,t){var r=G(e,"hx-select");if(r){var n=z().createDocumentFragment();W(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function ye(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":ce(r,n,i);return;case"afterbegin":he(r,n,i);return;case"beforebegin":de(r,n,i);return;case"beforeend":ve(r,n,i);return;case"afterend":ge(r,n,i);return;case"delete":pe(r,n,i);return;default:var o=sr(t);for(var a=0;a<o.length;a++){var f=o[a];try{var s=f.handleSwap(e,r,n,i);if(s){if(typeof s.length!=="undefined"){for(var l=0;l<s.length;l++){var u=s[l];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){i.tasks.push(se(u))}}}return}}catch(e){pt(e)}}if(e==="innerHTML"){me(r,n,i)}else{ye(U.config.defaultSwapStyle,t,r,n,i)}}}function be(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function we(e,t,r,n,i){i.title=be(n);var o=g(n);if(o){ie(o,i);o=xe(r,o);oe(o);return ye(e,r,t,o,i)}}function Se(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!x(a)){a={value:a}}$(r,o,a)}}}else{$(r,n,[])}}var Ee=/\s/;var Ce=/[\s,]/;var Re=/[_$a-zA-Z]/;var Oe=/[_$a-zA-Z0-9]/;var Le=['"',"'","/"];var qe=/[^\s]/;function Ae(e){var t=[];var r=0;while(r<e.length){if(Re.exec(e.charAt(r))){var n=r;while(Oe.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Le.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function Te(e,t,r){return Re.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function He(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Jt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(z().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(Te(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var Ne="input, textarea, select";function ke(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=Ae(t);do{c(n,qe);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var o={trigger:"every"};c(n,qe);o.pollInterval=v(c(n,/[,\[\s]/));c(n,qe);var a=He(e,n,"event");if(a){o.eventFilter=a}r.push(o)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var a=He(e,n,"event");if(a){s.eventFilter=a}while(n.length>0&&n[0]!==","){c(n,qe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Ce))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Ce);if(u==="closest"||u==="find"){n.shift();u+=" "+c(n,Ce)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Ce)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Ce))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Ce)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Ce)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,qe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,Ne)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ie(e){_(e).cancelled=true}function Me(e,t,r,n){var i=_(e);i.timeout=setTimeout(function(){if(Y(e)&&i.cancelled!==true){if(!je(n,dt("hx:poll:trigger",{triggerSpec:n,target:e}))){Z(t,r,e)}Me(e,t,V(e,"hx-"+t),n)}},n.pollInterval)}function De(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&De(t)&&t.target===""||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href");r.pushURL=true}else{var o=f(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=f(t,"action")}e.forEach(function(e){Be(t,n,i,r,e,true)})}}function Pe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&H(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Xe(e,t){return _(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function je(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(z().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Be(o,a,s,e,l,u){var t;if(l.from){t=N(o,l.from)}else{t=[o]}W(t,function(n){var i=function(e){if(!Y(o)){n.removeEventListener(l.trigger,i);return}if(Xe(o,e)){return}if(u||Pe(e,o)){e.preventDefault()}if(je(l,e)){return}var t=_(e);t.triggerSpec=l;if(t.handledFor==null){t.handledFor=[]}var r=_(o);if(t.handledFor.indexOf(o)<0){t.handledFor.push(o);if(l.consume){e.stopPropagation()}if(l.target&&e.target){if(!d(e.target,l.target)){return}}if(l.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(l.changed){if(r.lastValue===o.value){return}else{r.lastValue=o.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(l.throttle){if(!r.throttle){Z(a,s,o,e);r.throttle=setTimeout(function(){r.throttle=null},l.throttle)}}else if(l.delay){r.delayed=setTimeout(function(){Z(a,s,o,e)},l.delay)}else{Z(a,s,o,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:l.trigger,listener:i,on:n});n.addEventListener(l.trigger,i)})}var Ue=false;var Ve=null;function ze(){if(!Ve){Ve=function(){Ue=true};window.addEventListener("scroll",Ve);setInterval(function(){if(Ue){Ue=false;W(z().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){_e(e)})}},200)}}function _e(e){if(!s(e,"data-hx-revealed")&&b(e)){e.setAttribute("data-hx-revealed","true");var t=_(e);if(t.initialized){Z(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Z(t.verb,t.path,e)},{once:true})}}}function We(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Je(e,o[1],0)}if(o[0]==="send"){Ze(e)}}}function Je(s,r,n){if(!Y(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=U.createWebSocket(r);t.onerror=function(e){J(s,"htmx:wsError",{error:e,socket:t});$e(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=Ge(n);setTimeout(function(){Je(s,r,n+1)},t)}};t.onopen=function(e){n=0};_(s).webSocket=t;t.addEventListener("message",function(e){if($e(s)){return}var t=e.data;gt(s,function(e){t=e.transformResponse(t,null,s)});var r=zt(s);var n=g(t);var i=y(n.children);for(var o=0;o<i.length;o++){var a=i[o];B(V(a,"hx-swap-oob")||"true",a,r)}Ct(r.tasks)})}function $e(e){if(!Y(e)){_(e).webSocket.close();return true}}function Ze(u){var f=h(u,function(e){return _(e).webSocket!=null});if(f){u.addEventListener(ke(u)[0].trigger,function(e){var t=_(f).webSocket;var r=Xt(u,f);var n=Mt(u,"post");var i=n.errors;var o=n.values;var a=Gt(u);var s=Q(o,a);var l=jt(s,u);l["HEADERS"]=r;if(i&&i.length>0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Pe(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ge(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}pt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ke(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Ye(e,o[1])}if(o[0]==="swap"){Qe(e,o[1])}}}function Ye(t,e){var r=U.createEventSource(e);r.onerror=function(e){J(t,"htmx:sseError",{error:e,source:r});tt(t)};_(t).sseEventSource=r}function Qe(o,a){var s=h(o,rt);if(s){var l=_(s).sseEventSource;var u=function(e){if(tt(s)){l.removeEventListener(a,u);return}var t=e.data;gt(o,function(e){t=e.transformResponse(t,null,o)});var r=Ut(o);var n=ne(o);var i=zt(o);we(r.swapStyle,o,n,t,i);Ct(i.tasks);$(o,"htmx:sseMessage",e)};_(o).sseListener=u;l.addEventListener(a,u)}else{J(o,"htmx:noSSESourceError")}}function et(e,t,r,n){var i=h(e,rt);if(i){var o=_(i).sseEventSource;var a=function(){if(!tt(i)){if(Y(e)){Z(t,r,e)}else{o.removeEventListener(n,a)}}};_(e).sseListener=a;o.addEventListener(n,a)}else{J(e,"htmx:noSSESourceError")}}function tt(e){if(!Y(e)){_(e).sseEventSource.close();return true}}function rt(e){return _(e).sseEventSource!=null}function nt(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Z(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function it(o,a,e){var t=false;W(n,function(n){if(s(o,"hx-"+n)){var i=V(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){et(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){ze();_e(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=ee(o,e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){$(o,"intersect");break}}},t);r.observe(o);Be(o,n,i,a,e)}else if(e.trigger==="load"){nt(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Me(o,n,i,e)}else{Be(o,n,i,a,e)}})}});return t}function ot(e){if(e.type==="text/javascript"||e.type==="module"||e.type===""){var t=z().createElement("script");W(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(U.config.inlineScriptNonce){t.nonce=U.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){pt(e)}finally{r.removeChild(e)}}}function at(e){if(d(e,"script")){ot(e)}W(R(e,"script"),function(e){ot(e)})}function st(){return document.querySelector("[hx-boost], [data-hx-boost]")}function lt(e){if(e.querySelectorAll){var t=st()?", a, form":"";var r=e.querySelectorAll(i+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [hx-data-ext]");return r}else{return[]}}function ut(r){var e=function(e){if(d(e.target,"button, input[type='submit']")){var t=_(r);t.lastButtonClicked=e.target}};r.addEventListener("click",e);r.addEventListener("focusin",e);r.addEventListener("focusout",function(e){var t=_(r);t.lastButtonClicked=null})}function ft(e){if(e.closest&&e.closest(U.config.disableSelector)){return}var t=_(e);if(!t.initialized){t.initialized=true;$(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=ke(e);var n=it(e,t,r);if(!n&&G(e,"hx-boost")==="true"){Fe(e,t,r)}if(e.tagName==="FORM"){ut(e)}var i=V(e,"hx-sse");if(i){Ke(e,t,i)}var o=V(e,"hx-ws");if(o){We(e,t,o)}$(e,"htmx:afterProcessNode")}}function ct(e){e=k(e);ft(e);W(lt(e),function(e){ft(e)})}function ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function dt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=z().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function J(e,t,r){$(e,t,Q({error:t},r))}function vt(e){return e==="htmx:afterProcessNode"}function gt(e,t){W(sr(e),function(e){try{t(e)}catch(e){pt(e)}})}function pt(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function $(e,t,r){e=k(e);if(r==null){r={}}r["elt"]=e;var n=dt(t,r);if(U.logger&&!vt(t)){U.logger(e,t,r)}if(r.error){pt(r.error);$(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=ht(t);if(i&&o!==t){var a=dt(o,n.detail);i=i&&e.dispatchEvent(a)}gt(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var mt=location.pathname+location.search;function xt(){var e=z().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||z().body}function yt(e,t,r,n){var i=S(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>U.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(z().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function bt(e){var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function wt(e){var t=U.config.requestClass;var r=e.cloneNode(true);W(R(r,"."+t),function(e){q(e,t)});return r.innerHTML}function St(){var e=xt();var t=mt||location.pathname+location.search;$(z().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(U.config.historyEnabled)history.replaceState({htmx:true},z().title,window.location.href);yt(t,wt(e),z().title,window.scrollY)}function Et(e){if(U.config.historyEnabled)history.pushState({htmx:true},"",e);mt=e}function Ct(e){W(e,function(e){e.call()})}function Rt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};$(z().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){$(z().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=xt();var r=zt(t);me(t,e,r);Ct(r.tasks);mt=n;$(z().body,"htmx:historyRestore",{path:n})}else{J(z().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Ot(e){St();e=e||location.pathname+location.search;var t=bt(e);if(t){var r=g(t.content);var n=xt();var i=zt(n);me(n,r,i);Ct(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);mt=e;$(z().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Rt(e)}}}function Lt(e){var t=G(e,"hx-push-url");return t&&t!=="false"||_(e).boosted&&_(e).pushURL}function qt(e){var t=G(e,"hx-push-url");return t==="true"||t==="false"?null:t}function At(e){var t=F(e,"hx-indicator");if(t==null){t=[e]}W(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Tt(e){W(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function Ht(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Nt(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 kt(t,r,n,e,i){if(e==null||Ht(t,e)){return}else{t.push(e)}if(Nt(e)){var o=f(e,"name");var a=e.value;if(e.multiple){a=y(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=y(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){It(e,n)}}if(d(e,"form")){var l=e.elements;W(l,function(e){kt(t,r,n,e,i)})}}function It(e,t){if(e.willValidate){$(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});$(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Mt(e,t){var r=[];var n={};var i={};var o=[];var a=_(e);var s=d(e,"form")&&e.noValidate!==true;if(a.lastButtonClicked){s=s&&a.lastButtonClicked.formNoValidate!==true}if(t!=="get"){kt(r,i,o,H(e,"form"),s)}kt(r,n,o,e,s);if(a.lastButtonClicked){var l=f(a.lastButtonClicked,"name");if(l){n[l]=a.lastButtonClicked.value}}var u=F(e,"hx-include");W(u,function(e){kt(r,n,o,e,s);if(!d(e,"form")){W(e.querySelectorAll(Ne),function(e){kt(r,n,o,e,s)})}});n=Q(n,i);return{errors:o,values:n}}function Dt(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function Ft(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=Dt(t,r,e)})}else{t=Dt(t,r,n)}}}return t}function Pt(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){W(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Xt(e,t,r){var n={"HX-Request":"true","HX-Trigger":f(e,"id"),"HX-Trigger-Name":f(e,"name"),"HX-Target":V(t,"id"),"HX-Current-URL":z().location.href};Wt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(_(e).boosted){n["HX-Boosted"]="true"}return n}function jt(t,e){var r=G(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){W(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};W(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Bt(e){return f(e,"href")&&f(e,"href").indexOf("#")>=0}function Ut(e,t){var r=t?t:G(e,"hx-swap");var n={swapStyle:_(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(_(e).boosted&&!Bt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var o=1;o<i.length;o++){var a=i[o];if(a.indexOf("swap:")===0){n["swapDelay"]=v(a.substr(5))}if(a.indexOf("settle:")===0){n["settleDelay"]=v(a.substr(7))}if(a.indexOf("scroll:")===0){var s=a.substr(7);var l=s.split(":");var f=l.pop();var u=l.length>0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(a.indexOf("show:")===0){var c=a.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(a.indexOf("focus-scroll:")===0){var d=a.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function Vt(t,r,n){var i=null;gt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(G(r,"hx-encoding")==="multipart/form-data"||d(r,"form")&&f(r,"enctype")==="multipart/form-data"){return Pt(n)}else{return Ft(n)}}}function zt(e){return{tasks:[],elts:[e]}}function _t(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ee(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var o=t.showTarget;if(t.showTarget==="window"){o="body"}i=ee(r,o)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function Wt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}else if(o.indexOf("js:")===0){o=o.substr(3);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Jt(e,function(){return Function("return ("+o+")")()},{})}else{s=S(o)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Wt(u(e),t,r,n)}function Jt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function $t(e,t){return Wt(e,"hx-vars",true,t)}function Zt(e,t){return Wt(e,"hx-vals",false,t)}function Gt(e){return Q($t(e),Zt(e))}function Kt(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Yt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(z().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Qt(e,t){return e.getAllResponseHeaders().match(t)}function er(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return Z(e,t,null,null,{targetOverride:k(r),returnPromise:true})}else{return Z(e,t,k(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:k(r.target),swapOverride:r.swap,returnPromise:true})}}else{return Z(e,t,null,null,{returnPromise:true})}}function tr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Z(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=z().body}var v=r.handler||rr;if(!Y(n)){return}var g=r.targetOverride||ne(n);if(g==null||g==te){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=_(n);var o=G(n,"hx-sync");var m=null;var x=false;if(o){var y=o.split(":");var b=y[0].trim();if(b==="this"){p=re(n,"hx-sync")}else{p=ee(n,b)}o=(y[1]||"drop").trim();i=_(p);if(o==="drop"&&i.xhr&&i.abortable!==true){return}else if(o==="abort"){if(i.xhr){return}else{x=true}}else if(o==="replace"){$(p,"htmx:abort")}else if(o.indexOf("queue")===0){var w=o.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=_(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){Z(e,t,n,f,r)})}return}}var a=new XMLHttpRequest;i.xhr=a;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=G(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){K(c);s();return d}}var R=G(n,"hx-confirm");if(R){if(!confirm(R)){K(c);s();return d}}var O=Xt(n,g,C);if(r.headers){O=Q(O,r.headers)}var L=Mt(n,e);var q=L.errors;var A=L.values;if(r.values){A=Q(A,r.values)}var T=Gt(n);var H=Q(A,T);var N=jt(H,n);if(e!=="get"&&G(n,"hx-encoding")==null){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=z().location.href}var k=Wt(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:q,withCredentials:r.credentials||k.credentials||U.config.withCredentials,timeout:r.timeout||k.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){K(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;q=l.errors;if(q&&q.length>0){$(n,"htmx:validation:halted",l);K(c);s();return d}var I=t.split("#");var M=I[0];var D=I[1];if(e==="get"){var F=M;var P=Object.keys(N).length!==0;if(P){if(F.indexOf("?")<0){F+="?"}else{F+="&"}F+=Ft(N);if(D){F+="#"+D}}a.open("GET",F,true)}else{a.open(e.toUpperCase(),t,true)}a.overrideMimeType("text/html");a.withCredentials=l.withCredentials;a.timeout=l.timeout;if(k.noHeaders){}else{for(var X in O){if(O.hasOwnProperty(X)){var j=O[X];Kt(a,X,j)}}}var u={xhr:a,target:g,requestConfig:l,etc:r,pathInfo:{path:t,finalPath:F,anchor:D}};a.onload=function(){try{var e=tr(n);v(n,u);Tt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!Y(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(Y(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}K(c);s()}catch(e){J(n,"htmx:onLoadError",Q({error:e},u));throw e}};a.onerror=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);K(h);s()};a.onabort=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);K(h);s()};a.ontimeout=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);K(h);s()};if(!$(n,"htmx:beforeRequest",u)){K(c);s();return d}var B=At(n);W(["loadstart","loadend","progress","abort"],function(t){W([a,a.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);a.send(e==="get"?null:Vt(a,n,N));return d}function rr(s,l){var u=l.xhr;var f=l.target;var r=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(Qt(u,/HX-Trigger:/i)){Se(u,"HX-Trigger",s)}if(Qt(u,/HX-Push:/i)){var c=u.getResponseHeader("HX-Push")}if(Qt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Qt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(Qt(u,/HX-Retarget:/i)){l.target=z().querySelector(u.getResponseHeader("HX-Retarget"))}var h;if(c=="false"){h=false}else{h=Lt(s)||c}var n=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var e=u.status>=400;var t=Q({shouldSwap:n,serverResponse:d,isError:e},l);if(!$(f,"htmx:beforeSwap",t))return;f=t.target;d=t.serverResponse;e=t.isError;l.failed=e;l.successful=!e;if(t.shouldSwap){if(u.status===286){Ie(s)}gt(s,function(e){d=e.transformResponse(d,u,s)});if(h){St()}var i=r.swapOverride;var v=Ut(s,i);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=zt(f);we(v.swapStyle,f,s,d,n);if(t.elt&&!Y(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);W(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(l.pathInfo.anchor){location.hash=l.pathInfo.anchor}if(Qt(u,/HX-Trigger-After-Swap:/i)){var o=s;if(!Y(s)){o=z().body}Se(u,"HX-Trigger-After-Swap",o)}var a=function(){W(n.tasks,function(e){e.call()});W(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h){var e=c||qt(s)||Yt(u)||l.pathInfo.finalPath||l.pathInfo.path;Et(e);$(z().body,"htmx:pushedIntoHistory",{path:e})}if(n.title){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}_t(n.elts,v);if(Qt(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!Y(s)){r=z().body}Se(u,"HX-Trigger-After-Settle",r)}};if(v.settleDelay>0){setTimeout(a,v.settleDelay)}else{a()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(v.swapDelay>0){setTimeout(o,v.swapDelay)}else{o()}}if(e){J(s,"htmx:responseError",Q({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var nr={};function ir(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function or(e,t){if(t.init){t.init(r)}nr[e]=Q(ir(),t)}function ar(e){delete nr[e]}function sr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){W(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=nr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return sr(u(e),r,n)}function lr(e){if(z().readyState!=="loading"){e()}else{z().addEventListener("DOMContentLoaded",e)}}function ur(){if(U.config.includeIndicatorStyles!==false){z().head.insertAdjacentHTML("beforeend","<style> ."+U.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+U.config.requestClass+" ."+U.config.indicatorClass+"{opacity:1} ."+U.config.requestClass+"."+U.config.indicatorClass+"{opacity:1} </style>")}}function fr(){var e=z().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function cr(){var e=fr();if(e){U.config=Q(U.config,e)}}lr(function(){cr();ur();var e=z().body;ct(e);var t=z().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=_(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){Ot();W(t,function(e){$(e,"htmx:restored",{document:z(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file diff --git a/code/ch5_partials/ch5_final_video_collector/static/js/htmx.js b/code/ch5_partials/ch5_final_video_collector/static/js/htmx.js index e38f6ed..27e57bc 100644 --- a/code/ch5_partials/ch5_final_video_collector/static/js/htmx.js +++ b/code/ch5_partials/ch5_final_video_collector/static/js/htmx.js @@ -1,7 +1,9 @@ //AMD insanity (function (root, factory) { + //@ts-ignore if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. + //@ts-ignore define([], factory); } else { // Browser globals @@ -12,6 +14,8 @@ return (function () { 'use strict'; // Public API + //** @type {import("./htmx").HtmxApi} */ + // TODO: list all methods in public API var htmx = { onLoad: onLoadHelper, process: processNode, @@ -35,7 +39,6 @@ return (function () { removeExtension : removeExtension, logAll : logAll, logger : null, - useTemplateFragments: false, config : { historyEnabled:true, historyCacheSize:10, @@ -46,13 +49,19 @@ return (function () { includeIndicatorStyles:true, indicatorClass:'htmx-indicator', requestClass:'htmx-request', + addedClass:'htmx-added', settlingClass:'htmx-settling', swappingClass:'htmx-swapping', allowEval:true, + inlineScriptNonce:'', attributesToSettle:["class", "style", "width", "height"], withCredentials:false, + timeout:0, wsReconnectDelay: 'full-jitter', disableSelector: "[hx-disable], [data-hx-disable]", + useTemplateFragments: false, + scrollBehavior: 'smooth', + defaultFocusScroll: false, }, parseInterval:parseInterval, _:internalEval, @@ -61,9 +70,36 @@ return (function () { }, createWebSocket: function(url){ return new WebSocket(url, []); - } + }, + version: "1.7.0" }; + /** @type {import("./htmx").HtmxInternalApi} */ + var internalAPI = { + bodyContains: bodyContains, + filterValues: filterValues, + hasAttribute: hasAttribute, + getAttributeValue: getAttributeValue, + getClosestMatch: getClosestMatch, + getExpressionVars: getExpressionVars, + getHeaders: getHeaders, + getInputValues: getInputValues, + getInternalData: getInternalData, + getSwapSpecification: getSwapSpecification, + getTriggerSpecs: getTriggerSpecs, + getTarget: getTarget, + makeFragment: makeFragment, + mergeObjects: mergeObjects, + makeSettleInfo: makeSettleInfo, + oobSwap: oobSwap, + selectAndSwap: selectAndSwap, + settleImmediately: settleImmediately, + shouldCancel: shouldCancel, + triggerEvent: triggerEvent, + triggerErrorEvent: triggerErrorEvent, + withExtensions: withExtensions, + } + var VERBS = ['get', 'post', 'put', 'delete', 'patch']; var VERB_SELECTOR = VERBS.map(function(verb){ return "[hx-" + verb + "], [data-hx-" + verb + "]" @@ -73,19 +109,24 @@ return (function () { // Utilities //==================================================================== - function parseInterval(str) { - if (str == undefined) { - return undefined - } - if (str.slice(-2) == "ms") { - return parseFloat(str.slice(0,-2)) || undefined - } - if (str.slice(-1) == "s") { - return (parseFloat(str.slice(0,-1)) * 1000) || undefined - } - return parseFloat(str) || undefined + function parseInterval(str) { + if (str == undefined) { + return undefined + } + if (str.slice(-2) == "ms") { + return parseFloat(str.slice(0,-2)) || undefined + } + if (str.slice(-1) == "s") { + return (parseFloat(str.slice(0,-1)) * 1000) || undefined + } + return parseFloat(str) || undefined } + /** + * @param {HTMLElement} elt + * @param {string} name + * @returns {(string | null)} + */ function getRawAttribute(elt, name) { return elt.getAttribute && elt.getAttribute(name); } @@ -96,18 +137,36 @@ return (function () { elt.hasAttribute("data-" + qualifiedName)); } + /** + * + * @param {HTMLElement} elt + * @param {string} qualifiedName + * @returns {(string | null)} + */ function getAttributeValue(elt, qualifiedName) { return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); } + /** + * @param {HTMLElement} elt + * @returns {HTMLElement | null} + */ function parentElt(elt) { return elt.parentElement; } + /** + * @returns {Document} + */ function getDocument() { return document; } + /** + * @param {HTMLElement} elt + * @param {(e:HTMLElement) => boolean} condition + * @returns {HTMLElement | null} + */ function getClosestMatch(elt, condition) { if (condition(elt)) { return elt; @@ -118,22 +177,47 @@ return (function () { } } + function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ + var attributeValue = getAttributeValue(ancestor, attributeName); + var disinherit = getAttributeValue(ancestor, "hx-disinherit"); + if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) { + return "unset"; + } else { + return attributeValue + } + } + + /** + * @param {HTMLElement} elt + * @param {string} attributeName + * @returns {string | null} + */ function getClosestAttributeValue(elt, attributeName) { var closestAttr = null; getClosestMatch(elt, function (e) { - return closestAttr = getAttributeValue(e, attributeName); + return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName); }); - return closestAttr; + if (closestAttr !== "unset") { + return closestAttr; + } } + /** + * @param {HTMLElement} elt + * @param {string} selector + * @returns {boolean} + */ function matches(elt, selector) { + // @ts-ignore: non-standard properties for browser compatability // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || - elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector - || elt.webkitMatchesSelector || elt.oMatchesSelector; + var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; return matchesFunction && matchesFunction.call(elt, selector); } + /** + * @param {string} str + * @returns {string} + */ function getStartTag(str) { var tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i var match = tagMatcher.exec( str ); @@ -144,23 +228,40 @@ return (function () { } } + /** + * + * @param {string} resp + * @param {number} depth + * @returns {Element} + */ function parseHTML(resp, depth) { var parser = new DOMParser(); var responseDoc = parser.parseFromString(resp, "text/html"); + + /** @type {Element} */ var responseNode = responseDoc.body; while (depth > 0) { depth--; + // @ts-ignore responseNode = responseNode.firstChild; } if (responseNode == null) { + // @ts-ignore responseNode = getDocument().createDocumentFragment(); } return responseNode; } + /** + * + * @param {string} resp + * @returns {Element} + */ function makeFragment(resp) { if (htmx.config.useTemplateFragments) { var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0); + // @ts-ignore type mismatch between DocumentFragment and Element. + // TODO: Are these close enough for htmx to use interchangably? return documentFragment.querySelector('template').content; } else { var startTag = getStartTag(resp); @@ -186,24 +287,45 @@ return (function () { } } + /** + * @param {Function} func + */ function maybeCall(func){ if(func) { func(); } } + /** + * @param {any} o + * @param {string} type + * @returns + */ function isType(o, type) { return Object.prototype.toString.call(o) === "[object " + type + "]"; } + /** + * @param {*} o + * @returns {o is Function} + */ function isFunction(o) { return isType(o, "Function"); } + /** + * @param {*} o + * @returns {o is Object} + */ function isRawObject(o) { return isType(o, "Object"); } + /** + * getInternalData retrieves "private" data stored by htmx within an element + * @param {HTMLElement} elt + * @returns {*} + */ function getInternalData(elt) { var dataProp = 'htmx-internal-data'; var data = elt[dataProp]; @@ -213,6 +335,11 @@ return (function () { return data; } + /** + * toArray converts an ArrayLike object into a real array. + * @param {ArrayLike} arr + * @returns {any[]} + */ function toArray(arr) { var returnArr = []; if (arr) { @@ -238,14 +365,25 @@ return (function () { return elemTop < window.innerHeight && elemBottom >= 0; } - function bodyContains(elt) { - return getDocument().body.contains(elt); - } + function bodyContains(elt) { + if (elt.getRootNode() instanceof ShadowRoot) { + return getDocument().body.contains(elt.getRootNode().host); + } else { + return getDocument().body.contains(elt); + } + } function splitOnWhitespace(trigger) { return trigger.trim().split(/\s+/); } + /** + * mergeObjects takes all of the keys from + * obj2 and duplicates them into obj1 + * @param {Object} obj1 + * @param {Object} obj2 + * @returns {Object} + */ function mergeObjects(obj1, obj2) { for (var key in obj2) { if (obj2.hasOwnProperty(key)) { @@ -319,7 +457,7 @@ return (function () { if (delay) { setTimeout(function(){addClassToElement(elt, clazz);}, delay) } else { - elt.classList.add(clazz); + elt.classList && elt.classList.add(clazz); } } @@ -328,7 +466,13 @@ return (function () { if (delay) { setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) } else { - elt.classList.remove(clazz); + if (elt.classList) { + elt.classList.remove(clazz); + // if there are no classes left, remove the class attribute + if (elt.classList.length === 0) { + elt.removeAttribute("class"); + } + } } } @@ -360,17 +504,25 @@ return (function () { } function querySelectorAllExt(elt, selector) { - if (selector.indexOf("closest ") === 0) { + if (selector.indexOf("closest ") === 0) { return [closest(elt, selector.substr(8))]; } else if (selector.indexOf("find ") === 0) { return [find(elt, selector.substr(5))]; + } else if (selector === 'document') { + return [document]; + } else if (selector === 'window') { + return [window]; } else { return getDocument().querySelectorAll(selector); } } function querySelectorExt(eltOrSelector, selector) { - return querySelectorAllExt(eltOrSelector, selector)[0] + if (selector) { + return querySelectorAllExt(eltOrSelector, selector)[0]; + } else { + return querySelectorAllExt(getDocument().body, eltOrSelector)[0]; + } } function resolveTarget(arg2) { @@ -418,13 +570,36 @@ return (function () { //==================================================================== // Node processing //==================================================================== + + var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors + function findAttributeTargets(elt, attrName) { + var attrTarget = getClosestAttributeValue(elt, attrName); + if (attrTarget) { + if (attrTarget === "this") { + return [findThisElement(elt, attrName)]; + } else { + var result = querySelectorAllExt(elt, attrTarget); + if (result.length === 0) { + logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!"); + return [DUMMY_ELT] + } else { + return result; + } + } + } + } + + function findThisElement(elt, attribute){ + return getClosestMatch(elt, function (elt) { + return getAttributeValue(elt, attribute) != null; + }) + } function getTarget(elt) { - var explicitTarget = getClosestMatch(elt, function(e){return getAttributeValue(e,"hx-target") !== null}); - if (explicitTarget) { - var targetStr = getAttributeValue(explicitTarget, "hx-target"); + var targetStr = getClosestAttributeValue(elt, "hx-target"); + if (targetStr) { if (targetStr === "this") { - return explicitTarget; + return findThisElement(elt,'hx-target'); } else { return querySelectorExt(elt, targetStr) } @@ -476,6 +651,13 @@ return (function () { return swapStyle === "outerHTML"; } + /** + * + * @param {string} oobValue + * @param {HTMLElement} oobElement + * @param {*} settleInfo + * @returns + */ function oobSwap(oobValue, oobElement, settleInfo) { var selector = "#" + oobElement.id; var swapStyle = "outerHTML"; @@ -488,18 +670,35 @@ return (function () { swapStyle = oobValue; } - var target = getDocument().querySelector(selector); - if (target) { - var fragment; - fragment = getDocument().createDocumentFragment(); - fragment.appendChild(oobElement); // pulls the child out of the existing fragment - if (!isInlineSwap(swapStyle, target)) { - fragment = oobElement; // if this is not an inline swap, we use the content of the node, not the node itself - } - swap(swapStyle, target, target, fragment, settleInfo); + var targets = getDocument().querySelectorAll(selector); + if (targets) { + forEach( + targets, + function (target) { + var fragment; + var oobElementClone = oobElement.cloneNode(true); + fragment = getDocument().createDocumentFragment(); + fragment.appendChild(oobElementClone); + if (!isInlineSwap(swapStyle, target)) { + fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself + } + + var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment }; + if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return; + + target = beforeSwapDetails.target; // allow re-targeting + if (beforeSwapDetails['shouldSwap']){ + swap(swapStyle, target, target, fragment, settleInfo); + } + forEach(settleInfo.elts, function (elt) { + triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails); + }); + } + ); + oobElement.parentNode.removeChild(oobElement); } else { oobElement.parentNode.removeChild(oobElement); - triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}) + triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}); } return oobValue; } @@ -540,6 +739,7 @@ return (function () { function makeAjaxLoadTask(child) { return function () { + removeClassFromElement(child, htmx.config.addedClass); processNode(child); processScripts(child); processFocus(child) @@ -559,6 +759,7 @@ return (function () { handleAttributes(parentNode, fragment, settleInfo); while(fragment.childNodes.length > 0){ var child = fragment.firstChild; + addClassToElement(child, htmx.config.addedClass); parentNode.insertBefore(child, insertBefore); if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { settleInfo.tasks.push(makeAjaxLoadTask(child)); @@ -574,6 +775,9 @@ return (function () { if (internalData.sseEventSource) { internalData.sseEventSource.close(); } + + triggerEvent(element, "htmx:beforeCleanupElement") + if (internalData.listenerInfos) { forEach(internalData.listenerInfos, function(info) { if (element !== info.on) { @@ -590,12 +794,14 @@ return (function () { if (target.tagName === "BODY") { return swapInnerHTML(target, fragment, settleInfo); } else { + // @type {HTMLElement} + var newElt var eltBeforeNewContent = target.previousSibling; insertNodesBefore(parentElt(target), target, fragment, settleInfo); if (eltBeforeNewContent == null) { - var newElt = parentElt(target).firstChild; + newElt = parentElt(target).firstChild; } else { - var newElt = eltBeforeNewContent.nextSibling; + newElt = eltBeforeNewContent.nextSibling; } getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later settleInfo.elts = [] // clear existing elements @@ -625,6 +831,10 @@ return (function () { function swapAfterEnd(target, fragment, settleInfo) { return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo); } + function swapDelete(target, fragment, settleInfo) { + cleanUpElement(target); + return parentElt(target).removeChild(target); + } function swapInnerHTML(target, fragment, settleInfo) { var firstChild = target.firstChild; @@ -670,6 +880,9 @@ return (function () { case "afterend": swapAfterEnd(target, fragment, settleInfo); return; + case "delete": + swapDelete(target, fragment, settleInfo); + return; default: var extensions = getExtensions(elt); for (var i = 0; i < extensions.length; i++) { @@ -692,32 +905,27 @@ return (function () { logError(e); } } - swapInnerHTML(target, fragment, settleInfo); + if (swapStyle === "innerHTML") { + swapInnerHTML(target, fragment, settleInfo); + } else { + swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo); + } } } - var TITLE_FINDER = /<title>([\s\S]+?)<\/title>/im; function findTitle(content) { - if(content.indexOf('<title>') > -1 && - (content.indexOf('<svg>') == -1 || - content.indexOf('<title>') < content.indexOf('<svg>'))) { - var result = TITLE_FINDER.exec(content); + if (content.indexOf('<title') > -1) { + var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, ''); + var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im); + if (result) { - return result[1]; + return result[2]; } } } function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) { - var title = findTitle(responseText); - if(title) { - var titleElt = find("title"); - if(titleElt) { - titleElt.innerHTML = title; - } else { - window.document.title = title; - } - } + settleInfo.title = findTitle(responseText); var fragment = makeFragment(responseText); if (fragment) { handleOutOfBandSwaps(fragment, settleInfo); @@ -840,6 +1048,11 @@ return (function () { } var INPUT_SELECTOR = 'input, textarea, select'; + + /** + * @param {HTMLElement} elt + * @returns {import("./htmx").HtmxTriggerSpecification[]} + */ function getTriggerSpecs(elt) { var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); var triggerSpecs = []; @@ -853,7 +1066,12 @@ return (function () { if (trigger === "every") { var every = {trigger: 'every'}; consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, WHITESPACE)); + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); + consumeUntil(tokens, NOT_WHITESPACE); + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + every.eventFilter = eventFilter; + } triggerSpecs.push(every); } else if (trigger.indexOf("sse:") === 0) { triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); @@ -877,7 +1095,17 @@ return (function () { triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); } else if (token === "from" && tokens[0] === ":") { tokens.shift(); - triggerSpec.from = consumeUntil(tokens, WHITESPACE_OR_COMMA); + var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); + if (from_arg === "closest" || from_arg === "find") { + tokens.shift(); + from_arg += + " " + + consumeUntil( + tokens, + WHITESPACE_OR_COMMA + ); + } + triggerSpec.from = from_arg; } else if (token === "target" && tokens[0] === ":") { tokens.shift(); triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA); @@ -919,14 +1147,16 @@ return (function () { getInternalData(elt).cancelled = true; } - function processPolling(elt, verb, path, interval) { + function processPolling(elt, verb, path, spec) { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - issueAjaxRequest(verb, path, elt); - processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), interval); + if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { + issueAjaxRequest(verb, path, elt); + } + processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), spec); } - }, interval); + }, spec.pollInterval); } function isLocalLink(elt) { @@ -936,7 +1166,7 @@ return (function () { } function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt)) || elt.tagName === "FORM") { + if ((elt.tagName === "A" && isLocalLink(elt) && elt.target === "") || elt.tagName === "FORM") { nodeData.boosted = true; var verb, path; if (elt.tagName === "A") { @@ -957,11 +1187,26 @@ return (function () { } } - function shouldCancel(elt) { - return elt.tagName === "FORM" || - (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) || - (elt.tagName === "A" && elt.href && (elt.getAttribute('href') === '#' || - elt.getAttribute('href').indexOf("#") !== 0)); + /** + * + * @param {Event} evt + * @param {HTMLElement} elt + * @returns + */ + function shouldCancel(evt, elt) { + if (evt.type === "submit" || evt.type === "click") { + if (elt.tagName === "FORM") { + return true; + } + if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { + return true; + } + if (elt.tagName === "A" && elt.href && + (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) { + return true; + } + } + return false; } function ignoreBoostedAnchorCtrlClick(elt, evt) { @@ -982,86 +1227,90 @@ return (function () { } function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { - var eltToListenOn = elt; + var eltsToListenOn; if (triggerSpec.from) { - eltToListenOn = find(triggerSpec.from); + eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); + } else { + eltsToListenOn = [elt]; } - var eventListener = function (evt) { - if (!bodyContains(elt)) { - eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); - return; - } - if (ignoreBoostedAnchorCtrlClick(elt, evt)) { - return; - } - if(explicitCancel || shouldCancel(elt)){ - evt.preventDefault(); - } - if (maybeFilterEvent(triggerSpec, evt)) { - return; - } - var eventData = getInternalData(evt); - eventData.triggerSpec = triggerSpec; - if (eventData.handledFor == null) { - eventData.handledFor = []; - } - var elementData = getInternalData(elt); - if (eventData.handledFor.indexOf(elt) < 0) { - eventData.handledFor.push(elt); - if (triggerSpec.consume) { - evt.stopPropagation(); - } - if (triggerSpec.target && evt.target) { - if (!matches(evt.target, triggerSpec.target)) { - return; - } - } - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } + forEach(eltsToListenOn, function (eltToListenOn) { + var eventListener = function (evt) { + if (!bodyContains(elt)) { + eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); + return; } - if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { - return; - } else { - elementData.lastValue = elt.value; - } + if (ignoreBoostedAnchorCtrlClick(elt, evt)) { + return; } - if (elementData.delayed) { - clearTimeout(elementData.delayed); + if (explicitCancel || shouldCancel(evt, elt)) { + evt.preventDefault(); } - if (elementData.throttle) { + if (maybeFilterEvent(triggerSpec, evt)) { return; } + var eventData = getInternalData(evt); + eventData.triggerSpec = triggerSpec; + if (eventData.handledFor == null) { + eventData.handledFor = []; + } + var elementData = getInternalData(elt); + if (eventData.handledFor.indexOf(elt) < 0) { + eventData.handledFor.push(elt); + if (triggerSpec.consume) { + evt.stopPropagation(); + } + if (triggerSpec.target && evt.target) { + if (!matches(evt.target, triggerSpec.target)) { + return; + } + } + 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); + } + if (elementData.throttle) { + return; + } - if (triggerSpec.throttle) { - if(!elementData.throttle) { + if (triggerSpec.throttle) { + if (!elementData.throttle) { + issueAjaxRequest(verb, path, elt, evt); + elementData.throttle = setTimeout(function () { + elementData.throttle = null; + }, triggerSpec.throttle); + } + } else if (triggerSpec.delay) { + elementData.delayed = setTimeout(function () { + issueAjaxRequest(verb, path, elt, evt); + }, triggerSpec.delay); + } else { issueAjaxRequest(verb, path, elt, evt); - elementData.throttle = setTimeout(function(){ - elementData.throttle = null; - }, triggerSpec.throttle); } - } else if (triggerSpec.delay) { - elementData.delayed = setTimeout(function(){ - issueAjaxRequest(verb, path, elt, evt); - }, triggerSpec.delay); - } else { - issueAjaxRequest(verb, path, elt, evt); } - } - }; - if (nodeData.listenerInfos == null) { - nodeData.listenerInfos = []; - } - nodeData.listenerInfos.push({ - trigger: triggerSpec.trigger, - listener: eventListener, - on: eltToListenOn + }; + if (nodeData.listenerInfos == null) { + nodeData.listenerInfos = []; + } + nodeData.listenerInfos.push({ + trigger: triggerSpec.trigger, + listener: eventListener, + on: eltToListenOn + }) + eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); }) - eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); } var windowIsScrolling = false // used by initScrollHandler @@ -1084,9 +1333,9 @@ return (function () { } function maybeReveal(elt) { - var nodeData = getInternalData(elt); - if (!nodeData.revealed && isScrolledIntoView(elt)) { - nodeData.revealed = true; + if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { + elt.setAttribute('data-hx-revealed', 'true'); + var nodeData = getInternalData(elt); if (nodeData.initialized) { issueAjaxRequest(nodeData.verb, nodeData.path, elt); } else { @@ -1099,6 +1348,10 @@ return (function () { } } + //==================================================================== + // Web Sockets + //==================================================================== + function processWebSocketInfo(elt, nodeData, info) { var values = splitOnWhitespace(info); for (var i = 0; i < values.length; i++) { @@ -1132,7 +1385,7 @@ return (function () { }; socket.onclose = function (e) { - if ([1006, 1012, 1013].includes(e.code)) { // Abnormal Closure/Service Restart/Try Again Later + if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later var delay = getWebSocketReconnectDelay(retryCount); setTimeout(function() { ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout @@ -1193,7 +1446,7 @@ return (function () { return; } webSocket.send(JSON.stringify(filteredParameters)); - if(shouldCancel(elt)){ + if(shouldCancel(evt, elt)){ evt.preventDefault(); } }); @@ -1205,6 +1458,7 @@ return (function () { function getWebSocketReconnectDelay(retryCount) { var delay = htmx.config.wsReconnectDelay; if (typeof delay === 'function') { + // @ts-ignore return delay(retryCount); } if (delay === 'full-jitter') { @@ -1340,7 +1594,7 @@ return (function () { } else if (triggerSpec.trigger === "intersect") { var observerOptions = {}; if (triggerSpec.root) { - observerOptions.root = querySelectorExt(triggerSpec.root) + observerOptions.root = querySelectorExt(elt, triggerSpec.root) } if (triggerSpec.threshold) { observerOptions.threshold = parseFloat(triggerSpec.threshold); @@ -1360,7 +1614,7 @@ return (function () { loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); } else if (triggerSpec.pollInterval) { nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec.pollInterval); + processPolling(elt, verb, path, triggerSpec); } else { addEventListener(elt, verb, path, nodeData, triggerSpec); } @@ -1371,14 +1625,24 @@ return (function () { } function evalScript(script) { - if (script.type === "text/javascript" || script.type === "") { + if (script.type === "text/javascript" || script.type === "module" || script.type === "") { + var newScript = getDocument().createElement("script"); + forEach(script.attributes, function (attr) { + newScript.setAttribute(attr.name, attr.value); + }); + newScript.textContent = script.textContent; + newScript.async = false; + if (htmx.config.inlineScriptNonce) { + newScript.nonce = htmx.config.inlineScriptNonce; + } + var parent = script.parentElement; + try { - maybeEval(script, function () { - // wtf - https://stackoverflow.com/questions/9107240/1-evalthis-vs-evalthis-in-javascript - (1, eval)(script.innerText); - }); + parent.insertBefore(newScript, script); } catch (e) { logError(e); + } finally { + parent.removeChild(script); } } } @@ -1392,21 +1656,41 @@ return (function () { }); } - function isBoosted() { + function hasChanceOfBeingBoosted() { return document.querySelector("[hx-boost], [data-hx-boost]"); } function findElementsToProcess(elt) { if (elt.querySelectorAll) { - var boostedElts = isBoosted() ? ", a, form" : ""; + var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws]"); + " [data-hx-ws], [hx-ext], [hx-data-ext]"); return results; } else { return []; } } + function initButtonTracking(form){ + var maybeSetLastButtonClicked = function(evt){ + if (matches(evt.target, "button, input[type='submit']")) { + var internalData = getInternalData(form); + internalData.lastButtonClicked = evt.target; + } + }; + + // need to handle both click and focus in: + // focusin - in case someone tabs in to a button and hits the space bar + // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + + form.addEventListener('click', maybeSetLastButtonClicked) + form.addEventListener('focusin', maybeSetLastButtonClicked) + form.addEventListener('focusout', function(evt){ + var internalData = getInternalData(form); + internalData.lastButtonClicked = null; + }) + } + function initNode(elt) { if (elt.closest && elt.closest(htmx.config.disableSelector)) { return; @@ -1427,6 +1711,10 @@ return (function () { boostElement(elt, nodeData, triggerSpecs); } + if (elt.tagName === "FORM") { + initButtonTracking(elt); + } + var sseInfo = getAttributeValue(elt, 'hx-sse'); if (sseInfo) { processSSEInfo(elt, nodeData, sseInfo); @@ -1473,6 +1761,15 @@ return (function () { return eventName === "htmx:afterProcessNode" } + /** + * `withExtensions` locates all active extensions for a provided element, then + * executes the provided function using each of the active extensions. It should + * be called internally at every extendable execution point in htmx. + * + * @param {HTMLElement} elt + * @param {(extension:import("./htmx").HtmxExtension) => void} toDo + * @returns void + */ function withExtensions(elt, toDo) { forEach(getExtensions(elt), function(extension){ try { @@ -1520,7 +1817,7 @@ return (function () { //==================================================================== // History Support //==================================================================== - var currentPathForHistory = null; + var currentPathForHistory = location.pathname+location.search; function getHistoryElement() { var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]'); @@ -1569,7 +1866,7 @@ return (function () { return clone.innerHTML; } - function saveHistory() { + function saveCurrentPageToHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); @@ -1598,9 +1895,11 @@ return (function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); var fragment = makeFragment(this.response); + // @ts-ignore fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; var historyElement = getHistoryElement(); var settleInfo = makeSettleInfo(historyElement); + // @ts-ignore swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); currentPathForHistory = path; @@ -1613,7 +1912,7 @@ return (function () { } function restoreHistory(path) { - saveHistory(); + saveCurrentPageToHistory(); path = path || location.pathname+location.search; var cached = getCachedHistory(path); if (cached) { @@ -1628,6 +1927,8 @@ return (function () { triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); } else { if (htmx.config.refreshOnHistoryMiss) { + + // @ts-ignore: optional parameter in reload() function throws error window.location.reload(true); } else { loadHistoryFromServer(path); @@ -1647,10 +1948,8 @@ return (function () { } function addRequestIndicatorClasses(elt) { - var indicator = getClosestAttributeValue(elt, 'hx-indicator'); - if (indicator) { - var indicators = querySelectorAllExt(elt, indicator); - } else { + var indicators = findAttributeTargets(elt, 'hx-indicator'); + if (indicators == null) { indicators = [elt]; } forEach(indicators, function (ic) { @@ -1753,14 +2052,22 @@ return (function () { } } + /** + * @param {HTMLElement} elt + * @param {string} verb + */ function getInputValues(elt, verb) { var processed = []; var values = {}; var formValues = {}; var errors = []; + var internalData = getInternalData(elt); - // only validate when form is directly submitted and novalidate is not set + // only validate when form is directly submitted and novalidate or formnovalidate are not set var validate = matches(elt, 'form') && elt.noValidate !== true; + if (internalData.lastButtonClicked) { + validate = validate && internalData.lastButtonClicked.formNoValidate !== true; + } // for a non-GET include the closest form if (verb !== 'get') { @@ -1770,21 +2077,26 @@ return (function () { // include the element itself processInputValue(processed, values, errors, elt, validate); - // include any explicit includes - var includes = getClosestAttributeValue(elt, "hx-include"); - if (includes) { - var nodes = querySelectorAllExt(elt, includes); - forEach(nodes, function(node) { - processInputValue(processed, values, errors, node, validate); - // if a non-form is included, include any input values within it - if (!matches(node, 'form')) { - forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { - processInputValue(processed, values, errors, descendant, validate); - }) - } - }); + // if a button or submit was clicked last, include its value + if (internalData.lastButtonClicked) { + var name = getRawAttribute(internalData.lastButtonClicked,"name"); + if (name) { + values[name] = internalData.lastButtonClicked.value; + } } + // include any explicit includes + var includes = findAttributeTargets(elt, "hx-include"); + forEach(includes, function(node) { + processInputValue(processed, values, errors, node, validate); + // if a non-form is included, include any input values within it + if (!matches(node, 'form')) { + forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { + processInputValue(processed, values, errors, descendant, validate); + }) + } + }); + // form values take precedence, overriding the regular values values = mergeObjects(values, formValues); @@ -1795,7 +2107,11 @@ return (function () { if (returnStr !== "") { returnStr += "&"; } - returnStr += encodeURIComponent(name) + "=" + encodeURIComponent(realValue); + if (String(realValue) === "[object Object]") { + realValue = JSON.stringify(realValue); + } + var s = encodeURIComponent(realValue); + returnStr += encodeURIComponent(name) + "=" + s; return returnStr; } @@ -1837,6 +2153,12 @@ return (function () { // Ajax //==================================================================== + /** + * @param {HTMLElement} elt + * @param {HTMLElement} target + * @param {string} prompt + * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification + */ function getHeaders(elt, target, prompt) { var headers = { "HX-Request" : "true", @@ -1849,9 +2171,20 @@ return (function () { if (prompt !== undefined) { headers["HX-Prompt"] = prompt; } + if (getInternalData(elt).boosted) { + headers["HX-Boosted"] = "true"; + } return headers; } + /** + * filterValues takes an object containing form input values + * and returns a new object that only contains keys that are + * specified by the closest "hx-params" attribute + * @param {Object} inputValues + * @param {HTMLElement} elt + * @returns {Object} + */ function filterValues(inputValues, elt) { var paramsValue = getClosestAttributeValue(elt, "hx-params"); if (paramsValue) { @@ -1882,8 +2215,14 @@ return (function () { return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0 } - function getSwapSpecification(elt) { - var swapInfo = getClosestAttributeValue(elt, "hx-swap"); + /** + * + * @param {HTMLElement} elt + * @param {string} swapInfoOverride + * @returns {import("./htmx").HtmxSwapSpecification} + */ + function getSwapSpecification(elt, swapInfoOverride) { + var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap"); var swapSpec = { "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, "swapDelay" : htmx.config.defaultSwapDelay, @@ -1905,10 +2244,24 @@ return (function () { swapSpec["settleDelay"] = parseInterval(modifier.substr(7)); } if (modifier.indexOf("scroll:") === 0) { - swapSpec["scroll"] = modifier.substr(7); + var scrollSpec = modifier.substr(7); + var splitSpec = scrollSpec.split(":"); + var scrollVal = splitSpec.pop(); + var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; + swapSpec["scroll"] = scrollVal; + swapSpec["scrollTarget"] = selectorVal; } if (modifier.indexOf("show:") === 0) { - swapSpec["show"] = modifier.substr(5); + var showSpec = modifier.substr(5); + var splitSpec = showSpec.split(":"); + var showVal = splitSpec.pop(); + var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; + swapSpec["show"] = showVal; + swapSpec["showTarget"] = selectorVal; + } + if (modifier.indexOf("focus-scroll:") === 0) { + var focusScrollVal = modifier.substr("focus-scroll:".length); + swapSpec["focusScroll"] = focusScrollVal == "true"; } } } @@ -1926,7 +2279,8 @@ return (function () { if (encodedParameters != null) { return encodedParameters; } else { - if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data") { + if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || + (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) { return makeFormData(filteredParameters); } else { return urlEncode(filteredParameters); @@ -1934,6 +2288,11 @@ return (function () { } } + /** + * + * @param {Element} target + * @returns {import("./htmx").HtmxSettleInfo} + */ function makeSettleInfo(target) { return {tasks: [], elts: [target]}; } @@ -1942,23 +2301,46 @@ return (function () { var first = content[0]; var last = content[content.length - 1]; if (swapSpec.scroll) { - if (swapSpec.scroll === "top" && first) { - first.scrollTop = 0; + var target = null; + if (swapSpec.scrollTarget) { + target = querySelectorExt(first, swapSpec.scrollTarget); + } + if (swapSpec.scroll === "top" && (first || target)) { + target = target || first; + target.scrollTop = 0; } - if (swapSpec.scroll === "bottom" && last) { - last.scrollTop = last.scrollHeight; + if (swapSpec.scroll === "bottom" && (last || target)) { + target = target || last; + target.scrollTop = target.scrollHeight; } } if (swapSpec.show) { - if (swapSpec.show === "top" && first) { - first.scrollIntoView(true); + var target = null; + if (swapSpec.showTarget) { + var targetStr = swapSpec.showTarget; + if (swapSpec.showTarget === "window") { + targetStr = "body"; + } + target = querySelectorExt(first, targetStr); + } + if (swapSpec.show === "top" && (first || target)) { + target = target || first; + target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior}); } - if (swapSpec.show === "bottom" && last) { - last.scrollIntoView(false); + if (swapSpec.show === "bottom" && (last || target)) { + target = target || last; + target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior}); } } } + /** + * @param {HTMLElement} elt + * @param {string} attr + * @param {boolean=} evalAsDefault + * @param {Object=} values + * @returns {Object} + */ function getValuesForElement(elt, attr, evalAsDefault, values) { if (values == null) { values = {}; @@ -1973,6 +2355,9 @@ return (function () { if (str.indexOf("javascript:") === 0) { str = str.substr(11); evaluateValue = true; + } else if (str.indexOf("js:") === 0) { + str = str.substr(3); + evaluateValue = true; } if (str.indexOf('{') !== 0) { str = "{" + str + "}"; @@ -2003,14 +2388,28 @@ return (function () { } } + /** + * @param {HTMLElement} elt + * @param {*} expressionVars + * @returns + */ function getHXVarsForElement(elt, expressionVars) { return getValuesForElement(elt, "hx-vars", true, expressionVars); } + /** + * @param {HTMLElement} elt + * @param {*} expressionVars + * @returns + */ function getHXValsForElement(elt, expressionVars) { return getValuesForElement(elt, "hx-vals", false, expressionVars); } + /** + * @param {HTMLElement} elt + * @returns {Object} + */ function getExpressionVars(elt) { return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)); } @@ -2044,10 +2443,12 @@ return (function () { } function ajaxHelper(verb, path, context) { + verb = verb.toLowerCase(); if (context) { if (context instanceof Element || isType(context, 'String')) { return issueAjaxRequest(verb, path, null, null, { - targetOverride: resolveTarget(context) + targetOverride: resolveTarget(context), + returnPromise: true }); } else { return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, @@ -2055,11 +2456,15 @@ return (function () { handler : context.handler, headers : context.headers, values : context.values, - targetOverride: resolveTarget(context.target) + targetOverride: resolveTarget(context.target), + swapOverride: context.swap, + returnPromise: true }); } } else { - return issueAjaxRequest(verb, path); + return issueAjaxRequest(verb, path, null, null, { + returnPromise: true + }); } } @@ -2076,7 +2481,7 @@ return (function () { var resolve = null; var reject = null; etc = etc != null ? etc : {}; - if(typeof Promise !== "undefined"){ + if(etc.returnPromise && typeof Promise !== "undefined"){ var promise = new Promise(function (_resolve, _reject) { resolve = _resolve; reject = _reject; @@ -2091,40 +2496,85 @@ return (function () { return; // do not issue requests for elements removed from the DOM } var target = etc.targetOverride || getTarget(elt); - if (target == null) { + if (target == null || target == DUMMY_ELT) { triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); return; } + + var syncElt = elt; var eltData = getInternalData(elt); - if (eltData.requestInFlight) { - var queueStrategy = 'last'; - var eventData = getInternalData(event); - if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { - queueStrategy = eventData.triggerSpec.queue; - } - if (eltData.queuedRequests == null) { - eltData.queuedRequests = []; - } - if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); - } else if (queueStrategy === "all") { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); - } else if (queueStrategy === "last") { - eltData.queuedRequests = []; // dump existing queue - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); + var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); + var queueStrategy = null; + var abortable = false; + if (syncStrategy) { + var syncStrings = syncStrategy.split(":"); + var selector = syncStrings[0].trim(); + if (selector === "this") { + syncElt = findThisElement(elt, 'hx-sync'); + } else { + syncElt = querySelectorExt(elt, selector); + } + // default to the drop strategy + syncStrategy = (syncStrings[1] || 'drop').trim(); + eltData = getInternalData(syncElt); + if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { + return; + } else if (syncStrategy === "abort") { + if (eltData.xhr) { + return; + } else { + abortable = true; + } + } else if (syncStrategy === "replace") { + triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue + } else if (syncStrategy.indexOf("queue") === 0) { + var queueStrArray = syncStrategy.split(" "); + queueStrategy = (queueStrArray[1] || "last").trim(); } - return; - } else { - eltData.requestInFlight = true; } + + if (eltData.xhr) { + if (eltData.abortable) { + triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue + } else { + if(queueStrategy == null){ + if (event) { + var eventData = getInternalData(event); + if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { + queueStrategy = eventData.triggerSpec.queue; + } + } + if (queueStrategy == null) { + queueStrategy = "last"; + } + } + if (eltData.queuedRequests == null) { + eltData.queuedRequests = []; + } + if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } else if (queueStrategy === "all") { + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } else if (queueStrategy === "last") { + eltData.queuedRequests = []; // dump existing queue + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } + return; + } + } + + var xhr = new XMLHttpRequest(); + eltData.xhr = xhr; + eltData.abortable = abortable; var endRequestLock = function(){ - eltData.requestInFlight = false + eltData.xhr = null; + eltData.abortable = false; if (eltData.queuedRequests != null && eltData.queuedRequests.length > 0) { var queuedRequest = eltData.queuedRequests.shift(); @@ -2152,11 +2602,10 @@ return (function () { } } - var xhr = new XMLHttpRequest(); var headers = getHeaders(elt, target, promptResponse); if (etc.headers) { - headers = mergeObjects(headers, etc.values); + headers = mergeObjects(headers, etc.headers); } var results = getInputValues(elt, verb); var errors = results.errors; @@ -2169,7 +2618,7 @@ return (function () { var filteredParameters = filterValues(allParameters, elt); if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null) { - headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; + headers['Content-Type'] = 'application/x-www-form-urlencoded'; } // behavior of anchors w/ empty href is to use the current URL @@ -2177,6 +2626,8 @@ return (function () { path = getDocument().location.href; } + var requestAttrValues = getValuesForElement(elt, 'hx-request'); + var requestConfig = { parameters: filteredParameters, unfilteredParameters: allParameters, @@ -2184,6 +2635,8 @@ return (function () { target:target, verb:verb, errors:errors, + withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, + timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, path:path, triggeringEvent:event }; @@ -2231,17 +2684,22 @@ return (function () { } xhr.overrideMimeType("text/html"); - xhr.withCredentials = htmx.config.withCredentials; + xhr.withCredentials = requestConfig.withCredentials; + xhr.timeout = requestConfig.timeout; // request headers - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - var headerValue = headers[header]; - safelySetHeaderValue(xhr, header, headerValue); + if (requestAttrValues.noHeaders) { + // ignore all headers + } else { + for (var header in headers) { + if (headers.hasOwnProperty(header)) { + var headerValue = headers[header]; + safelySetHeaderValue(xhr, header, headerValue); + } } } - var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, pathInfo:{ + var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, etc:etc, pathInfo:{ path:path, finalPath:finalPathForGet, anchor:anchor } }; @@ -2289,6 +2747,13 @@ return (function () { maybeCall(reject); endRequestLock(); } + xhr.ontimeout = function() { + removeRequestIndicatorClasses(indicators); + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); + triggerErrorEvent(elt, 'htmx:timeout', responseInfo); + maybeCall(reject); + endRequestLock(); + } if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){ maybeCall(resolve); endRequestLock() @@ -2315,6 +2780,7 @@ return (function () { function handleAjaxResponse(elt, responseInfo) { var xhr = responseInfo.xhr; var target = responseInfo.target; + var etc = responseInfo.etc; if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; @@ -2338,123 +2804,162 @@ return (function () { } } - var shouldSaveHistory = shouldPush(elt) || pushedUrl; + if (hasHeader(xhr,/HX-Retarget:/i)) { + responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget")); + } - if (xhr.status >= 200 && xhr.status < 400) { + /** @type {boolean} */ + var shouldSaveHistory + if (pushedUrl == "false") { + shouldSaveHistory = false + } else { + shouldSaveHistory = shouldPush(elt) || pushedUrl; + } + + // by default htmx only swaps on 200 return codes and does not swap + // on 204 'No Content' + // this can be ovverriden by responding to the htmx:beforeSwap event and + // overriding the detail.shouldSwap property + var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; + var serverResponse = xhr.response; + var isError = xhr.status >= 400; + var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo); + if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; + + target = beforeSwapDetails.target; // allow re-targeting + serverResponse = beforeSwapDetails.serverResponse; // allow updating content + isError = beforeSwapDetails.isError; // allow updating error + + responseInfo.failed = isError; // Make failed property available to response events + responseInfo.successful = !isError; // Make successful property available to response events + + if (beforeSwapDetails.shouldSwap) { if (xhr.status === 286) { cancelPolling(elt); } - // don't process 'No Content' - if (xhr.status !== 204) { - if (!triggerEvent(target, 'htmx:beforeSwap', responseInfo)) return; - var serverResponse = xhr.response; - withExtensions(elt, function(extension){ - serverResponse = extension.transformResponse(serverResponse, xhr, elt); - }); + withExtensions(elt, function (extension) { + serverResponse = extension.transformResponse(serverResponse, xhr, elt); + }); - // Save current page - if (shouldSaveHistory) { - saveHistory(); - } + // Save current page + if (shouldSaveHistory) { + saveCurrentPageToHistory(); + } + + var swapOverride = etc.swapOverride; + var swapSpec = getSwapSpecification(elt, swapOverride); - var swapSpec = getSwapSpecification(elt); + target.classList.add(htmx.config.swappingClass); + var doSwap = function () { + try { - target.classList.add(htmx.config.swappingClass); - var doSwap = function () { + var activeElt = document.activeElement; + var selectionInfo = {}; try { + selectionInfo = { + elt: activeElt, + // @ts-ignore + start: activeElt ? activeElt.selectionStart : null, + // @ts-ignore + end: activeElt ? activeElt.selectionEnd : null + }; + } catch (e) { + // safari issue - see https://github.com/microsoft/playwright/issues/5894 + } - var activeElt = document.activeElement; - var selectionInfo = {}; - try { - selectionInfo = { - elt: activeElt, - start: activeElt ? activeElt.selectionStart : null, - end: activeElt ? activeElt.selectionEnd : null - }; - } catch (e) { - // safari issue - see https://github.com/microsoft/playwright/issues/5894 + var settleInfo = makeSettleInfo(target); + selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + + if (selectionInfo.elt && + !bodyContains(selectionInfo.elt) && + selectionInfo.elt.id) { + var newActiveElt = document.getElementById(selectionInfo.elt.id); + var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; + if (newActiveElt) { + // @ts-ignore + if (selectionInfo.start && newActiveElt.setSelectionRange) { + // @ts-ignore + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + } + newActiveElt.focus(focusOptions); } + } - var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + target.classList.remove(htmx.config.swappingClass); + forEach(settleInfo.elts, function (elt) { + if (elt.classList) { + elt.classList.add(htmx.config.settlingClass); + } + triggerEvent(elt, 'htmx:afterSwap', responseInfo); + }); + if (responseInfo.pathInfo.anchor) { + location.hash = responseInfo.pathInfo.anchor; + } - if (selectionInfo.elt && - !bodyContains(selectionInfo.elt) && - selectionInfo.elt.id) { - var newActiveElt = document.getElementById(selectionInfo.elt.id); - if (newActiveElt) { - if (selectionInfo.start && newActiveElt.setSelectionRange) { - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); - } - newActiveElt.focus(); - } + if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { + var finalElt = elt; + if (!bodyContains(elt)) { + finalElt = getDocument().body; } + handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); + } - target.classList.remove(htmx.config.swappingClass); + var doSettle = function () { + forEach(settleInfo.tasks, function (task) { + task.call(); + }); forEach(settleInfo.elts, function (elt) { if (elt.classList) { - elt.classList.add(htmx.config.settlingClass); + elt.classList.remove(htmx.config.settlingClass); } - triggerEvent(elt, 'htmx:afterSwap', responseInfo); + triggerEvent(elt, 'htmx:afterSettle', responseInfo); }); - if (responseInfo.pathInfo.anchor) { - location.hash = responseInfo.pathInfo.anchor; + // push URL and save new page + if (shouldSaveHistory) { + var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; + pushUrlIntoHistory(pathToPush); + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: pathToPush}); } - if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; + if(settleInfo.title) { + var titleElt = find("title"); + if(titleElt) { + titleElt.innerHTML = settleInfo.title; + } else { + window.document.title = settleInfo.title; } - handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); } - var doSettle = function(){ - forEach(settleInfo.tasks, function (task) { - task.call(); - }); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.remove(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSettle', responseInfo); - }); - // push URL and save new page - if (shouldSaveHistory) { - var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; - pushUrlIntoHistory(pathToPush); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path:pathToPush}); - } - updateScrollState(settleInfo.elts, swapSpec); + updateScrollState(settleInfo.elts, swapSpec); - if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); + if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { + var finalElt = elt; + if (!bodyContains(elt)) { + finalElt = getDocument().body; } + handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'htmx:swapError', responseInfo); - throw e; } - }; - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); + if (swapSpec.settleDelay > 0) { + setTimeout(doSettle, swapSpec.settleDelay) + } else { + doSettle(); + } + } catch (e) { + triggerErrorEvent(elt, 'htmx:swapError', responseInfo); + throw e; } + }; + + if (swapSpec.swapDelay > 0) { + setTimeout(doSwap, swapSpec.swapDelay) + } else { + doSwap(); } - } else { + } + if (isError) { triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.path}, responseInfo)); } } @@ -2462,9 +2967,17 @@ return (function () { //==================================================================== // Extensions API //==================================================================== + + /** @type {Object<string, import("./htmx").HtmxExtension>} */ var extensions = {}; + + /** + * extensionBase defines the default functions for all extensions. + * @returns {import("./htmx").HtmxExtension} + */ function extensionBase() { return { + init: function(api) {return null;}, onEvent : function(name, evt) {return true;}, transformResponse : function(text, xhr, elt) {return text;}, isInlineSwap : function(swapStyle) {return false;}, @@ -2473,15 +2986,37 @@ return (function () { } } + /** + * defineExtension initializes the extension and adds it to the htmx registry + * + * @param {string} name + * @param {import("./htmx").HtmxExtension} extension + */ function defineExtension(name, extension) { + if(extension.init) { + extension.init(internalAPI) + } extensions[name] = mergeObjects(extensionBase(), extension); } + /** + * removeExtension removes an extension from the htmx registry + * + * @param {string} name + */ function removeExtension(name) { delete extensions[name]; } - function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + /** + * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element + * + * @param {HTMLElement} elt + * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn + * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore + */ + function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + if (elt == undefined) { return extensionsToReturn; } @@ -2536,6 +3071,7 @@ return (function () { function getMetaConfig() { var element = getDocument().querySelector('meta[name="htmx-config"]'); if (element) { + // @ts-ignore return parseJSON(element.content); } else { return null; @@ -2555,9 +3091,25 @@ return (function () { insertIndicatorStyles(); var body = getDocument().body; processNode(body); + var restoredElts = getDocument().querySelectorAll( + "[hx-trigger='restored'],[data-hx-trigger='restored']" + ); + body.addEventListener("htmx:abort", function (evt) { + var target = evt.target; + var internalData = getInternalData(target); + if (internalData && internalData.xhr) { + internalData.xhr.abort(); + } + }); window.onpopstate = function (event) { if (event.state && event.state.htmx) { restoreHistory(); + forEach(restoredElts, function(elt){ + triggerEvent(elt, 'htmx:restored', { + 'document': getDocument(), + 'triggerEvent': triggerEvent + }); + }); } }; setTimeout(function () { diff --git a/code/ch5_partials/ch5_final_video_collector/static/js/htmx.min.js b/code/ch5_partials/ch5_final_video_collector/static/js/htmx.min.js index 57f33b2..998414c 100644 --- a/code/ch5_partials/ch5_final_video_collector/static/js/htmx.min.js +++ b/code/ch5_partials/ch5_final_video_collector/static/js/htmx.min.js @@ -1 +1 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var k={onLoad:t,process:rt,on:I,off:M,trigger:lt,ajax:$t,find:w,findAll:S,closest:L,values:function(e,t){var r=Lt(e,t||"post");return r.values},remove:E,addClass:q,removeClass:R,toggleClass:C,takeClass:O,defineExtension:Qt,removeExtension:er,logAll:b,logger:null,useTemplateFragments:false,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,attributesToSettle:["class","style","width","height"],withCredentials:false,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]"},parseInterval:f,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])}};var r=["get","post","put","delete","patch"];var n=r.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function f(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function l(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function D(e,t){return l(e,t)||l(e,"data-"+t)}function c(e){return e.parentElement}function F(){return document}function h(e,t){if(t(e)){return e}else if(c(e)){return h(c(e),t)}else{return null}}function X(e,t){var r=null;h(e,function(e){return r=D(e,t)});return r}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function i(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 o(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=F().createDocumentFragment()}return i}function u(e){if(k.config.useTemplateFragments){var t=o("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=i(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return o("<table>"+e+"</table>",1);case"col":return o("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return o("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return o("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return o("<div>"+e+"</div>",1);default:return o(e,0)}}}function P(e){if(e){e()}}function a(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function v(e){return a(e,"Function")}function g(e){return a(e,"Object")}function U(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function p(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function j(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function m(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function z(e){return F().body.contains(e)}function y(e){return e.trim().split(/\s+/)}function V(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function x(e){try{return JSON.parse(e)}catch(e){ut(e);return null}}function e(e){return Ut(F().body,function(){return eval(e)})}function t(t){var e=k.on("htmx:load",function(e){t(e.detail.elt)});return e}function b(){k.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function w(e,t){if(t){return e.querySelector(t)}else{return w(F(),e)}}function S(e,t){if(t){return e.querySelectorAll(t)}else{return S(F(),e)}}function E(e,t){e=H(e);if(t){setTimeout(function(){E(e)},t)}else{e.parentElement.removeChild(e)}}function q(e,t,r){e=H(e);if(r){setTimeout(function(){q(e,t)},r)}else{e.classList.add(t)}}function R(e,t,r){e=H(e);if(r){setTimeout(function(){R(e,t)},r)}else{e.classList.remove(t)}}function C(e,t){e=H(e);e.classList.toggle(t)}function O(e,t){e=H(e);j(e.parentElement.children,function(e){R(e,t)});q(e,t)}function L(e,t){e=H(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&c(e))}}function A(e,t){if(t.indexOf("closest ")===0){return[L(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[w(e,t.substr(5))]}else{return F().querySelectorAll(t)}}function T(e,t){return A(e,t)[0]}function H(e){if(a(e,"String")){return w(e)}else{return e}}function N(e,t,r){if(v(t)){return{target:F().body,event:e,listener:t}}else{return{target:H(e),event:t,listener:r}}}function I(t,r,n){rr(function(){var e=N(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=v(r);return e?r:n}function M(t,r,n){rr(function(){var e=N(t,r,n);e.target.removeEventListener(e.event,e.listener)});return v(r)?r:n}function _(e){var t=h(e,function(e){return D(e,"hx-target")!==null});if(t){var r=D(t,"hx-target");if(r==="this"){return t}else{return T(e,r)}}else{var n=U(e);if(n.boosted){return F().body}else{return e}}}function B(e){var t=k.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function W(t,r){j(t.attributes,function(e){if(!r.hasAttribute(e.name)&&B(e.name)){t.removeAttribute(e.name)}});j(r.attributes,function(e){if(B(e.name)){t.setAttribute(e.name,e.value)}})}function $(e,t){var r=tr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){ut(e)}}return e==="outerHTML"}function J(e,t,r){var n="#"+t.id;var i="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){i=e.substr(0,e.indexOf(":"));n=e.substr(e.indexOf(":")+1,e.length)}else{i=e}var o=F().querySelector(n);if(o){var a;a=F().createDocumentFragment();a.appendChild(t);if(!$(i,o)){a=t}le(i,o,o,a,r)}else{t.parentNode.removeChild(t);ot(F().body,"htmx:oobErrorNoTarget",{content:t})}return e}function Z(e,r){j(S(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=D(e,"hx-swap-oob");if(t!=null){J(t,e,r)}})}function G(e){j(S(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=D(e,"id");var r=F().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function K(n,e,i){j(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();W(e,t);i.tasks.push(function(){W(e,r)})}}})}function Y(e){return function(){rt(e);Ye(e);Q(e);lt(e,"htmx:load")}}function Q(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ee(e,t,r,n){K(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Y(i))}}}function te(t){var e=U(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}if(e.listenerInfos){j(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){j(t.children,function(e){te(e)})}}function re(e,t,r){if(e.tagName==="BODY"){return se(e,t,r)}else{var n=e.previousSibling;ee(c(e),e,t,r);if(n==null){var i=c(e).firstChild}else{var i=n.nextSibling}U(e).replacedWith=i;r.elts=[];while(i&&i!==e){if(i.nodeType===Node.ELEMENT_NODE){r.elts.push(i)}i=i.nextElementSibling}te(e);c(e).removeChild(e)}}function ne(e,t,r){return ee(e,e.firstChild,t,r)}function ie(e,t,r){return ee(c(e),e,t,r)}function oe(e,t,r){return ee(e,null,t,r)}function ae(e,t,r){return ee(c(e),e.nextSibling,t,r)}function se(e,t,r){var n=e.firstChild;ee(e,n,t,r);if(n){while(n.nextSibling){te(n.nextSibling);e.removeChild(n.nextSibling)}te(n);e.removeChild(n)}}function ue(e,t){var r=X(e,"hx-select");if(r){var n=F().createDocumentFragment();j(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function le(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":re(r,n,i);return;case"afterbegin":ne(r,n,i);return;case"beforebegin":ie(r,n,i);return;case"beforeend":oe(r,n,i);return;case"afterend":ae(r,n,i);return;default:var o=tr(t);for(var a=0;a<o.length;a++){var s=o[a];try{var u=s.handleSwap(e,r,n,i);if(u){if(typeof u.length!=="undefined"){for(var l=0;l<u.length;l++){var f=u[l];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Y(f))}}}return}}catch(e){ut(e)}}se(r,n,i)}}var fe=/<title>([\s\S]+?)<\/title>/im;function ce(e){if(e.indexOf("<title>")>-1&&(e.indexOf("<svg>")==-1||e.indexOf("<title>")<e.indexOf("<svg>"))){var t=fe.exec(e);if(t){return t[1]}}}function he(e,t,r,n,i){var o=ce(n);if(o){var a=w("title");if(a){a.innerHTML=o}else{window.document.title=o}}var s=u(n);if(s){Z(s,i);s=ue(r,s);G(s);return le(e,r,t,s,i)}}function de(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=x(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!g(a)){a={value:a}}lt(r,o,a)}}}else{lt(r,n,[])}}var ve=/\s/;var ge=/[\s,]/;var pe=/[_$a-zA-Z]/;var me=/[_$a-zA-Z0-9]/;var ye=['"',"'","/"];var xe=/[^\s]/;function be(e){var t=[];var r=0;while(r<e.length){if(pe.exec(e.charAt(r))){var n=r;while(me.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(ye.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function we(e,t,r){return pe.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function Se(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Ut(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){ot(F().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(we(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function Ee(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var qe="input, textarea, select";function Re(e){var t=D(e,"hx-trigger");var r=[];if(t){var n=be(t);do{Ee(n,xe);var i=n.length;var o=Ee(n,/[,\[\s]/);if(o!==""){if(o==="every"){var a={trigger:"every"};Ee(n,xe);a.pollInterval=f(Ee(n,ve));r.push(a)}else if(o.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:o.substr(4)})}else{var s={trigger:o};var u=Se(e,n,"event");if(u){s.eventFilter=u}while(n.length>0&&n[0]!==","){Ee(n,xe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=f(Ee(n,ge))}else if(l==="from"&&n[0]===":"){n.shift();s.from=Ee(n,ge)}else if(l==="target"&&n[0]===":"){n.shift();s.target=Ee(n,ge)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=f(Ee(n,ge))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=Ee(n,ge)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=Ee(n,ge)}else{ot(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===i){ot(e,"htmx:syntax:error",{token:n.shift()})}Ee(n,xe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,qe)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ce(e){U(e).cancelled=true}function Oe(e,t,r,n){var i=U(e);i.timeout=setTimeout(function(){if(z(e)&&i.cancelled!==true){Zt(t,r,e);Oe(e,t,D(e,"hx-"+t),n)}},n)}function Le(e){return location.hostname===e.hostname&&l(e,"href")&&l(e,"href").indexOf("#")!==0}function Ae(t,r,e){if(t.tagName==="A"&&Le(t)||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=l(t,"href");r.pushURL=true}else{var o=l(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=l(t,"action")}e.forEach(function(e){Ie(t,n,i,r,e,true)})}}function Te(e){return e.tagName==="FORM"||d(e,'input[type="submit"], button')&&L(e,"form")!==null||e.tagName==="A"&&e.href&&(e.getAttribute("href")==="#"||e.getAttribute("href").indexOf("#")!==0)}function He(e,t){return U(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function Ne(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){ot(F().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Ie(n,i,o,e,a,s){var u=n;if(a.from){u=w(a.from)}var l=function(e){if(!z(n)){u.removeEventListener(a.trigger,l);return}if(He(n,e)){return}if(s||Te(n)){e.preventDefault()}if(Ne(a,e)){return}var t=U(e);t.triggerSpec=a;if(t.handledFor==null){t.handledFor=[]}var r=U(n);if(t.handledFor.indexOf(n)<0){t.handledFor.push(n);if(a.consume){e.stopPropagation()}if(a.target&&e.target){if(!d(e.target,a.target)){return}}if(a.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(a.changed){if(r.lastValue===n.value){return}else{r.lastValue=n.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(a.throttle){if(!r.throttle){Zt(i,o,n,e);r.throttle=setTimeout(function(){r.throttle=null},a.throttle)}}else if(a.delay){r.delayed=setTimeout(function(){Zt(i,o,n,e)},a.delay)}else{Zt(i,o,n,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:a.trigger,listener:l,on:u});u.addEventListener(a.trigger,l)}var Me=false;var ke=null;function De(){if(!ke){ke=function(){Me=true};window.addEventListener("scroll",ke);setInterval(function(){if(Me){Me=false;j(F().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){Fe(e)})}},200)}}function Fe(e){var t=U(e);if(!t.revealed&&m(e)){t.revealed=true;if(t.initialized){Zt(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Zt(t.verb,t.path,e)},{once:true})}}}function Xe(e,t,r){var n=y(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Pe(e,o[1],0)}if(o[0]==="send"){je(e)}}}function Pe(s,r,n){if(!z(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=k.createWebSocket(r);t.onerror=function(e){ot(s,"htmx:wsError",{error:e,socket:t});Ue(s)};t.onclose=function(e){if([1006,1012,1013].includes(e.code)){var t=ze(n);setTimeout(function(){Pe(s,r,n+1)},t)}};t.onopen=function(e){n=0};U(s).webSocket=t;t.addEventListener("message",function(e){if(Ue(s)){return}var t=e.data;st(s,function(e){t=e.transformResponse(t,null,s)});var r=Ft(s);var n=u(t);var i=p(n.children);for(var o=0;o<i.length;o++){var a=i[o];J(D(a,"hx-swap-oob")||"true",a,r)}mt(r.tasks)})}function Ue(e){if(!z(e)){U(e).webSocket.close();return true}}function je(l){var f=h(l,function(e){return U(e).webSocket!=null});if(f){l.addEventListener(Re(l)[0].trigger,function(e){var t=U(f).webSocket;var r=Nt(l,f);var n=Lt(l,"post");var i=n.errors;var o=n.values;var a=Vt(l);var s=V(o,a);var u=It(s,l);u["HEADERS"]=r;if(i&&i.length>0){lt(l,"htmx:validation:halted",i);return}t.send(JSON.stringify(u));if(Te(l)){e.preventDefault()}})}else{ot(l,"htmx:noWebSocketSourceError")}}function ze(e){var t=k.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}ut('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ve(e,t,r){var n=y(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){_e(e,o[1])}if(o[0]==="swap"){Be(e,o[1])}}}function _e(t,e){var r=k.createEventSource(e);r.onerror=function(e){ot(t,"htmx:sseError",{error:e,source:r});$e(t)};U(t).sseEventSource=r}function Be(o,a){var s=h(o,Je);if(s){var u=U(s).sseEventSource;var l=function(e){if($e(s)){u.removeEventListener(a,l);return}var t=e.data;st(o,function(e){t=e.transformResponse(t,null,o)});var r=kt(o);var n=_(o);var i=Ft(o);he(r.swapStyle,o,n,t,i);mt(i.tasks);lt(o,"htmx:sseMessage",e)};U(o).sseListener=l;u.addEventListener(a,l)}else{ot(o,"htmx:noSSESourceError")}}function We(e,t,r,n){var i=h(e,Je);if(i){var o=U(i).sseEventSource;var a=function(){if(!$e(i)){if(z(e)){Zt(t,r,e)}else{o.removeEventListener(n,a)}}};U(e).sseListener=a;o.addEventListener(n,a)}else{ot(e,"htmx:noSSESourceError")}}function $e(e){if(!z(e)){U(e).sseEventSource.close();return true}}function Je(e){return U(e).sseEventSource!=null}function Ze(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Zt(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function Ge(o,a,e){var t=false;j(r,function(n){if(s(o,"hx-"+n)){var i=D(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){We(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){De();Fe(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=T(e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){lt(o,"intersect");break}}},t);r.observe(o);Ie(o,n,i,a,e)}else if(e.trigger==="load"){Ze(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Oe(o,n,i,e.pollInterval)}else{Ie(o,n,i,a,e)}})}});return t}function Ke(e){if(e.type==="text/javascript"||e.type===""){try{Ut(e,function(){(1,eval)(e.innerText)})}catch(e){ut(e)}}}function Ye(e){if(d(e,"script")){Ke(e)}j(S(e,"script"),function(e){Ke(e)})}function Qe(){return document.querySelector("[hx-boost], [data-hx-boost]")}function et(e){if(e.querySelectorAll){var t=Qe()?", a, form":"";var r=e.querySelectorAll(n+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws]");return r}else{return[]}}function tt(e){if(e.closest&&e.closest(k.config.disableSelector)){return}var t=U(e);if(!t.initialized){t.initialized=true;lt(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=Re(e);var n=Ge(e,t,r);if(!n&&X(e,"hx-boost")==="true"){Ae(e,t,r)}var i=D(e,"hx-sse");if(i){Ve(e,t,i)}var o=D(e,"hx-ws");if(o){Xe(e,t,o)}lt(e,"htmx:afterProcessNode")}}function rt(e){e=H(e);tt(e);j(et(e),function(e){tt(e)})}function nt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function it(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=F().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function ot(e,t,r){lt(e,t,V({error:t},r))}function at(e){return e==="htmx:afterProcessNode"}function st(e,t){j(tr(e),function(e){try{t(e)}catch(e){ut(e)}})}function ut(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function lt(e,t,r){e=H(e);if(r==null){r={}}r["elt"]=e;var n=it(t,r);if(k.logger&&!at(t)){k.logger(e,t,r)}if(r.error){ut(r.error);lt(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=nt(t);if(i&&o!==t){var a=it(o,n.detail);i=i&&e.dispatchEvent(a)}st(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var ft=null;function ct(){var e=F().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||F().body}function ht(e,t,r,n){var i=x(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>k.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ot(F().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function dt(e){var t=x(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function vt(e){var t=k.config.requestClass;var r=e.cloneNode(true);j(S(r,"."+t),function(e){R(e,t)});return r.innerHTML}function gt(){var e=ct();var t=ft||location.pathname+location.search;lt(F().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(k.config.historyEnabled)history.replaceState({htmx:true},F().title,window.location.href);ht(t,vt(e),F().title,window.scrollY)}function pt(e){if(k.config.historyEnabled)history.pushState({htmx:true},"",e);ft=e}function mt(e){j(e,function(e){e.call()})}function yt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};lt(F().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){lt(F().body,"htmx:historyCacheMissLoad",i);var e=u(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=ct();var r=Ft(t);se(t,e,r);mt(r.tasks);ft=n;lt(F().body,"htmx:historyRestore",{path:n})}else{ot(F().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function xt(e){gt();e=e||location.pathname+location.search;var t=dt(e);if(t){var r=u(t.content);var n=ct();var i=Ft(n);se(n,r,i);mt(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);ft=e;lt(F().body,"htmx:historyRestore",{path:e})}else{if(k.config.refreshOnHistoryMiss){window.location.reload(true)}else{yt(e)}}}function bt(e){var t=X(e,"hx-push-url");return t&&t!=="false"||U(e).boosted&&U(e).pushURL}function wt(e){var t=X(e,"hx-push-url");return t==="true"||t==="false"?null:t}function St(e){var t=X(e,"hx-indicator");if(t){var r=A(e,t)}else{r=[e]}j(r,function(e){e.classList["add"].call(e.classList,k.config.requestClass)});return r}function Et(e){j(e,function(e){e.classList["remove"].call(e.classList,k.config.requestClass)})}function qt(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Rt(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 Ct(t,r,n,e,i){if(e==null||qt(t,e)){return}else{t.push(e)}if(Rt(e)){var o=l(e,"name");var a=e.value;if(e.multiple){a=p(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=p(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){Ot(e,n)}}if(d(e,"form")){var u=e.elements;j(u,function(e){Ct(t,r,n,e,i)})}}function Ot(e,t){if(e.willValidate){lt(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});lt(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Lt(e,t){var r=[];var n={};var i={};var o=[];var a=d(e,"form")&&e.noValidate!==true;if(t!=="get"){Ct(r,i,o,L(e,"form"),a)}Ct(r,n,o,e,a);var s=X(e,"hx-include");if(s){var u=A(e,s);j(u,function(e){Ct(r,n,o,e,a);if(!d(e,"form")){j(e.querySelectorAll(qe),function(e){Ct(r,n,o,e,a)})}})}n=V(n,i);return{errors:o,values:n}}function At(e,t,r){if(e!==""){e+="&"}e+=encodeURIComponent(t)+"="+encodeURIComponent(r);return e}function Tt(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){j(n,function(e){t=At(t,r,e)})}else{t=At(t,r,n)}}}return t}function Ht(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){j(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Nt(e,t,r){var n={"HX-Request":"true","HX-Trigger":l(e,"id"),"HX-Trigger-Name":l(e,"name"),"HX-Target":D(t,"id"),"HX-Current-URL":F().location.href};Pt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}return n}function It(t,e){var r=X(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){j(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};j(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Mt(e){return l(e,"href")&&l(e,"href").indexOf("#")>=0}function kt(e){var t=X(e,"hx-swap");var r={swapStyle:U(e).boosted?"innerHTML":k.config.defaultSwapStyle,swapDelay:k.config.defaultSwapDelay,settleDelay:k.config.defaultSettleDelay};if(U(e).boosted&&!Mt(e)){r["show"]="top"}if(t){var n=y(t);if(n.length>0){r["swapStyle"]=n[0];for(var i=1;i<n.length;i++){var o=n[i];if(o.indexOf("swap:")===0){r["swapDelay"]=f(o.substr(5))}if(o.indexOf("settle:")===0){r["settleDelay"]=f(o.substr(7))}if(o.indexOf("scroll:")===0){r["scroll"]=o.substr(7)}if(o.indexOf("show:")===0){r["show"]=o.substr(5)}}}}return r}function Dt(t,r,n){var i=null;st(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(X(r,"hx-encoding")==="multipart/form-data"){return Ht(n)}else{return Tt(n)}}}function Ft(e){return{tasks:[],elts:[e]}}function Xt(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){if(t.scroll==="top"&&r){r.scrollTop=0}if(t.scroll==="bottom"&&n){n.scrollTop=n.scrollHeight}}if(t.show){if(t.show==="top"&&r){r.scrollIntoView(true)}if(t.show==="bottom"&&n){n.scrollIntoView(false)}}}function Pt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=D(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Ut(e,function(){return Function("return ("+o+")")()},{})}else{s=x(o)}for(var u in s){if(s.hasOwnProperty(u)){if(n[u]==null){n[u]=s[u]}}}}return Pt(c(e),t,r,n)}function Ut(e,t,r){if(k.config.allowEval){return t()}else{ot(e,"htmx:evalDisallowedError");return r}}function jt(e,t){return Pt(e,"hx-vars",true,t)}function zt(e,t){return Pt(e,"hx-vals",false,t)}function Vt(e){return V(jt(e),zt(e))}function _t(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Bt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ot(F().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Wt(e,t){return e.getAllResponseHeaders().match(t)}function $t(e,t,r){if(r){if(r instanceof Element||a(r,"String")){return Zt(e,t,null,null,{targetOverride:H(r)})}else{return Zt(e,t,H(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:H(r.target)})}}else{return Zt(e,t)}}function Jt(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Zt(e,t,n,r,i){var o=null;var a=null;i=i!=null?i:{};if(typeof Promise!=="undefined"){var s=new Promise(function(e,t){o=e;a=t})}if(n==null){n=F().body}var u=i.handler||Gt;if(!z(n)){return}var l=i.targetOverride||_(n);if(l==null){ot(n,"htmx:targetError",{target:D(n,"hx-target")});return}var f=U(n);if(f.requestInFlight){var c="last";var h=U(r);if(h&&h.triggerSpec&&h.triggerSpec.queue){c=h.triggerSpec.queue}if(f.queuedRequests==null){f.queuedRequests=[]}if(c==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){Zt(e,t,n,r)})}else if(c==="all"){f.queuedRequests.push(function(){Zt(e,t,n,r)})}else if(c==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){Zt(e,t,n,r)})}return}else{f.requestInFlight=true}var d=function(){f.requestInFlight=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var v=X(n,"hx-prompt");if(v){var g=prompt(v);if(g===null||!lt(n,"htmx:prompt",{prompt:g,target:l})){P(o);d();return s}}var p=X(n,"hx-confirm");if(p){if(!confirm(p)){P(o);d();return s}}var m=new XMLHttpRequest;var y=Nt(n,l,g);if(i.headers){y=V(y,i.values)}var x=Lt(n,e);var b=x.errors;var w=x.values;if(i.values){w=V(w,i.values)}var S=Vt(n);var E=V(w,S);var q=It(E,n);if(e!=="get"&&X(n,"hx-encoding")==null){y["Content-Type"]="application/x-www-form-urlencoded; charset=UTF-8"}if(t==null||t===""){t=F().location.href}var R={parameters:q,unfilteredParameters:E,headers:y,target:l,verb:e,errors:b,path:t,triggeringEvent:r};if(!lt(n,"htmx:configRequest",R)){P(o);d();return s}t=R.path;e=R.verb;y=R.headers;q=R.parameters;b=R.errors;if(b&&b.length>0){lt(n,"htmx:validation:halted",R);P(o);d();return s}var C=t.split("#");var O=C[0];var L=C[1];if(e==="get"){var A=O;var T=Object.keys(q).length!==0;if(T){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=Tt(q);if(L){A+="#"+L}}m.open("GET",A,true)}else{m.open(e.toUpperCase(),t,true)}m.overrideMimeType("text/html");m.withCredentials=k.config.withCredentials;for(var H in y){if(y.hasOwnProperty(H)){var N=y[H];_t(m,H,N)}}var I={xhr:m,target:l,requestConfig:R,pathInfo:{path:t,finalPath:A,anchor:L}};m.onload=function(){try{var e=Jt(n);u(n,I);Et(M);lt(n,"htmx:afterRequest",I);lt(n,"htmx:afterOnLoad",I);if(!z(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(z(r)){t=r}}if(t){lt(t,"htmx:afterRequest",I);lt(t,"htmx:afterOnLoad",I)}}P(o);d()}catch(e){ot(n,"htmx:onLoadError",V({error:e},I));throw e}};m.onerror=function(){Et(M);ot(n,"htmx:afterRequest",I);ot(n,"htmx:sendError",I);P(a);d()};m.onabort=function(){Et(M);ot(n,"htmx:afterRequest",I);ot(n,"htmx:sendAbort",I);P(a);d()};if(!lt(n,"htmx:beforeRequest",I)){P(o);d();return s}var M=St(n);j(["loadstart","loadend","progress","abort"],function(t){j([m,m.upload],function(e){e.addEventListener(t,function(e){lt(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});lt(n,"htmx:beforeSend",I);m.send(e==="get"?null:Dt(m,n,q));return s}function Gt(a,s){var u=s.xhr;var l=s.target;if(!lt(a,"htmx:beforeOnLoad",s))return;if(Wt(u,/HX-Trigger:/i)){de(u,"HX-Trigger",a)}if(Wt(u,/HX-Push:/i)){var f=u.getResponseHeader("HX-Push")}if(Wt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Wt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}var c=bt(a)||f;if(u.status>=200&&u.status<400){if(u.status===286){Ce(a)}if(u.status!==204){if(!lt(l,"htmx:beforeSwap",s))return;var h=u.response;st(a,function(e){h=e.transformResponse(h,u,a)});if(c){gt()}var d=kt(a);l.classList.add(k.config.swappingClass);var e=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r=Ft(l);he(d.swapStyle,l,a,h,r);if(t.elt&&!z(t.elt)&&t.elt.id){var n=document.getElementById(t.elt.id);if(n){if(t.start&&n.setSelectionRange){n.setSelectionRange(t.start,t.end)}n.focus()}}l.classList.remove(k.config.swappingClass);j(r.elts,function(e){if(e.classList){e.classList.add(k.config.settlingClass)}lt(e,"htmx:afterSwap",s)});if(s.pathInfo.anchor){location.hash=s.pathInfo.anchor}if(Wt(u,/HX-Trigger-After-Swap:/i)){var i=a;if(!z(a)){i=F().body}de(u,"HX-Trigger-After-Swap",i)}var o=function(){j(r.tasks,function(e){e.call()});j(r.elts,function(e){if(e.classList){e.classList.remove(k.config.settlingClass)}lt(e,"htmx:afterSettle",s)});if(c){var e=f||wt(a)||Bt(u)||s.pathInfo.finalPath||s.pathInfo.path;pt(e);lt(F().body,"htmx:pushedIntoHistory",{path:e})}Xt(r.elts,d);if(Wt(u,/HX-Trigger-After-Settle:/i)){var t=a;if(!z(a)){t=F().body}de(u,"HX-Trigger-After-Settle",t)}};if(d.settleDelay>0){setTimeout(o,d.settleDelay)}else{o()}}catch(e){ot(a,"htmx:swapError",s);throw e}};if(d.swapDelay>0){setTimeout(e,d.swapDelay)}else{e()}}}else{ot(a,"htmx:responseError",V({error:"Response Status Error Code "+u.status+" from "+s.pathInfo.path},s))}}var Kt={};function Yt(){return{onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Qt(e,t){Kt[e]=V(Yt(),t)}function er(e){delete Kt[e]}function tr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=D(e,"hx-ext");if(t){j(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Kt[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return tr(c(e),r,n)}function rr(e){if(F().readyState!=="loading"){e()}else{F().addEventListener("DOMContentLoaded",e)}}function nr(){if(k.config.includeIndicatorStyles!==false){F().head.insertAdjacentHTML("beforeend","<style> ."+k.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+k.config.requestClass+" ."+k.config.indicatorClass+"{opacity:1} ."+k.config.requestClass+"."+k.config.indicatorClass+"{opacity:1} </style>")}}function ir(){var e=F().querySelector('meta[name="htmx-config"]');if(e){return x(e.content)}else{return null}}function or(){var e=ir();if(e){k.config=V(k.config,e)}}rr(function(){or();nr();var e=F().body;rt(e);window.onpopstate=function(e){if(e.state&&e.state.htmx){xt()}};setTimeout(function(){lt(e,"htmx:load",{})},0)});return k}()}); \ No newline at end of file +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(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 l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=k(e);e.classList.toggle(t)}function T(e,t){e=k(e);W(e.parentElement.children,function(e){q(e,t)});L(e,t)}function H(e,t){e=k(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function N(e,t){if(t.indexOf("closest ")===0){return[H(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[C(e,t.substr(5))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return z().querySelectorAll(t)}}function ee(e,t){if(t){return N(e,t)[0]}else{return N(z().body,e)[0]}}function k(e){if(p(e,"String")){return C(e)}else{return e}}function I(e,t,r){if(m(t)){return{target:z().body,event:e,listener:t}}else{return{target:k(e),event:t,listener:r}}}function M(t,r,n){lr(function(){var e=I(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function D(t,r,n){lr(function(){var e=I(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var te=z().createElement("output");function F(e,t){var r=G(e,t);if(r){if(r==="this"){return[re(e,t)]}else{var n=N(e,r);if(n.length===0){pt('The selector "'+r+'" on '+t+" returned no matches!");return[te]}else{return n}}}}function re(e,t){return h(e,function(e){return V(e,t)!=null})}function ne(e){var t=G(e,"hx-target");if(t){if(t==="this"){return re(e,"hx-target")}else{return ee(e,t)}}else{var r=_(e);if(r.boosted){return z().body}else{return e}}}function P(e){var t=U.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function X(t,r){W(t.attributes,function(e){if(!r.hasAttribute(e.name)&&P(e.name)){t.removeAttribute(e.name)}});W(r.attributes,function(e){if(P(e.name)){t.setAttribute(e.name,e.value)}})}function j(e,t){var r=sr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){pt(e)}}return e==="outerHTML"}function B(e,i,o){var t="#"+i.id;var a="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){a=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{a=e}var r=z().querySelectorAll(t);if(r){W(r,function(e){var t;var r=i.cloneNode(true);t=z().createDocumentFragment();t.appendChild(r);if(!j(a,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ye(a,e,e,t,o)}W(o.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(z().body,"htmx:oobErrorNoTarget",{content:i})}return e}function ie(e,r){W(R(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=V(e,"hx-swap-oob");if(t!=null){B(t,e,r)}})}function oe(e){W(R(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=V(e,"id");var r=z().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function ae(n,e,i){W(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();X(e,t);i.tasks.push(function(){X(e,r)})}}})}function se(e){return function(){q(e,U.config.addedClass);ct(e);at(e);le(e);$(e,"htmx:load")}}function le(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ue(e,t,r,n){ae(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(se(i))}}}function fe(t){var e=_(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){W(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){W(t.children,function(e){fe(e)})}}function ce(e,t,r){if(e.tagName==="BODY"){return me(e,t,r)}else{var n;var i=e.previousSibling;ue(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}_(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}fe(e);u(e).removeChild(e)}}function he(e,t,r){return ue(e,e.firstChild,t,r)}function de(e,t,r){return ue(u(e),e,t,r)}function ve(e,t,r){return ue(e,null,t,r)}function ge(e,t,r){return ue(u(e),e.nextSibling,t,r)}function pe(e,t,r){fe(e);return u(e).removeChild(e)}function me(e,t,r){var n=e.firstChild;ue(e,n,t,r);if(n){while(n.nextSibling){fe(n.nextSibling);e.removeChild(n.nextSibling)}fe(n);e.removeChild(n)}}function xe(e,t){var r=G(e,"hx-select");if(r){var n=z().createDocumentFragment();W(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function ye(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":ce(r,n,i);return;case"afterbegin":he(r,n,i);return;case"beforebegin":de(r,n,i);return;case"beforeend":ve(r,n,i);return;case"afterend":ge(r,n,i);return;case"delete":pe(r,n,i);return;default:var o=sr(t);for(var a=0;a<o.length;a++){var f=o[a];try{var s=f.handleSwap(e,r,n,i);if(s){if(typeof s.length!=="undefined"){for(var l=0;l<s.length;l++){var u=s[l];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){i.tasks.push(se(u))}}}return}}catch(e){pt(e)}}if(e==="innerHTML"){me(r,n,i)}else{ye(U.config.defaultSwapStyle,t,r,n,i)}}}function be(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function we(e,t,r,n,i){i.title=be(n);var o=g(n);if(o){ie(o,i);o=xe(r,o);oe(o);return ye(e,r,t,o,i)}}function Se(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!x(a)){a={value:a}}$(r,o,a)}}}else{$(r,n,[])}}var Ee=/\s/;var Ce=/[\s,]/;var Re=/[_$a-zA-Z]/;var Oe=/[_$a-zA-Z0-9]/;var Le=['"',"'","/"];var qe=/[^\s]/;function Ae(e){var t=[];var r=0;while(r<e.length){if(Re.exec(e.charAt(r))){var n=r;while(Oe.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Le.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function Te(e,t,r){return Re.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function He(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Jt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(z().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(Te(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var Ne="input, textarea, select";function ke(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=Ae(t);do{c(n,qe);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var o={trigger:"every"};c(n,qe);o.pollInterval=v(c(n,/[,\[\s]/));c(n,qe);var a=He(e,n,"event");if(a){o.eventFilter=a}r.push(o)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var a=He(e,n,"event");if(a){s.eventFilter=a}while(n.length>0&&n[0]!==","){c(n,qe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Ce))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Ce);if(u==="closest"||u==="find"){n.shift();u+=" "+c(n,Ce)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Ce)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Ce))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Ce)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Ce)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,qe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,Ne)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ie(e){_(e).cancelled=true}function Me(e,t,r,n){var i=_(e);i.timeout=setTimeout(function(){if(Y(e)&&i.cancelled!==true){if(!je(n,dt("hx:poll:trigger",{triggerSpec:n,target:e}))){Z(t,r,e)}Me(e,t,V(e,"hx-"+t),n)}},n.pollInterval)}function De(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&De(t)&&t.target===""||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href");r.pushURL=true}else{var o=f(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=f(t,"action")}e.forEach(function(e){Be(t,n,i,r,e,true)})}}function Pe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&H(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Xe(e,t){return _(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function je(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(z().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Be(o,a,s,e,l,u){var t;if(l.from){t=N(o,l.from)}else{t=[o]}W(t,function(n){var i=function(e){if(!Y(o)){n.removeEventListener(l.trigger,i);return}if(Xe(o,e)){return}if(u||Pe(e,o)){e.preventDefault()}if(je(l,e)){return}var t=_(e);t.triggerSpec=l;if(t.handledFor==null){t.handledFor=[]}var r=_(o);if(t.handledFor.indexOf(o)<0){t.handledFor.push(o);if(l.consume){e.stopPropagation()}if(l.target&&e.target){if(!d(e.target,l.target)){return}}if(l.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(l.changed){if(r.lastValue===o.value){return}else{r.lastValue=o.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(l.throttle){if(!r.throttle){Z(a,s,o,e);r.throttle=setTimeout(function(){r.throttle=null},l.throttle)}}else if(l.delay){r.delayed=setTimeout(function(){Z(a,s,o,e)},l.delay)}else{Z(a,s,o,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:l.trigger,listener:i,on:n});n.addEventListener(l.trigger,i)})}var Ue=false;var Ve=null;function ze(){if(!Ve){Ve=function(){Ue=true};window.addEventListener("scroll",Ve);setInterval(function(){if(Ue){Ue=false;W(z().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){_e(e)})}},200)}}function _e(e){if(!s(e,"data-hx-revealed")&&b(e)){e.setAttribute("data-hx-revealed","true");var t=_(e);if(t.initialized){Z(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Z(t.verb,t.path,e)},{once:true})}}}function We(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Je(e,o[1],0)}if(o[0]==="send"){Ze(e)}}}function Je(s,r,n){if(!Y(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=U.createWebSocket(r);t.onerror=function(e){J(s,"htmx:wsError",{error:e,socket:t});$e(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=Ge(n);setTimeout(function(){Je(s,r,n+1)},t)}};t.onopen=function(e){n=0};_(s).webSocket=t;t.addEventListener("message",function(e){if($e(s)){return}var t=e.data;gt(s,function(e){t=e.transformResponse(t,null,s)});var r=zt(s);var n=g(t);var i=y(n.children);for(var o=0;o<i.length;o++){var a=i[o];B(V(a,"hx-swap-oob")||"true",a,r)}Ct(r.tasks)})}function $e(e){if(!Y(e)){_(e).webSocket.close();return true}}function Ze(u){var f=h(u,function(e){return _(e).webSocket!=null});if(f){u.addEventListener(ke(u)[0].trigger,function(e){var t=_(f).webSocket;var r=Xt(u,f);var n=Mt(u,"post");var i=n.errors;var o=n.values;var a=Gt(u);var s=Q(o,a);var l=jt(s,u);l["HEADERS"]=r;if(i&&i.length>0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Pe(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ge(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}pt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ke(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Ye(e,o[1])}if(o[0]==="swap"){Qe(e,o[1])}}}function Ye(t,e){var r=U.createEventSource(e);r.onerror=function(e){J(t,"htmx:sseError",{error:e,source:r});tt(t)};_(t).sseEventSource=r}function Qe(o,a){var s=h(o,rt);if(s){var l=_(s).sseEventSource;var u=function(e){if(tt(s)){l.removeEventListener(a,u);return}var t=e.data;gt(o,function(e){t=e.transformResponse(t,null,o)});var r=Ut(o);var n=ne(o);var i=zt(o);we(r.swapStyle,o,n,t,i);Ct(i.tasks);$(o,"htmx:sseMessage",e)};_(o).sseListener=u;l.addEventListener(a,u)}else{J(o,"htmx:noSSESourceError")}}function et(e,t,r,n){var i=h(e,rt);if(i){var o=_(i).sseEventSource;var a=function(){if(!tt(i)){if(Y(e)){Z(t,r,e)}else{o.removeEventListener(n,a)}}};_(e).sseListener=a;o.addEventListener(n,a)}else{J(e,"htmx:noSSESourceError")}}function tt(e){if(!Y(e)){_(e).sseEventSource.close();return true}}function rt(e){return _(e).sseEventSource!=null}function nt(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Z(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function it(o,a,e){var t=false;W(n,function(n){if(s(o,"hx-"+n)){var i=V(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){et(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){ze();_e(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=ee(o,e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){$(o,"intersect");break}}},t);r.observe(o);Be(o,n,i,a,e)}else if(e.trigger==="load"){nt(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Me(o,n,i,e)}else{Be(o,n,i,a,e)}})}});return t}function ot(e){if(e.type==="text/javascript"||e.type==="module"||e.type===""){var t=z().createElement("script");W(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(U.config.inlineScriptNonce){t.nonce=U.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){pt(e)}finally{r.removeChild(e)}}}function at(e){if(d(e,"script")){ot(e)}W(R(e,"script"),function(e){ot(e)})}function st(){return document.querySelector("[hx-boost], [data-hx-boost]")}function lt(e){if(e.querySelectorAll){var t=st()?", a, form":"";var r=e.querySelectorAll(i+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [hx-data-ext]");return r}else{return[]}}function ut(r){var e=function(e){if(d(e.target,"button, input[type='submit']")){var t=_(r);t.lastButtonClicked=e.target}};r.addEventListener("click",e);r.addEventListener("focusin",e);r.addEventListener("focusout",function(e){var t=_(r);t.lastButtonClicked=null})}function ft(e){if(e.closest&&e.closest(U.config.disableSelector)){return}var t=_(e);if(!t.initialized){t.initialized=true;$(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=ke(e);var n=it(e,t,r);if(!n&&G(e,"hx-boost")==="true"){Fe(e,t,r)}if(e.tagName==="FORM"){ut(e)}var i=V(e,"hx-sse");if(i){Ke(e,t,i)}var o=V(e,"hx-ws");if(o){We(e,t,o)}$(e,"htmx:afterProcessNode")}}function ct(e){e=k(e);ft(e);W(lt(e),function(e){ft(e)})}function ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function dt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=z().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function J(e,t,r){$(e,t,Q({error:t},r))}function vt(e){return e==="htmx:afterProcessNode"}function gt(e,t){W(sr(e),function(e){try{t(e)}catch(e){pt(e)}})}function pt(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function $(e,t,r){e=k(e);if(r==null){r={}}r["elt"]=e;var n=dt(t,r);if(U.logger&&!vt(t)){U.logger(e,t,r)}if(r.error){pt(r.error);$(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=ht(t);if(i&&o!==t){var a=dt(o,n.detail);i=i&&e.dispatchEvent(a)}gt(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var mt=location.pathname+location.search;function xt(){var e=z().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||z().body}function yt(e,t,r,n){var i=S(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>U.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(z().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function bt(e){var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function wt(e){var t=U.config.requestClass;var r=e.cloneNode(true);W(R(r,"."+t),function(e){q(e,t)});return r.innerHTML}function St(){var e=xt();var t=mt||location.pathname+location.search;$(z().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(U.config.historyEnabled)history.replaceState({htmx:true},z().title,window.location.href);yt(t,wt(e),z().title,window.scrollY)}function Et(e){if(U.config.historyEnabled)history.pushState({htmx:true},"",e);mt=e}function Ct(e){W(e,function(e){e.call()})}function Rt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};$(z().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){$(z().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=xt();var r=zt(t);me(t,e,r);Ct(r.tasks);mt=n;$(z().body,"htmx:historyRestore",{path:n})}else{J(z().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Ot(e){St();e=e||location.pathname+location.search;var t=bt(e);if(t){var r=g(t.content);var n=xt();var i=zt(n);me(n,r,i);Ct(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);mt=e;$(z().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Rt(e)}}}function Lt(e){var t=G(e,"hx-push-url");return t&&t!=="false"||_(e).boosted&&_(e).pushURL}function qt(e){var t=G(e,"hx-push-url");return t==="true"||t==="false"?null:t}function At(e){var t=F(e,"hx-indicator");if(t==null){t=[e]}W(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Tt(e){W(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function Ht(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Nt(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 kt(t,r,n,e,i){if(e==null||Ht(t,e)){return}else{t.push(e)}if(Nt(e)){var o=f(e,"name");var a=e.value;if(e.multiple){a=y(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=y(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){It(e,n)}}if(d(e,"form")){var l=e.elements;W(l,function(e){kt(t,r,n,e,i)})}}function It(e,t){if(e.willValidate){$(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});$(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Mt(e,t){var r=[];var n={};var i={};var o=[];var a=_(e);var s=d(e,"form")&&e.noValidate!==true;if(a.lastButtonClicked){s=s&&a.lastButtonClicked.formNoValidate!==true}if(t!=="get"){kt(r,i,o,H(e,"form"),s)}kt(r,n,o,e,s);if(a.lastButtonClicked){var l=f(a.lastButtonClicked,"name");if(l){n[l]=a.lastButtonClicked.value}}var u=F(e,"hx-include");W(u,function(e){kt(r,n,o,e,s);if(!d(e,"form")){W(e.querySelectorAll(Ne),function(e){kt(r,n,o,e,s)})}});n=Q(n,i);return{errors:o,values:n}}function Dt(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function Ft(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=Dt(t,r,e)})}else{t=Dt(t,r,n)}}}return t}function Pt(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){W(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Xt(e,t,r){var n={"HX-Request":"true","HX-Trigger":f(e,"id"),"HX-Trigger-Name":f(e,"name"),"HX-Target":V(t,"id"),"HX-Current-URL":z().location.href};Wt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(_(e).boosted){n["HX-Boosted"]="true"}return n}function jt(t,e){var r=G(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){W(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};W(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Bt(e){return f(e,"href")&&f(e,"href").indexOf("#")>=0}function Ut(e,t){var r=t?t:G(e,"hx-swap");var n={swapStyle:_(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(_(e).boosted&&!Bt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var o=1;o<i.length;o++){var a=i[o];if(a.indexOf("swap:")===0){n["swapDelay"]=v(a.substr(5))}if(a.indexOf("settle:")===0){n["settleDelay"]=v(a.substr(7))}if(a.indexOf("scroll:")===0){var s=a.substr(7);var l=s.split(":");var f=l.pop();var u=l.length>0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(a.indexOf("show:")===0){var c=a.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(a.indexOf("focus-scroll:")===0){var d=a.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function Vt(t,r,n){var i=null;gt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(G(r,"hx-encoding")==="multipart/form-data"||d(r,"form")&&f(r,"enctype")==="multipart/form-data"){return Pt(n)}else{return Ft(n)}}}function zt(e){return{tasks:[],elts:[e]}}function _t(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ee(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var o=t.showTarget;if(t.showTarget==="window"){o="body"}i=ee(r,o)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function Wt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}else if(o.indexOf("js:")===0){o=o.substr(3);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Jt(e,function(){return Function("return ("+o+")")()},{})}else{s=S(o)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Wt(u(e),t,r,n)}function Jt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function $t(e,t){return Wt(e,"hx-vars",true,t)}function Zt(e,t){return Wt(e,"hx-vals",false,t)}function Gt(e){return Q($t(e),Zt(e))}function Kt(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Yt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(z().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Qt(e,t){return e.getAllResponseHeaders().match(t)}function er(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return Z(e,t,null,null,{targetOverride:k(r),returnPromise:true})}else{return Z(e,t,k(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:k(r.target),swapOverride:r.swap,returnPromise:true})}}else{return Z(e,t,null,null,{returnPromise:true})}}function tr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Z(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=z().body}var v=r.handler||rr;if(!Y(n)){return}var g=r.targetOverride||ne(n);if(g==null||g==te){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=_(n);var o=G(n,"hx-sync");var m=null;var x=false;if(o){var y=o.split(":");var b=y[0].trim();if(b==="this"){p=re(n,"hx-sync")}else{p=ee(n,b)}o=(y[1]||"drop").trim();i=_(p);if(o==="drop"&&i.xhr&&i.abortable!==true){return}else if(o==="abort"){if(i.xhr){return}else{x=true}}else if(o==="replace"){$(p,"htmx:abort")}else if(o.indexOf("queue")===0){var w=o.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=_(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){Z(e,t,n,f,r)})}return}}var a=new XMLHttpRequest;i.xhr=a;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=G(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){K(c);s();return d}}var R=G(n,"hx-confirm");if(R){if(!confirm(R)){K(c);s();return d}}var O=Xt(n,g,C);if(r.headers){O=Q(O,r.headers)}var L=Mt(n,e);var q=L.errors;var A=L.values;if(r.values){A=Q(A,r.values)}var T=Gt(n);var H=Q(A,T);var N=jt(H,n);if(e!=="get"&&G(n,"hx-encoding")==null){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=z().location.href}var k=Wt(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:q,withCredentials:r.credentials||k.credentials||U.config.withCredentials,timeout:r.timeout||k.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){K(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;q=l.errors;if(q&&q.length>0){$(n,"htmx:validation:halted",l);K(c);s();return d}var I=t.split("#");var M=I[0];var D=I[1];if(e==="get"){var F=M;var P=Object.keys(N).length!==0;if(P){if(F.indexOf("?")<0){F+="?"}else{F+="&"}F+=Ft(N);if(D){F+="#"+D}}a.open("GET",F,true)}else{a.open(e.toUpperCase(),t,true)}a.overrideMimeType("text/html");a.withCredentials=l.withCredentials;a.timeout=l.timeout;if(k.noHeaders){}else{for(var X in O){if(O.hasOwnProperty(X)){var j=O[X];Kt(a,X,j)}}}var u={xhr:a,target:g,requestConfig:l,etc:r,pathInfo:{path:t,finalPath:F,anchor:D}};a.onload=function(){try{var e=tr(n);v(n,u);Tt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!Y(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(Y(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}K(c);s()}catch(e){J(n,"htmx:onLoadError",Q({error:e},u));throw e}};a.onerror=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);K(h);s()};a.onabort=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);K(h);s()};a.ontimeout=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);K(h);s()};if(!$(n,"htmx:beforeRequest",u)){K(c);s();return d}var B=At(n);W(["loadstart","loadend","progress","abort"],function(t){W([a,a.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);a.send(e==="get"?null:Vt(a,n,N));return d}function rr(s,l){var u=l.xhr;var f=l.target;var r=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(Qt(u,/HX-Trigger:/i)){Se(u,"HX-Trigger",s)}if(Qt(u,/HX-Push:/i)){var c=u.getResponseHeader("HX-Push")}if(Qt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Qt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(Qt(u,/HX-Retarget:/i)){l.target=z().querySelector(u.getResponseHeader("HX-Retarget"))}var h;if(c=="false"){h=false}else{h=Lt(s)||c}var n=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var e=u.status>=400;var t=Q({shouldSwap:n,serverResponse:d,isError:e},l);if(!$(f,"htmx:beforeSwap",t))return;f=t.target;d=t.serverResponse;e=t.isError;l.failed=e;l.successful=!e;if(t.shouldSwap){if(u.status===286){Ie(s)}gt(s,function(e){d=e.transformResponse(d,u,s)});if(h){St()}var i=r.swapOverride;var v=Ut(s,i);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=zt(f);we(v.swapStyle,f,s,d,n);if(t.elt&&!Y(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);W(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(l.pathInfo.anchor){location.hash=l.pathInfo.anchor}if(Qt(u,/HX-Trigger-After-Swap:/i)){var o=s;if(!Y(s)){o=z().body}Se(u,"HX-Trigger-After-Swap",o)}var a=function(){W(n.tasks,function(e){e.call()});W(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h){var e=c||qt(s)||Yt(u)||l.pathInfo.finalPath||l.pathInfo.path;Et(e);$(z().body,"htmx:pushedIntoHistory",{path:e})}if(n.title){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}_t(n.elts,v);if(Qt(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!Y(s)){r=z().body}Se(u,"HX-Trigger-After-Settle",r)}};if(v.settleDelay>0){setTimeout(a,v.settleDelay)}else{a()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(v.swapDelay>0){setTimeout(o,v.swapDelay)}else{o()}}if(e){J(s,"htmx:responseError",Q({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var nr={};function ir(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function or(e,t){if(t.init){t.init(r)}nr[e]=Q(ir(),t)}function ar(e){delete nr[e]}function sr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){W(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=nr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return sr(u(e),r,n)}function lr(e){if(z().readyState!=="loading"){e()}else{z().addEventListener("DOMContentLoaded",e)}}function ur(){if(U.config.includeIndicatorStyles!==false){z().head.insertAdjacentHTML("beforeend","<style> ."+U.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+U.config.requestClass+" ."+U.config.indicatorClass+"{opacity:1} ."+U.config.requestClass+"."+U.config.indicatorClass+"{opacity:1} </style>")}}function fr(){var e=z().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function cr(){var e=fr();if(e){U.config=Q(U.config,e)}}lr(function(){cr();ur();var e=z().body;ct(e);var t=z().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=_(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){Ot();W(t,function(e){$(e,"htmx:restored",{document:z(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file diff --git a/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.js b/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.js index e38f6ed..27e57bc 100644 --- a/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.js +++ b/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.js @@ -1,7 +1,9 @@ //AMD insanity (function (root, factory) { + //@ts-ignore if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. + //@ts-ignore define([], factory); } else { // Browser globals @@ -12,6 +14,8 @@ return (function () { 'use strict'; // Public API + //** @type {import("./htmx").HtmxApi} */ + // TODO: list all methods in public API var htmx = { onLoad: onLoadHelper, process: processNode, @@ -35,7 +39,6 @@ return (function () { removeExtension : removeExtension, logAll : logAll, logger : null, - useTemplateFragments: false, config : { historyEnabled:true, historyCacheSize:10, @@ -46,13 +49,19 @@ return (function () { includeIndicatorStyles:true, indicatorClass:'htmx-indicator', requestClass:'htmx-request', + addedClass:'htmx-added', settlingClass:'htmx-settling', swappingClass:'htmx-swapping', allowEval:true, + inlineScriptNonce:'', attributesToSettle:["class", "style", "width", "height"], withCredentials:false, + timeout:0, wsReconnectDelay: 'full-jitter', disableSelector: "[hx-disable], [data-hx-disable]", + useTemplateFragments: false, + scrollBehavior: 'smooth', + defaultFocusScroll: false, }, parseInterval:parseInterval, _:internalEval, @@ -61,9 +70,36 @@ return (function () { }, createWebSocket: function(url){ return new WebSocket(url, []); - } + }, + version: "1.7.0" }; + /** @type {import("./htmx").HtmxInternalApi} */ + var internalAPI = { + bodyContains: bodyContains, + filterValues: filterValues, + hasAttribute: hasAttribute, + getAttributeValue: getAttributeValue, + getClosestMatch: getClosestMatch, + getExpressionVars: getExpressionVars, + getHeaders: getHeaders, + getInputValues: getInputValues, + getInternalData: getInternalData, + getSwapSpecification: getSwapSpecification, + getTriggerSpecs: getTriggerSpecs, + getTarget: getTarget, + makeFragment: makeFragment, + mergeObjects: mergeObjects, + makeSettleInfo: makeSettleInfo, + oobSwap: oobSwap, + selectAndSwap: selectAndSwap, + settleImmediately: settleImmediately, + shouldCancel: shouldCancel, + triggerEvent: triggerEvent, + triggerErrorEvent: triggerErrorEvent, + withExtensions: withExtensions, + } + var VERBS = ['get', 'post', 'put', 'delete', 'patch']; var VERB_SELECTOR = VERBS.map(function(verb){ return "[hx-" + verb + "], [data-hx-" + verb + "]" @@ -73,19 +109,24 @@ return (function () { // Utilities //==================================================================== - function parseInterval(str) { - if (str == undefined) { - return undefined - } - if (str.slice(-2) == "ms") { - return parseFloat(str.slice(0,-2)) || undefined - } - if (str.slice(-1) == "s") { - return (parseFloat(str.slice(0,-1)) * 1000) || undefined - } - return parseFloat(str) || undefined + function parseInterval(str) { + if (str == undefined) { + return undefined + } + if (str.slice(-2) == "ms") { + return parseFloat(str.slice(0,-2)) || undefined + } + if (str.slice(-1) == "s") { + return (parseFloat(str.slice(0,-1)) * 1000) || undefined + } + return parseFloat(str) || undefined } + /** + * @param {HTMLElement} elt + * @param {string} name + * @returns {(string | null)} + */ function getRawAttribute(elt, name) { return elt.getAttribute && elt.getAttribute(name); } @@ -96,18 +137,36 @@ return (function () { elt.hasAttribute("data-" + qualifiedName)); } + /** + * + * @param {HTMLElement} elt + * @param {string} qualifiedName + * @returns {(string | null)} + */ function getAttributeValue(elt, qualifiedName) { return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); } + /** + * @param {HTMLElement} elt + * @returns {HTMLElement | null} + */ function parentElt(elt) { return elt.parentElement; } + /** + * @returns {Document} + */ function getDocument() { return document; } + /** + * @param {HTMLElement} elt + * @param {(e:HTMLElement) => boolean} condition + * @returns {HTMLElement | null} + */ function getClosestMatch(elt, condition) { if (condition(elt)) { return elt; @@ -118,22 +177,47 @@ return (function () { } } + function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ + var attributeValue = getAttributeValue(ancestor, attributeName); + var disinherit = getAttributeValue(ancestor, "hx-disinherit"); + if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) { + return "unset"; + } else { + return attributeValue + } + } + + /** + * @param {HTMLElement} elt + * @param {string} attributeName + * @returns {string | null} + */ function getClosestAttributeValue(elt, attributeName) { var closestAttr = null; getClosestMatch(elt, function (e) { - return closestAttr = getAttributeValue(e, attributeName); + return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName); }); - return closestAttr; + if (closestAttr !== "unset") { + return closestAttr; + } } + /** + * @param {HTMLElement} elt + * @param {string} selector + * @returns {boolean} + */ function matches(elt, selector) { + // @ts-ignore: non-standard properties for browser compatability // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || - elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector - || elt.webkitMatchesSelector || elt.oMatchesSelector; + var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; return matchesFunction && matchesFunction.call(elt, selector); } + /** + * @param {string} str + * @returns {string} + */ function getStartTag(str) { var tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i var match = tagMatcher.exec( str ); @@ -144,23 +228,40 @@ return (function () { } } + /** + * + * @param {string} resp + * @param {number} depth + * @returns {Element} + */ function parseHTML(resp, depth) { var parser = new DOMParser(); var responseDoc = parser.parseFromString(resp, "text/html"); + + /** @type {Element} */ var responseNode = responseDoc.body; while (depth > 0) { depth--; + // @ts-ignore responseNode = responseNode.firstChild; } if (responseNode == null) { + // @ts-ignore responseNode = getDocument().createDocumentFragment(); } return responseNode; } + /** + * + * @param {string} resp + * @returns {Element} + */ function makeFragment(resp) { if (htmx.config.useTemplateFragments) { var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0); + // @ts-ignore type mismatch between DocumentFragment and Element. + // TODO: Are these close enough for htmx to use interchangably? return documentFragment.querySelector('template').content; } else { var startTag = getStartTag(resp); @@ -186,24 +287,45 @@ return (function () { } } + /** + * @param {Function} func + */ function maybeCall(func){ if(func) { func(); } } + /** + * @param {any} o + * @param {string} type + * @returns + */ function isType(o, type) { return Object.prototype.toString.call(o) === "[object " + type + "]"; } + /** + * @param {*} o + * @returns {o is Function} + */ function isFunction(o) { return isType(o, "Function"); } + /** + * @param {*} o + * @returns {o is Object} + */ function isRawObject(o) { return isType(o, "Object"); } + /** + * getInternalData retrieves "private" data stored by htmx within an element + * @param {HTMLElement} elt + * @returns {*} + */ function getInternalData(elt) { var dataProp = 'htmx-internal-data'; var data = elt[dataProp]; @@ -213,6 +335,11 @@ return (function () { return data; } + /** + * toArray converts an ArrayLike object into a real array. + * @param {ArrayLike} arr + * @returns {any[]} + */ function toArray(arr) { var returnArr = []; if (arr) { @@ -238,14 +365,25 @@ return (function () { return elemTop < window.innerHeight && elemBottom >= 0; } - function bodyContains(elt) { - return getDocument().body.contains(elt); - } + function bodyContains(elt) { + if (elt.getRootNode() instanceof ShadowRoot) { + return getDocument().body.contains(elt.getRootNode().host); + } else { + return getDocument().body.contains(elt); + } + } function splitOnWhitespace(trigger) { return trigger.trim().split(/\s+/); } + /** + * mergeObjects takes all of the keys from + * obj2 and duplicates them into obj1 + * @param {Object} obj1 + * @param {Object} obj2 + * @returns {Object} + */ function mergeObjects(obj1, obj2) { for (var key in obj2) { if (obj2.hasOwnProperty(key)) { @@ -319,7 +457,7 @@ return (function () { if (delay) { setTimeout(function(){addClassToElement(elt, clazz);}, delay) } else { - elt.classList.add(clazz); + elt.classList && elt.classList.add(clazz); } } @@ -328,7 +466,13 @@ return (function () { if (delay) { setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) } else { - elt.classList.remove(clazz); + if (elt.classList) { + elt.classList.remove(clazz); + // if there are no classes left, remove the class attribute + if (elt.classList.length === 0) { + elt.removeAttribute("class"); + } + } } } @@ -360,17 +504,25 @@ return (function () { } function querySelectorAllExt(elt, selector) { - if (selector.indexOf("closest ") === 0) { + if (selector.indexOf("closest ") === 0) { return [closest(elt, selector.substr(8))]; } else if (selector.indexOf("find ") === 0) { return [find(elt, selector.substr(5))]; + } else if (selector === 'document') { + return [document]; + } else if (selector === 'window') { + return [window]; } else { return getDocument().querySelectorAll(selector); } } function querySelectorExt(eltOrSelector, selector) { - return querySelectorAllExt(eltOrSelector, selector)[0] + if (selector) { + return querySelectorAllExt(eltOrSelector, selector)[0]; + } else { + return querySelectorAllExt(getDocument().body, eltOrSelector)[0]; + } } function resolveTarget(arg2) { @@ -418,13 +570,36 @@ return (function () { //==================================================================== // Node processing //==================================================================== + + var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors + function findAttributeTargets(elt, attrName) { + var attrTarget = getClosestAttributeValue(elt, attrName); + if (attrTarget) { + if (attrTarget === "this") { + return [findThisElement(elt, attrName)]; + } else { + var result = querySelectorAllExt(elt, attrTarget); + if (result.length === 0) { + logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!"); + return [DUMMY_ELT] + } else { + return result; + } + } + } + } + + function findThisElement(elt, attribute){ + return getClosestMatch(elt, function (elt) { + return getAttributeValue(elt, attribute) != null; + }) + } function getTarget(elt) { - var explicitTarget = getClosestMatch(elt, function(e){return getAttributeValue(e,"hx-target") !== null}); - if (explicitTarget) { - var targetStr = getAttributeValue(explicitTarget, "hx-target"); + var targetStr = getClosestAttributeValue(elt, "hx-target"); + if (targetStr) { if (targetStr === "this") { - return explicitTarget; + return findThisElement(elt,'hx-target'); } else { return querySelectorExt(elt, targetStr) } @@ -476,6 +651,13 @@ return (function () { return swapStyle === "outerHTML"; } + /** + * + * @param {string} oobValue + * @param {HTMLElement} oobElement + * @param {*} settleInfo + * @returns + */ function oobSwap(oobValue, oobElement, settleInfo) { var selector = "#" + oobElement.id; var swapStyle = "outerHTML"; @@ -488,18 +670,35 @@ return (function () { swapStyle = oobValue; } - var target = getDocument().querySelector(selector); - if (target) { - var fragment; - fragment = getDocument().createDocumentFragment(); - fragment.appendChild(oobElement); // pulls the child out of the existing fragment - if (!isInlineSwap(swapStyle, target)) { - fragment = oobElement; // if this is not an inline swap, we use the content of the node, not the node itself - } - swap(swapStyle, target, target, fragment, settleInfo); + var targets = getDocument().querySelectorAll(selector); + if (targets) { + forEach( + targets, + function (target) { + var fragment; + var oobElementClone = oobElement.cloneNode(true); + fragment = getDocument().createDocumentFragment(); + fragment.appendChild(oobElementClone); + if (!isInlineSwap(swapStyle, target)) { + fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself + } + + var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment }; + if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return; + + target = beforeSwapDetails.target; // allow re-targeting + if (beforeSwapDetails['shouldSwap']){ + swap(swapStyle, target, target, fragment, settleInfo); + } + forEach(settleInfo.elts, function (elt) { + triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails); + }); + } + ); + oobElement.parentNode.removeChild(oobElement); } else { oobElement.parentNode.removeChild(oobElement); - triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}) + triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}); } return oobValue; } @@ -540,6 +739,7 @@ return (function () { function makeAjaxLoadTask(child) { return function () { + removeClassFromElement(child, htmx.config.addedClass); processNode(child); processScripts(child); processFocus(child) @@ -559,6 +759,7 @@ return (function () { handleAttributes(parentNode, fragment, settleInfo); while(fragment.childNodes.length > 0){ var child = fragment.firstChild; + addClassToElement(child, htmx.config.addedClass); parentNode.insertBefore(child, insertBefore); if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { settleInfo.tasks.push(makeAjaxLoadTask(child)); @@ -574,6 +775,9 @@ return (function () { if (internalData.sseEventSource) { internalData.sseEventSource.close(); } + + triggerEvent(element, "htmx:beforeCleanupElement") + if (internalData.listenerInfos) { forEach(internalData.listenerInfos, function(info) { if (element !== info.on) { @@ -590,12 +794,14 @@ return (function () { if (target.tagName === "BODY") { return swapInnerHTML(target, fragment, settleInfo); } else { + // @type {HTMLElement} + var newElt var eltBeforeNewContent = target.previousSibling; insertNodesBefore(parentElt(target), target, fragment, settleInfo); if (eltBeforeNewContent == null) { - var newElt = parentElt(target).firstChild; + newElt = parentElt(target).firstChild; } else { - var newElt = eltBeforeNewContent.nextSibling; + newElt = eltBeforeNewContent.nextSibling; } getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later settleInfo.elts = [] // clear existing elements @@ -625,6 +831,10 @@ return (function () { function swapAfterEnd(target, fragment, settleInfo) { return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo); } + function swapDelete(target, fragment, settleInfo) { + cleanUpElement(target); + return parentElt(target).removeChild(target); + } function swapInnerHTML(target, fragment, settleInfo) { var firstChild = target.firstChild; @@ -670,6 +880,9 @@ return (function () { case "afterend": swapAfterEnd(target, fragment, settleInfo); return; + case "delete": + swapDelete(target, fragment, settleInfo); + return; default: var extensions = getExtensions(elt); for (var i = 0; i < extensions.length; i++) { @@ -692,32 +905,27 @@ return (function () { logError(e); } } - swapInnerHTML(target, fragment, settleInfo); + if (swapStyle === "innerHTML") { + swapInnerHTML(target, fragment, settleInfo); + } else { + swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo); + } } } - var TITLE_FINDER = /<title>([\s\S]+?)<\/title>/im; function findTitle(content) { - if(content.indexOf('<title>') > -1 && - (content.indexOf('<svg>') == -1 || - content.indexOf('<title>') < content.indexOf('<svg>'))) { - var result = TITLE_FINDER.exec(content); + if (content.indexOf('<title') > -1) { + var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, ''); + var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im); + if (result) { - return result[1]; + return result[2]; } } } function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) { - var title = findTitle(responseText); - if(title) { - var titleElt = find("title"); - if(titleElt) { - titleElt.innerHTML = title; - } else { - window.document.title = title; - } - } + settleInfo.title = findTitle(responseText); var fragment = makeFragment(responseText); if (fragment) { handleOutOfBandSwaps(fragment, settleInfo); @@ -840,6 +1048,11 @@ return (function () { } var INPUT_SELECTOR = 'input, textarea, select'; + + /** + * @param {HTMLElement} elt + * @returns {import("./htmx").HtmxTriggerSpecification[]} + */ function getTriggerSpecs(elt) { var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); var triggerSpecs = []; @@ -853,7 +1066,12 @@ return (function () { if (trigger === "every") { var every = {trigger: 'every'}; consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, WHITESPACE)); + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); + consumeUntil(tokens, NOT_WHITESPACE); + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + every.eventFilter = eventFilter; + } triggerSpecs.push(every); } else if (trigger.indexOf("sse:") === 0) { triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); @@ -877,7 +1095,17 @@ return (function () { triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); } else if (token === "from" && tokens[0] === ":") { tokens.shift(); - triggerSpec.from = consumeUntil(tokens, WHITESPACE_OR_COMMA); + var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); + if (from_arg === "closest" || from_arg === "find") { + tokens.shift(); + from_arg += + " " + + consumeUntil( + tokens, + WHITESPACE_OR_COMMA + ); + } + triggerSpec.from = from_arg; } else if (token === "target" && tokens[0] === ":") { tokens.shift(); triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA); @@ -919,14 +1147,16 @@ return (function () { getInternalData(elt).cancelled = true; } - function processPolling(elt, verb, path, interval) { + function processPolling(elt, verb, path, spec) { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - issueAjaxRequest(verb, path, elt); - processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), interval); + if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { + issueAjaxRequest(verb, path, elt); + } + processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), spec); } - }, interval); + }, spec.pollInterval); } function isLocalLink(elt) { @@ -936,7 +1166,7 @@ return (function () { } function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt)) || elt.tagName === "FORM") { + if ((elt.tagName === "A" && isLocalLink(elt) && elt.target === "") || elt.tagName === "FORM") { nodeData.boosted = true; var verb, path; if (elt.tagName === "A") { @@ -957,11 +1187,26 @@ return (function () { } } - function shouldCancel(elt) { - return elt.tagName === "FORM" || - (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) || - (elt.tagName === "A" && elt.href && (elt.getAttribute('href') === '#' || - elt.getAttribute('href').indexOf("#") !== 0)); + /** + * + * @param {Event} evt + * @param {HTMLElement} elt + * @returns + */ + function shouldCancel(evt, elt) { + if (evt.type === "submit" || evt.type === "click") { + if (elt.tagName === "FORM") { + return true; + } + if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { + return true; + } + if (elt.tagName === "A" && elt.href && + (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) { + return true; + } + } + return false; } function ignoreBoostedAnchorCtrlClick(elt, evt) { @@ -982,86 +1227,90 @@ return (function () { } function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { - var eltToListenOn = elt; + var eltsToListenOn; if (triggerSpec.from) { - eltToListenOn = find(triggerSpec.from); + eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); + } else { + eltsToListenOn = [elt]; } - var eventListener = function (evt) { - if (!bodyContains(elt)) { - eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); - return; - } - if (ignoreBoostedAnchorCtrlClick(elt, evt)) { - return; - } - if(explicitCancel || shouldCancel(elt)){ - evt.preventDefault(); - } - if (maybeFilterEvent(triggerSpec, evt)) { - return; - } - var eventData = getInternalData(evt); - eventData.triggerSpec = triggerSpec; - if (eventData.handledFor == null) { - eventData.handledFor = []; - } - var elementData = getInternalData(elt); - if (eventData.handledFor.indexOf(elt) < 0) { - eventData.handledFor.push(elt); - if (triggerSpec.consume) { - evt.stopPropagation(); - } - if (triggerSpec.target && evt.target) { - if (!matches(evt.target, triggerSpec.target)) { - return; - } - } - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } + forEach(eltsToListenOn, function (eltToListenOn) { + var eventListener = function (evt) { + if (!bodyContains(elt)) { + eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); + return; } - if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { - return; - } else { - elementData.lastValue = elt.value; - } + if (ignoreBoostedAnchorCtrlClick(elt, evt)) { + return; } - if (elementData.delayed) { - clearTimeout(elementData.delayed); + if (explicitCancel || shouldCancel(evt, elt)) { + evt.preventDefault(); } - if (elementData.throttle) { + if (maybeFilterEvent(triggerSpec, evt)) { return; } + var eventData = getInternalData(evt); + eventData.triggerSpec = triggerSpec; + if (eventData.handledFor == null) { + eventData.handledFor = []; + } + var elementData = getInternalData(elt); + if (eventData.handledFor.indexOf(elt) < 0) { + eventData.handledFor.push(elt); + if (triggerSpec.consume) { + evt.stopPropagation(); + } + if (triggerSpec.target && evt.target) { + if (!matches(evt.target, triggerSpec.target)) { + return; + } + } + 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); + } + if (elementData.throttle) { + return; + } - if (triggerSpec.throttle) { - if(!elementData.throttle) { + if (triggerSpec.throttle) { + if (!elementData.throttle) { + issueAjaxRequest(verb, path, elt, evt); + elementData.throttle = setTimeout(function () { + elementData.throttle = null; + }, triggerSpec.throttle); + } + } else if (triggerSpec.delay) { + elementData.delayed = setTimeout(function () { + issueAjaxRequest(verb, path, elt, evt); + }, triggerSpec.delay); + } else { issueAjaxRequest(verb, path, elt, evt); - elementData.throttle = setTimeout(function(){ - elementData.throttle = null; - }, triggerSpec.throttle); } - } else if (triggerSpec.delay) { - elementData.delayed = setTimeout(function(){ - issueAjaxRequest(verb, path, elt, evt); - }, triggerSpec.delay); - } else { - issueAjaxRequest(verb, path, elt, evt); } - } - }; - if (nodeData.listenerInfos == null) { - nodeData.listenerInfos = []; - } - nodeData.listenerInfos.push({ - trigger: triggerSpec.trigger, - listener: eventListener, - on: eltToListenOn + }; + if (nodeData.listenerInfos == null) { + nodeData.listenerInfos = []; + } + nodeData.listenerInfos.push({ + trigger: triggerSpec.trigger, + listener: eventListener, + on: eltToListenOn + }) + eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); }) - eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); } var windowIsScrolling = false // used by initScrollHandler @@ -1084,9 +1333,9 @@ return (function () { } function maybeReveal(elt) { - var nodeData = getInternalData(elt); - if (!nodeData.revealed && isScrolledIntoView(elt)) { - nodeData.revealed = true; + if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { + elt.setAttribute('data-hx-revealed', 'true'); + var nodeData = getInternalData(elt); if (nodeData.initialized) { issueAjaxRequest(nodeData.verb, nodeData.path, elt); } else { @@ -1099,6 +1348,10 @@ return (function () { } } + //==================================================================== + // Web Sockets + //==================================================================== + function processWebSocketInfo(elt, nodeData, info) { var values = splitOnWhitespace(info); for (var i = 0; i < values.length; i++) { @@ -1132,7 +1385,7 @@ return (function () { }; socket.onclose = function (e) { - if ([1006, 1012, 1013].includes(e.code)) { // Abnormal Closure/Service Restart/Try Again Later + if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later var delay = getWebSocketReconnectDelay(retryCount); setTimeout(function() { ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout @@ -1193,7 +1446,7 @@ return (function () { return; } webSocket.send(JSON.stringify(filteredParameters)); - if(shouldCancel(elt)){ + if(shouldCancel(evt, elt)){ evt.preventDefault(); } }); @@ -1205,6 +1458,7 @@ return (function () { function getWebSocketReconnectDelay(retryCount) { var delay = htmx.config.wsReconnectDelay; if (typeof delay === 'function') { + // @ts-ignore return delay(retryCount); } if (delay === 'full-jitter') { @@ -1340,7 +1594,7 @@ return (function () { } else if (triggerSpec.trigger === "intersect") { var observerOptions = {}; if (triggerSpec.root) { - observerOptions.root = querySelectorExt(triggerSpec.root) + observerOptions.root = querySelectorExt(elt, triggerSpec.root) } if (triggerSpec.threshold) { observerOptions.threshold = parseFloat(triggerSpec.threshold); @@ -1360,7 +1614,7 @@ return (function () { loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); } else if (triggerSpec.pollInterval) { nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec.pollInterval); + processPolling(elt, verb, path, triggerSpec); } else { addEventListener(elt, verb, path, nodeData, triggerSpec); } @@ -1371,14 +1625,24 @@ return (function () { } function evalScript(script) { - if (script.type === "text/javascript" || script.type === "") { + if (script.type === "text/javascript" || script.type === "module" || script.type === "") { + var newScript = getDocument().createElement("script"); + forEach(script.attributes, function (attr) { + newScript.setAttribute(attr.name, attr.value); + }); + newScript.textContent = script.textContent; + newScript.async = false; + if (htmx.config.inlineScriptNonce) { + newScript.nonce = htmx.config.inlineScriptNonce; + } + var parent = script.parentElement; + try { - maybeEval(script, function () { - // wtf - https://stackoverflow.com/questions/9107240/1-evalthis-vs-evalthis-in-javascript - (1, eval)(script.innerText); - }); + parent.insertBefore(newScript, script); } catch (e) { logError(e); + } finally { + parent.removeChild(script); } } } @@ -1392,21 +1656,41 @@ return (function () { }); } - function isBoosted() { + function hasChanceOfBeingBoosted() { return document.querySelector("[hx-boost], [data-hx-boost]"); } function findElementsToProcess(elt) { if (elt.querySelectorAll) { - var boostedElts = isBoosted() ? ", a, form" : ""; + var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws]"); + " [data-hx-ws], [hx-ext], [hx-data-ext]"); return results; } else { return []; } } + function initButtonTracking(form){ + var maybeSetLastButtonClicked = function(evt){ + if (matches(evt.target, "button, input[type='submit']")) { + var internalData = getInternalData(form); + internalData.lastButtonClicked = evt.target; + } + }; + + // need to handle both click and focus in: + // focusin - in case someone tabs in to a button and hits the space bar + // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + + form.addEventListener('click', maybeSetLastButtonClicked) + form.addEventListener('focusin', maybeSetLastButtonClicked) + form.addEventListener('focusout', function(evt){ + var internalData = getInternalData(form); + internalData.lastButtonClicked = null; + }) + } + function initNode(elt) { if (elt.closest && elt.closest(htmx.config.disableSelector)) { return; @@ -1427,6 +1711,10 @@ return (function () { boostElement(elt, nodeData, triggerSpecs); } + if (elt.tagName === "FORM") { + initButtonTracking(elt); + } + var sseInfo = getAttributeValue(elt, 'hx-sse'); if (sseInfo) { processSSEInfo(elt, nodeData, sseInfo); @@ -1473,6 +1761,15 @@ return (function () { return eventName === "htmx:afterProcessNode" } + /** + * `withExtensions` locates all active extensions for a provided element, then + * executes the provided function using each of the active extensions. It should + * be called internally at every extendable execution point in htmx. + * + * @param {HTMLElement} elt + * @param {(extension:import("./htmx").HtmxExtension) => void} toDo + * @returns void + */ function withExtensions(elt, toDo) { forEach(getExtensions(elt), function(extension){ try { @@ -1520,7 +1817,7 @@ return (function () { //==================================================================== // History Support //==================================================================== - var currentPathForHistory = null; + var currentPathForHistory = location.pathname+location.search; function getHistoryElement() { var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]'); @@ -1569,7 +1866,7 @@ return (function () { return clone.innerHTML; } - function saveHistory() { + function saveCurrentPageToHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); @@ -1598,9 +1895,11 @@ return (function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); var fragment = makeFragment(this.response); + // @ts-ignore fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; var historyElement = getHistoryElement(); var settleInfo = makeSettleInfo(historyElement); + // @ts-ignore swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); currentPathForHistory = path; @@ -1613,7 +1912,7 @@ return (function () { } function restoreHistory(path) { - saveHistory(); + saveCurrentPageToHistory(); path = path || location.pathname+location.search; var cached = getCachedHistory(path); if (cached) { @@ -1628,6 +1927,8 @@ return (function () { triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); } else { if (htmx.config.refreshOnHistoryMiss) { + + // @ts-ignore: optional parameter in reload() function throws error window.location.reload(true); } else { loadHistoryFromServer(path); @@ -1647,10 +1948,8 @@ return (function () { } function addRequestIndicatorClasses(elt) { - var indicator = getClosestAttributeValue(elt, 'hx-indicator'); - if (indicator) { - var indicators = querySelectorAllExt(elt, indicator); - } else { + var indicators = findAttributeTargets(elt, 'hx-indicator'); + if (indicators == null) { indicators = [elt]; } forEach(indicators, function (ic) { @@ -1753,14 +2052,22 @@ return (function () { } } + /** + * @param {HTMLElement} elt + * @param {string} verb + */ function getInputValues(elt, verb) { var processed = []; var values = {}; var formValues = {}; var errors = []; + var internalData = getInternalData(elt); - // only validate when form is directly submitted and novalidate is not set + // only validate when form is directly submitted and novalidate or formnovalidate are not set var validate = matches(elt, 'form') && elt.noValidate !== true; + if (internalData.lastButtonClicked) { + validate = validate && internalData.lastButtonClicked.formNoValidate !== true; + } // for a non-GET include the closest form if (verb !== 'get') { @@ -1770,21 +2077,26 @@ return (function () { // include the element itself processInputValue(processed, values, errors, elt, validate); - // include any explicit includes - var includes = getClosestAttributeValue(elt, "hx-include"); - if (includes) { - var nodes = querySelectorAllExt(elt, includes); - forEach(nodes, function(node) { - processInputValue(processed, values, errors, node, validate); - // if a non-form is included, include any input values within it - if (!matches(node, 'form')) { - forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { - processInputValue(processed, values, errors, descendant, validate); - }) - } - }); + // if a button or submit was clicked last, include its value + if (internalData.lastButtonClicked) { + var name = getRawAttribute(internalData.lastButtonClicked,"name"); + if (name) { + values[name] = internalData.lastButtonClicked.value; + } } + // include any explicit includes + var includes = findAttributeTargets(elt, "hx-include"); + forEach(includes, function(node) { + processInputValue(processed, values, errors, node, validate); + // if a non-form is included, include any input values within it + if (!matches(node, 'form')) { + forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { + processInputValue(processed, values, errors, descendant, validate); + }) + } + }); + // form values take precedence, overriding the regular values values = mergeObjects(values, formValues); @@ -1795,7 +2107,11 @@ return (function () { if (returnStr !== "") { returnStr += "&"; } - returnStr += encodeURIComponent(name) + "=" + encodeURIComponent(realValue); + if (String(realValue) === "[object Object]") { + realValue = JSON.stringify(realValue); + } + var s = encodeURIComponent(realValue); + returnStr += encodeURIComponent(name) + "=" + s; return returnStr; } @@ -1837,6 +2153,12 @@ return (function () { // Ajax //==================================================================== + /** + * @param {HTMLElement} elt + * @param {HTMLElement} target + * @param {string} prompt + * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification + */ function getHeaders(elt, target, prompt) { var headers = { "HX-Request" : "true", @@ -1849,9 +2171,20 @@ return (function () { if (prompt !== undefined) { headers["HX-Prompt"] = prompt; } + if (getInternalData(elt).boosted) { + headers["HX-Boosted"] = "true"; + } return headers; } + /** + * filterValues takes an object containing form input values + * and returns a new object that only contains keys that are + * specified by the closest "hx-params" attribute + * @param {Object} inputValues + * @param {HTMLElement} elt + * @returns {Object} + */ function filterValues(inputValues, elt) { var paramsValue = getClosestAttributeValue(elt, "hx-params"); if (paramsValue) { @@ -1882,8 +2215,14 @@ return (function () { return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0 } - function getSwapSpecification(elt) { - var swapInfo = getClosestAttributeValue(elt, "hx-swap"); + /** + * + * @param {HTMLElement} elt + * @param {string} swapInfoOverride + * @returns {import("./htmx").HtmxSwapSpecification} + */ + function getSwapSpecification(elt, swapInfoOverride) { + var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap"); var swapSpec = { "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, "swapDelay" : htmx.config.defaultSwapDelay, @@ -1905,10 +2244,24 @@ return (function () { swapSpec["settleDelay"] = parseInterval(modifier.substr(7)); } if (modifier.indexOf("scroll:") === 0) { - swapSpec["scroll"] = modifier.substr(7); + var scrollSpec = modifier.substr(7); + var splitSpec = scrollSpec.split(":"); + var scrollVal = splitSpec.pop(); + var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; + swapSpec["scroll"] = scrollVal; + swapSpec["scrollTarget"] = selectorVal; } if (modifier.indexOf("show:") === 0) { - swapSpec["show"] = modifier.substr(5); + var showSpec = modifier.substr(5); + var splitSpec = showSpec.split(":"); + var showVal = splitSpec.pop(); + var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; + swapSpec["show"] = showVal; + swapSpec["showTarget"] = selectorVal; + } + if (modifier.indexOf("focus-scroll:") === 0) { + var focusScrollVal = modifier.substr("focus-scroll:".length); + swapSpec["focusScroll"] = focusScrollVal == "true"; } } } @@ -1926,7 +2279,8 @@ return (function () { if (encodedParameters != null) { return encodedParameters; } else { - if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data") { + if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || + (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) { return makeFormData(filteredParameters); } else { return urlEncode(filteredParameters); @@ -1934,6 +2288,11 @@ return (function () { } } + /** + * + * @param {Element} target + * @returns {import("./htmx").HtmxSettleInfo} + */ function makeSettleInfo(target) { return {tasks: [], elts: [target]}; } @@ -1942,23 +2301,46 @@ return (function () { var first = content[0]; var last = content[content.length - 1]; if (swapSpec.scroll) { - if (swapSpec.scroll === "top" && first) { - first.scrollTop = 0; + var target = null; + if (swapSpec.scrollTarget) { + target = querySelectorExt(first, swapSpec.scrollTarget); + } + if (swapSpec.scroll === "top" && (first || target)) { + target = target || first; + target.scrollTop = 0; } - if (swapSpec.scroll === "bottom" && last) { - last.scrollTop = last.scrollHeight; + if (swapSpec.scroll === "bottom" && (last || target)) { + target = target || last; + target.scrollTop = target.scrollHeight; } } if (swapSpec.show) { - if (swapSpec.show === "top" && first) { - first.scrollIntoView(true); + var target = null; + if (swapSpec.showTarget) { + var targetStr = swapSpec.showTarget; + if (swapSpec.showTarget === "window") { + targetStr = "body"; + } + target = querySelectorExt(first, targetStr); + } + if (swapSpec.show === "top" && (first || target)) { + target = target || first; + target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior}); } - if (swapSpec.show === "bottom" && last) { - last.scrollIntoView(false); + if (swapSpec.show === "bottom" && (last || target)) { + target = target || last; + target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior}); } } } + /** + * @param {HTMLElement} elt + * @param {string} attr + * @param {boolean=} evalAsDefault + * @param {Object=} values + * @returns {Object} + */ function getValuesForElement(elt, attr, evalAsDefault, values) { if (values == null) { values = {}; @@ -1973,6 +2355,9 @@ return (function () { if (str.indexOf("javascript:") === 0) { str = str.substr(11); evaluateValue = true; + } else if (str.indexOf("js:") === 0) { + str = str.substr(3); + evaluateValue = true; } if (str.indexOf('{') !== 0) { str = "{" + str + "}"; @@ -2003,14 +2388,28 @@ return (function () { } } + /** + * @param {HTMLElement} elt + * @param {*} expressionVars + * @returns + */ function getHXVarsForElement(elt, expressionVars) { return getValuesForElement(elt, "hx-vars", true, expressionVars); } + /** + * @param {HTMLElement} elt + * @param {*} expressionVars + * @returns + */ function getHXValsForElement(elt, expressionVars) { return getValuesForElement(elt, "hx-vals", false, expressionVars); } + /** + * @param {HTMLElement} elt + * @returns {Object} + */ function getExpressionVars(elt) { return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)); } @@ -2044,10 +2443,12 @@ return (function () { } function ajaxHelper(verb, path, context) { + verb = verb.toLowerCase(); if (context) { if (context instanceof Element || isType(context, 'String')) { return issueAjaxRequest(verb, path, null, null, { - targetOverride: resolveTarget(context) + targetOverride: resolveTarget(context), + returnPromise: true }); } else { return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, @@ -2055,11 +2456,15 @@ return (function () { handler : context.handler, headers : context.headers, values : context.values, - targetOverride: resolveTarget(context.target) + targetOverride: resolveTarget(context.target), + swapOverride: context.swap, + returnPromise: true }); } } else { - return issueAjaxRequest(verb, path); + return issueAjaxRequest(verb, path, null, null, { + returnPromise: true + }); } } @@ -2076,7 +2481,7 @@ return (function () { var resolve = null; var reject = null; etc = etc != null ? etc : {}; - if(typeof Promise !== "undefined"){ + if(etc.returnPromise && typeof Promise !== "undefined"){ var promise = new Promise(function (_resolve, _reject) { resolve = _resolve; reject = _reject; @@ -2091,40 +2496,85 @@ return (function () { return; // do not issue requests for elements removed from the DOM } var target = etc.targetOverride || getTarget(elt); - if (target == null) { + if (target == null || target == DUMMY_ELT) { triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); return; } + + var syncElt = elt; var eltData = getInternalData(elt); - if (eltData.requestInFlight) { - var queueStrategy = 'last'; - var eventData = getInternalData(event); - if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { - queueStrategy = eventData.triggerSpec.queue; - } - if (eltData.queuedRequests == null) { - eltData.queuedRequests = []; - } - if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); - } else if (queueStrategy === "all") { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); - } else if (queueStrategy === "last") { - eltData.queuedRequests = []; // dump existing queue - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); + var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); + var queueStrategy = null; + var abortable = false; + if (syncStrategy) { + var syncStrings = syncStrategy.split(":"); + var selector = syncStrings[0].trim(); + if (selector === "this") { + syncElt = findThisElement(elt, 'hx-sync'); + } else { + syncElt = querySelectorExt(elt, selector); + } + // default to the drop strategy + syncStrategy = (syncStrings[1] || 'drop').trim(); + eltData = getInternalData(syncElt); + if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { + return; + } else if (syncStrategy === "abort") { + if (eltData.xhr) { + return; + } else { + abortable = true; + } + } else if (syncStrategy === "replace") { + triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue + } else if (syncStrategy.indexOf("queue") === 0) { + var queueStrArray = syncStrategy.split(" "); + queueStrategy = (queueStrArray[1] || "last").trim(); } - return; - } else { - eltData.requestInFlight = true; } + + if (eltData.xhr) { + if (eltData.abortable) { + triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue + } else { + if(queueStrategy == null){ + if (event) { + var eventData = getInternalData(event); + if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { + queueStrategy = eventData.triggerSpec.queue; + } + } + if (queueStrategy == null) { + queueStrategy = "last"; + } + } + if (eltData.queuedRequests == null) { + eltData.queuedRequests = []; + } + if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } else if (queueStrategy === "all") { + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } else if (queueStrategy === "last") { + eltData.queuedRequests = []; // dump existing queue + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } + return; + } + } + + var xhr = new XMLHttpRequest(); + eltData.xhr = xhr; + eltData.abortable = abortable; var endRequestLock = function(){ - eltData.requestInFlight = false + eltData.xhr = null; + eltData.abortable = false; if (eltData.queuedRequests != null && eltData.queuedRequests.length > 0) { var queuedRequest = eltData.queuedRequests.shift(); @@ -2152,11 +2602,10 @@ return (function () { } } - var xhr = new XMLHttpRequest(); var headers = getHeaders(elt, target, promptResponse); if (etc.headers) { - headers = mergeObjects(headers, etc.values); + headers = mergeObjects(headers, etc.headers); } var results = getInputValues(elt, verb); var errors = results.errors; @@ -2169,7 +2618,7 @@ return (function () { var filteredParameters = filterValues(allParameters, elt); if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null) { - headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; + headers['Content-Type'] = 'application/x-www-form-urlencoded'; } // behavior of anchors w/ empty href is to use the current URL @@ -2177,6 +2626,8 @@ return (function () { path = getDocument().location.href; } + var requestAttrValues = getValuesForElement(elt, 'hx-request'); + var requestConfig = { parameters: filteredParameters, unfilteredParameters: allParameters, @@ -2184,6 +2635,8 @@ return (function () { target:target, verb:verb, errors:errors, + withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, + timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, path:path, triggeringEvent:event }; @@ -2231,17 +2684,22 @@ return (function () { } xhr.overrideMimeType("text/html"); - xhr.withCredentials = htmx.config.withCredentials; + xhr.withCredentials = requestConfig.withCredentials; + xhr.timeout = requestConfig.timeout; // request headers - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - var headerValue = headers[header]; - safelySetHeaderValue(xhr, header, headerValue); + if (requestAttrValues.noHeaders) { + // ignore all headers + } else { + for (var header in headers) { + if (headers.hasOwnProperty(header)) { + var headerValue = headers[header]; + safelySetHeaderValue(xhr, header, headerValue); + } } } - var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, pathInfo:{ + var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, etc:etc, pathInfo:{ path:path, finalPath:finalPathForGet, anchor:anchor } }; @@ -2289,6 +2747,13 @@ return (function () { maybeCall(reject); endRequestLock(); } + xhr.ontimeout = function() { + removeRequestIndicatorClasses(indicators); + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); + triggerErrorEvent(elt, 'htmx:timeout', responseInfo); + maybeCall(reject); + endRequestLock(); + } if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){ maybeCall(resolve); endRequestLock() @@ -2315,6 +2780,7 @@ return (function () { function handleAjaxResponse(elt, responseInfo) { var xhr = responseInfo.xhr; var target = responseInfo.target; + var etc = responseInfo.etc; if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; @@ -2338,123 +2804,162 @@ return (function () { } } - var shouldSaveHistory = shouldPush(elt) || pushedUrl; + if (hasHeader(xhr,/HX-Retarget:/i)) { + responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget")); + } - if (xhr.status >= 200 && xhr.status < 400) { + /** @type {boolean} */ + var shouldSaveHistory + if (pushedUrl == "false") { + shouldSaveHistory = false + } else { + shouldSaveHistory = shouldPush(elt) || pushedUrl; + } + + // by default htmx only swaps on 200 return codes and does not swap + // on 204 'No Content' + // this can be ovverriden by responding to the htmx:beforeSwap event and + // overriding the detail.shouldSwap property + var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; + var serverResponse = xhr.response; + var isError = xhr.status >= 400; + var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo); + if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; + + target = beforeSwapDetails.target; // allow re-targeting + serverResponse = beforeSwapDetails.serverResponse; // allow updating content + isError = beforeSwapDetails.isError; // allow updating error + + responseInfo.failed = isError; // Make failed property available to response events + responseInfo.successful = !isError; // Make successful property available to response events + + if (beforeSwapDetails.shouldSwap) { if (xhr.status === 286) { cancelPolling(elt); } - // don't process 'No Content' - if (xhr.status !== 204) { - if (!triggerEvent(target, 'htmx:beforeSwap', responseInfo)) return; - var serverResponse = xhr.response; - withExtensions(elt, function(extension){ - serverResponse = extension.transformResponse(serverResponse, xhr, elt); - }); + withExtensions(elt, function (extension) { + serverResponse = extension.transformResponse(serverResponse, xhr, elt); + }); - // Save current page - if (shouldSaveHistory) { - saveHistory(); - } + // Save current page + if (shouldSaveHistory) { + saveCurrentPageToHistory(); + } + + var swapOverride = etc.swapOverride; + var swapSpec = getSwapSpecification(elt, swapOverride); - var swapSpec = getSwapSpecification(elt); + target.classList.add(htmx.config.swappingClass); + var doSwap = function () { + try { - target.classList.add(htmx.config.swappingClass); - var doSwap = function () { + var activeElt = document.activeElement; + var selectionInfo = {}; try { + selectionInfo = { + elt: activeElt, + // @ts-ignore + start: activeElt ? activeElt.selectionStart : null, + // @ts-ignore + end: activeElt ? activeElt.selectionEnd : null + }; + } catch (e) { + // safari issue - see https://github.com/microsoft/playwright/issues/5894 + } - var activeElt = document.activeElement; - var selectionInfo = {}; - try { - selectionInfo = { - elt: activeElt, - start: activeElt ? activeElt.selectionStart : null, - end: activeElt ? activeElt.selectionEnd : null - }; - } catch (e) { - // safari issue - see https://github.com/microsoft/playwright/issues/5894 + var settleInfo = makeSettleInfo(target); + selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + + if (selectionInfo.elt && + !bodyContains(selectionInfo.elt) && + selectionInfo.elt.id) { + var newActiveElt = document.getElementById(selectionInfo.elt.id); + var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; + if (newActiveElt) { + // @ts-ignore + if (selectionInfo.start && newActiveElt.setSelectionRange) { + // @ts-ignore + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + } + newActiveElt.focus(focusOptions); } + } - var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + target.classList.remove(htmx.config.swappingClass); + forEach(settleInfo.elts, function (elt) { + if (elt.classList) { + elt.classList.add(htmx.config.settlingClass); + } + triggerEvent(elt, 'htmx:afterSwap', responseInfo); + }); + if (responseInfo.pathInfo.anchor) { + location.hash = responseInfo.pathInfo.anchor; + } - if (selectionInfo.elt && - !bodyContains(selectionInfo.elt) && - selectionInfo.elt.id) { - var newActiveElt = document.getElementById(selectionInfo.elt.id); - if (newActiveElt) { - if (selectionInfo.start && newActiveElt.setSelectionRange) { - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); - } - newActiveElt.focus(); - } + if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { + var finalElt = elt; + if (!bodyContains(elt)) { + finalElt = getDocument().body; } + handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); + } - target.classList.remove(htmx.config.swappingClass); + var doSettle = function () { + forEach(settleInfo.tasks, function (task) { + task.call(); + }); forEach(settleInfo.elts, function (elt) { if (elt.classList) { - elt.classList.add(htmx.config.settlingClass); + elt.classList.remove(htmx.config.settlingClass); } - triggerEvent(elt, 'htmx:afterSwap', responseInfo); + triggerEvent(elt, 'htmx:afterSettle', responseInfo); }); - if (responseInfo.pathInfo.anchor) { - location.hash = responseInfo.pathInfo.anchor; + // push URL and save new page + if (shouldSaveHistory) { + var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; + pushUrlIntoHistory(pathToPush); + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: pathToPush}); } - if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; + if(settleInfo.title) { + var titleElt = find("title"); + if(titleElt) { + titleElt.innerHTML = settleInfo.title; + } else { + window.document.title = settleInfo.title; } - handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); } - var doSettle = function(){ - forEach(settleInfo.tasks, function (task) { - task.call(); - }); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.remove(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSettle', responseInfo); - }); - // push URL and save new page - if (shouldSaveHistory) { - var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; - pushUrlIntoHistory(pathToPush); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path:pathToPush}); - } - updateScrollState(settleInfo.elts, swapSpec); + updateScrollState(settleInfo.elts, swapSpec); - if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); + if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { + var finalElt = elt; + if (!bodyContains(elt)) { + finalElt = getDocument().body; } + handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'htmx:swapError', responseInfo); - throw e; } - }; - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); + if (swapSpec.settleDelay > 0) { + setTimeout(doSettle, swapSpec.settleDelay) + } else { + doSettle(); + } + } catch (e) { + triggerErrorEvent(elt, 'htmx:swapError', responseInfo); + throw e; } + }; + + if (swapSpec.swapDelay > 0) { + setTimeout(doSwap, swapSpec.swapDelay) + } else { + doSwap(); } - } else { + } + if (isError) { triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.path}, responseInfo)); } } @@ -2462,9 +2967,17 @@ return (function () { //==================================================================== // Extensions API //==================================================================== + + /** @type {Object<string, import("./htmx").HtmxExtension>} */ var extensions = {}; + + /** + * extensionBase defines the default functions for all extensions. + * @returns {import("./htmx").HtmxExtension} + */ function extensionBase() { return { + init: function(api) {return null;}, onEvent : function(name, evt) {return true;}, transformResponse : function(text, xhr, elt) {return text;}, isInlineSwap : function(swapStyle) {return false;}, @@ -2473,15 +2986,37 @@ return (function () { } } + /** + * defineExtension initializes the extension and adds it to the htmx registry + * + * @param {string} name + * @param {import("./htmx").HtmxExtension} extension + */ function defineExtension(name, extension) { + if(extension.init) { + extension.init(internalAPI) + } extensions[name] = mergeObjects(extensionBase(), extension); } + /** + * removeExtension removes an extension from the htmx registry + * + * @param {string} name + */ function removeExtension(name) { delete extensions[name]; } - function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + /** + * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element + * + * @param {HTMLElement} elt + * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn + * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore + */ + function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + if (elt == undefined) { return extensionsToReturn; } @@ -2536,6 +3071,7 @@ return (function () { function getMetaConfig() { var element = getDocument().querySelector('meta[name="htmx-config"]'); if (element) { + // @ts-ignore return parseJSON(element.content); } else { return null; @@ -2555,9 +3091,25 @@ return (function () { insertIndicatorStyles(); var body = getDocument().body; processNode(body); + var restoredElts = getDocument().querySelectorAll( + "[hx-trigger='restored'],[data-hx-trigger='restored']" + ); + body.addEventListener("htmx:abort", function (evt) { + var target = evt.target; + var internalData = getInternalData(target); + if (internalData && internalData.xhr) { + internalData.xhr.abort(); + } + }); window.onpopstate = function (event) { if (event.state && event.state.htmx) { restoreHistory(); + forEach(restoredElts, function(elt){ + triggerEvent(elt, 'htmx:restored', { + 'document': getDocument(), + 'triggerEvent': triggerEvent + }); + }); } }; setTimeout(function () { diff --git a/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.min.js b/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.min.js index 57f33b2..998414c 100644 --- a/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.min.js +++ b/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.min.js @@ -1 +1 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var k={onLoad:t,process:rt,on:I,off:M,trigger:lt,ajax:$t,find:w,findAll:S,closest:L,values:function(e,t){var r=Lt(e,t||"post");return r.values},remove:E,addClass:q,removeClass:R,toggleClass:C,takeClass:O,defineExtension:Qt,removeExtension:er,logAll:b,logger:null,useTemplateFragments:false,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,attributesToSettle:["class","style","width","height"],withCredentials:false,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]"},parseInterval:f,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])}};var r=["get","post","put","delete","patch"];var n=r.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function f(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function l(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function D(e,t){return l(e,t)||l(e,"data-"+t)}function c(e){return e.parentElement}function F(){return document}function h(e,t){if(t(e)){return e}else if(c(e)){return h(c(e),t)}else{return null}}function X(e,t){var r=null;h(e,function(e){return r=D(e,t)});return r}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function i(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 o(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=F().createDocumentFragment()}return i}function u(e){if(k.config.useTemplateFragments){var t=o("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=i(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return o("<table>"+e+"</table>",1);case"col":return o("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return o("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return o("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return o("<div>"+e+"</div>",1);default:return o(e,0)}}}function P(e){if(e){e()}}function a(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function v(e){return a(e,"Function")}function g(e){return a(e,"Object")}function U(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function p(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function j(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function m(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function z(e){return F().body.contains(e)}function y(e){return e.trim().split(/\s+/)}function V(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function x(e){try{return JSON.parse(e)}catch(e){ut(e);return null}}function e(e){return Ut(F().body,function(){return eval(e)})}function t(t){var e=k.on("htmx:load",function(e){t(e.detail.elt)});return e}function b(){k.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function w(e,t){if(t){return e.querySelector(t)}else{return w(F(),e)}}function S(e,t){if(t){return e.querySelectorAll(t)}else{return S(F(),e)}}function E(e,t){e=H(e);if(t){setTimeout(function(){E(e)},t)}else{e.parentElement.removeChild(e)}}function q(e,t,r){e=H(e);if(r){setTimeout(function(){q(e,t)},r)}else{e.classList.add(t)}}function R(e,t,r){e=H(e);if(r){setTimeout(function(){R(e,t)},r)}else{e.classList.remove(t)}}function C(e,t){e=H(e);e.classList.toggle(t)}function O(e,t){e=H(e);j(e.parentElement.children,function(e){R(e,t)});q(e,t)}function L(e,t){e=H(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&c(e))}}function A(e,t){if(t.indexOf("closest ")===0){return[L(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[w(e,t.substr(5))]}else{return F().querySelectorAll(t)}}function T(e,t){return A(e,t)[0]}function H(e){if(a(e,"String")){return w(e)}else{return e}}function N(e,t,r){if(v(t)){return{target:F().body,event:e,listener:t}}else{return{target:H(e),event:t,listener:r}}}function I(t,r,n){rr(function(){var e=N(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=v(r);return e?r:n}function M(t,r,n){rr(function(){var e=N(t,r,n);e.target.removeEventListener(e.event,e.listener)});return v(r)?r:n}function _(e){var t=h(e,function(e){return D(e,"hx-target")!==null});if(t){var r=D(t,"hx-target");if(r==="this"){return t}else{return T(e,r)}}else{var n=U(e);if(n.boosted){return F().body}else{return e}}}function B(e){var t=k.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function W(t,r){j(t.attributes,function(e){if(!r.hasAttribute(e.name)&&B(e.name)){t.removeAttribute(e.name)}});j(r.attributes,function(e){if(B(e.name)){t.setAttribute(e.name,e.value)}})}function $(e,t){var r=tr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){ut(e)}}return e==="outerHTML"}function J(e,t,r){var n="#"+t.id;var i="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){i=e.substr(0,e.indexOf(":"));n=e.substr(e.indexOf(":")+1,e.length)}else{i=e}var o=F().querySelector(n);if(o){var a;a=F().createDocumentFragment();a.appendChild(t);if(!$(i,o)){a=t}le(i,o,o,a,r)}else{t.parentNode.removeChild(t);ot(F().body,"htmx:oobErrorNoTarget",{content:t})}return e}function Z(e,r){j(S(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=D(e,"hx-swap-oob");if(t!=null){J(t,e,r)}})}function G(e){j(S(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=D(e,"id");var r=F().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function K(n,e,i){j(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();W(e,t);i.tasks.push(function(){W(e,r)})}}})}function Y(e){return function(){rt(e);Ye(e);Q(e);lt(e,"htmx:load")}}function Q(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ee(e,t,r,n){K(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Y(i))}}}function te(t){var e=U(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}if(e.listenerInfos){j(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){j(t.children,function(e){te(e)})}}function re(e,t,r){if(e.tagName==="BODY"){return se(e,t,r)}else{var n=e.previousSibling;ee(c(e),e,t,r);if(n==null){var i=c(e).firstChild}else{var i=n.nextSibling}U(e).replacedWith=i;r.elts=[];while(i&&i!==e){if(i.nodeType===Node.ELEMENT_NODE){r.elts.push(i)}i=i.nextElementSibling}te(e);c(e).removeChild(e)}}function ne(e,t,r){return ee(e,e.firstChild,t,r)}function ie(e,t,r){return ee(c(e),e,t,r)}function oe(e,t,r){return ee(e,null,t,r)}function ae(e,t,r){return ee(c(e),e.nextSibling,t,r)}function se(e,t,r){var n=e.firstChild;ee(e,n,t,r);if(n){while(n.nextSibling){te(n.nextSibling);e.removeChild(n.nextSibling)}te(n);e.removeChild(n)}}function ue(e,t){var r=X(e,"hx-select");if(r){var n=F().createDocumentFragment();j(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function le(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":re(r,n,i);return;case"afterbegin":ne(r,n,i);return;case"beforebegin":ie(r,n,i);return;case"beforeend":oe(r,n,i);return;case"afterend":ae(r,n,i);return;default:var o=tr(t);for(var a=0;a<o.length;a++){var s=o[a];try{var u=s.handleSwap(e,r,n,i);if(u){if(typeof u.length!=="undefined"){for(var l=0;l<u.length;l++){var f=u[l];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Y(f))}}}return}}catch(e){ut(e)}}se(r,n,i)}}var fe=/<title>([\s\S]+?)<\/title>/im;function ce(e){if(e.indexOf("<title>")>-1&&(e.indexOf("<svg>")==-1||e.indexOf("<title>")<e.indexOf("<svg>"))){var t=fe.exec(e);if(t){return t[1]}}}function he(e,t,r,n,i){var o=ce(n);if(o){var a=w("title");if(a){a.innerHTML=o}else{window.document.title=o}}var s=u(n);if(s){Z(s,i);s=ue(r,s);G(s);return le(e,r,t,s,i)}}function de(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=x(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!g(a)){a={value:a}}lt(r,o,a)}}}else{lt(r,n,[])}}var ve=/\s/;var ge=/[\s,]/;var pe=/[_$a-zA-Z]/;var me=/[_$a-zA-Z0-9]/;var ye=['"',"'","/"];var xe=/[^\s]/;function be(e){var t=[];var r=0;while(r<e.length){if(pe.exec(e.charAt(r))){var n=r;while(me.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(ye.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function we(e,t,r){return pe.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function Se(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Ut(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){ot(F().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(we(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function Ee(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var qe="input, textarea, select";function Re(e){var t=D(e,"hx-trigger");var r=[];if(t){var n=be(t);do{Ee(n,xe);var i=n.length;var o=Ee(n,/[,\[\s]/);if(o!==""){if(o==="every"){var a={trigger:"every"};Ee(n,xe);a.pollInterval=f(Ee(n,ve));r.push(a)}else if(o.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:o.substr(4)})}else{var s={trigger:o};var u=Se(e,n,"event");if(u){s.eventFilter=u}while(n.length>0&&n[0]!==","){Ee(n,xe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=f(Ee(n,ge))}else if(l==="from"&&n[0]===":"){n.shift();s.from=Ee(n,ge)}else if(l==="target"&&n[0]===":"){n.shift();s.target=Ee(n,ge)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=f(Ee(n,ge))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=Ee(n,ge)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=Ee(n,ge)}else{ot(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===i){ot(e,"htmx:syntax:error",{token:n.shift()})}Ee(n,xe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,qe)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ce(e){U(e).cancelled=true}function Oe(e,t,r,n){var i=U(e);i.timeout=setTimeout(function(){if(z(e)&&i.cancelled!==true){Zt(t,r,e);Oe(e,t,D(e,"hx-"+t),n)}},n)}function Le(e){return location.hostname===e.hostname&&l(e,"href")&&l(e,"href").indexOf("#")!==0}function Ae(t,r,e){if(t.tagName==="A"&&Le(t)||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=l(t,"href");r.pushURL=true}else{var o=l(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=l(t,"action")}e.forEach(function(e){Ie(t,n,i,r,e,true)})}}function Te(e){return e.tagName==="FORM"||d(e,'input[type="submit"], button')&&L(e,"form")!==null||e.tagName==="A"&&e.href&&(e.getAttribute("href")==="#"||e.getAttribute("href").indexOf("#")!==0)}function He(e,t){return U(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function Ne(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){ot(F().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Ie(n,i,o,e,a,s){var u=n;if(a.from){u=w(a.from)}var l=function(e){if(!z(n)){u.removeEventListener(a.trigger,l);return}if(He(n,e)){return}if(s||Te(n)){e.preventDefault()}if(Ne(a,e)){return}var t=U(e);t.triggerSpec=a;if(t.handledFor==null){t.handledFor=[]}var r=U(n);if(t.handledFor.indexOf(n)<0){t.handledFor.push(n);if(a.consume){e.stopPropagation()}if(a.target&&e.target){if(!d(e.target,a.target)){return}}if(a.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(a.changed){if(r.lastValue===n.value){return}else{r.lastValue=n.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(a.throttle){if(!r.throttle){Zt(i,o,n,e);r.throttle=setTimeout(function(){r.throttle=null},a.throttle)}}else if(a.delay){r.delayed=setTimeout(function(){Zt(i,o,n,e)},a.delay)}else{Zt(i,o,n,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:a.trigger,listener:l,on:u});u.addEventListener(a.trigger,l)}var Me=false;var ke=null;function De(){if(!ke){ke=function(){Me=true};window.addEventListener("scroll",ke);setInterval(function(){if(Me){Me=false;j(F().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){Fe(e)})}},200)}}function Fe(e){var t=U(e);if(!t.revealed&&m(e)){t.revealed=true;if(t.initialized){Zt(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Zt(t.verb,t.path,e)},{once:true})}}}function Xe(e,t,r){var n=y(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Pe(e,o[1],0)}if(o[0]==="send"){je(e)}}}function Pe(s,r,n){if(!z(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=k.createWebSocket(r);t.onerror=function(e){ot(s,"htmx:wsError",{error:e,socket:t});Ue(s)};t.onclose=function(e){if([1006,1012,1013].includes(e.code)){var t=ze(n);setTimeout(function(){Pe(s,r,n+1)},t)}};t.onopen=function(e){n=0};U(s).webSocket=t;t.addEventListener("message",function(e){if(Ue(s)){return}var t=e.data;st(s,function(e){t=e.transformResponse(t,null,s)});var r=Ft(s);var n=u(t);var i=p(n.children);for(var o=0;o<i.length;o++){var a=i[o];J(D(a,"hx-swap-oob")||"true",a,r)}mt(r.tasks)})}function Ue(e){if(!z(e)){U(e).webSocket.close();return true}}function je(l){var f=h(l,function(e){return U(e).webSocket!=null});if(f){l.addEventListener(Re(l)[0].trigger,function(e){var t=U(f).webSocket;var r=Nt(l,f);var n=Lt(l,"post");var i=n.errors;var o=n.values;var a=Vt(l);var s=V(o,a);var u=It(s,l);u["HEADERS"]=r;if(i&&i.length>0){lt(l,"htmx:validation:halted",i);return}t.send(JSON.stringify(u));if(Te(l)){e.preventDefault()}})}else{ot(l,"htmx:noWebSocketSourceError")}}function ze(e){var t=k.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}ut('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ve(e,t,r){var n=y(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){_e(e,o[1])}if(o[0]==="swap"){Be(e,o[1])}}}function _e(t,e){var r=k.createEventSource(e);r.onerror=function(e){ot(t,"htmx:sseError",{error:e,source:r});$e(t)};U(t).sseEventSource=r}function Be(o,a){var s=h(o,Je);if(s){var u=U(s).sseEventSource;var l=function(e){if($e(s)){u.removeEventListener(a,l);return}var t=e.data;st(o,function(e){t=e.transformResponse(t,null,o)});var r=kt(o);var n=_(o);var i=Ft(o);he(r.swapStyle,o,n,t,i);mt(i.tasks);lt(o,"htmx:sseMessage",e)};U(o).sseListener=l;u.addEventListener(a,l)}else{ot(o,"htmx:noSSESourceError")}}function We(e,t,r,n){var i=h(e,Je);if(i){var o=U(i).sseEventSource;var a=function(){if(!$e(i)){if(z(e)){Zt(t,r,e)}else{o.removeEventListener(n,a)}}};U(e).sseListener=a;o.addEventListener(n,a)}else{ot(e,"htmx:noSSESourceError")}}function $e(e){if(!z(e)){U(e).sseEventSource.close();return true}}function Je(e){return U(e).sseEventSource!=null}function Ze(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Zt(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function Ge(o,a,e){var t=false;j(r,function(n){if(s(o,"hx-"+n)){var i=D(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){We(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){De();Fe(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=T(e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){lt(o,"intersect");break}}},t);r.observe(o);Ie(o,n,i,a,e)}else if(e.trigger==="load"){Ze(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Oe(o,n,i,e.pollInterval)}else{Ie(o,n,i,a,e)}})}});return t}function Ke(e){if(e.type==="text/javascript"||e.type===""){try{Ut(e,function(){(1,eval)(e.innerText)})}catch(e){ut(e)}}}function Ye(e){if(d(e,"script")){Ke(e)}j(S(e,"script"),function(e){Ke(e)})}function Qe(){return document.querySelector("[hx-boost], [data-hx-boost]")}function et(e){if(e.querySelectorAll){var t=Qe()?", a, form":"";var r=e.querySelectorAll(n+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws]");return r}else{return[]}}function tt(e){if(e.closest&&e.closest(k.config.disableSelector)){return}var t=U(e);if(!t.initialized){t.initialized=true;lt(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=Re(e);var n=Ge(e,t,r);if(!n&&X(e,"hx-boost")==="true"){Ae(e,t,r)}var i=D(e,"hx-sse");if(i){Ve(e,t,i)}var o=D(e,"hx-ws");if(o){Xe(e,t,o)}lt(e,"htmx:afterProcessNode")}}function rt(e){e=H(e);tt(e);j(et(e),function(e){tt(e)})}function nt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function it(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=F().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function ot(e,t,r){lt(e,t,V({error:t},r))}function at(e){return e==="htmx:afterProcessNode"}function st(e,t){j(tr(e),function(e){try{t(e)}catch(e){ut(e)}})}function ut(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function lt(e,t,r){e=H(e);if(r==null){r={}}r["elt"]=e;var n=it(t,r);if(k.logger&&!at(t)){k.logger(e,t,r)}if(r.error){ut(r.error);lt(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=nt(t);if(i&&o!==t){var a=it(o,n.detail);i=i&&e.dispatchEvent(a)}st(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var ft=null;function ct(){var e=F().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||F().body}function ht(e,t,r,n){var i=x(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>k.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ot(F().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function dt(e){var t=x(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function vt(e){var t=k.config.requestClass;var r=e.cloneNode(true);j(S(r,"."+t),function(e){R(e,t)});return r.innerHTML}function gt(){var e=ct();var t=ft||location.pathname+location.search;lt(F().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(k.config.historyEnabled)history.replaceState({htmx:true},F().title,window.location.href);ht(t,vt(e),F().title,window.scrollY)}function pt(e){if(k.config.historyEnabled)history.pushState({htmx:true},"",e);ft=e}function mt(e){j(e,function(e){e.call()})}function yt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};lt(F().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){lt(F().body,"htmx:historyCacheMissLoad",i);var e=u(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=ct();var r=Ft(t);se(t,e,r);mt(r.tasks);ft=n;lt(F().body,"htmx:historyRestore",{path:n})}else{ot(F().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function xt(e){gt();e=e||location.pathname+location.search;var t=dt(e);if(t){var r=u(t.content);var n=ct();var i=Ft(n);se(n,r,i);mt(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);ft=e;lt(F().body,"htmx:historyRestore",{path:e})}else{if(k.config.refreshOnHistoryMiss){window.location.reload(true)}else{yt(e)}}}function bt(e){var t=X(e,"hx-push-url");return t&&t!=="false"||U(e).boosted&&U(e).pushURL}function wt(e){var t=X(e,"hx-push-url");return t==="true"||t==="false"?null:t}function St(e){var t=X(e,"hx-indicator");if(t){var r=A(e,t)}else{r=[e]}j(r,function(e){e.classList["add"].call(e.classList,k.config.requestClass)});return r}function Et(e){j(e,function(e){e.classList["remove"].call(e.classList,k.config.requestClass)})}function qt(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Rt(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 Ct(t,r,n,e,i){if(e==null||qt(t,e)){return}else{t.push(e)}if(Rt(e)){var o=l(e,"name");var a=e.value;if(e.multiple){a=p(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=p(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){Ot(e,n)}}if(d(e,"form")){var u=e.elements;j(u,function(e){Ct(t,r,n,e,i)})}}function Ot(e,t){if(e.willValidate){lt(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});lt(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Lt(e,t){var r=[];var n={};var i={};var o=[];var a=d(e,"form")&&e.noValidate!==true;if(t!=="get"){Ct(r,i,o,L(e,"form"),a)}Ct(r,n,o,e,a);var s=X(e,"hx-include");if(s){var u=A(e,s);j(u,function(e){Ct(r,n,o,e,a);if(!d(e,"form")){j(e.querySelectorAll(qe),function(e){Ct(r,n,o,e,a)})}})}n=V(n,i);return{errors:o,values:n}}function At(e,t,r){if(e!==""){e+="&"}e+=encodeURIComponent(t)+"="+encodeURIComponent(r);return e}function Tt(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){j(n,function(e){t=At(t,r,e)})}else{t=At(t,r,n)}}}return t}function Ht(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){j(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Nt(e,t,r){var n={"HX-Request":"true","HX-Trigger":l(e,"id"),"HX-Trigger-Name":l(e,"name"),"HX-Target":D(t,"id"),"HX-Current-URL":F().location.href};Pt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}return n}function It(t,e){var r=X(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){j(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};j(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Mt(e){return l(e,"href")&&l(e,"href").indexOf("#")>=0}function kt(e){var t=X(e,"hx-swap");var r={swapStyle:U(e).boosted?"innerHTML":k.config.defaultSwapStyle,swapDelay:k.config.defaultSwapDelay,settleDelay:k.config.defaultSettleDelay};if(U(e).boosted&&!Mt(e)){r["show"]="top"}if(t){var n=y(t);if(n.length>0){r["swapStyle"]=n[0];for(var i=1;i<n.length;i++){var o=n[i];if(o.indexOf("swap:")===0){r["swapDelay"]=f(o.substr(5))}if(o.indexOf("settle:")===0){r["settleDelay"]=f(o.substr(7))}if(o.indexOf("scroll:")===0){r["scroll"]=o.substr(7)}if(o.indexOf("show:")===0){r["show"]=o.substr(5)}}}}return r}function Dt(t,r,n){var i=null;st(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(X(r,"hx-encoding")==="multipart/form-data"){return Ht(n)}else{return Tt(n)}}}function Ft(e){return{tasks:[],elts:[e]}}function Xt(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){if(t.scroll==="top"&&r){r.scrollTop=0}if(t.scroll==="bottom"&&n){n.scrollTop=n.scrollHeight}}if(t.show){if(t.show==="top"&&r){r.scrollIntoView(true)}if(t.show==="bottom"&&n){n.scrollIntoView(false)}}}function Pt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=D(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Ut(e,function(){return Function("return ("+o+")")()},{})}else{s=x(o)}for(var u in s){if(s.hasOwnProperty(u)){if(n[u]==null){n[u]=s[u]}}}}return Pt(c(e),t,r,n)}function Ut(e,t,r){if(k.config.allowEval){return t()}else{ot(e,"htmx:evalDisallowedError");return r}}function jt(e,t){return Pt(e,"hx-vars",true,t)}function zt(e,t){return Pt(e,"hx-vals",false,t)}function Vt(e){return V(jt(e),zt(e))}function _t(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Bt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ot(F().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Wt(e,t){return e.getAllResponseHeaders().match(t)}function $t(e,t,r){if(r){if(r instanceof Element||a(r,"String")){return Zt(e,t,null,null,{targetOverride:H(r)})}else{return Zt(e,t,H(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:H(r.target)})}}else{return Zt(e,t)}}function Jt(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Zt(e,t,n,r,i){var o=null;var a=null;i=i!=null?i:{};if(typeof Promise!=="undefined"){var s=new Promise(function(e,t){o=e;a=t})}if(n==null){n=F().body}var u=i.handler||Gt;if(!z(n)){return}var l=i.targetOverride||_(n);if(l==null){ot(n,"htmx:targetError",{target:D(n,"hx-target")});return}var f=U(n);if(f.requestInFlight){var c="last";var h=U(r);if(h&&h.triggerSpec&&h.triggerSpec.queue){c=h.triggerSpec.queue}if(f.queuedRequests==null){f.queuedRequests=[]}if(c==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){Zt(e,t,n,r)})}else if(c==="all"){f.queuedRequests.push(function(){Zt(e,t,n,r)})}else if(c==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){Zt(e,t,n,r)})}return}else{f.requestInFlight=true}var d=function(){f.requestInFlight=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var v=X(n,"hx-prompt");if(v){var g=prompt(v);if(g===null||!lt(n,"htmx:prompt",{prompt:g,target:l})){P(o);d();return s}}var p=X(n,"hx-confirm");if(p){if(!confirm(p)){P(o);d();return s}}var m=new XMLHttpRequest;var y=Nt(n,l,g);if(i.headers){y=V(y,i.values)}var x=Lt(n,e);var b=x.errors;var w=x.values;if(i.values){w=V(w,i.values)}var S=Vt(n);var E=V(w,S);var q=It(E,n);if(e!=="get"&&X(n,"hx-encoding")==null){y["Content-Type"]="application/x-www-form-urlencoded; charset=UTF-8"}if(t==null||t===""){t=F().location.href}var R={parameters:q,unfilteredParameters:E,headers:y,target:l,verb:e,errors:b,path:t,triggeringEvent:r};if(!lt(n,"htmx:configRequest",R)){P(o);d();return s}t=R.path;e=R.verb;y=R.headers;q=R.parameters;b=R.errors;if(b&&b.length>0){lt(n,"htmx:validation:halted",R);P(o);d();return s}var C=t.split("#");var O=C[0];var L=C[1];if(e==="get"){var A=O;var T=Object.keys(q).length!==0;if(T){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=Tt(q);if(L){A+="#"+L}}m.open("GET",A,true)}else{m.open(e.toUpperCase(),t,true)}m.overrideMimeType("text/html");m.withCredentials=k.config.withCredentials;for(var H in y){if(y.hasOwnProperty(H)){var N=y[H];_t(m,H,N)}}var I={xhr:m,target:l,requestConfig:R,pathInfo:{path:t,finalPath:A,anchor:L}};m.onload=function(){try{var e=Jt(n);u(n,I);Et(M);lt(n,"htmx:afterRequest",I);lt(n,"htmx:afterOnLoad",I);if(!z(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(z(r)){t=r}}if(t){lt(t,"htmx:afterRequest",I);lt(t,"htmx:afterOnLoad",I)}}P(o);d()}catch(e){ot(n,"htmx:onLoadError",V({error:e},I));throw e}};m.onerror=function(){Et(M);ot(n,"htmx:afterRequest",I);ot(n,"htmx:sendError",I);P(a);d()};m.onabort=function(){Et(M);ot(n,"htmx:afterRequest",I);ot(n,"htmx:sendAbort",I);P(a);d()};if(!lt(n,"htmx:beforeRequest",I)){P(o);d();return s}var M=St(n);j(["loadstart","loadend","progress","abort"],function(t){j([m,m.upload],function(e){e.addEventListener(t,function(e){lt(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});lt(n,"htmx:beforeSend",I);m.send(e==="get"?null:Dt(m,n,q));return s}function Gt(a,s){var u=s.xhr;var l=s.target;if(!lt(a,"htmx:beforeOnLoad",s))return;if(Wt(u,/HX-Trigger:/i)){de(u,"HX-Trigger",a)}if(Wt(u,/HX-Push:/i)){var f=u.getResponseHeader("HX-Push")}if(Wt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Wt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}var c=bt(a)||f;if(u.status>=200&&u.status<400){if(u.status===286){Ce(a)}if(u.status!==204){if(!lt(l,"htmx:beforeSwap",s))return;var h=u.response;st(a,function(e){h=e.transformResponse(h,u,a)});if(c){gt()}var d=kt(a);l.classList.add(k.config.swappingClass);var e=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r=Ft(l);he(d.swapStyle,l,a,h,r);if(t.elt&&!z(t.elt)&&t.elt.id){var n=document.getElementById(t.elt.id);if(n){if(t.start&&n.setSelectionRange){n.setSelectionRange(t.start,t.end)}n.focus()}}l.classList.remove(k.config.swappingClass);j(r.elts,function(e){if(e.classList){e.classList.add(k.config.settlingClass)}lt(e,"htmx:afterSwap",s)});if(s.pathInfo.anchor){location.hash=s.pathInfo.anchor}if(Wt(u,/HX-Trigger-After-Swap:/i)){var i=a;if(!z(a)){i=F().body}de(u,"HX-Trigger-After-Swap",i)}var o=function(){j(r.tasks,function(e){e.call()});j(r.elts,function(e){if(e.classList){e.classList.remove(k.config.settlingClass)}lt(e,"htmx:afterSettle",s)});if(c){var e=f||wt(a)||Bt(u)||s.pathInfo.finalPath||s.pathInfo.path;pt(e);lt(F().body,"htmx:pushedIntoHistory",{path:e})}Xt(r.elts,d);if(Wt(u,/HX-Trigger-After-Settle:/i)){var t=a;if(!z(a)){t=F().body}de(u,"HX-Trigger-After-Settle",t)}};if(d.settleDelay>0){setTimeout(o,d.settleDelay)}else{o()}}catch(e){ot(a,"htmx:swapError",s);throw e}};if(d.swapDelay>0){setTimeout(e,d.swapDelay)}else{e()}}}else{ot(a,"htmx:responseError",V({error:"Response Status Error Code "+u.status+" from "+s.pathInfo.path},s))}}var Kt={};function Yt(){return{onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Qt(e,t){Kt[e]=V(Yt(),t)}function er(e){delete Kt[e]}function tr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=D(e,"hx-ext");if(t){j(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Kt[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return tr(c(e),r,n)}function rr(e){if(F().readyState!=="loading"){e()}else{F().addEventListener("DOMContentLoaded",e)}}function nr(){if(k.config.includeIndicatorStyles!==false){F().head.insertAdjacentHTML("beforeend","<style> ."+k.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+k.config.requestClass+" ."+k.config.indicatorClass+"{opacity:1} ."+k.config.requestClass+"."+k.config.indicatorClass+"{opacity:1} </style>")}}function ir(){var e=F().querySelector('meta[name="htmx-config"]');if(e){return x(e.content)}else{return null}}function or(){var e=ir();if(e){k.config=V(k.config,e)}}rr(function(){or();nr();var e=F().body;rt(e);window.onpopstate=function(e){if(e.state&&e.state.htmx){xt()}};setTimeout(function(){lt(e,"htmx:load",{})},0)});return k}()}); \ No newline at end of file +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(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 l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=k(e);e.classList.toggle(t)}function T(e,t){e=k(e);W(e.parentElement.children,function(e){q(e,t)});L(e,t)}function H(e,t){e=k(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function N(e,t){if(t.indexOf("closest ")===0){return[H(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[C(e,t.substr(5))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return z().querySelectorAll(t)}}function ee(e,t){if(t){return N(e,t)[0]}else{return N(z().body,e)[0]}}function k(e){if(p(e,"String")){return C(e)}else{return e}}function I(e,t,r){if(m(t)){return{target:z().body,event:e,listener:t}}else{return{target:k(e),event:t,listener:r}}}function M(t,r,n){lr(function(){var e=I(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function D(t,r,n){lr(function(){var e=I(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var te=z().createElement("output");function F(e,t){var r=G(e,t);if(r){if(r==="this"){return[re(e,t)]}else{var n=N(e,r);if(n.length===0){pt('The selector "'+r+'" on '+t+" returned no matches!");return[te]}else{return n}}}}function re(e,t){return h(e,function(e){return V(e,t)!=null})}function ne(e){var t=G(e,"hx-target");if(t){if(t==="this"){return re(e,"hx-target")}else{return ee(e,t)}}else{var r=_(e);if(r.boosted){return z().body}else{return e}}}function P(e){var t=U.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function X(t,r){W(t.attributes,function(e){if(!r.hasAttribute(e.name)&&P(e.name)){t.removeAttribute(e.name)}});W(r.attributes,function(e){if(P(e.name)){t.setAttribute(e.name,e.value)}})}function j(e,t){var r=sr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){pt(e)}}return e==="outerHTML"}function B(e,i,o){var t="#"+i.id;var a="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){a=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{a=e}var r=z().querySelectorAll(t);if(r){W(r,function(e){var t;var r=i.cloneNode(true);t=z().createDocumentFragment();t.appendChild(r);if(!j(a,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ye(a,e,e,t,o)}W(o.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(z().body,"htmx:oobErrorNoTarget",{content:i})}return e}function ie(e,r){W(R(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=V(e,"hx-swap-oob");if(t!=null){B(t,e,r)}})}function oe(e){W(R(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=V(e,"id");var r=z().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function ae(n,e,i){W(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();X(e,t);i.tasks.push(function(){X(e,r)})}}})}function se(e){return function(){q(e,U.config.addedClass);ct(e);at(e);le(e);$(e,"htmx:load")}}function le(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ue(e,t,r,n){ae(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(se(i))}}}function fe(t){var e=_(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){W(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){W(t.children,function(e){fe(e)})}}function ce(e,t,r){if(e.tagName==="BODY"){return me(e,t,r)}else{var n;var i=e.previousSibling;ue(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}_(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}fe(e);u(e).removeChild(e)}}function he(e,t,r){return ue(e,e.firstChild,t,r)}function de(e,t,r){return ue(u(e),e,t,r)}function ve(e,t,r){return ue(e,null,t,r)}function ge(e,t,r){return ue(u(e),e.nextSibling,t,r)}function pe(e,t,r){fe(e);return u(e).removeChild(e)}function me(e,t,r){var n=e.firstChild;ue(e,n,t,r);if(n){while(n.nextSibling){fe(n.nextSibling);e.removeChild(n.nextSibling)}fe(n);e.removeChild(n)}}function xe(e,t){var r=G(e,"hx-select");if(r){var n=z().createDocumentFragment();W(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function ye(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":ce(r,n,i);return;case"afterbegin":he(r,n,i);return;case"beforebegin":de(r,n,i);return;case"beforeend":ve(r,n,i);return;case"afterend":ge(r,n,i);return;case"delete":pe(r,n,i);return;default:var o=sr(t);for(var a=0;a<o.length;a++){var f=o[a];try{var s=f.handleSwap(e,r,n,i);if(s){if(typeof s.length!=="undefined"){for(var l=0;l<s.length;l++){var u=s[l];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){i.tasks.push(se(u))}}}return}}catch(e){pt(e)}}if(e==="innerHTML"){me(r,n,i)}else{ye(U.config.defaultSwapStyle,t,r,n,i)}}}function be(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function we(e,t,r,n,i){i.title=be(n);var o=g(n);if(o){ie(o,i);o=xe(r,o);oe(o);return ye(e,r,t,o,i)}}function Se(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!x(a)){a={value:a}}$(r,o,a)}}}else{$(r,n,[])}}var Ee=/\s/;var Ce=/[\s,]/;var Re=/[_$a-zA-Z]/;var Oe=/[_$a-zA-Z0-9]/;var Le=['"',"'","/"];var qe=/[^\s]/;function Ae(e){var t=[];var r=0;while(r<e.length){if(Re.exec(e.charAt(r))){var n=r;while(Oe.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Le.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function Te(e,t,r){return Re.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function He(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Jt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(z().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(Te(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var Ne="input, textarea, select";function ke(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=Ae(t);do{c(n,qe);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var o={trigger:"every"};c(n,qe);o.pollInterval=v(c(n,/[,\[\s]/));c(n,qe);var a=He(e,n,"event");if(a){o.eventFilter=a}r.push(o)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var a=He(e,n,"event");if(a){s.eventFilter=a}while(n.length>0&&n[0]!==","){c(n,qe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Ce))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Ce);if(u==="closest"||u==="find"){n.shift();u+=" "+c(n,Ce)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Ce)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Ce))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Ce)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Ce)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,qe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,Ne)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ie(e){_(e).cancelled=true}function Me(e,t,r,n){var i=_(e);i.timeout=setTimeout(function(){if(Y(e)&&i.cancelled!==true){if(!je(n,dt("hx:poll:trigger",{triggerSpec:n,target:e}))){Z(t,r,e)}Me(e,t,V(e,"hx-"+t),n)}},n.pollInterval)}function De(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&De(t)&&t.target===""||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href");r.pushURL=true}else{var o=f(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=f(t,"action")}e.forEach(function(e){Be(t,n,i,r,e,true)})}}function Pe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&H(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Xe(e,t){return _(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function je(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(z().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Be(o,a,s,e,l,u){var t;if(l.from){t=N(o,l.from)}else{t=[o]}W(t,function(n){var i=function(e){if(!Y(o)){n.removeEventListener(l.trigger,i);return}if(Xe(o,e)){return}if(u||Pe(e,o)){e.preventDefault()}if(je(l,e)){return}var t=_(e);t.triggerSpec=l;if(t.handledFor==null){t.handledFor=[]}var r=_(o);if(t.handledFor.indexOf(o)<0){t.handledFor.push(o);if(l.consume){e.stopPropagation()}if(l.target&&e.target){if(!d(e.target,l.target)){return}}if(l.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(l.changed){if(r.lastValue===o.value){return}else{r.lastValue=o.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(l.throttle){if(!r.throttle){Z(a,s,o,e);r.throttle=setTimeout(function(){r.throttle=null},l.throttle)}}else if(l.delay){r.delayed=setTimeout(function(){Z(a,s,o,e)},l.delay)}else{Z(a,s,o,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:l.trigger,listener:i,on:n});n.addEventListener(l.trigger,i)})}var Ue=false;var Ve=null;function ze(){if(!Ve){Ve=function(){Ue=true};window.addEventListener("scroll",Ve);setInterval(function(){if(Ue){Ue=false;W(z().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){_e(e)})}},200)}}function _e(e){if(!s(e,"data-hx-revealed")&&b(e)){e.setAttribute("data-hx-revealed","true");var t=_(e);if(t.initialized){Z(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Z(t.verb,t.path,e)},{once:true})}}}function We(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Je(e,o[1],0)}if(o[0]==="send"){Ze(e)}}}function Je(s,r,n){if(!Y(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=U.createWebSocket(r);t.onerror=function(e){J(s,"htmx:wsError",{error:e,socket:t});$e(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=Ge(n);setTimeout(function(){Je(s,r,n+1)},t)}};t.onopen=function(e){n=0};_(s).webSocket=t;t.addEventListener("message",function(e){if($e(s)){return}var t=e.data;gt(s,function(e){t=e.transformResponse(t,null,s)});var r=zt(s);var n=g(t);var i=y(n.children);for(var o=0;o<i.length;o++){var a=i[o];B(V(a,"hx-swap-oob")||"true",a,r)}Ct(r.tasks)})}function $e(e){if(!Y(e)){_(e).webSocket.close();return true}}function Ze(u){var f=h(u,function(e){return _(e).webSocket!=null});if(f){u.addEventListener(ke(u)[0].trigger,function(e){var t=_(f).webSocket;var r=Xt(u,f);var n=Mt(u,"post");var i=n.errors;var o=n.values;var a=Gt(u);var s=Q(o,a);var l=jt(s,u);l["HEADERS"]=r;if(i&&i.length>0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Pe(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ge(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}pt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ke(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Ye(e,o[1])}if(o[0]==="swap"){Qe(e,o[1])}}}function Ye(t,e){var r=U.createEventSource(e);r.onerror=function(e){J(t,"htmx:sseError",{error:e,source:r});tt(t)};_(t).sseEventSource=r}function Qe(o,a){var s=h(o,rt);if(s){var l=_(s).sseEventSource;var u=function(e){if(tt(s)){l.removeEventListener(a,u);return}var t=e.data;gt(o,function(e){t=e.transformResponse(t,null,o)});var r=Ut(o);var n=ne(o);var i=zt(o);we(r.swapStyle,o,n,t,i);Ct(i.tasks);$(o,"htmx:sseMessage",e)};_(o).sseListener=u;l.addEventListener(a,u)}else{J(o,"htmx:noSSESourceError")}}function et(e,t,r,n){var i=h(e,rt);if(i){var o=_(i).sseEventSource;var a=function(){if(!tt(i)){if(Y(e)){Z(t,r,e)}else{o.removeEventListener(n,a)}}};_(e).sseListener=a;o.addEventListener(n,a)}else{J(e,"htmx:noSSESourceError")}}function tt(e){if(!Y(e)){_(e).sseEventSource.close();return true}}function rt(e){return _(e).sseEventSource!=null}function nt(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Z(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function it(o,a,e){var t=false;W(n,function(n){if(s(o,"hx-"+n)){var i=V(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){et(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){ze();_e(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=ee(o,e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){$(o,"intersect");break}}},t);r.observe(o);Be(o,n,i,a,e)}else if(e.trigger==="load"){nt(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Me(o,n,i,e)}else{Be(o,n,i,a,e)}})}});return t}function ot(e){if(e.type==="text/javascript"||e.type==="module"||e.type===""){var t=z().createElement("script");W(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(U.config.inlineScriptNonce){t.nonce=U.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){pt(e)}finally{r.removeChild(e)}}}function at(e){if(d(e,"script")){ot(e)}W(R(e,"script"),function(e){ot(e)})}function st(){return document.querySelector("[hx-boost], [data-hx-boost]")}function lt(e){if(e.querySelectorAll){var t=st()?", a, form":"";var r=e.querySelectorAll(i+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [hx-data-ext]");return r}else{return[]}}function ut(r){var e=function(e){if(d(e.target,"button, input[type='submit']")){var t=_(r);t.lastButtonClicked=e.target}};r.addEventListener("click",e);r.addEventListener("focusin",e);r.addEventListener("focusout",function(e){var t=_(r);t.lastButtonClicked=null})}function ft(e){if(e.closest&&e.closest(U.config.disableSelector)){return}var t=_(e);if(!t.initialized){t.initialized=true;$(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=ke(e);var n=it(e,t,r);if(!n&&G(e,"hx-boost")==="true"){Fe(e,t,r)}if(e.tagName==="FORM"){ut(e)}var i=V(e,"hx-sse");if(i){Ke(e,t,i)}var o=V(e,"hx-ws");if(o){We(e,t,o)}$(e,"htmx:afterProcessNode")}}function ct(e){e=k(e);ft(e);W(lt(e),function(e){ft(e)})}function ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function dt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=z().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function J(e,t,r){$(e,t,Q({error:t},r))}function vt(e){return e==="htmx:afterProcessNode"}function gt(e,t){W(sr(e),function(e){try{t(e)}catch(e){pt(e)}})}function pt(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function $(e,t,r){e=k(e);if(r==null){r={}}r["elt"]=e;var n=dt(t,r);if(U.logger&&!vt(t)){U.logger(e,t,r)}if(r.error){pt(r.error);$(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=ht(t);if(i&&o!==t){var a=dt(o,n.detail);i=i&&e.dispatchEvent(a)}gt(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var mt=location.pathname+location.search;function xt(){var e=z().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||z().body}function yt(e,t,r,n){var i=S(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>U.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(z().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function bt(e){var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function wt(e){var t=U.config.requestClass;var r=e.cloneNode(true);W(R(r,"."+t),function(e){q(e,t)});return r.innerHTML}function St(){var e=xt();var t=mt||location.pathname+location.search;$(z().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(U.config.historyEnabled)history.replaceState({htmx:true},z().title,window.location.href);yt(t,wt(e),z().title,window.scrollY)}function Et(e){if(U.config.historyEnabled)history.pushState({htmx:true},"",e);mt=e}function Ct(e){W(e,function(e){e.call()})}function Rt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};$(z().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){$(z().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=xt();var r=zt(t);me(t,e,r);Ct(r.tasks);mt=n;$(z().body,"htmx:historyRestore",{path:n})}else{J(z().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Ot(e){St();e=e||location.pathname+location.search;var t=bt(e);if(t){var r=g(t.content);var n=xt();var i=zt(n);me(n,r,i);Ct(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);mt=e;$(z().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Rt(e)}}}function Lt(e){var t=G(e,"hx-push-url");return t&&t!=="false"||_(e).boosted&&_(e).pushURL}function qt(e){var t=G(e,"hx-push-url");return t==="true"||t==="false"?null:t}function At(e){var t=F(e,"hx-indicator");if(t==null){t=[e]}W(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Tt(e){W(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function Ht(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Nt(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 kt(t,r,n,e,i){if(e==null||Ht(t,e)){return}else{t.push(e)}if(Nt(e)){var o=f(e,"name");var a=e.value;if(e.multiple){a=y(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=y(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){It(e,n)}}if(d(e,"form")){var l=e.elements;W(l,function(e){kt(t,r,n,e,i)})}}function It(e,t){if(e.willValidate){$(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});$(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Mt(e,t){var r=[];var n={};var i={};var o=[];var a=_(e);var s=d(e,"form")&&e.noValidate!==true;if(a.lastButtonClicked){s=s&&a.lastButtonClicked.formNoValidate!==true}if(t!=="get"){kt(r,i,o,H(e,"form"),s)}kt(r,n,o,e,s);if(a.lastButtonClicked){var l=f(a.lastButtonClicked,"name");if(l){n[l]=a.lastButtonClicked.value}}var u=F(e,"hx-include");W(u,function(e){kt(r,n,o,e,s);if(!d(e,"form")){W(e.querySelectorAll(Ne),function(e){kt(r,n,o,e,s)})}});n=Q(n,i);return{errors:o,values:n}}function Dt(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function Ft(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=Dt(t,r,e)})}else{t=Dt(t,r,n)}}}return t}function Pt(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){W(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Xt(e,t,r){var n={"HX-Request":"true","HX-Trigger":f(e,"id"),"HX-Trigger-Name":f(e,"name"),"HX-Target":V(t,"id"),"HX-Current-URL":z().location.href};Wt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(_(e).boosted){n["HX-Boosted"]="true"}return n}function jt(t,e){var r=G(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){W(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};W(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Bt(e){return f(e,"href")&&f(e,"href").indexOf("#")>=0}function Ut(e,t){var r=t?t:G(e,"hx-swap");var n={swapStyle:_(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(_(e).boosted&&!Bt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var o=1;o<i.length;o++){var a=i[o];if(a.indexOf("swap:")===0){n["swapDelay"]=v(a.substr(5))}if(a.indexOf("settle:")===0){n["settleDelay"]=v(a.substr(7))}if(a.indexOf("scroll:")===0){var s=a.substr(7);var l=s.split(":");var f=l.pop();var u=l.length>0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(a.indexOf("show:")===0){var c=a.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(a.indexOf("focus-scroll:")===0){var d=a.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function Vt(t,r,n){var i=null;gt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(G(r,"hx-encoding")==="multipart/form-data"||d(r,"form")&&f(r,"enctype")==="multipart/form-data"){return Pt(n)}else{return Ft(n)}}}function zt(e){return{tasks:[],elts:[e]}}function _t(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ee(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var o=t.showTarget;if(t.showTarget==="window"){o="body"}i=ee(r,o)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function Wt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}else if(o.indexOf("js:")===0){o=o.substr(3);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Jt(e,function(){return Function("return ("+o+")")()},{})}else{s=S(o)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Wt(u(e),t,r,n)}function Jt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function $t(e,t){return Wt(e,"hx-vars",true,t)}function Zt(e,t){return Wt(e,"hx-vals",false,t)}function Gt(e){return Q($t(e),Zt(e))}function Kt(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Yt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(z().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Qt(e,t){return e.getAllResponseHeaders().match(t)}function er(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return Z(e,t,null,null,{targetOverride:k(r),returnPromise:true})}else{return Z(e,t,k(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:k(r.target),swapOverride:r.swap,returnPromise:true})}}else{return Z(e,t,null,null,{returnPromise:true})}}function tr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Z(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=z().body}var v=r.handler||rr;if(!Y(n)){return}var g=r.targetOverride||ne(n);if(g==null||g==te){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=_(n);var o=G(n,"hx-sync");var m=null;var x=false;if(o){var y=o.split(":");var b=y[0].trim();if(b==="this"){p=re(n,"hx-sync")}else{p=ee(n,b)}o=(y[1]||"drop").trim();i=_(p);if(o==="drop"&&i.xhr&&i.abortable!==true){return}else if(o==="abort"){if(i.xhr){return}else{x=true}}else if(o==="replace"){$(p,"htmx:abort")}else if(o.indexOf("queue")===0){var w=o.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=_(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){Z(e,t,n,f,r)})}return}}var a=new XMLHttpRequest;i.xhr=a;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=G(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){K(c);s();return d}}var R=G(n,"hx-confirm");if(R){if(!confirm(R)){K(c);s();return d}}var O=Xt(n,g,C);if(r.headers){O=Q(O,r.headers)}var L=Mt(n,e);var q=L.errors;var A=L.values;if(r.values){A=Q(A,r.values)}var T=Gt(n);var H=Q(A,T);var N=jt(H,n);if(e!=="get"&&G(n,"hx-encoding")==null){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=z().location.href}var k=Wt(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:q,withCredentials:r.credentials||k.credentials||U.config.withCredentials,timeout:r.timeout||k.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){K(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;q=l.errors;if(q&&q.length>0){$(n,"htmx:validation:halted",l);K(c);s();return d}var I=t.split("#");var M=I[0];var D=I[1];if(e==="get"){var F=M;var P=Object.keys(N).length!==0;if(P){if(F.indexOf("?")<0){F+="?"}else{F+="&"}F+=Ft(N);if(D){F+="#"+D}}a.open("GET",F,true)}else{a.open(e.toUpperCase(),t,true)}a.overrideMimeType("text/html");a.withCredentials=l.withCredentials;a.timeout=l.timeout;if(k.noHeaders){}else{for(var X in O){if(O.hasOwnProperty(X)){var j=O[X];Kt(a,X,j)}}}var u={xhr:a,target:g,requestConfig:l,etc:r,pathInfo:{path:t,finalPath:F,anchor:D}};a.onload=function(){try{var e=tr(n);v(n,u);Tt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!Y(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(Y(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}K(c);s()}catch(e){J(n,"htmx:onLoadError",Q({error:e},u));throw e}};a.onerror=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);K(h);s()};a.onabort=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);K(h);s()};a.ontimeout=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);K(h);s()};if(!$(n,"htmx:beforeRequest",u)){K(c);s();return d}var B=At(n);W(["loadstart","loadend","progress","abort"],function(t){W([a,a.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);a.send(e==="get"?null:Vt(a,n,N));return d}function rr(s,l){var u=l.xhr;var f=l.target;var r=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(Qt(u,/HX-Trigger:/i)){Se(u,"HX-Trigger",s)}if(Qt(u,/HX-Push:/i)){var c=u.getResponseHeader("HX-Push")}if(Qt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Qt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(Qt(u,/HX-Retarget:/i)){l.target=z().querySelector(u.getResponseHeader("HX-Retarget"))}var h;if(c=="false"){h=false}else{h=Lt(s)||c}var n=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var e=u.status>=400;var t=Q({shouldSwap:n,serverResponse:d,isError:e},l);if(!$(f,"htmx:beforeSwap",t))return;f=t.target;d=t.serverResponse;e=t.isError;l.failed=e;l.successful=!e;if(t.shouldSwap){if(u.status===286){Ie(s)}gt(s,function(e){d=e.transformResponse(d,u,s)});if(h){St()}var i=r.swapOverride;var v=Ut(s,i);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=zt(f);we(v.swapStyle,f,s,d,n);if(t.elt&&!Y(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);W(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(l.pathInfo.anchor){location.hash=l.pathInfo.anchor}if(Qt(u,/HX-Trigger-After-Swap:/i)){var o=s;if(!Y(s)){o=z().body}Se(u,"HX-Trigger-After-Swap",o)}var a=function(){W(n.tasks,function(e){e.call()});W(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h){var e=c||qt(s)||Yt(u)||l.pathInfo.finalPath||l.pathInfo.path;Et(e);$(z().body,"htmx:pushedIntoHistory",{path:e})}if(n.title){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}_t(n.elts,v);if(Qt(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!Y(s)){r=z().body}Se(u,"HX-Trigger-After-Settle",r)}};if(v.settleDelay>0){setTimeout(a,v.settleDelay)}else{a()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(v.swapDelay>0){setTimeout(o,v.swapDelay)}else{o()}}if(e){J(s,"htmx:responseError",Q({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var nr={};function ir(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function or(e,t){if(t.init){t.init(r)}nr[e]=Q(ir(),t)}function ar(e){delete nr[e]}function sr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){W(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=nr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return sr(u(e),r,n)}function lr(e){if(z().readyState!=="loading"){e()}else{z().addEventListener("DOMContentLoaded",e)}}function ur(){if(U.config.includeIndicatorStyles!==false){z().head.insertAdjacentHTML("beforeend","<style> ."+U.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+U.config.requestClass+" ."+U.config.indicatorClass+"{opacity:1} ."+U.config.requestClass+"."+U.config.indicatorClass+"{opacity:1} </style>")}}function fr(){var e=z().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function cr(){var e=fr();if(e){U.config=Q(U.config,e)}}lr(function(){cr();ur();var e=z().body;ct(e);var t=z().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=_(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){Ot();W(t,function(e){$(e,"htmx:restored",{document:z(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file diff --git a/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.js b/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.js index e38f6ed..27e57bc 100644 --- a/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.js +++ b/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.js @@ -1,7 +1,9 @@ //AMD insanity (function (root, factory) { + //@ts-ignore if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. + //@ts-ignore define([], factory); } else { // Browser globals @@ -12,6 +14,8 @@ return (function () { 'use strict'; // Public API + //** @type {import("./htmx").HtmxApi} */ + // TODO: list all methods in public API var htmx = { onLoad: onLoadHelper, process: processNode, @@ -35,7 +39,6 @@ return (function () { removeExtension : removeExtension, logAll : logAll, logger : null, - useTemplateFragments: false, config : { historyEnabled:true, historyCacheSize:10, @@ -46,13 +49,19 @@ return (function () { includeIndicatorStyles:true, indicatorClass:'htmx-indicator', requestClass:'htmx-request', + addedClass:'htmx-added', settlingClass:'htmx-settling', swappingClass:'htmx-swapping', allowEval:true, + inlineScriptNonce:'', attributesToSettle:["class", "style", "width", "height"], withCredentials:false, + timeout:0, wsReconnectDelay: 'full-jitter', disableSelector: "[hx-disable], [data-hx-disable]", + useTemplateFragments: false, + scrollBehavior: 'smooth', + defaultFocusScroll: false, }, parseInterval:parseInterval, _:internalEval, @@ -61,9 +70,36 @@ return (function () { }, createWebSocket: function(url){ return new WebSocket(url, []); - } + }, + version: "1.7.0" }; + /** @type {import("./htmx").HtmxInternalApi} */ + var internalAPI = { + bodyContains: bodyContains, + filterValues: filterValues, + hasAttribute: hasAttribute, + getAttributeValue: getAttributeValue, + getClosestMatch: getClosestMatch, + getExpressionVars: getExpressionVars, + getHeaders: getHeaders, + getInputValues: getInputValues, + getInternalData: getInternalData, + getSwapSpecification: getSwapSpecification, + getTriggerSpecs: getTriggerSpecs, + getTarget: getTarget, + makeFragment: makeFragment, + mergeObjects: mergeObjects, + makeSettleInfo: makeSettleInfo, + oobSwap: oobSwap, + selectAndSwap: selectAndSwap, + settleImmediately: settleImmediately, + shouldCancel: shouldCancel, + triggerEvent: triggerEvent, + triggerErrorEvent: triggerErrorEvent, + withExtensions: withExtensions, + } + var VERBS = ['get', 'post', 'put', 'delete', 'patch']; var VERB_SELECTOR = VERBS.map(function(verb){ return "[hx-" + verb + "], [data-hx-" + verb + "]" @@ -73,19 +109,24 @@ return (function () { // Utilities //==================================================================== - function parseInterval(str) { - if (str == undefined) { - return undefined - } - if (str.slice(-2) == "ms") { - return parseFloat(str.slice(0,-2)) || undefined - } - if (str.slice(-1) == "s") { - return (parseFloat(str.slice(0,-1)) * 1000) || undefined - } - return parseFloat(str) || undefined + function parseInterval(str) { + if (str == undefined) { + return undefined + } + if (str.slice(-2) == "ms") { + return parseFloat(str.slice(0,-2)) || undefined + } + if (str.slice(-1) == "s") { + return (parseFloat(str.slice(0,-1)) * 1000) || undefined + } + return parseFloat(str) || undefined } + /** + * @param {HTMLElement} elt + * @param {string} name + * @returns {(string | null)} + */ function getRawAttribute(elt, name) { return elt.getAttribute && elt.getAttribute(name); } @@ -96,18 +137,36 @@ return (function () { elt.hasAttribute("data-" + qualifiedName)); } + /** + * + * @param {HTMLElement} elt + * @param {string} qualifiedName + * @returns {(string | null)} + */ function getAttributeValue(elt, qualifiedName) { return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); } + /** + * @param {HTMLElement} elt + * @returns {HTMLElement | null} + */ function parentElt(elt) { return elt.parentElement; } + /** + * @returns {Document} + */ function getDocument() { return document; } + /** + * @param {HTMLElement} elt + * @param {(e:HTMLElement) => boolean} condition + * @returns {HTMLElement | null} + */ function getClosestMatch(elt, condition) { if (condition(elt)) { return elt; @@ -118,22 +177,47 @@ return (function () { } } + function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ + var attributeValue = getAttributeValue(ancestor, attributeName); + var disinherit = getAttributeValue(ancestor, "hx-disinherit"); + if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) { + return "unset"; + } else { + return attributeValue + } + } + + /** + * @param {HTMLElement} elt + * @param {string} attributeName + * @returns {string | null} + */ function getClosestAttributeValue(elt, attributeName) { var closestAttr = null; getClosestMatch(elt, function (e) { - return closestAttr = getAttributeValue(e, attributeName); + return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName); }); - return closestAttr; + if (closestAttr !== "unset") { + return closestAttr; + } } + /** + * @param {HTMLElement} elt + * @param {string} selector + * @returns {boolean} + */ function matches(elt, selector) { + // @ts-ignore: non-standard properties for browser compatability // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || - elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector - || elt.webkitMatchesSelector || elt.oMatchesSelector; + var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; return matchesFunction && matchesFunction.call(elt, selector); } + /** + * @param {string} str + * @returns {string} + */ function getStartTag(str) { var tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i var match = tagMatcher.exec( str ); @@ -144,23 +228,40 @@ return (function () { } } + /** + * + * @param {string} resp + * @param {number} depth + * @returns {Element} + */ function parseHTML(resp, depth) { var parser = new DOMParser(); var responseDoc = parser.parseFromString(resp, "text/html"); + + /** @type {Element} */ var responseNode = responseDoc.body; while (depth > 0) { depth--; + // @ts-ignore responseNode = responseNode.firstChild; } if (responseNode == null) { + // @ts-ignore responseNode = getDocument().createDocumentFragment(); } return responseNode; } + /** + * + * @param {string} resp + * @returns {Element} + */ function makeFragment(resp) { if (htmx.config.useTemplateFragments) { var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0); + // @ts-ignore type mismatch between DocumentFragment and Element. + // TODO: Are these close enough for htmx to use interchangably? return documentFragment.querySelector('template').content; } else { var startTag = getStartTag(resp); @@ -186,24 +287,45 @@ return (function () { } } + /** + * @param {Function} func + */ function maybeCall(func){ if(func) { func(); } } + /** + * @param {any} o + * @param {string} type + * @returns + */ function isType(o, type) { return Object.prototype.toString.call(o) === "[object " + type + "]"; } + /** + * @param {*} o + * @returns {o is Function} + */ function isFunction(o) { return isType(o, "Function"); } + /** + * @param {*} o + * @returns {o is Object} + */ function isRawObject(o) { return isType(o, "Object"); } + /** + * getInternalData retrieves "private" data stored by htmx within an element + * @param {HTMLElement} elt + * @returns {*} + */ function getInternalData(elt) { var dataProp = 'htmx-internal-data'; var data = elt[dataProp]; @@ -213,6 +335,11 @@ return (function () { return data; } + /** + * toArray converts an ArrayLike object into a real array. + * @param {ArrayLike} arr + * @returns {any[]} + */ function toArray(arr) { var returnArr = []; if (arr) { @@ -238,14 +365,25 @@ return (function () { return elemTop < window.innerHeight && elemBottom >= 0; } - function bodyContains(elt) { - return getDocument().body.contains(elt); - } + function bodyContains(elt) { + if (elt.getRootNode() instanceof ShadowRoot) { + return getDocument().body.contains(elt.getRootNode().host); + } else { + return getDocument().body.contains(elt); + } + } function splitOnWhitespace(trigger) { return trigger.trim().split(/\s+/); } + /** + * mergeObjects takes all of the keys from + * obj2 and duplicates them into obj1 + * @param {Object} obj1 + * @param {Object} obj2 + * @returns {Object} + */ function mergeObjects(obj1, obj2) { for (var key in obj2) { if (obj2.hasOwnProperty(key)) { @@ -319,7 +457,7 @@ return (function () { if (delay) { setTimeout(function(){addClassToElement(elt, clazz);}, delay) } else { - elt.classList.add(clazz); + elt.classList && elt.classList.add(clazz); } } @@ -328,7 +466,13 @@ return (function () { if (delay) { setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) } else { - elt.classList.remove(clazz); + if (elt.classList) { + elt.classList.remove(clazz); + // if there are no classes left, remove the class attribute + if (elt.classList.length === 0) { + elt.removeAttribute("class"); + } + } } } @@ -360,17 +504,25 @@ return (function () { } function querySelectorAllExt(elt, selector) { - if (selector.indexOf("closest ") === 0) { + if (selector.indexOf("closest ") === 0) { return [closest(elt, selector.substr(8))]; } else if (selector.indexOf("find ") === 0) { return [find(elt, selector.substr(5))]; + } else if (selector === 'document') { + return [document]; + } else if (selector === 'window') { + return [window]; } else { return getDocument().querySelectorAll(selector); } } function querySelectorExt(eltOrSelector, selector) { - return querySelectorAllExt(eltOrSelector, selector)[0] + if (selector) { + return querySelectorAllExt(eltOrSelector, selector)[0]; + } else { + return querySelectorAllExt(getDocument().body, eltOrSelector)[0]; + } } function resolveTarget(arg2) { @@ -418,13 +570,36 @@ return (function () { //==================================================================== // Node processing //==================================================================== + + var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors + function findAttributeTargets(elt, attrName) { + var attrTarget = getClosestAttributeValue(elt, attrName); + if (attrTarget) { + if (attrTarget === "this") { + return [findThisElement(elt, attrName)]; + } else { + var result = querySelectorAllExt(elt, attrTarget); + if (result.length === 0) { + logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!"); + return [DUMMY_ELT] + } else { + return result; + } + } + } + } + + function findThisElement(elt, attribute){ + return getClosestMatch(elt, function (elt) { + return getAttributeValue(elt, attribute) != null; + }) + } function getTarget(elt) { - var explicitTarget = getClosestMatch(elt, function(e){return getAttributeValue(e,"hx-target") !== null}); - if (explicitTarget) { - var targetStr = getAttributeValue(explicitTarget, "hx-target"); + var targetStr = getClosestAttributeValue(elt, "hx-target"); + if (targetStr) { if (targetStr === "this") { - return explicitTarget; + return findThisElement(elt,'hx-target'); } else { return querySelectorExt(elt, targetStr) } @@ -476,6 +651,13 @@ return (function () { return swapStyle === "outerHTML"; } + /** + * + * @param {string} oobValue + * @param {HTMLElement} oobElement + * @param {*} settleInfo + * @returns + */ function oobSwap(oobValue, oobElement, settleInfo) { var selector = "#" + oobElement.id; var swapStyle = "outerHTML"; @@ -488,18 +670,35 @@ return (function () { swapStyle = oobValue; } - var target = getDocument().querySelector(selector); - if (target) { - var fragment; - fragment = getDocument().createDocumentFragment(); - fragment.appendChild(oobElement); // pulls the child out of the existing fragment - if (!isInlineSwap(swapStyle, target)) { - fragment = oobElement; // if this is not an inline swap, we use the content of the node, not the node itself - } - swap(swapStyle, target, target, fragment, settleInfo); + var targets = getDocument().querySelectorAll(selector); + if (targets) { + forEach( + targets, + function (target) { + var fragment; + var oobElementClone = oobElement.cloneNode(true); + fragment = getDocument().createDocumentFragment(); + fragment.appendChild(oobElementClone); + if (!isInlineSwap(swapStyle, target)) { + fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself + } + + var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment }; + if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return; + + target = beforeSwapDetails.target; // allow re-targeting + if (beforeSwapDetails['shouldSwap']){ + swap(swapStyle, target, target, fragment, settleInfo); + } + forEach(settleInfo.elts, function (elt) { + triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails); + }); + } + ); + oobElement.parentNode.removeChild(oobElement); } else { oobElement.parentNode.removeChild(oobElement); - triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}) + triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}); } return oobValue; } @@ -540,6 +739,7 @@ return (function () { function makeAjaxLoadTask(child) { return function () { + removeClassFromElement(child, htmx.config.addedClass); processNode(child); processScripts(child); processFocus(child) @@ -559,6 +759,7 @@ return (function () { handleAttributes(parentNode, fragment, settleInfo); while(fragment.childNodes.length > 0){ var child = fragment.firstChild; + addClassToElement(child, htmx.config.addedClass); parentNode.insertBefore(child, insertBefore); if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { settleInfo.tasks.push(makeAjaxLoadTask(child)); @@ -574,6 +775,9 @@ return (function () { if (internalData.sseEventSource) { internalData.sseEventSource.close(); } + + triggerEvent(element, "htmx:beforeCleanupElement") + if (internalData.listenerInfos) { forEach(internalData.listenerInfos, function(info) { if (element !== info.on) { @@ -590,12 +794,14 @@ return (function () { if (target.tagName === "BODY") { return swapInnerHTML(target, fragment, settleInfo); } else { + // @type {HTMLElement} + var newElt var eltBeforeNewContent = target.previousSibling; insertNodesBefore(parentElt(target), target, fragment, settleInfo); if (eltBeforeNewContent == null) { - var newElt = parentElt(target).firstChild; + newElt = parentElt(target).firstChild; } else { - var newElt = eltBeforeNewContent.nextSibling; + newElt = eltBeforeNewContent.nextSibling; } getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later settleInfo.elts = [] // clear existing elements @@ -625,6 +831,10 @@ return (function () { function swapAfterEnd(target, fragment, settleInfo) { return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo); } + function swapDelete(target, fragment, settleInfo) { + cleanUpElement(target); + return parentElt(target).removeChild(target); + } function swapInnerHTML(target, fragment, settleInfo) { var firstChild = target.firstChild; @@ -670,6 +880,9 @@ return (function () { case "afterend": swapAfterEnd(target, fragment, settleInfo); return; + case "delete": + swapDelete(target, fragment, settleInfo); + return; default: var extensions = getExtensions(elt); for (var i = 0; i < extensions.length; i++) { @@ -692,32 +905,27 @@ return (function () { logError(e); } } - swapInnerHTML(target, fragment, settleInfo); + if (swapStyle === "innerHTML") { + swapInnerHTML(target, fragment, settleInfo); + } else { + swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo); + } } } - var TITLE_FINDER = /<title>([\s\S]+?)<\/title>/im; function findTitle(content) { - if(content.indexOf('<title>') > -1 && - (content.indexOf('<svg>') == -1 || - content.indexOf('<title>') < content.indexOf('<svg>'))) { - var result = TITLE_FINDER.exec(content); + if (content.indexOf('<title') > -1) { + var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, ''); + var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im); + if (result) { - return result[1]; + return result[2]; } } } function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) { - var title = findTitle(responseText); - if(title) { - var titleElt = find("title"); - if(titleElt) { - titleElt.innerHTML = title; - } else { - window.document.title = title; - } - } + settleInfo.title = findTitle(responseText); var fragment = makeFragment(responseText); if (fragment) { handleOutOfBandSwaps(fragment, settleInfo); @@ -840,6 +1048,11 @@ return (function () { } var INPUT_SELECTOR = 'input, textarea, select'; + + /** + * @param {HTMLElement} elt + * @returns {import("./htmx").HtmxTriggerSpecification[]} + */ function getTriggerSpecs(elt) { var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); var triggerSpecs = []; @@ -853,7 +1066,12 @@ return (function () { if (trigger === "every") { var every = {trigger: 'every'}; consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, WHITESPACE)); + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); + consumeUntil(tokens, NOT_WHITESPACE); + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + every.eventFilter = eventFilter; + } triggerSpecs.push(every); } else if (trigger.indexOf("sse:") === 0) { triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); @@ -877,7 +1095,17 @@ return (function () { triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); } else if (token === "from" && tokens[0] === ":") { tokens.shift(); - triggerSpec.from = consumeUntil(tokens, WHITESPACE_OR_COMMA); + var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); + if (from_arg === "closest" || from_arg === "find") { + tokens.shift(); + from_arg += + " " + + consumeUntil( + tokens, + WHITESPACE_OR_COMMA + ); + } + triggerSpec.from = from_arg; } else if (token === "target" && tokens[0] === ":") { tokens.shift(); triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA); @@ -919,14 +1147,16 @@ return (function () { getInternalData(elt).cancelled = true; } - function processPolling(elt, verb, path, interval) { + function processPolling(elt, verb, path, spec) { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - issueAjaxRequest(verb, path, elt); - processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), interval); + if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { + issueAjaxRequest(verb, path, elt); + } + processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), spec); } - }, interval); + }, spec.pollInterval); } function isLocalLink(elt) { @@ -936,7 +1166,7 @@ return (function () { } function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt)) || elt.tagName === "FORM") { + if ((elt.tagName === "A" && isLocalLink(elt) && elt.target === "") || elt.tagName === "FORM") { nodeData.boosted = true; var verb, path; if (elt.tagName === "A") { @@ -957,11 +1187,26 @@ return (function () { } } - function shouldCancel(elt) { - return elt.tagName === "FORM" || - (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) || - (elt.tagName === "A" && elt.href && (elt.getAttribute('href') === '#' || - elt.getAttribute('href').indexOf("#") !== 0)); + /** + * + * @param {Event} evt + * @param {HTMLElement} elt + * @returns + */ + function shouldCancel(evt, elt) { + if (evt.type === "submit" || evt.type === "click") { + if (elt.tagName === "FORM") { + return true; + } + if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { + return true; + } + if (elt.tagName === "A" && elt.href && + (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) { + return true; + } + } + return false; } function ignoreBoostedAnchorCtrlClick(elt, evt) { @@ -982,86 +1227,90 @@ return (function () { } function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { - var eltToListenOn = elt; + var eltsToListenOn; if (triggerSpec.from) { - eltToListenOn = find(triggerSpec.from); + eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); + } else { + eltsToListenOn = [elt]; } - var eventListener = function (evt) { - if (!bodyContains(elt)) { - eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); - return; - } - if (ignoreBoostedAnchorCtrlClick(elt, evt)) { - return; - } - if(explicitCancel || shouldCancel(elt)){ - evt.preventDefault(); - } - if (maybeFilterEvent(triggerSpec, evt)) { - return; - } - var eventData = getInternalData(evt); - eventData.triggerSpec = triggerSpec; - if (eventData.handledFor == null) { - eventData.handledFor = []; - } - var elementData = getInternalData(elt); - if (eventData.handledFor.indexOf(elt) < 0) { - eventData.handledFor.push(elt); - if (triggerSpec.consume) { - evt.stopPropagation(); - } - if (triggerSpec.target && evt.target) { - if (!matches(evt.target, triggerSpec.target)) { - return; - } - } - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } + forEach(eltsToListenOn, function (eltToListenOn) { + var eventListener = function (evt) { + if (!bodyContains(elt)) { + eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); + return; } - if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { - return; - } else { - elementData.lastValue = elt.value; - } + if (ignoreBoostedAnchorCtrlClick(elt, evt)) { + return; } - if (elementData.delayed) { - clearTimeout(elementData.delayed); + if (explicitCancel || shouldCancel(evt, elt)) { + evt.preventDefault(); } - if (elementData.throttle) { + if (maybeFilterEvent(triggerSpec, evt)) { return; } + var eventData = getInternalData(evt); + eventData.triggerSpec = triggerSpec; + if (eventData.handledFor == null) { + eventData.handledFor = []; + } + var elementData = getInternalData(elt); + if (eventData.handledFor.indexOf(elt) < 0) { + eventData.handledFor.push(elt); + if (triggerSpec.consume) { + evt.stopPropagation(); + } + if (triggerSpec.target && evt.target) { + if (!matches(evt.target, triggerSpec.target)) { + return; + } + } + 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); + } + if (elementData.throttle) { + return; + } - if (triggerSpec.throttle) { - if(!elementData.throttle) { + if (triggerSpec.throttle) { + if (!elementData.throttle) { + issueAjaxRequest(verb, path, elt, evt); + elementData.throttle = setTimeout(function () { + elementData.throttle = null; + }, triggerSpec.throttle); + } + } else if (triggerSpec.delay) { + elementData.delayed = setTimeout(function () { + issueAjaxRequest(verb, path, elt, evt); + }, triggerSpec.delay); + } else { issueAjaxRequest(verb, path, elt, evt); - elementData.throttle = setTimeout(function(){ - elementData.throttle = null; - }, triggerSpec.throttle); } - } else if (triggerSpec.delay) { - elementData.delayed = setTimeout(function(){ - issueAjaxRequest(verb, path, elt, evt); - }, triggerSpec.delay); - } else { - issueAjaxRequest(verb, path, elt, evt); } - } - }; - if (nodeData.listenerInfos == null) { - nodeData.listenerInfos = []; - } - nodeData.listenerInfos.push({ - trigger: triggerSpec.trigger, - listener: eventListener, - on: eltToListenOn + }; + if (nodeData.listenerInfos == null) { + nodeData.listenerInfos = []; + } + nodeData.listenerInfos.push({ + trigger: triggerSpec.trigger, + listener: eventListener, + on: eltToListenOn + }) + eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); }) - eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); } var windowIsScrolling = false // used by initScrollHandler @@ -1084,9 +1333,9 @@ return (function () { } function maybeReveal(elt) { - var nodeData = getInternalData(elt); - if (!nodeData.revealed && isScrolledIntoView(elt)) { - nodeData.revealed = true; + if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { + elt.setAttribute('data-hx-revealed', 'true'); + var nodeData = getInternalData(elt); if (nodeData.initialized) { issueAjaxRequest(nodeData.verb, nodeData.path, elt); } else { @@ -1099,6 +1348,10 @@ return (function () { } } + //==================================================================== + // Web Sockets + //==================================================================== + function processWebSocketInfo(elt, nodeData, info) { var values = splitOnWhitespace(info); for (var i = 0; i < values.length; i++) { @@ -1132,7 +1385,7 @@ return (function () { }; socket.onclose = function (e) { - if ([1006, 1012, 1013].includes(e.code)) { // Abnormal Closure/Service Restart/Try Again Later + if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later var delay = getWebSocketReconnectDelay(retryCount); setTimeout(function() { ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout @@ -1193,7 +1446,7 @@ return (function () { return; } webSocket.send(JSON.stringify(filteredParameters)); - if(shouldCancel(elt)){ + if(shouldCancel(evt, elt)){ evt.preventDefault(); } }); @@ -1205,6 +1458,7 @@ return (function () { function getWebSocketReconnectDelay(retryCount) { var delay = htmx.config.wsReconnectDelay; if (typeof delay === 'function') { + // @ts-ignore return delay(retryCount); } if (delay === 'full-jitter') { @@ -1340,7 +1594,7 @@ return (function () { } else if (triggerSpec.trigger === "intersect") { var observerOptions = {}; if (triggerSpec.root) { - observerOptions.root = querySelectorExt(triggerSpec.root) + observerOptions.root = querySelectorExt(elt, triggerSpec.root) } if (triggerSpec.threshold) { observerOptions.threshold = parseFloat(triggerSpec.threshold); @@ -1360,7 +1614,7 @@ return (function () { loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); } else if (triggerSpec.pollInterval) { nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec.pollInterval); + processPolling(elt, verb, path, triggerSpec); } else { addEventListener(elt, verb, path, nodeData, triggerSpec); } @@ -1371,14 +1625,24 @@ return (function () { } function evalScript(script) { - if (script.type === "text/javascript" || script.type === "") { + if (script.type === "text/javascript" || script.type === "module" || script.type === "") { + var newScript = getDocument().createElement("script"); + forEach(script.attributes, function (attr) { + newScript.setAttribute(attr.name, attr.value); + }); + newScript.textContent = script.textContent; + newScript.async = false; + if (htmx.config.inlineScriptNonce) { + newScript.nonce = htmx.config.inlineScriptNonce; + } + var parent = script.parentElement; + try { - maybeEval(script, function () { - // wtf - https://stackoverflow.com/questions/9107240/1-evalthis-vs-evalthis-in-javascript - (1, eval)(script.innerText); - }); + parent.insertBefore(newScript, script); } catch (e) { logError(e); + } finally { + parent.removeChild(script); } } } @@ -1392,21 +1656,41 @@ return (function () { }); } - function isBoosted() { + function hasChanceOfBeingBoosted() { return document.querySelector("[hx-boost], [data-hx-boost]"); } function findElementsToProcess(elt) { if (elt.querySelectorAll) { - var boostedElts = isBoosted() ? ", a, form" : ""; + var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws]"); + " [data-hx-ws], [hx-ext], [hx-data-ext]"); return results; } else { return []; } } + function initButtonTracking(form){ + var maybeSetLastButtonClicked = function(evt){ + if (matches(evt.target, "button, input[type='submit']")) { + var internalData = getInternalData(form); + internalData.lastButtonClicked = evt.target; + } + }; + + // need to handle both click and focus in: + // focusin - in case someone tabs in to a button and hits the space bar + // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + + form.addEventListener('click', maybeSetLastButtonClicked) + form.addEventListener('focusin', maybeSetLastButtonClicked) + form.addEventListener('focusout', function(evt){ + var internalData = getInternalData(form); + internalData.lastButtonClicked = null; + }) + } + function initNode(elt) { if (elt.closest && elt.closest(htmx.config.disableSelector)) { return; @@ -1427,6 +1711,10 @@ return (function () { boostElement(elt, nodeData, triggerSpecs); } + if (elt.tagName === "FORM") { + initButtonTracking(elt); + } + var sseInfo = getAttributeValue(elt, 'hx-sse'); if (sseInfo) { processSSEInfo(elt, nodeData, sseInfo); @@ -1473,6 +1761,15 @@ return (function () { return eventName === "htmx:afterProcessNode" } + /** + * `withExtensions` locates all active extensions for a provided element, then + * executes the provided function using each of the active extensions. It should + * be called internally at every extendable execution point in htmx. + * + * @param {HTMLElement} elt + * @param {(extension:import("./htmx").HtmxExtension) => void} toDo + * @returns void + */ function withExtensions(elt, toDo) { forEach(getExtensions(elt), function(extension){ try { @@ -1520,7 +1817,7 @@ return (function () { //==================================================================== // History Support //==================================================================== - var currentPathForHistory = null; + var currentPathForHistory = location.pathname+location.search; function getHistoryElement() { var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]'); @@ -1569,7 +1866,7 @@ return (function () { return clone.innerHTML; } - function saveHistory() { + function saveCurrentPageToHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); @@ -1598,9 +1895,11 @@ return (function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); var fragment = makeFragment(this.response); + // @ts-ignore fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; var historyElement = getHistoryElement(); var settleInfo = makeSettleInfo(historyElement); + // @ts-ignore swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); currentPathForHistory = path; @@ -1613,7 +1912,7 @@ return (function () { } function restoreHistory(path) { - saveHistory(); + saveCurrentPageToHistory(); path = path || location.pathname+location.search; var cached = getCachedHistory(path); if (cached) { @@ -1628,6 +1927,8 @@ return (function () { triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); } else { if (htmx.config.refreshOnHistoryMiss) { + + // @ts-ignore: optional parameter in reload() function throws error window.location.reload(true); } else { loadHistoryFromServer(path); @@ -1647,10 +1948,8 @@ return (function () { } function addRequestIndicatorClasses(elt) { - var indicator = getClosestAttributeValue(elt, 'hx-indicator'); - if (indicator) { - var indicators = querySelectorAllExt(elt, indicator); - } else { + var indicators = findAttributeTargets(elt, 'hx-indicator'); + if (indicators == null) { indicators = [elt]; } forEach(indicators, function (ic) { @@ -1753,14 +2052,22 @@ return (function () { } } + /** + * @param {HTMLElement} elt + * @param {string} verb + */ function getInputValues(elt, verb) { var processed = []; var values = {}; var formValues = {}; var errors = []; + var internalData = getInternalData(elt); - // only validate when form is directly submitted and novalidate is not set + // only validate when form is directly submitted and novalidate or formnovalidate are not set var validate = matches(elt, 'form') && elt.noValidate !== true; + if (internalData.lastButtonClicked) { + validate = validate && internalData.lastButtonClicked.formNoValidate !== true; + } // for a non-GET include the closest form if (verb !== 'get') { @@ -1770,21 +2077,26 @@ return (function () { // include the element itself processInputValue(processed, values, errors, elt, validate); - // include any explicit includes - var includes = getClosestAttributeValue(elt, "hx-include"); - if (includes) { - var nodes = querySelectorAllExt(elt, includes); - forEach(nodes, function(node) { - processInputValue(processed, values, errors, node, validate); - // if a non-form is included, include any input values within it - if (!matches(node, 'form')) { - forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { - processInputValue(processed, values, errors, descendant, validate); - }) - } - }); + // if a button or submit was clicked last, include its value + if (internalData.lastButtonClicked) { + var name = getRawAttribute(internalData.lastButtonClicked,"name"); + if (name) { + values[name] = internalData.lastButtonClicked.value; + } } + // include any explicit includes + var includes = findAttributeTargets(elt, "hx-include"); + forEach(includes, function(node) { + processInputValue(processed, values, errors, node, validate); + // if a non-form is included, include any input values within it + if (!matches(node, 'form')) { + forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { + processInputValue(processed, values, errors, descendant, validate); + }) + } + }); + // form values take precedence, overriding the regular values values = mergeObjects(values, formValues); @@ -1795,7 +2107,11 @@ return (function () { if (returnStr !== "") { returnStr += "&"; } - returnStr += encodeURIComponent(name) + "=" + encodeURIComponent(realValue); + if (String(realValue) === "[object Object]") { + realValue = JSON.stringify(realValue); + } + var s = encodeURIComponent(realValue); + returnStr += encodeURIComponent(name) + "=" + s; return returnStr; } @@ -1837,6 +2153,12 @@ return (function () { // Ajax //==================================================================== + /** + * @param {HTMLElement} elt + * @param {HTMLElement} target + * @param {string} prompt + * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification + */ function getHeaders(elt, target, prompt) { var headers = { "HX-Request" : "true", @@ -1849,9 +2171,20 @@ return (function () { if (prompt !== undefined) { headers["HX-Prompt"] = prompt; } + if (getInternalData(elt).boosted) { + headers["HX-Boosted"] = "true"; + } return headers; } + /** + * filterValues takes an object containing form input values + * and returns a new object that only contains keys that are + * specified by the closest "hx-params" attribute + * @param {Object} inputValues + * @param {HTMLElement} elt + * @returns {Object} + */ function filterValues(inputValues, elt) { var paramsValue = getClosestAttributeValue(elt, "hx-params"); if (paramsValue) { @@ -1882,8 +2215,14 @@ return (function () { return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0 } - function getSwapSpecification(elt) { - var swapInfo = getClosestAttributeValue(elt, "hx-swap"); + /** + * + * @param {HTMLElement} elt + * @param {string} swapInfoOverride + * @returns {import("./htmx").HtmxSwapSpecification} + */ + function getSwapSpecification(elt, swapInfoOverride) { + var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap"); var swapSpec = { "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, "swapDelay" : htmx.config.defaultSwapDelay, @@ -1905,10 +2244,24 @@ return (function () { swapSpec["settleDelay"] = parseInterval(modifier.substr(7)); } if (modifier.indexOf("scroll:") === 0) { - swapSpec["scroll"] = modifier.substr(7); + var scrollSpec = modifier.substr(7); + var splitSpec = scrollSpec.split(":"); + var scrollVal = splitSpec.pop(); + var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; + swapSpec["scroll"] = scrollVal; + swapSpec["scrollTarget"] = selectorVal; } if (modifier.indexOf("show:") === 0) { - swapSpec["show"] = modifier.substr(5); + var showSpec = modifier.substr(5); + var splitSpec = showSpec.split(":"); + var showVal = splitSpec.pop(); + var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; + swapSpec["show"] = showVal; + swapSpec["showTarget"] = selectorVal; + } + if (modifier.indexOf("focus-scroll:") === 0) { + var focusScrollVal = modifier.substr("focus-scroll:".length); + swapSpec["focusScroll"] = focusScrollVal == "true"; } } } @@ -1926,7 +2279,8 @@ return (function () { if (encodedParameters != null) { return encodedParameters; } else { - if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data") { + if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || + (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) { return makeFormData(filteredParameters); } else { return urlEncode(filteredParameters); @@ -1934,6 +2288,11 @@ return (function () { } } + /** + * + * @param {Element} target + * @returns {import("./htmx").HtmxSettleInfo} + */ function makeSettleInfo(target) { return {tasks: [], elts: [target]}; } @@ -1942,23 +2301,46 @@ return (function () { var first = content[0]; var last = content[content.length - 1]; if (swapSpec.scroll) { - if (swapSpec.scroll === "top" && first) { - first.scrollTop = 0; + var target = null; + if (swapSpec.scrollTarget) { + target = querySelectorExt(first, swapSpec.scrollTarget); + } + if (swapSpec.scroll === "top" && (first || target)) { + target = target || first; + target.scrollTop = 0; } - if (swapSpec.scroll === "bottom" && last) { - last.scrollTop = last.scrollHeight; + if (swapSpec.scroll === "bottom" && (last || target)) { + target = target || last; + target.scrollTop = target.scrollHeight; } } if (swapSpec.show) { - if (swapSpec.show === "top" && first) { - first.scrollIntoView(true); + var target = null; + if (swapSpec.showTarget) { + var targetStr = swapSpec.showTarget; + if (swapSpec.showTarget === "window") { + targetStr = "body"; + } + target = querySelectorExt(first, targetStr); + } + if (swapSpec.show === "top" && (first || target)) { + target = target || first; + target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior}); } - if (swapSpec.show === "bottom" && last) { - last.scrollIntoView(false); + if (swapSpec.show === "bottom" && (last || target)) { + target = target || last; + target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior}); } } } + /** + * @param {HTMLElement} elt + * @param {string} attr + * @param {boolean=} evalAsDefault + * @param {Object=} values + * @returns {Object} + */ function getValuesForElement(elt, attr, evalAsDefault, values) { if (values == null) { values = {}; @@ -1973,6 +2355,9 @@ return (function () { if (str.indexOf("javascript:") === 0) { str = str.substr(11); evaluateValue = true; + } else if (str.indexOf("js:") === 0) { + str = str.substr(3); + evaluateValue = true; } if (str.indexOf('{') !== 0) { str = "{" + str + "}"; @@ -2003,14 +2388,28 @@ return (function () { } } + /** + * @param {HTMLElement} elt + * @param {*} expressionVars + * @returns + */ function getHXVarsForElement(elt, expressionVars) { return getValuesForElement(elt, "hx-vars", true, expressionVars); } + /** + * @param {HTMLElement} elt + * @param {*} expressionVars + * @returns + */ function getHXValsForElement(elt, expressionVars) { return getValuesForElement(elt, "hx-vals", false, expressionVars); } + /** + * @param {HTMLElement} elt + * @returns {Object} + */ function getExpressionVars(elt) { return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)); } @@ -2044,10 +2443,12 @@ return (function () { } function ajaxHelper(verb, path, context) { + verb = verb.toLowerCase(); if (context) { if (context instanceof Element || isType(context, 'String')) { return issueAjaxRequest(verb, path, null, null, { - targetOverride: resolveTarget(context) + targetOverride: resolveTarget(context), + returnPromise: true }); } else { return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, @@ -2055,11 +2456,15 @@ return (function () { handler : context.handler, headers : context.headers, values : context.values, - targetOverride: resolveTarget(context.target) + targetOverride: resolveTarget(context.target), + swapOverride: context.swap, + returnPromise: true }); } } else { - return issueAjaxRequest(verb, path); + return issueAjaxRequest(verb, path, null, null, { + returnPromise: true + }); } } @@ -2076,7 +2481,7 @@ return (function () { var resolve = null; var reject = null; etc = etc != null ? etc : {}; - if(typeof Promise !== "undefined"){ + if(etc.returnPromise && typeof Promise !== "undefined"){ var promise = new Promise(function (_resolve, _reject) { resolve = _resolve; reject = _reject; @@ -2091,40 +2496,85 @@ return (function () { return; // do not issue requests for elements removed from the DOM } var target = etc.targetOverride || getTarget(elt); - if (target == null) { + if (target == null || target == DUMMY_ELT) { triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); return; } + + var syncElt = elt; var eltData = getInternalData(elt); - if (eltData.requestInFlight) { - var queueStrategy = 'last'; - var eventData = getInternalData(event); - if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { - queueStrategy = eventData.triggerSpec.queue; - } - if (eltData.queuedRequests == null) { - eltData.queuedRequests = []; - } - if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); - } else if (queueStrategy === "all") { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); - } else if (queueStrategy === "last") { - eltData.queuedRequests = []; // dump existing queue - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); + var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); + var queueStrategy = null; + var abortable = false; + if (syncStrategy) { + var syncStrings = syncStrategy.split(":"); + var selector = syncStrings[0].trim(); + if (selector === "this") { + syncElt = findThisElement(elt, 'hx-sync'); + } else { + syncElt = querySelectorExt(elt, selector); + } + // default to the drop strategy + syncStrategy = (syncStrings[1] || 'drop').trim(); + eltData = getInternalData(syncElt); + if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { + return; + } else if (syncStrategy === "abort") { + if (eltData.xhr) { + return; + } else { + abortable = true; + } + } else if (syncStrategy === "replace") { + triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue + } else if (syncStrategy.indexOf("queue") === 0) { + var queueStrArray = syncStrategy.split(" "); + queueStrategy = (queueStrArray[1] || "last").trim(); } - return; - } else { - eltData.requestInFlight = true; } + + if (eltData.xhr) { + if (eltData.abortable) { + triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue + } else { + if(queueStrategy == null){ + if (event) { + var eventData = getInternalData(event); + if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { + queueStrategy = eventData.triggerSpec.queue; + } + } + if (queueStrategy == null) { + queueStrategy = "last"; + } + } + if (eltData.queuedRequests == null) { + eltData.queuedRequests = []; + } + if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } else if (queueStrategy === "all") { + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } else if (queueStrategy === "last") { + eltData.queuedRequests = []; // dump existing queue + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } + return; + } + } + + var xhr = new XMLHttpRequest(); + eltData.xhr = xhr; + eltData.abortable = abortable; var endRequestLock = function(){ - eltData.requestInFlight = false + eltData.xhr = null; + eltData.abortable = false; if (eltData.queuedRequests != null && eltData.queuedRequests.length > 0) { var queuedRequest = eltData.queuedRequests.shift(); @@ -2152,11 +2602,10 @@ return (function () { } } - var xhr = new XMLHttpRequest(); var headers = getHeaders(elt, target, promptResponse); if (etc.headers) { - headers = mergeObjects(headers, etc.values); + headers = mergeObjects(headers, etc.headers); } var results = getInputValues(elt, verb); var errors = results.errors; @@ -2169,7 +2618,7 @@ return (function () { var filteredParameters = filterValues(allParameters, elt); if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null) { - headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; + headers['Content-Type'] = 'application/x-www-form-urlencoded'; } // behavior of anchors w/ empty href is to use the current URL @@ -2177,6 +2626,8 @@ return (function () { path = getDocument().location.href; } + var requestAttrValues = getValuesForElement(elt, 'hx-request'); + var requestConfig = { parameters: filteredParameters, unfilteredParameters: allParameters, @@ -2184,6 +2635,8 @@ return (function () { target:target, verb:verb, errors:errors, + withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, + timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, path:path, triggeringEvent:event }; @@ -2231,17 +2684,22 @@ return (function () { } xhr.overrideMimeType("text/html"); - xhr.withCredentials = htmx.config.withCredentials; + xhr.withCredentials = requestConfig.withCredentials; + xhr.timeout = requestConfig.timeout; // request headers - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - var headerValue = headers[header]; - safelySetHeaderValue(xhr, header, headerValue); + if (requestAttrValues.noHeaders) { + // ignore all headers + } else { + for (var header in headers) { + if (headers.hasOwnProperty(header)) { + var headerValue = headers[header]; + safelySetHeaderValue(xhr, header, headerValue); + } } } - var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, pathInfo:{ + var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, etc:etc, pathInfo:{ path:path, finalPath:finalPathForGet, anchor:anchor } }; @@ -2289,6 +2747,13 @@ return (function () { maybeCall(reject); endRequestLock(); } + xhr.ontimeout = function() { + removeRequestIndicatorClasses(indicators); + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); + triggerErrorEvent(elt, 'htmx:timeout', responseInfo); + maybeCall(reject); + endRequestLock(); + } if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){ maybeCall(resolve); endRequestLock() @@ -2315,6 +2780,7 @@ return (function () { function handleAjaxResponse(elt, responseInfo) { var xhr = responseInfo.xhr; var target = responseInfo.target; + var etc = responseInfo.etc; if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; @@ -2338,123 +2804,162 @@ return (function () { } } - var shouldSaveHistory = shouldPush(elt) || pushedUrl; + if (hasHeader(xhr,/HX-Retarget:/i)) { + responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget")); + } - if (xhr.status >= 200 && xhr.status < 400) { + /** @type {boolean} */ + var shouldSaveHistory + if (pushedUrl == "false") { + shouldSaveHistory = false + } else { + shouldSaveHistory = shouldPush(elt) || pushedUrl; + } + + // by default htmx only swaps on 200 return codes and does not swap + // on 204 'No Content' + // this can be ovverriden by responding to the htmx:beforeSwap event and + // overriding the detail.shouldSwap property + var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; + var serverResponse = xhr.response; + var isError = xhr.status >= 400; + var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo); + if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; + + target = beforeSwapDetails.target; // allow re-targeting + serverResponse = beforeSwapDetails.serverResponse; // allow updating content + isError = beforeSwapDetails.isError; // allow updating error + + responseInfo.failed = isError; // Make failed property available to response events + responseInfo.successful = !isError; // Make successful property available to response events + + if (beforeSwapDetails.shouldSwap) { if (xhr.status === 286) { cancelPolling(elt); } - // don't process 'No Content' - if (xhr.status !== 204) { - if (!triggerEvent(target, 'htmx:beforeSwap', responseInfo)) return; - var serverResponse = xhr.response; - withExtensions(elt, function(extension){ - serverResponse = extension.transformResponse(serverResponse, xhr, elt); - }); + withExtensions(elt, function (extension) { + serverResponse = extension.transformResponse(serverResponse, xhr, elt); + }); - // Save current page - if (shouldSaveHistory) { - saveHistory(); - } + // Save current page + if (shouldSaveHistory) { + saveCurrentPageToHistory(); + } + + var swapOverride = etc.swapOverride; + var swapSpec = getSwapSpecification(elt, swapOverride); - var swapSpec = getSwapSpecification(elt); + target.classList.add(htmx.config.swappingClass); + var doSwap = function () { + try { - target.classList.add(htmx.config.swappingClass); - var doSwap = function () { + var activeElt = document.activeElement; + var selectionInfo = {}; try { + selectionInfo = { + elt: activeElt, + // @ts-ignore + start: activeElt ? activeElt.selectionStart : null, + // @ts-ignore + end: activeElt ? activeElt.selectionEnd : null + }; + } catch (e) { + // safari issue - see https://github.com/microsoft/playwright/issues/5894 + } - var activeElt = document.activeElement; - var selectionInfo = {}; - try { - selectionInfo = { - elt: activeElt, - start: activeElt ? activeElt.selectionStart : null, - end: activeElt ? activeElt.selectionEnd : null - }; - } catch (e) { - // safari issue - see https://github.com/microsoft/playwright/issues/5894 + var settleInfo = makeSettleInfo(target); + selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + + if (selectionInfo.elt && + !bodyContains(selectionInfo.elt) && + selectionInfo.elt.id) { + var newActiveElt = document.getElementById(selectionInfo.elt.id); + var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; + if (newActiveElt) { + // @ts-ignore + if (selectionInfo.start && newActiveElt.setSelectionRange) { + // @ts-ignore + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + } + newActiveElt.focus(focusOptions); } + } - var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + target.classList.remove(htmx.config.swappingClass); + forEach(settleInfo.elts, function (elt) { + if (elt.classList) { + elt.classList.add(htmx.config.settlingClass); + } + triggerEvent(elt, 'htmx:afterSwap', responseInfo); + }); + if (responseInfo.pathInfo.anchor) { + location.hash = responseInfo.pathInfo.anchor; + } - if (selectionInfo.elt && - !bodyContains(selectionInfo.elt) && - selectionInfo.elt.id) { - var newActiveElt = document.getElementById(selectionInfo.elt.id); - if (newActiveElt) { - if (selectionInfo.start && newActiveElt.setSelectionRange) { - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); - } - newActiveElt.focus(); - } + if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { + var finalElt = elt; + if (!bodyContains(elt)) { + finalElt = getDocument().body; } + handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); + } - target.classList.remove(htmx.config.swappingClass); + var doSettle = function () { + forEach(settleInfo.tasks, function (task) { + task.call(); + }); forEach(settleInfo.elts, function (elt) { if (elt.classList) { - elt.classList.add(htmx.config.settlingClass); + elt.classList.remove(htmx.config.settlingClass); } - triggerEvent(elt, 'htmx:afterSwap', responseInfo); + triggerEvent(elt, 'htmx:afterSettle', responseInfo); }); - if (responseInfo.pathInfo.anchor) { - location.hash = responseInfo.pathInfo.anchor; + // push URL and save new page + if (shouldSaveHistory) { + var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; + pushUrlIntoHistory(pathToPush); + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: pathToPush}); } - if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; + if(settleInfo.title) { + var titleElt = find("title"); + if(titleElt) { + titleElt.innerHTML = settleInfo.title; + } else { + window.document.title = settleInfo.title; } - handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); } - var doSettle = function(){ - forEach(settleInfo.tasks, function (task) { - task.call(); - }); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.remove(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSettle', responseInfo); - }); - // push URL and save new page - if (shouldSaveHistory) { - var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; - pushUrlIntoHistory(pathToPush); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path:pathToPush}); - } - updateScrollState(settleInfo.elts, swapSpec); + updateScrollState(settleInfo.elts, swapSpec); - if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); + if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { + var finalElt = elt; + if (!bodyContains(elt)) { + finalElt = getDocument().body; } + handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'htmx:swapError', responseInfo); - throw e; } - }; - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); + if (swapSpec.settleDelay > 0) { + setTimeout(doSettle, swapSpec.settleDelay) + } else { + doSettle(); + } + } catch (e) { + triggerErrorEvent(elt, 'htmx:swapError', responseInfo); + throw e; } + }; + + if (swapSpec.swapDelay > 0) { + setTimeout(doSwap, swapSpec.swapDelay) + } else { + doSwap(); } - } else { + } + if (isError) { triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.path}, responseInfo)); } } @@ -2462,9 +2967,17 @@ return (function () { //==================================================================== // Extensions API //==================================================================== + + /** @type {Object<string, import("./htmx").HtmxExtension>} */ var extensions = {}; + + /** + * extensionBase defines the default functions for all extensions. + * @returns {import("./htmx").HtmxExtension} + */ function extensionBase() { return { + init: function(api) {return null;}, onEvent : function(name, evt) {return true;}, transformResponse : function(text, xhr, elt) {return text;}, isInlineSwap : function(swapStyle) {return false;}, @@ -2473,15 +2986,37 @@ return (function () { } } + /** + * defineExtension initializes the extension and adds it to the htmx registry + * + * @param {string} name + * @param {import("./htmx").HtmxExtension} extension + */ function defineExtension(name, extension) { + if(extension.init) { + extension.init(internalAPI) + } extensions[name] = mergeObjects(extensionBase(), extension); } + /** + * removeExtension removes an extension from the htmx registry + * + * @param {string} name + */ function removeExtension(name) { delete extensions[name]; } - function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + /** + * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element + * + * @param {HTMLElement} elt + * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn + * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore + */ + function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + if (elt == undefined) { return extensionsToReturn; } @@ -2536,6 +3071,7 @@ return (function () { function getMetaConfig() { var element = getDocument().querySelector('meta[name="htmx-config"]'); if (element) { + // @ts-ignore return parseJSON(element.content); } else { return null; @@ -2555,9 +3091,25 @@ return (function () { insertIndicatorStyles(); var body = getDocument().body; processNode(body); + var restoredElts = getDocument().querySelectorAll( + "[hx-trigger='restored'],[data-hx-trigger='restored']" + ); + body.addEventListener("htmx:abort", function (evt) { + var target = evt.target; + var internalData = getInternalData(target); + if (internalData && internalData.xhr) { + internalData.xhr.abort(); + } + }); window.onpopstate = function (event) { if (event.state && event.state.htmx) { restoreHistory(); + forEach(restoredElts, function(elt){ + triggerEvent(elt, 'htmx:restored', { + 'document': getDocument(), + 'triggerEvent': triggerEvent + }); + }); } }; setTimeout(function () { diff --git a/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.min.js b/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.min.js index 57f33b2..998414c 100644 --- a/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.min.js +++ b/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.min.js @@ -1 +1 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var k={onLoad:t,process:rt,on:I,off:M,trigger:lt,ajax:$t,find:w,findAll:S,closest:L,values:function(e,t){var r=Lt(e,t||"post");return r.values},remove:E,addClass:q,removeClass:R,toggleClass:C,takeClass:O,defineExtension:Qt,removeExtension:er,logAll:b,logger:null,useTemplateFragments:false,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,attributesToSettle:["class","style","width","height"],withCredentials:false,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]"},parseInterval:f,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])}};var r=["get","post","put","delete","patch"];var n=r.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function f(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function l(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function D(e,t){return l(e,t)||l(e,"data-"+t)}function c(e){return e.parentElement}function F(){return document}function h(e,t){if(t(e)){return e}else if(c(e)){return h(c(e),t)}else{return null}}function X(e,t){var r=null;h(e,function(e){return r=D(e,t)});return r}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function i(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 o(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=F().createDocumentFragment()}return i}function u(e){if(k.config.useTemplateFragments){var t=o("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=i(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return o("<table>"+e+"</table>",1);case"col":return o("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return o("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return o("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return o("<div>"+e+"</div>",1);default:return o(e,0)}}}function P(e){if(e){e()}}function a(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function v(e){return a(e,"Function")}function g(e){return a(e,"Object")}function U(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function p(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function j(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function m(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function z(e){return F().body.contains(e)}function y(e){return e.trim().split(/\s+/)}function V(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function x(e){try{return JSON.parse(e)}catch(e){ut(e);return null}}function e(e){return Ut(F().body,function(){return eval(e)})}function t(t){var e=k.on("htmx:load",function(e){t(e.detail.elt)});return e}function b(){k.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function w(e,t){if(t){return e.querySelector(t)}else{return w(F(),e)}}function S(e,t){if(t){return e.querySelectorAll(t)}else{return S(F(),e)}}function E(e,t){e=H(e);if(t){setTimeout(function(){E(e)},t)}else{e.parentElement.removeChild(e)}}function q(e,t,r){e=H(e);if(r){setTimeout(function(){q(e,t)},r)}else{e.classList.add(t)}}function R(e,t,r){e=H(e);if(r){setTimeout(function(){R(e,t)},r)}else{e.classList.remove(t)}}function C(e,t){e=H(e);e.classList.toggle(t)}function O(e,t){e=H(e);j(e.parentElement.children,function(e){R(e,t)});q(e,t)}function L(e,t){e=H(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&c(e))}}function A(e,t){if(t.indexOf("closest ")===0){return[L(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[w(e,t.substr(5))]}else{return F().querySelectorAll(t)}}function T(e,t){return A(e,t)[0]}function H(e){if(a(e,"String")){return w(e)}else{return e}}function N(e,t,r){if(v(t)){return{target:F().body,event:e,listener:t}}else{return{target:H(e),event:t,listener:r}}}function I(t,r,n){rr(function(){var e=N(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=v(r);return e?r:n}function M(t,r,n){rr(function(){var e=N(t,r,n);e.target.removeEventListener(e.event,e.listener)});return v(r)?r:n}function _(e){var t=h(e,function(e){return D(e,"hx-target")!==null});if(t){var r=D(t,"hx-target");if(r==="this"){return t}else{return T(e,r)}}else{var n=U(e);if(n.boosted){return F().body}else{return e}}}function B(e){var t=k.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function W(t,r){j(t.attributes,function(e){if(!r.hasAttribute(e.name)&&B(e.name)){t.removeAttribute(e.name)}});j(r.attributes,function(e){if(B(e.name)){t.setAttribute(e.name,e.value)}})}function $(e,t){var r=tr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){ut(e)}}return e==="outerHTML"}function J(e,t,r){var n="#"+t.id;var i="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){i=e.substr(0,e.indexOf(":"));n=e.substr(e.indexOf(":")+1,e.length)}else{i=e}var o=F().querySelector(n);if(o){var a;a=F().createDocumentFragment();a.appendChild(t);if(!$(i,o)){a=t}le(i,o,o,a,r)}else{t.parentNode.removeChild(t);ot(F().body,"htmx:oobErrorNoTarget",{content:t})}return e}function Z(e,r){j(S(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=D(e,"hx-swap-oob");if(t!=null){J(t,e,r)}})}function G(e){j(S(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=D(e,"id");var r=F().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function K(n,e,i){j(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();W(e,t);i.tasks.push(function(){W(e,r)})}}})}function Y(e){return function(){rt(e);Ye(e);Q(e);lt(e,"htmx:load")}}function Q(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ee(e,t,r,n){K(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Y(i))}}}function te(t){var e=U(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}if(e.listenerInfos){j(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){j(t.children,function(e){te(e)})}}function re(e,t,r){if(e.tagName==="BODY"){return se(e,t,r)}else{var n=e.previousSibling;ee(c(e),e,t,r);if(n==null){var i=c(e).firstChild}else{var i=n.nextSibling}U(e).replacedWith=i;r.elts=[];while(i&&i!==e){if(i.nodeType===Node.ELEMENT_NODE){r.elts.push(i)}i=i.nextElementSibling}te(e);c(e).removeChild(e)}}function ne(e,t,r){return ee(e,e.firstChild,t,r)}function ie(e,t,r){return ee(c(e),e,t,r)}function oe(e,t,r){return ee(e,null,t,r)}function ae(e,t,r){return ee(c(e),e.nextSibling,t,r)}function se(e,t,r){var n=e.firstChild;ee(e,n,t,r);if(n){while(n.nextSibling){te(n.nextSibling);e.removeChild(n.nextSibling)}te(n);e.removeChild(n)}}function ue(e,t){var r=X(e,"hx-select");if(r){var n=F().createDocumentFragment();j(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function le(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":re(r,n,i);return;case"afterbegin":ne(r,n,i);return;case"beforebegin":ie(r,n,i);return;case"beforeend":oe(r,n,i);return;case"afterend":ae(r,n,i);return;default:var o=tr(t);for(var a=0;a<o.length;a++){var s=o[a];try{var u=s.handleSwap(e,r,n,i);if(u){if(typeof u.length!=="undefined"){for(var l=0;l<u.length;l++){var f=u[l];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Y(f))}}}return}}catch(e){ut(e)}}se(r,n,i)}}var fe=/<title>([\s\S]+?)<\/title>/im;function ce(e){if(e.indexOf("<title>")>-1&&(e.indexOf("<svg>")==-1||e.indexOf("<title>")<e.indexOf("<svg>"))){var t=fe.exec(e);if(t){return t[1]}}}function he(e,t,r,n,i){var o=ce(n);if(o){var a=w("title");if(a){a.innerHTML=o}else{window.document.title=o}}var s=u(n);if(s){Z(s,i);s=ue(r,s);G(s);return le(e,r,t,s,i)}}function de(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=x(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!g(a)){a={value:a}}lt(r,o,a)}}}else{lt(r,n,[])}}var ve=/\s/;var ge=/[\s,]/;var pe=/[_$a-zA-Z]/;var me=/[_$a-zA-Z0-9]/;var ye=['"',"'","/"];var xe=/[^\s]/;function be(e){var t=[];var r=0;while(r<e.length){if(pe.exec(e.charAt(r))){var n=r;while(me.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(ye.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function we(e,t,r){return pe.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function Se(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Ut(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){ot(F().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(we(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function Ee(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var qe="input, textarea, select";function Re(e){var t=D(e,"hx-trigger");var r=[];if(t){var n=be(t);do{Ee(n,xe);var i=n.length;var o=Ee(n,/[,\[\s]/);if(o!==""){if(o==="every"){var a={trigger:"every"};Ee(n,xe);a.pollInterval=f(Ee(n,ve));r.push(a)}else if(o.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:o.substr(4)})}else{var s={trigger:o};var u=Se(e,n,"event");if(u){s.eventFilter=u}while(n.length>0&&n[0]!==","){Ee(n,xe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=f(Ee(n,ge))}else if(l==="from"&&n[0]===":"){n.shift();s.from=Ee(n,ge)}else if(l==="target"&&n[0]===":"){n.shift();s.target=Ee(n,ge)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=f(Ee(n,ge))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=Ee(n,ge)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=Ee(n,ge)}else{ot(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===i){ot(e,"htmx:syntax:error",{token:n.shift()})}Ee(n,xe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,qe)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ce(e){U(e).cancelled=true}function Oe(e,t,r,n){var i=U(e);i.timeout=setTimeout(function(){if(z(e)&&i.cancelled!==true){Zt(t,r,e);Oe(e,t,D(e,"hx-"+t),n)}},n)}function Le(e){return location.hostname===e.hostname&&l(e,"href")&&l(e,"href").indexOf("#")!==0}function Ae(t,r,e){if(t.tagName==="A"&&Le(t)||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=l(t,"href");r.pushURL=true}else{var o=l(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=l(t,"action")}e.forEach(function(e){Ie(t,n,i,r,e,true)})}}function Te(e){return e.tagName==="FORM"||d(e,'input[type="submit"], button')&&L(e,"form")!==null||e.tagName==="A"&&e.href&&(e.getAttribute("href")==="#"||e.getAttribute("href").indexOf("#")!==0)}function He(e,t){return U(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function Ne(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){ot(F().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Ie(n,i,o,e,a,s){var u=n;if(a.from){u=w(a.from)}var l=function(e){if(!z(n)){u.removeEventListener(a.trigger,l);return}if(He(n,e)){return}if(s||Te(n)){e.preventDefault()}if(Ne(a,e)){return}var t=U(e);t.triggerSpec=a;if(t.handledFor==null){t.handledFor=[]}var r=U(n);if(t.handledFor.indexOf(n)<0){t.handledFor.push(n);if(a.consume){e.stopPropagation()}if(a.target&&e.target){if(!d(e.target,a.target)){return}}if(a.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(a.changed){if(r.lastValue===n.value){return}else{r.lastValue=n.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(a.throttle){if(!r.throttle){Zt(i,o,n,e);r.throttle=setTimeout(function(){r.throttle=null},a.throttle)}}else if(a.delay){r.delayed=setTimeout(function(){Zt(i,o,n,e)},a.delay)}else{Zt(i,o,n,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:a.trigger,listener:l,on:u});u.addEventListener(a.trigger,l)}var Me=false;var ke=null;function De(){if(!ke){ke=function(){Me=true};window.addEventListener("scroll",ke);setInterval(function(){if(Me){Me=false;j(F().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){Fe(e)})}},200)}}function Fe(e){var t=U(e);if(!t.revealed&&m(e)){t.revealed=true;if(t.initialized){Zt(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Zt(t.verb,t.path,e)},{once:true})}}}function Xe(e,t,r){var n=y(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Pe(e,o[1],0)}if(o[0]==="send"){je(e)}}}function Pe(s,r,n){if(!z(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=k.createWebSocket(r);t.onerror=function(e){ot(s,"htmx:wsError",{error:e,socket:t});Ue(s)};t.onclose=function(e){if([1006,1012,1013].includes(e.code)){var t=ze(n);setTimeout(function(){Pe(s,r,n+1)},t)}};t.onopen=function(e){n=0};U(s).webSocket=t;t.addEventListener("message",function(e){if(Ue(s)){return}var t=e.data;st(s,function(e){t=e.transformResponse(t,null,s)});var r=Ft(s);var n=u(t);var i=p(n.children);for(var o=0;o<i.length;o++){var a=i[o];J(D(a,"hx-swap-oob")||"true",a,r)}mt(r.tasks)})}function Ue(e){if(!z(e)){U(e).webSocket.close();return true}}function je(l){var f=h(l,function(e){return U(e).webSocket!=null});if(f){l.addEventListener(Re(l)[0].trigger,function(e){var t=U(f).webSocket;var r=Nt(l,f);var n=Lt(l,"post");var i=n.errors;var o=n.values;var a=Vt(l);var s=V(o,a);var u=It(s,l);u["HEADERS"]=r;if(i&&i.length>0){lt(l,"htmx:validation:halted",i);return}t.send(JSON.stringify(u));if(Te(l)){e.preventDefault()}})}else{ot(l,"htmx:noWebSocketSourceError")}}function ze(e){var t=k.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}ut('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ve(e,t,r){var n=y(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){_e(e,o[1])}if(o[0]==="swap"){Be(e,o[1])}}}function _e(t,e){var r=k.createEventSource(e);r.onerror=function(e){ot(t,"htmx:sseError",{error:e,source:r});$e(t)};U(t).sseEventSource=r}function Be(o,a){var s=h(o,Je);if(s){var u=U(s).sseEventSource;var l=function(e){if($e(s)){u.removeEventListener(a,l);return}var t=e.data;st(o,function(e){t=e.transformResponse(t,null,o)});var r=kt(o);var n=_(o);var i=Ft(o);he(r.swapStyle,o,n,t,i);mt(i.tasks);lt(o,"htmx:sseMessage",e)};U(o).sseListener=l;u.addEventListener(a,l)}else{ot(o,"htmx:noSSESourceError")}}function We(e,t,r,n){var i=h(e,Je);if(i){var o=U(i).sseEventSource;var a=function(){if(!$e(i)){if(z(e)){Zt(t,r,e)}else{o.removeEventListener(n,a)}}};U(e).sseListener=a;o.addEventListener(n,a)}else{ot(e,"htmx:noSSESourceError")}}function $e(e){if(!z(e)){U(e).sseEventSource.close();return true}}function Je(e){return U(e).sseEventSource!=null}function Ze(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Zt(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function Ge(o,a,e){var t=false;j(r,function(n){if(s(o,"hx-"+n)){var i=D(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){We(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){De();Fe(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=T(e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){lt(o,"intersect");break}}},t);r.observe(o);Ie(o,n,i,a,e)}else if(e.trigger==="load"){Ze(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Oe(o,n,i,e.pollInterval)}else{Ie(o,n,i,a,e)}})}});return t}function Ke(e){if(e.type==="text/javascript"||e.type===""){try{Ut(e,function(){(1,eval)(e.innerText)})}catch(e){ut(e)}}}function Ye(e){if(d(e,"script")){Ke(e)}j(S(e,"script"),function(e){Ke(e)})}function Qe(){return document.querySelector("[hx-boost], [data-hx-boost]")}function et(e){if(e.querySelectorAll){var t=Qe()?", a, form":"";var r=e.querySelectorAll(n+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws]");return r}else{return[]}}function tt(e){if(e.closest&&e.closest(k.config.disableSelector)){return}var t=U(e);if(!t.initialized){t.initialized=true;lt(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=Re(e);var n=Ge(e,t,r);if(!n&&X(e,"hx-boost")==="true"){Ae(e,t,r)}var i=D(e,"hx-sse");if(i){Ve(e,t,i)}var o=D(e,"hx-ws");if(o){Xe(e,t,o)}lt(e,"htmx:afterProcessNode")}}function rt(e){e=H(e);tt(e);j(et(e),function(e){tt(e)})}function nt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function it(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=F().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function ot(e,t,r){lt(e,t,V({error:t},r))}function at(e){return e==="htmx:afterProcessNode"}function st(e,t){j(tr(e),function(e){try{t(e)}catch(e){ut(e)}})}function ut(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function lt(e,t,r){e=H(e);if(r==null){r={}}r["elt"]=e;var n=it(t,r);if(k.logger&&!at(t)){k.logger(e,t,r)}if(r.error){ut(r.error);lt(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=nt(t);if(i&&o!==t){var a=it(o,n.detail);i=i&&e.dispatchEvent(a)}st(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var ft=null;function ct(){var e=F().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||F().body}function ht(e,t,r,n){var i=x(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>k.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ot(F().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function dt(e){var t=x(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function vt(e){var t=k.config.requestClass;var r=e.cloneNode(true);j(S(r,"."+t),function(e){R(e,t)});return r.innerHTML}function gt(){var e=ct();var t=ft||location.pathname+location.search;lt(F().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(k.config.historyEnabled)history.replaceState({htmx:true},F().title,window.location.href);ht(t,vt(e),F().title,window.scrollY)}function pt(e){if(k.config.historyEnabled)history.pushState({htmx:true},"",e);ft=e}function mt(e){j(e,function(e){e.call()})}function yt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};lt(F().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){lt(F().body,"htmx:historyCacheMissLoad",i);var e=u(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=ct();var r=Ft(t);se(t,e,r);mt(r.tasks);ft=n;lt(F().body,"htmx:historyRestore",{path:n})}else{ot(F().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function xt(e){gt();e=e||location.pathname+location.search;var t=dt(e);if(t){var r=u(t.content);var n=ct();var i=Ft(n);se(n,r,i);mt(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);ft=e;lt(F().body,"htmx:historyRestore",{path:e})}else{if(k.config.refreshOnHistoryMiss){window.location.reload(true)}else{yt(e)}}}function bt(e){var t=X(e,"hx-push-url");return t&&t!=="false"||U(e).boosted&&U(e).pushURL}function wt(e){var t=X(e,"hx-push-url");return t==="true"||t==="false"?null:t}function St(e){var t=X(e,"hx-indicator");if(t){var r=A(e,t)}else{r=[e]}j(r,function(e){e.classList["add"].call(e.classList,k.config.requestClass)});return r}function Et(e){j(e,function(e){e.classList["remove"].call(e.classList,k.config.requestClass)})}function qt(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Rt(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 Ct(t,r,n,e,i){if(e==null||qt(t,e)){return}else{t.push(e)}if(Rt(e)){var o=l(e,"name");var a=e.value;if(e.multiple){a=p(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=p(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){Ot(e,n)}}if(d(e,"form")){var u=e.elements;j(u,function(e){Ct(t,r,n,e,i)})}}function Ot(e,t){if(e.willValidate){lt(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});lt(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Lt(e,t){var r=[];var n={};var i={};var o=[];var a=d(e,"form")&&e.noValidate!==true;if(t!=="get"){Ct(r,i,o,L(e,"form"),a)}Ct(r,n,o,e,a);var s=X(e,"hx-include");if(s){var u=A(e,s);j(u,function(e){Ct(r,n,o,e,a);if(!d(e,"form")){j(e.querySelectorAll(qe),function(e){Ct(r,n,o,e,a)})}})}n=V(n,i);return{errors:o,values:n}}function At(e,t,r){if(e!==""){e+="&"}e+=encodeURIComponent(t)+"="+encodeURIComponent(r);return e}function Tt(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){j(n,function(e){t=At(t,r,e)})}else{t=At(t,r,n)}}}return t}function Ht(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){j(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Nt(e,t,r){var n={"HX-Request":"true","HX-Trigger":l(e,"id"),"HX-Trigger-Name":l(e,"name"),"HX-Target":D(t,"id"),"HX-Current-URL":F().location.href};Pt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}return n}function It(t,e){var r=X(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){j(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};j(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Mt(e){return l(e,"href")&&l(e,"href").indexOf("#")>=0}function kt(e){var t=X(e,"hx-swap");var r={swapStyle:U(e).boosted?"innerHTML":k.config.defaultSwapStyle,swapDelay:k.config.defaultSwapDelay,settleDelay:k.config.defaultSettleDelay};if(U(e).boosted&&!Mt(e)){r["show"]="top"}if(t){var n=y(t);if(n.length>0){r["swapStyle"]=n[0];for(var i=1;i<n.length;i++){var o=n[i];if(o.indexOf("swap:")===0){r["swapDelay"]=f(o.substr(5))}if(o.indexOf("settle:")===0){r["settleDelay"]=f(o.substr(7))}if(o.indexOf("scroll:")===0){r["scroll"]=o.substr(7)}if(o.indexOf("show:")===0){r["show"]=o.substr(5)}}}}return r}function Dt(t,r,n){var i=null;st(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(X(r,"hx-encoding")==="multipart/form-data"){return Ht(n)}else{return Tt(n)}}}function Ft(e){return{tasks:[],elts:[e]}}function Xt(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){if(t.scroll==="top"&&r){r.scrollTop=0}if(t.scroll==="bottom"&&n){n.scrollTop=n.scrollHeight}}if(t.show){if(t.show==="top"&&r){r.scrollIntoView(true)}if(t.show==="bottom"&&n){n.scrollIntoView(false)}}}function Pt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=D(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Ut(e,function(){return Function("return ("+o+")")()},{})}else{s=x(o)}for(var u in s){if(s.hasOwnProperty(u)){if(n[u]==null){n[u]=s[u]}}}}return Pt(c(e),t,r,n)}function Ut(e,t,r){if(k.config.allowEval){return t()}else{ot(e,"htmx:evalDisallowedError");return r}}function jt(e,t){return Pt(e,"hx-vars",true,t)}function zt(e,t){return Pt(e,"hx-vals",false,t)}function Vt(e){return V(jt(e),zt(e))}function _t(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Bt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ot(F().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Wt(e,t){return e.getAllResponseHeaders().match(t)}function $t(e,t,r){if(r){if(r instanceof Element||a(r,"String")){return Zt(e,t,null,null,{targetOverride:H(r)})}else{return Zt(e,t,H(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:H(r.target)})}}else{return Zt(e,t)}}function Jt(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Zt(e,t,n,r,i){var o=null;var a=null;i=i!=null?i:{};if(typeof Promise!=="undefined"){var s=new Promise(function(e,t){o=e;a=t})}if(n==null){n=F().body}var u=i.handler||Gt;if(!z(n)){return}var l=i.targetOverride||_(n);if(l==null){ot(n,"htmx:targetError",{target:D(n,"hx-target")});return}var f=U(n);if(f.requestInFlight){var c="last";var h=U(r);if(h&&h.triggerSpec&&h.triggerSpec.queue){c=h.triggerSpec.queue}if(f.queuedRequests==null){f.queuedRequests=[]}if(c==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){Zt(e,t,n,r)})}else if(c==="all"){f.queuedRequests.push(function(){Zt(e,t,n,r)})}else if(c==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){Zt(e,t,n,r)})}return}else{f.requestInFlight=true}var d=function(){f.requestInFlight=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var v=X(n,"hx-prompt");if(v){var g=prompt(v);if(g===null||!lt(n,"htmx:prompt",{prompt:g,target:l})){P(o);d();return s}}var p=X(n,"hx-confirm");if(p){if(!confirm(p)){P(o);d();return s}}var m=new XMLHttpRequest;var y=Nt(n,l,g);if(i.headers){y=V(y,i.values)}var x=Lt(n,e);var b=x.errors;var w=x.values;if(i.values){w=V(w,i.values)}var S=Vt(n);var E=V(w,S);var q=It(E,n);if(e!=="get"&&X(n,"hx-encoding")==null){y["Content-Type"]="application/x-www-form-urlencoded; charset=UTF-8"}if(t==null||t===""){t=F().location.href}var R={parameters:q,unfilteredParameters:E,headers:y,target:l,verb:e,errors:b,path:t,triggeringEvent:r};if(!lt(n,"htmx:configRequest",R)){P(o);d();return s}t=R.path;e=R.verb;y=R.headers;q=R.parameters;b=R.errors;if(b&&b.length>0){lt(n,"htmx:validation:halted",R);P(o);d();return s}var C=t.split("#");var O=C[0];var L=C[1];if(e==="get"){var A=O;var T=Object.keys(q).length!==0;if(T){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=Tt(q);if(L){A+="#"+L}}m.open("GET",A,true)}else{m.open(e.toUpperCase(),t,true)}m.overrideMimeType("text/html");m.withCredentials=k.config.withCredentials;for(var H in y){if(y.hasOwnProperty(H)){var N=y[H];_t(m,H,N)}}var I={xhr:m,target:l,requestConfig:R,pathInfo:{path:t,finalPath:A,anchor:L}};m.onload=function(){try{var e=Jt(n);u(n,I);Et(M);lt(n,"htmx:afterRequest",I);lt(n,"htmx:afterOnLoad",I);if(!z(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(z(r)){t=r}}if(t){lt(t,"htmx:afterRequest",I);lt(t,"htmx:afterOnLoad",I)}}P(o);d()}catch(e){ot(n,"htmx:onLoadError",V({error:e},I));throw e}};m.onerror=function(){Et(M);ot(n,"htmx:afterRequest",I);ot(n,"htmx:sendError",I);P(a);d()};m.onabort=function(){Et(M);ot(n,"htmx:afterRequest",I);ot(n,"htmx:sendAbort",I);P(a);d()};if(!lt(n,"htmx:beforeRequest",I)){P(o);d();return s}var M=St(n);j(["loadstart","loadend","progress","abort"],function(t){j([m,m.upload],function(e){e.addEventListener(t,function(e){lt(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});lt(n,"htmx:beforeSend",I);m.send(e==="get"?null:Dt(m,n,q));return s}function Gt(a,s){var u=s.xhr;var l=s.target;if(!lt(a,"htmx:beforeOnLoad",s))return;if(Wt(u,/HX-Trigger:/i)){de(u,"HX-Trigger",a)}if(Wt(u,/HX-Push:/i)){var f=u.getResponseHeader("HX-Push")}if(Wt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Wt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}var c=bt(a)||f;if(u.status>=200&&u.status<400){if(u.status===286){Ce(a)}if(u.status!==204){if(!lt(l,"htmx:beforeSwap",s))return;var h=u.response;st(a,function(e){h=e.transformResponse(h,u,a)});if(c){gt()}var d=kt(a);l.classList.add(k.config.swappingClass);var e=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r=Ft(l);he(d.swapStyle,l,a,h,r);if(t.elt&&!z(t.elt)&&t.elt.id){var n=document.getElementById(t.elt.id);if(n){if(t.start&&n.setSelectionRange){n.setSelectionRange(t.start,t.end)}n.focus()}}l.classList.remove(k.config.swappingClass);j(r.elts,function(e){if(e.classList){e.classList.add(k.config.settlingClass)}lt(e,"htmx:afterSwap",s)});if(s.pathInfo.anchor){location.hash=s.pathInfo.anchor}if(Wt(u,/HX-Trigger-After-Swap:/i)){var i=a;if(!z(a)){i=F().body}de(u,"HX-Trigger-After-Swap",i)}var o=function(){j(r.tasks,function(e){e.call()});j(r.elts,function(e){if(e.classList){e.classList.remove(k.config.settlingClass)}lt(e,"htmx:afterSettle",s)});if(c){var e=f||wt(a)||Bt(u)||s.pathInfo.finalPath||s.pathInfo.path;pt(e);lt(F().body,"htmx:pushedIntoHistory",{path:e})}Xt(r.elts,d);if(Wt(u,/HX-Trigger-After-Settle:/i)){var t=a;if(!z(a)){t=F().body}de(u,"HX-Trigger-After-Settle",t)}};if(d.settleDelay>0){setTimeout(o,d.settleDelay)}else{o()}}catch(e){ot(a,"htmx:swapError",s);throw e}};if(d.swapDelay>0){setTimeout(e,d.swapDelay)}else{e()}}}else{ot(a,"htmx:responseError",V({error:"Response Status Error Code "+u.status+" from "+s.pathInfo.path},s))}}var Kt={};function Yt(){return{onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Qt(e,t){Kt[e]=V(Yt(),t)}function er(e){delete Kt[e]}function tr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=D(e,"hx-ext");if(t){j(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Kt[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return tr(c(e),r,n)}function rr(e){if(F().readyState!=="loading"){e()}else{F().addEventListener("DOMContentLoaded",e)}}function nr(){if(k.config.includeIndicatorStyles!==false){F().head.insertAdjacentHTML("beforeend","<style> ."+k.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+k.config.requestClass+" ."+k.config.indicatorClass+"{opacity:1} ."+k.config.requestClass+"."+k.config.indicatorClass+"{opacity:1} </style>")}}function ir(){var e=F().querySelector('meta[name="htmx-config"]');if(e){return x(e.content)}else{return null}}function or(){var e=ir();if(e){k.config=V(k.config,e)}}rr(function(){or();nr();var e=F().body;rt(e);window.onpopstate=function(e){if(e.state&&e.state.htmx){xt()}};setTimeout(function(){lt(e,"htmx:load",{})},0)});return k}()}); \ No newline at end of file +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(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 l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=k(e);e.classList.toggle(t)}function T(e,t){e=k(e);W(e.parentElement.children,function(e){q(e,t)});L(e,t)}function H(e,t){e=k(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function N(e,t){if(t.indexOf("closest ")===0){return[H(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[C(e,t.substr(5))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return z().querySelectorAll(t)}}function ee(e,t){if(t){return N(e,t)[0]}else{return N(z().body,e)[0]}}function k(e){if(p(e,"String")){return C(e)}else{return e}}function I(e,t,r){if(m(t)){return{target:z().body,event:e,listener:t}}else{return{target:k(e),event:t,listener:r}}}function M(t,r,n){lr(function(){var e=I(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function D(t,r,n){lr(function(){var e=I(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var te=z().createElement("output");function F(e,t){var r=G(e,t);if(r){if(r==="this"){return[re(e,t)]}else{var n=N(e,r);if(n.length===0){pt('The selector "'+r+'" on '+t+" returned no matches!");return[te]}else{return n}}}}function re(e,t){return h(e,function(e){return V(e,t)!=null})}function ne(e){var t=G(e,"hx-target");if(t){if(t==="this"){return re(e,"hx-target")}else{return ee(e,t)}}else{var r=_(e);if(r.boosted){return z().body}else{return e}}}function P(e){var t=U.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function X(t,r){W(t.attributes,function(e){if(!r.hasAttribute(e.name)&&P(e.name)){t.removeAttribute(e.name)}});W(r.attributes,function(e){if(P(e.name)){t.setAttribute(e.name,e.value)}})}function j(e,t){var r=sr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){pt(e)}}return e==="outerHTML"}function B(e,i,o){var t="#"+i.id;var a="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){a=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{a=e}var r=z().querySelectorAll(t);if(r){W(r,function(e){var t;var r=i.cloneNode(true);t=z().createDocumentFragment();t.appendChild(r);if(!j(a,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ye(a,e,e,t,o)}W(o.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(z().body,"htmx:oobErrorNoTarget",{content:i})}return e}function ie(e,r){W(R(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=V(e,"hx-swap-oob");if(t!=null){B(t,e,r)}})}function oe(e){W(R(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=V(e,"id");var r=z().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function ae(n,e,i){W(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();X(e,t);i.tasks.push(function(){X(e,r)})}}})}function se(e){return function(){q(e,U.config.addedClass);ct(e);at(e);le(e);$(e,"htmx:load")}}function le(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ue(e,t,r,n){ae(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(se(i))}}}function fe(t){var e=_(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){W(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){W(t.children,function(e){fe(e)})}}function ce(e,t,r){if(e.tagName==="BODY"){return me(e,t,r)}else{var n;var i=e.previousSibling;ue(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}_(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}fe(e);u(e).removeChild(e)}}function he(e,t,r){return ue(e,e.firstChild,t,r)}function de(e,t,r){return ue(u(e),e,t,r)}function ve(e,t,r){return ue(e,null,t,r)}function ge(e,t,r){return ue(u(e),e.nextSibling,t,r)}function pe(e,t,r){fe(e);return u(e).removeChild(e)}function me(e,t,r){var n=e.firstChild;ue(e,n,t,r);if(n){while(n.nextSibling){fe(n.nextSibling);e.removeChild(n.nextSibling)}fe(n);e.removeChild(n)}}function xe(e,t){var r=G(e,"hx-select");if(r){var n=z().createDocumentFragment();W(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function ye(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":ce(r,n,i);return;case"afterbegin":he(r,n,i);return;case"beforebegin":de(r,n,i);return;case"beforeend":ve(r,n,i);return;case"afterend":ge(r,n,i);return;case"delete":pe(r,n,i);return;default:var o=sr(t);for(var a=0;a<o.length;a++){var f=o[a];try{var s=f.handleSwap(e,r,n,i);if(s){if(typeof s.length!=="undefined"){for(var l=0;l<s.length;l++){var u=s[l];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){i.tasks.push(se(u))}}}return}}catch(e){pt(e)}}if(e==="innerHTML"){me(r,n,i)}else{ye(U.config.defaultSwapStyle,t,r,n,i)}}}function be(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function we(e,t,r,n,i){i.title=be(n);var o=g(n);if(o){ie(o,i);o=xe(r,o);oe(o);return ye(e,r,t,o,i)}}function Se(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!x(a)){a={value:a}}$(r,o,a)}}}else{$(r,n,[])}}var Ee=/\s/;var Ce=/[\s,]/;var Re=/[_$a-zA-Z]/;var Oe=/[_$a-zA-Z0-9]/;var Le=['"',"'","/"];var qe=/[^\s]/;function Ae(e){var t=[];var r=0;while(r<e.length){if(Re.exec(e.charAt(r))){var n=r;while(Oe.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Le.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function Te(e,t,r){return Re.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function He(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Jt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(z().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(Te(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var Ne="input, textarea, select";function ke(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=Ae(t);do{c(n,qe);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var o={trigger:"every"};c(n,qe);o.pollInterval=v(c(n,/[,\[\s]/));c(n,qe);var a=He(e,n,"event");if(a){o.eventFilter=a}r.push(o)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var a=He(e,n,"event");if(a){s.eventFilter=a}while(n.length>0&&n[0]!==","){c(n,qe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Ce))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Ce);if(u==="closest"||u==="find"){n.shift();u+=" "+c(n,Ce)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Ce)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Ce))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Ce)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Ce)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,qe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,Ne)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ie(e){_(e).cancelled=true}function Me(e,t,r,n){var i=_(e);i.timeout=setTimeout(function(){if(Y(e)&&i.cancelled!==true){if(!je(n,dt("hx:poll:trigger",{triggerSpec:n,target:e}))){Z(t,r,e)}Me(e,t,V(e,"hx-"+t),n)}},n.pollInterval)}function De(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&De(t)&&t.target===""||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href");r.pushURL=true}else{var o=f(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=f(t,"action")}e.forEach(function(e){Be(t,n,i,r,e,true)})}}function Pe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&H(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Xe(e,t){return _(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function je(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(z().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Be(o,a,s,e,l,u){var t;if(l.from){t=N(o,l.from)}else{t=[o]}W(t,function(n){var i=function(e){if(!Y(o)){n.removeEventListener(l.trigger,i);return}if(Xe(o,e)){return}if(u||Pe(e,o)){e.preventDefault()}if(je(l,e)){return}var t=_(e);t.triggerSpec=l;if(t.handledFor==null){t.handledFor=[]}var r=_(o);if(t.handledFor.indexOf(o)<0){t.handledFor.push(o);if(l.consume){e.stopPropagation()}if(l.target&&e.target){if(!d(e.target,l.target)){return}}if(l.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(l.changed){if(r.lastValue===o.value){return}else{r.lastValue=o.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(l.throttle){if(!r.throttle){Z(a,s,o,e);r.throttle=setTimeout(function(){r.throttle=null},l.throttle)}}else if(l.delay){r.delayed=setTimeout(function(){Z(a,s,o,e)},l.delay)}else{Z(a,s,o,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:l.trigger,listener:i,on:n});n.addEventListener(l.trigger,i)})}var Ue=false;var Ve=null;function ze(){if(!Ve){Ve=function(){Ue=true};window.addEventListener("scroll",Ve);setInterval(function(){if(Ue){Ue=false;W(z().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){_e(e)})}},200)}}function _e(e){if(!s(e,"data-hx-revealed")&&b(e)){e.setAttribute("data-hx-revealed","true");var t=_(e);if(t.initialized){Z(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Z(t.verb,t.path,e)},{once:true})}}}function We(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Je(e,o[1],0)}if(o[0]==="send"){Ze(e)}}}function Je(s,r,n){if(!Y(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=U.createWebSocket(r);t.onerror=function(e){J(s,"htmx:wsError",{error:e,socket:t});$e(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=Ge(n);setTimeout(function(){Je(s,r,n+1)},t)}};t.onopen=function(e){n=0};_(s).webSocket=t;t.addEventListener("message",function(e){if($e(s)){return}var t=e.data;gt(s,function(e){t=e.transformResponse(t,null,s)});var r=zt(s);var n=g(t);var i=y(n.children);for(var o=0;o<i.length;o++){var a=i[o];B(V(a,"hx-swap-oob")||"true",a,r)}Ct(r.tasks)})}function $e(e){if(!Y(e)){_(e).webSocket.close();return true}}function Ze(u){var f=h(u,function(e){return _(e).webSocket!=null});if(f){u.addEventListener(ke(u)[0].trigger,function(e){var t=_(f).webSocket;var r=Xt(u,f);var n=Mt(u,"post");var i=n.errors;var o=n.values;var a=Gt(u);var s=Q(o,a);var l=jt(s,u);l["HEADERS"]=r;if(i&&i.length>0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Pe(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ge(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}pt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ke(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Ye(e,o[1])}if(o[0]==="swap"){Qe(e,o[1])}}}function Ye(t,e){var r=U.createEventSource(e);r.onerror=function(e){J(t,"htmx:sseError",{error:e,source:r});tt(t)};_(t).sseEventSource=r}function Qe(o,a){var s=h(o,rt);if(s){var l=_(s).sseEventSource;var u=function(e){if(tt(s)){l.removeEventListener(a,u);return}var t=e.data;gt(o,function(e){t=e.transformResponse(t,null,o)});var r=Ut(o);var n=ne(o);var i=zt(o);we(r.swapStyle,o,n,t,i);Ct(i.tasks);$(o,"htmx:sseMessage",e)};_(o).sseListener=u;l.addEventListener(a,u)}else{J(o,"htmx:noSSESourceError")}}function et(e,t,r,n){var i=h(e,rt);if(i){var o=_(i).sseEventSource;var a=function(){if(!tt(i)){if(Y(e)){Z(t,r,e)}else{o.removeEventListener(n,a)}}};_(e).sseListener=a;o.addEventListener(n,a)}else{J(e,"htmx:noSSESourceError")}}function tt(e){if(!Y(e)){_(e).sseEventSource.close();return true}}function rt(e){return _(e).sseEventSource!=null}function nt(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Z(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function it(o,a,e){var t=false;W(n,function(n){if(s(o,"hx-"+n)){var i=V(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){et(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){ze();_e(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=ee(o,e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){$(o,"intersect");break}}},t);r.observe(o);Be(o,n,i,a,e)}else if(e.trigger==="load"){nt(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Me(o,n,i,e)}else{Be(o,n,i,a,e)}})}});return t}function ot(e){if(e.type==="text/javascript"||e.type==="module"||e.type===""){var t=z().createElement("script");W(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(U.config.inlineScriptNonce){t.nonce=U.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){pt(e)}finally{r.removeChild(e)}}}function at(e){if(d(e,"script")){ot(e)}W(R(e,"script"),function(e){ot(e)})}function st(){return document.querySelector("[hx-boost], [data-hx-boost]")}function lt(e){if(e.querySelectorAll){var t=st()?", a, form":"";var r=e.querySelectorAll(i+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [hx-data-ext]");return r}else{return[]}}function ut(r){var e=function(e){if(d(e.target,"button, input[type='submit']")){var t=_(r);t.lastButtonClicked=e.target}};r.addEventListener("click",e);r.addEventListener("focusin",e);r.addEventListener("focusout",function(e){var t=_(r);t.lastButtonClicked=null})}function ft(e){if(e.closest&&e.closest(U.config.disableSelector)){return}var t=_(e);if(!t.initialized){t.initialized=true;$(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=ke(e);var n=it(e,t,r);if(!n&&G(e,"hx-boost")==="true"){Fe(e,t,r)}if(e.tagName==="FORM"){ut(e)}var i=V(e,"hx-sse");if(i){Ke(e,t,i)}var o=V(e,"hx-ws");if(o){We(e,t,o)}$(e,"htmx:afterProcessNode")}}function ct(e){e=k(e);ft(e);W(lt(e),function(e){ft(e)})}function ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function dt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=z().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function J(e,t,r){$(e,t,Q({error:t},r))}function vt(e){return e==="htmx:afterProcessNode"}function gt(e,t){W(sr(e),function(e){try{t(e)}catch(e){pt(e)}})}function pt(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function $(e,t,r){e=k(e);if(r==null){r={}}r["elt"]=e;var n=dt(t,r);if(U.logger&&!vt(t)){U.logger(e,t,r)}if(r.error){pt(r.error);$(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=ht(t);if(i&&o!==t){var a=dt(o,n.detail);i=i&&e.dispatchEvent(a)}gt(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var mt=location.pathname+location.search;function xt(){var e=z().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||z().body}function yt(e,t,r,n){var i=S(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>U.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(z().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function bt(e){var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function wt(e){var t=U.config.requestClass;var r=e.cloneNode(true);W(R(r,"."+t),function(e){q(e,t)});return r.innerHTML}function St(){var e=xt();var t=mt||location.pathname+location.search;$(z().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(U.config.historyEnabled)history.replaceState({htmx:true},z().title,window.location.href);yt(t,wt(e),z().title,window.scrollY)}function Et(e){if(U.config.historyEnabled)history.pushState({htmx:true},"",e);mt=e}function Ct(e){W(e,function(e){e.call()})}function Rt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};$(z().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){$(z().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=xt();var r=zt(t);me(t,e,r);Ct(r.tasks);mt=n;$(z().body,"htmx:historyRestore",{path:n})}else{J(z().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Ot(e){St();e=e||location.pathname+location.search;var t=bt(e);if(t){var r=g(t.content);var n=xt();var i=zt(n);me(n,r,i);Ct(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);mt=e;$(z().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Rt(e)}}}function Lt(e){var t=G(e,"hx-push-url");return t&&t!=="false"||_(e).boosted&&_(e).pushURL}function qt(e){var t=G(e,"hx-push-url");return t==="true"||t==="false"?null:t}function At(e){var t=F(e,"hx-indicator");if(t==null){t=[e]}W(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Tt(e){W(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function Ht(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Nt(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 kt(t,r,n,e,i){if(e==null||Ht(t,e)){return}else{t.push(e)}if(Nt(e)){var o=f(e,"name");var a=e.value;if(e.multiple){a=y(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=y(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){It(e,n)}}if(d(e,"form")){var l=e.elements;W(l,function(e){kt(t,r,n,e,i)})}}function It(e,t){if(e.willValidate){$(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});$(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Mt(e,t){var r=[];var n={};var i={};var o=[];var a=_(e);var s=d(e,"form")&&e.noValidate!==true;if(a.lastButtonClicked){s=s&&a.lastButtonClicked.formNoValidate!==true}if(t!=="get"){kt(r,i,o,H(e,"form"),s)}kt(r,n,o,e,s);if(a.lastButtonClicked){var l=f(a.lastButtonClicked,"name");if(l){n[l]=a.lastButtonClicked.value}}var u=F(e,"hx-include");W(u,function(e){kt(r,n,o,e,s);if(!d(e,"form")){W(e.querySelectorAll(Ne),function(e){kt(r,n,o,e,s)})}});n=Q(n,i);return{errors:o,values:n}}function Dt(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function Ft(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=Dt(t,r,e)})}else{t=Dt(t,r,n)}}}return t}function Pt(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){W(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Xt(e,t,r){var n={"HX-Request":"true","HX-Trigger":f(e,"id"),"HX-Trigger-Name":f(e,"name"),"HX-Target":V(t,"id"),"HX-Current-URL":z().location.href};Wt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(_(e).boosted){n["HX-Boosted"]="true"}return n}function jt(t,e){var r=G(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){W(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};W(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Bt(e){return f(e,"href")&&f(e,"href").indexOf("#")>=0}function Ut(e,t){var r=t?t:G(e,"hx-swap");var n={swapStyle:_(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(_(e).boosted&&!Bt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var o=1;o<i.length;o++){var a=i[o];if(a.indexOf("swap:")===0){n["swapDelay"]=v(a.substr(5))}if(a.indexOf("settle:")===0){n["settleDelay"]=v(a.substr(7))}if(a.indexOf("scroll:")===0){var s=a.substr(7);var l=s.split(":");var f=l.pop();var u=l.length>0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(a.indexOf("show:")===0){var c=a.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(a.indexOf("focus-scroll:")===0){var d=a.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function Vt(t,r,n){var i=null;gt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(G(r,"hx-encoding")==="multipart/form-data"||d(r,"form")&&f(r,"enctype")==="multipart/form-data"){return Pt(n)}else{return Ft(n)}}}function zt(e){return{tasks:[],elts:[e]}}function _t(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ee(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var o=t.showTarget;if(t.showTarget==="window"){o="body"}i=ee(r,o)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function Wt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}else if(o.indexOf("js:")===0){o=o.substr(3);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Jt(e,function(){return Function("return ("+o+")")()},{})}else{s=S(o)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Wt(u(e),t,r,n)}function Jt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function $t(e,t){return Wt(e,"hx-vars",true,t)}function Zt(e,t){return Wt(e,"hx-vals",false,t)}function Gt(e){return Q($t(e),Zt(e))}function Kt(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Yt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(z().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Qt(e,t){return e.getAllResponseHeaders().match(t)}function er(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return Z(e,t,null,null,{targetOverride:k(r),returnPromise:true})}else{return Z(e,t,k(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:k(r.target),swapOverride:r.swap,returnPromise:true})}}else{return Z(e,t,null,null,{returnPromise:true})}}function tr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Z(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=z().body}var v=r.handler||rr;if(!Y(n)){return}var g=r.targetOverride||ne(n);if(g==null||g==te){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=_(n);var o=G(n,"hx-sync");var m=null;var x=false;if(o){var y=o.split(":");var b=y[0].trim();if(b==="this"){p=re(n,"hx-sync")}else{p=ee(n,b)}o=(y[1]||"drop").trim();i=_(p);if(o==="drop"&&i.xhr&&i.abortable!==true){return}else if(o==="abort"){if(i.xhr){return}else{x=true}}else if(o==="replace"){$(p,"htmx:abort")}else if(o.indexOf("queue")===0){var w=o.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=_(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){Z(e,t,n,f,r)})}return}}var a=new XMLHttpRequest;i.xhr=a;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=G(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){K(c);s();return d}}var R=G(n,"hx-confirm");if(R){if(!confirm(R)){K(c);s();return d}}var O=Xt(n,g,C);if(r.headers){O=Q(O,r.headers)}var L=Mt(n,e);var q=L.errors;var A=L.values;if(r.values){A=Q(A,r.values)}var T=Gt(n);var H=Q(A,T);var N=jt(H,n);if(e!=="get"&&G(n,"hx-encoding")==null){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=z().location.href}var k=Wt(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:q,withCredentials:r.credentials||k.credentials||U.config.withCredentials,timeout:r.timeout||k.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){K(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;q=l.errors;if(q&&q.length>0){$(n,"htmx:validation:halted",l);K(c);s();return d}var I=t.split("#");var M=I[0];var D=I[1];if(e==="get"){var F=M;var P=Object.keys(N).length!==0;if(P){if(F.indexOf("?")<0){F+="?"}else{F+="&"}F+=Ft(N);if(D){F+="#"+D}}a.open("GET",F,true)}else{a.open(e.toUpperCase(),t,true)}a.overrideMimeType("text/html");a.withCredentials=l.withCredentials;a.timeout=l.timeout;if(k.noHeaders){}else{for(var X in O){if(O.hasOwnProperty(X)){var j=O[X];Kt(a,X,j)}}}var u={xhr:a,target:g,requestConfig:l,etc:r,pathInfo:{path:t,finalPath:F,anchor:D}};a.onload=function(){try{var e=tr(n);v(n,u);Tt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!Y(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(Y(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}K(c);s()}catch(e){J(n,"htmx:onLoadError",Q({error:e},u));throw e}};a.onerror=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);K(h);s()};a.onabort=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);K(h);s()};a.ontimeout=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);K(h);s()};if(!$(n,"htmx:beforeRequest",u)){K(c);s();return d}var B=At(n);W(["loadstart","loadend","progress","abort"],function(t){W([a,a.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);a.send(e==="get"?null:Vt(a,n,N));return d}function rr(s,l){var u=l.xhr;var f=l.target;var r=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(Qt(u,/HX-Trigger:/i)){Se(u,"HX-Trigger",s)}if(Qt(u,/HX-Push:/i)){var c=u.getResponseHeader("HX-Push")}if(Qt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Qt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(Qt(u,/HX-Retarget:/i)){l.target=z().querySelector(u.getResponseHeader("HX-Retarget"))}var h;if(c=="false"){h=false}else{h=Lt(s)||c}var n=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var e=u.status>=400;var t=Q({shouldSwap:n,serverResponse:d,isError:e},l);if(!$(f,"htmx:beforeSwap",t))return;f=t.target;d=t.serverResponse;e=t.isError;l.failed=e;l.successful=!e;if(t.shouldSwap){if(u.status===286){Ie(s)}gt(s,function(e){d=e.transformResponse(d,u,s)});if(h){St()}var i=r.swapOverride;var v=Ut(s,i);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=zt(f);we(v.swapStyle,f,s,d,n);if(t.elt&&!Y(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);W(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(l.pathInfo.anchor){location.hash=l.pathInfo.anchor}if(Qt(u,/HX-Trigger-After-Swap:/i)){var o=s;if(!Y(s)){o=z().body}Se(u,"HX-Trigger-After-Swap",o)}var a=function(){W(n.tasks,function(e){e.call()});W(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h){var e=c||qt(s)||Yt(u)||l.pathInfo.finalPath||l.pathInfo.path;Et(e);$(z().body,"htmx:pushedIntoHistory",{path:e})}if(n.title){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}_t(n.elts,v);if(Qt(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!Y(s)){r=z().body}Se(u,"HX-Trigger-After-Settle",r)}};if(v.settleDelay>0){setTimeout(a,v.settleDelay)}else{a()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(v.swapDelay>0){setTimeout(o,v.swapDelay)}else{o()}}if(e){J(s,"htmx:responseError",Q({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var nr={};function ir(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function or(e,t){if(t.init){t.init(r)}nr[e]=Q(ir(),t)}function ar(e){delete nr[e]}function sr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){W(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=nr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return sr(u(e),r,n)}function lr(e){if(z().readyState!=="loading"){e()}else{z().addEventListener("DOMContentLoaded",e)}}function ur(){if(U.config.includeIndicatorStyles!==false){z().head.insertAdjacentHTML("beforeend","<style> ."+U.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+U.config.requestClass+" ."+U.config.indicatorClass+"{opacity:1} ."+U.config.requestClass+"."+U.config.indicatorClass+"{opacity:1} </style>")}}function fr(){var e=z().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function cr(){var e=fr();if(e){U.config=Q(U.config,e)}}lr(function(){cr();ur();var e=z().body;ct(e);var t=z().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=_(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){Ot();W(t,function(e){$(e,"htmx:restored",{document:z(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file diff --git a/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.js b/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.js index e38f6ed..27e57bc 100644 --- a/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.js +++ b/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.js @@ -1,7 +1,9 @@ //AMD insanity (function (root, factory) { + //@ts-ignore if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. + //@ts-ignore define([], factory); } else { // Browser globals @@ -12,6 +14,8 @@ return (function () { 'use strict'; // Public API + //** @type {import("./htmx").HtmxApi} */ + // TODO: list all methods in public API var htmx = { onLoad: onLoadHelper, process: processNode, @@ -35,7 +39,6 @@ return (function () { removeExtension : removeExtension, logAll : logAll, logger : null, - useTemplateFragments: false, config : { historyEnabled:true, historyCacheSize:10, @@ -46,13 +49,19 @@ return (function () { includeIndicatorStyles:true, indicatorClass:'htmx-indicator', requestClass:'htmx-request', + addedClass:'htmx-added', settlingClass:'htmx-settling', swappingClass:'htmx-swapping', allowEval:true, + inlineScriptNonce:'', attributesToSettle:["class", "style", "width", "height"], withCredentials:false, + timeout:0, wsReconnectDelay: 'full-jitter', disableSelector: "[hx-disable], [data-hx-disable]", + useTemplateFragments: false, + scrollBehavior: 'smooth', + defaultFocusScroll: false, }, parseInterval:parseInterval, _:internalEval, @@ -61,9 +70,36 @@ return (function () { }, createWebSocket: function(url){ return new WebSocket(url, []); - } + }, + version: "1.7.0" }; + /** @type {import("./htmx").HtmxInternalApi} */ + var internalAPI = { + bodyContains: bodyContains, + filterValues: filterValues, + hasAttribute: hasAttribute, + getAttributeValue: getAttributeValue, + getClosestMatch: getClosestMatch, + getExpressionVars: getExpressionVars, + getHeaders: getHeaders, + getInputValues: getInputValues, + getInternalData: getInternalData, + getSwapSpecification: getSwapSpecification, + getTriggerSpecs: getTriggerSpecs, + getTarget: getTarget, + makeFragment: makeFragment, + mergeObjects: mergeObjects, + makeSettleInfo: makeSettleInfo, + oobSwap: oobSwap, + selectAndSwap: selectAndSwap, + settleImmediately: settleImmediately, + shouldCancel: shouldCancel, + triggerEvent: triggerEvent, + triggerErrorEvent: triggerErrorEvent, + withExtensions: withExtensions, + } + var VERBS = ['get', 'post', 'put', 'delete', 'patch']; var VERB_SELECTOR = VERBS.map(function(verb){ return "[hx-" + verb + "], [data-hx-" + verb + "]" @@ -73,19 +109,24 @@ return (function () { // Utilities //==================================================================== - function parseInterval(str) { - if (str == undefined) { - return undefined - } - if (str.slice(-2) == "ms") { - return parseFloat(str.slice(0,-2)) || undefined - } - if (str.slice(-1) == "s") { - return (parseFloat(str.slice(0,-1)) * 1000) || undefined - } - return parseFloat(str) || undefined + function parseInterval(str) { + if (str == undefined) { + return undefined + } + if (str.slice(-2) == "ms") { + return parseFloat(str.slice(0,-2)) || undefined + } + if (str.slice(-1) == "s") { + return (parseFloat(str.slice(0,-1)) * 1000) || undefined + } + return parseFloat(str) || undefined } + /** + * @param {HTMLElement} elt + * @param {string} name + * @returns {(string | null)} + */ function getRawAttribute(elt, name) { return elt.getAttribute && elt.getAttribute(name); } @@ -96,18 +137,36 @@ return (function () { elt.hasAttribute("data-" + qualifiedName)); } + /** + * + * @param {HTMLElement} elt + * @param {string} qualifiedName + * @returns {(string | null)} + */ function getAttributeValue(elt, qualifiedName) { return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); } + /** + * @param {HTMLElement} elt + * @returns {HTMLElement | null} + */ function parentElt(elt) { return elt.parentElement; } + /** + * @returns {Document} + */ function getDocument() { return document; } + /** + * @param {HTMLElement} elt + * @param {(e:HTMLElement) => boolean} condition + * @returns {HTMLElement | null} + */ function getClosestMatch(elt, condition) { if (condition(elt)) { return elt; @@ -118,22 +177,47 @@ return (function () { } } + function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ + var attributeValue = getAttributeValue(ancestor, attributeName); + var disinherit = getAttributeValue(ancestor, "hx-disinherit"); + if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) { + return "unset"; + } else { + return attributeValue + } + } + + /** + * @param {HTMLElement} elt + * @param {string} attributeName + * @returns {string | null} + */ function getClosestAttributeValue(elt, attributeName) { var closestAttr = null; getClosestMatch(elt, function (e) { - return closestAttr = getAttributeValue(e, attributeName); + return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName); }); - return closestAttr; + if (closestAttr !== "unset") { + return closestAttr; + } } + /** + * @param {HTMLElement} elt + * @param {string} selector + * @returns {boolean} + */ function matches(elt, selector) { + // @ts-ignore: non-standard properties for browser compatability // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || - elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector - || elt.webkitMatchesSelector || elt.oMatchesSelector; + var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; return matchesFunction && matchesFunction.call(elt, selector); } + /** + * @param {string} str + * @returns {string} + */ function getStartTag(str) { var tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i var match = tagMatcher.exec( str ); @@ -144,23 +228,40 @@ return (function () { } } + /** + * + * @param {string} resp + * @param {number} depth + * @returns {Element} + */ function parseHTML(resp, depth) { var parser = new DOMParser(); var responseDoc = parser.parseFromString(resp, "text/html"); + + /** @type {Element} */ var responseNode = responseDoc.body; while (depth > 0) { depth--; + // @ts-ignore responseNode = responseNode.firstChild; } if (responseNode == null) { + // @ts-ignore responseNode = getDocument().createDocumentFragment(); } return responseNode; } + /** + * + * @param {string} resp + * @returns {Element} + */ function makeFragment(resp) { if (htmx.config.useTemplateFragments) { var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0); + // @ts-ignore type mismatch between DocumentFragment and Element. + // TODO: Are these close enough for htmx to use interchangably? return documentFragment.querySelector('template').content; } else { var startTag = getStartTag(resp); @@ -186,24 +287,45 @@ return (function () { } } + /** + * @param {Function} func + */ function maybeCall(func){ if(func) { func(); } } + /** + * @param {any} o + * @param {string} type + * @returns + */ function isType(o, type) { return Object.prototype.toString.call(o) === "[object " + type + "]"; } + /** + * @param {*} o + * @returns {o is Function} + */ function isFunction(o) { return isType(o, "Function"); } + /** + * @param {*} o + * @returns {o is Object} + */ function isRawObject(o) { return isType(o, "Object"); } + /** + * getInternalData retrieves "private" data stored by htmx within an element + * @param {HTMLElement} elt + * @returns {*} + */ function getInternalData(elt) { var dataProp = 'htmx-internal-data'; var data = elt[dataProp]; @@ -213,6 +335,11 @@ return (function () { return data; } + /** + * toArray converts an ArrayLike object into a real array. + * @param {ArrayLike} arr + * @returns {any[]} + */ function toArray(arr) { var returnArr = []; if (arr) { @@ -238,14 +365,25 @@ return (function () { return elemTop < window.innerHeight && elemBottom >= 0; } - function bodyContains(elt) { - return getDocument().body.contains(elt); - } + function bodyContains(elt) { + if (elt.getRootNode() instanceof ShadowRoot) { + return getDocument().body.contains(elt.getRootNode().host); + } else { + return getDocument().body.contains(elt); + } + } function splitOnWhitespace(trigger) { return trigger.trim().split(/\s+/); } + /** + * mergeObjects takes all of the keys from + * obj2 and duplicates them into obj1 + * @param {Object} obj1 + * @param {Object} obj2 + * @returns {Object} + */ function mergeObjects(obj1, obj2) { for (var key in obj2) { if (obj2.hasOwnProperty(key)) { @@ -319,7 +457,7 @@ return (function () { if (delay) { setTimeout(function(){addClassToElement(elt, clazz);}, delay) } else { - elt.classList.add(clazz); + elt.classList && elt.classList.add(clazz); } } @@ -328,7 +466,13 @@ return (function () { if (delay) { setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) } else { - elt.classList.remove(clazz); + if (elt.classList) { + elt.classList.remove(clazz); + // if there are no classes left, remove the class attribute + if (elt.classList.length === 0) { + elt.removeAttribute("class"); + } + } } } @@ -360,17 +504,25 @@ return (function () { } function querySelectorAllExt(elt, selector) { - if (selector.indexOf("closest ") === 0) { + if (selector.indexOf("closest ") === 0) { return [closest(elt, selector.substr(8))]; } else if (selector.indexOf("find ") === 0) { return [find(elt, selector.substr(5))]; + } else if (selector === 'document') { + return [document]; + } else if (selector === 'window') { + return [window]; } else { return getDocument().querySelectorAll(selector); } } function querySelectorExt(eltOrSelector, selector) { - return querySelectorAllExt(eltOrSelector, selector)[0] + if (selector) { + return querySelectorAllExt(eltOrSelector, selector)[0]; + } else { + return querySelectorAllExt(getDocument().body, eltOrSelector)[0]; + } } function resolveTarget(arg2) { @@ -418,13 +570,36 @@ return (function () { //==================================================================== // Node processing //==================================================================== + + var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors + function findAttributeTargets(elt, attrName) { + var attrTarget = getClosestAttributeValue(elt, attrName); + if (attrTarget) { + if (attrTarget === "this") { + return [findThisElement(elt, attrName)]; + } else { + var result = querySelectorAllExt(elt, attrTarget); + if (result.length === 0) { + logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!"); + return [DUMMY_ELT] + } else { + return result; + } + } + } + } + + function findThisElement(elt, attribute){ + return getClosestMatch(elt, function (elt) { + return getAttributeValue(elt, attribute) != null; + }) + } function getTarget(elt) { - var explicitTarget = getClosestMatch(elt, function(e){return getAttributeValue(e,"hx-target") !== null}); - if (explicitTarget) { - var targetStr = getAttributeValue(explicitTarget, "hx-target"); + var targetStr = getClosestAttributeValue(elt, "hx-target"); + if (targetStr) { if (targetStr === "this") { - return explicitTarget; + return findThisElement(elt,'hx-target'); } else { return querySelectorExt(elt, targetStr) } @@ -476,6 +651,13 @@ return (function () { return swapStyle === "outerHTML"; } + /** + * + * @param {string} oobValue + * @param {HTMLElement} oobElement + * @param {*} settleInfo + * @returns + */ function oobSwap(oobValue, oobElement, settleInfo) { var selector = "#" + oobElement.id; var swapStyle = "outerHTML"; @@ -488,18 +670,35 @@ return (function () { swapStyle = oobValue; } - var target = getDocument().querySelector(selector); - if (target) { - var fragment; - fragment = getDocument().createDocumentFragment(); - fragment.appendChild(oobElement); // pulls the child out of the existing fragment - if (!isInlineSwap(swapStyle, target)) { - fragment = oobElement; // if this is not an inline swap, we use the content of the node, not the node itself - } - swap(swapStyle, target, target, fragment, settleInfo); + var targets = getDocument().querySelectorAll(selector); + if (targets) { + forEach( + targets, + function (target) { + var fragment; + var oobElementClone = oobElement.cloneNode(true); + fragment = getDocument().createDocumentFragment(); + fragment.appendChild(oobElementClone); + if (!isInlineSwap(swapStyle, target)) { + fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself + } + + var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment }; + if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return; + + target = beforeSwapDetails.target; // allow re-targeting + if (beforeSwapDetails['shouldSwap']){ + swap(swapStyle, target, target, fragment, settleInfo); + } + forEach(settleInfo.elts, function (elt) { + triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails); + }); + } + ); + oobElement.parentNode.removeChild(oobElement); } else { oobElement.parentNode.removeChild(oobElement); - triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}) + triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}); } return oobValue; } @@ -540,6 +739,7 @@ return (function () { function makeAjaxLoadTask(child) { return function () { + removeClassFromElement(child, htmx.config.addedClass); processNode(child); processScripts(child); processFocus(child) @@ -559,6 +759,7 @@ return (function () { handleAttributes(parentNode, fragment, settleInfo); while(fragment.childNodes.length > 0){ var child = fragment.firstChild; + addClassToElement(child, htmx.config.addedClass); parentNode.insertBefore(child, insertBefore); if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { settleInfo.tasks.push(makeAjaxLoadTask(child)); @@ -574,6 +775,9 @@ return (function () { if (internalData.sseEventSource) { internalData.sseEventSource.close(); } + + triggerEvent(element, "htmx:beforeCleanupElement") + if (internalData.listenerInfos) { forEach(internalData.listenerInfos, function(info) { if (element !== info.on) { @@ -590,12 +794,14 @@ return (function () { if (target.tagName === "BODY") { return swapInnerHTML(target, fragment, settleInfo); } else { + // @type {HTMLElement} + var newElt var eltBeforeNewContent = target.previousSibling; insertNodesBefore(parentElt(target), target, fragment, settleInfo); if (eltBeforeNewContent == null) { - var newElt = parentElt(target).firstChild; + newElt = parentElt(target).firstChild; } else { - var newElt = eltBeforeNewContent.nextSibling; + newElt = eltBeforeNewContent.nextSibling; } getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later settleInfo.elts = [] // clear existing elements @@ -625,6 +831,10 @@ return (function () { function swapAfterEnd(target, fragment, settleInfo) { return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo); } + function swapDelete(target, fragment, settleInfo) { + cleanUpElement(target); + return parentElt(target).removeChild(target); + } function swapInnerHTML(target, fragment, settleInfo) { var firstChild = target.firstChild; @@ -670,6 +880,9 @@ return (function () { case "afterend": swapAfterEnd(target, fragment, settleInfo); return; + case "delete": + swapDelete(target, fragment, settleInfo); + return; default: var extensions = getExtensions(elt); for (var i = 0; i < extensions.length; i++) { @@ -692,32 +905,27 @@ return (function () { logError(e); } } - swapInnerHTML(target, fragment, settleInfo); + if (swapStyle === "innerHTML") { + swapInnerHTML(target, fragment, settleInfo); + } else { + swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo); + } } } - var TITLE_FINDER = /<title>([\s\S]+?)<\/title>/im; function findTitle(content) { - if(content.indexOf('<title>') > -1 && - (content.indexOf('<svg>') == -1 || - content.indexOf('<title>') < content.indexOf('<svg>'))) { - var result = TITLE_FINDER.exec(content); + if (content.indexOf('<title') > -1) { + var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, ''); + var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im); + if (result) { - return result[1]; + return result[2]; } } } function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) { - var title = findTitle(responseText); - if(title) { - var titleElt = find("title"); - if(titleElt) { - titleElt.innerHTML = title; - } else { - window.document.title = title; - } - } + settleInfo.title = findTitle(responseText); var fragment = makeFragment(responseText); if (fragment) { handleOutOfBandSwaps(fragment, settleInfo); @@ -840,6 +1048,11 @@ return (function () { } var INPUT_SELECTOR = 'input, textarea, select'; + + /** + * @param {HTMLElement} elt + * @returns {import("./htmx").HtmxTriggerSpecification[]} + */ function getTriggerSpecs(elt) { var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); var triggerSpecs = []; @@ -853,7 +1066,12 @@ return (function () { if (trigger === "every") { var every = {trigger: 'every'}; consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, WHITESPACE)); + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); + consumeUntil(tokens, NOT_WHITESPACE); + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + every.eventFilter = eventFilter; + } triggerSpecs.push(every); } else if (trigger.indexOf("sse:") === 0) { triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); @@ -877,7 +1095,17 @@ return (function () { triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); } else if (token === "from" && tokens[0] === ":") { tokens.shift(); - triggerSpec.from = consumeUntil(tokens, WHITESPACE_OR_COMMA); + var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); + if (from_arg === "closest" || from_arg === "find") { + tokens.shift(); + from_arg += + " " + + consumeUntil( + tokens, + WHITESPACE_OR_COMMA + ); + } + triggerSpec.from = from_arg; } else if (token === "target" && tokens[0] === ":") { tokens.shift(); triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA); @@ -919,14 +1147,16 @@ return (function () { getInternalData(elt).cancelled = true; } - function processPolling(elt, verb, path, interval) { + function processPolling(elt, verb, path, spec) { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - issueAjaxRequest(verb, path, elt); - processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), interval); + if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { + issueAjaxRequest(verb, path, elt); + } + processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), spec); } - }, interval); + }, spec.pollInterval); } function isLocalLink(elt) { @@ -936,7 +1166,7 @@ return (function () { } function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt)) || elt.tagName === "FORM") { + if ((elt.tagName === "A" && isLocalLink(elt) && elt.target === "") || elt.tagName === "FORM") { nodeData.boosted = true; var verb, path; if (elt.tagName === "A") { @@ -957,11 +1187,26 @@ return (function () { } } - function shouldCancel(elt) { - return elt.tagName === "FORM" || - (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) || - (elt.tagName === "A" && elt.href && (elt.getAttribute('href') === '#' || - elt.getAttribute('href').indexOf("#") !== 0)); + /** + * + * @param {Event} evt + * @param {HTMLElement} elt + * @returns + */ + function shouldCancel(evt, elt) { + if (evt.type === "submit" || evt.type === "click") { + if (elt.tagName === "FORM") { + return true; + } + if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { + return true; + } + if (elt.tagName === "A" && elt.href && + (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) { + return true; + } + } + return false; } function ignoreBoostedAnchorCtrlClick(elt, evt) { @@ -982,86 +1227,90 @@ return (function () { } function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { - var eltToListenOn = elt; + var eltsToListenOn; if (triggerSpec.from) { - eltToListenOn = find(triggerSpec.from); + eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); + } else { + eltsToListenOn = [elt]; } - var eventListener = function (evt) { - if (!bodyContains(elt)) { - eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); - return; - } - if (ignoreBoostedAnchorCtrlClick(elt, evt)) { - return; - } - if(explicitCancel || shouldCancel(elt)){ - evt.preventDefault(); - } - if (maybeFilterEvent(triggerSpec, evt)) { - return; - } - var eventData = getInternalData(evt); - eventData.triggerSpec = triggerSpec; - if (eventData.handledFor == null) { - eventData.handledFor = []; - } - var elementData = getInternalData(elt); - if (eventData.handledFor.indexOf(elt) < 0) { - eventData.handledFor.push(elt); - if (triggerSpec.consume) { - evt.stopPropagation(); - } - if (triggerSpec.target && evt.target) { - if (!matches(evt.target, triggerSpec.target)) { - return; - } - } - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } + forEach(eltsToListenOn, function (eltToListenOn) { + var eventListener = function (evt) { + if (!bodyContains(elt)) { + eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); + return; } - if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { - return; - } else { - elementData.lastValue = elt.value; - } + if (ignoreBoostedAnchorCtrlClick(elt, evt)) { + return; } - if (elementData.delayed) { - clearTimeout(elementData.delayed); + if (explicitCancel || shouldCancel(evt, elt)) { + evt.preventDefault(); } - if (elementData.throttle) { + if (maybeFilterEvent(triggerSpec, evt)) { return; } + var eventData = getInternalData(evt); + eventData.triggerSpec = triggerSpec; + if (eventData.handledFor == null) { + eventData.handledFor = []; + } + var elementData = getInternalData(elt); + if (eventData.handledFor.indexOf(elt) < 0) { + eventData.handledFor.push(elt); + if (triggerSpec.consume) { + evt.stopPropagation(); + } + if (triggerSpec.target && evt.target) { + if (!matches(evt.target, triggerSpec.target)) { + return; + } + } + 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); + } + if (elementData.throttle) { + return; + } - if (triggerSpec.throttle) { - if(!elementData.throttle) { + if (triggerSpec.throttle) { + if (!elementData.throttle) { + issueAjaxRequest(verb, path, elt, evt); + elementData.throttle = setTimeout(function () { + elementData.throttle = null; + }, triggerSpec.throttle); + } + } else if (triggerSpec.delay) { + elementData.delayed = setTimeout(function () { + issueAjaxRequest(verb, path, elt, evt); + }, triggerSpec.delay); + } else { issueAjaxRequest(verb, path, elt, evt); - elementData.throttle = setTimeout(function(){ - elementData.throttle = null; - }, triggerSpec.throttle); } - } else if (triggerSpec.delay) { - elementData.delayed = setTimeout(function(){ - issueAjaxRequest(verb, path, elt, evt); - }, triggerSpec.delay); - } else { - issueAjaxRequest(verb, path, elt, evt); } - } - }; - if (nodeData.listenerInfos == null) { - nodeData.listenerInfos = []; - } - nodeData.listenerInfos.push({ - trigger: triggerSpec.trigger, - listener: eventListener, - on: eltToListenOn + }; + if (nodeData.listenerInfos == null) { + nodeData.listenerInfos = []; + } + nodeData.listenerInfos.push({ + trigger: triggerSpec.trigger, + listener: eventListener, + on: eltToListenOn + }) + eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); }) - eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); } var windowIsScrolling = false // used by initScrollHandler @@ -1084,9 +1333,9 @@ return (function () { } function maybeReveal(elt) { - var nodeData = getInternalData(elt); - if (!nodeData.revealed && isScrolledIntoView(elt)) { - nodeData.revealed = true; + if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { + elt.setAttribute('data-hx-revealed', 'true'); + var nodeData = getInternalData(elt); if (nodeData.initialized) { issueAjaxRequest(nodeData.verb, nodeData.path, elt); } else { @@ -1099,6 +1348,10 @@ return (function () { } } + //==================================================================== + // Web Sockets + //==================================================================== + function processWebSocketInfo(elt, nodeData, info) { var values = splitOnWhitespace(info); for (var i = 0; i < values.length; i++) { @@ -1132,7 +1385,7 @@ return (function () { }; socket.onclose = function (e) { - if ([1006, 1012, 1013].includes(e.code)) { // Abnormal Closure/Service Restart/Try Again Later + if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later var delay = getWebSocketReconnectDelay(retryCount); setTimeout(function() { ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout @@ -1193,7 +1446,7 @@ return (function () { return; } webSocket.send(JSON.stringify(filteredParameters)); - if(shouldCancel(elt)){ + if(shouldCancel(evt, elt)){ evt.preventDefault(); } }); @@ -1205,6 +1458,7 @@ return (function () { function getWebSocketReconnectDelay(retryCount) { var delay = htmx.config.wsReconnectDelay; if (typeof delay === 'function') { + // @ts-ignore return delay(retryCount); } if (delay === 'full-jitter') { @@ -1340,7 +1594,7 @@ return (function () { } else if (triggerSpec.trigger === "intersect") { var observerOptions = {}; if (triggerSpec.root) { - observerOptions.root = querySelectorExt(triggerSpec.root) + observerOptions.root = querySelectorExt(elt, triggerSpec.root) } if (triggerSpec.threshold) { observerOptions.threshold = parseFloat(triggerSpec.threshold); @@ -1360,7 +1614,7 @@ return (function () { loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); } else if (triggerSpec.pollInterval) { nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec.pollInterval); + processPolling(elt, verb, path, triggerSpec); } else { addEventListener(elt, verb, path, nodeData, triggerSpec); } @@ -1371,14 +1625,24 @@ return (function () { } function evalScript(script) { - if (script.type === "text/javascript" || script.type === "") { + if (script.type === "text/javascript" || script.type === "module" || script.type === "") { + var newScript = getDocument().createElement("script"); + forEach(script.attributes, function (attr) { + newScript.setAttribute(attr.name, attr.value); + }); + newScript.textContent = script.textContent; + newScript.async = false; + if (htmx.config.inlineScriptNonce) { + newScript.nonce = htmx.config.inlineScriptNonce; + } + var parent = script.parentElement; + try { - maybeEval(script, function () { - // wtf - https://stackoverflow.com/questions/9107240/1-evalthis-vs-evalthis-in-javascript - (1, eval)(script.innerText); - }); + parent.insertBefore(newScript, script); } catch (e) { logError(e); + } finally { + parent.removeChild(script); } } } @@ -1392,21 +1656,41 @@ return (function () { }); } - function isBoosted() { + function hasChanceOfBeingBoosted() { return document.querySelector("[hx-boost], [data-hx-boost]"); } function findElementsToProcess(elt) { if (elt.querySelectorAll) { - var boostedElts = isBoosted() ? ", a, form" : ""; + var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws]"); + " [data-hx-ws], [hx-ext], [hx-data-ext]"); return results; } else { return []; } } + function initButtonTracking(form){ + var maybeSetLastButtonClicked = function(evt){ + if (matches(evt.target, "button, input[type='submit']")) { + var internalData = getInternalData(form); + internalData.lastButtonClicked = evt.target; + } + }; + + // need to handle both click and focus in: + // focusin - in case someone tabs in to a button and hits the space bar + // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + + form.addEventListener('click', maybeSetLastButtonClicked) + form.addEventListener('focusin', maybeSetLastButtonClicked) + form.addEventListener('focusout', function(evt){ + var internalData = getInternalData(form); + internalData.lastButtonClicked = null; + }) + } + function initNode(elt) { if (elt.closest && elt.closest(htmx.config.disableSelector)) { return; @@ -1427,6 +1711,10 @@ return (function () { boostElement(elt, nodeData, triggerSpecs); } + if (elt.tagName === "FORM") { + initButtonTracking(elt); + } + var sseInfo = getAttributeValue(elt, 'hx-sse'); if (sseInfo) { processSSEInfo(elt, nodeData, sseInfo); @@ -1473,6 +1761,15 @@ return (function () { return eventName === "htmx:afterProcessNode" } + /** + * `withExtensions` locates all active extensions for a provided element, then + * executes the provided function using each of the active extensions. It should + * be called internally at every extendable execution point in htmx. + * + * @param {HTMLElement} elt + * @param {(extension:import("./htmx").HtmxExtension) => void} toDo + * @returns void + */ function withExtensions(elt, toDo) { forEach(getExtensions(elt), function(extension){ try { @@ -1520,7 +1817,7 @@ return (function () { //==================================================================== // History Support //==================================================================== - var currentPathForHistory = null; + var currentPathForHistory = location.pathname+location.search; function getHistoryElement() { var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]'); @@ -1569,7 +1866,7 @@ return (function () { return clone.innerHTML; } - function saveHistory() { + function saveCurrentPageToHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); @@ -1598,9 +1895,11 @@ return (function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); var fragment = makeFragment(this.response); + // @ts-ignore fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; var historyElement = getHistoryElement(); var settleInfo = makeSettleInfo(historyElement); + // @ts-ignore swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); currentPathForHistory = path; @@ -1613,7 +1912,7 @@ return (function () { } function restoreHistory(path) { - saveHistory(); + saveCurrentPageToHistory(); path = path || location.pathname+location.search; var cached = getCachedHistory(path); if (cached) { @@ -1628,6 +1927,8 @@ return (function () { triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); } else { if (htmx.config.refreshOnHistoryMiss) { + + // @ts-ignore: optional parameter in reload() function throws error window.location.reload(true); } else { loadHistoryFromServer(path); @@ -1647,10 +1948,8 @@ return (function () { } function addRequestIndicatorClasses(elt) { - var indicator = getClosestAttributeValue(elt, 'hx-indicator'); - if (indicator) { - var indicators = querySelectorAllExt(elt, indicator); - } else { + var indicators = findAttributeTargets(elt, 'hx-indicator'); + if (indicators == null) { indicators = [elt]; } forEach(indicators, function (ic) { @@ -1753,14 +2052,22 @@ return (function () { } } + /** + * @param {HTMLElement} elt + * @param {string} verb + */ function getInputValues(elt, verb) { var processed = []; var values = {}; var formValues = {}; var errors = []; + var internalData = getInternalData(elt); - // only validate when form is directly submitted and novalidate is not set + // only validate when form is directly submitted and novalidate or formnovalidate are not set var validate = matches(elt, 'form') && elt.noValidate !== true; + if (internalData.lastButtonClicked) { + validate = validate && internalData.lastButtonClicked.formNoValidate !== true; + } // for a non-GET include the closest form if (verb !== 'get') { @@ -1770,21 +2077,26 @@ return (function () { // include the element itself processInputValue(processed, values, errors, elt, validate); - // include any explicit includes - var includes = getClosestAttributeValue(elt, "hx-include"); - if (includes) { - var nodes = querySelectorAllExt(elt, includes); - forEach(nodes, function(node) { - processInputValue(processed, values, errors, node, validate); - // if a non-form is included, include any input values within it - if (!matches(node, 'form')) { - forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { - processInputValue(processed, values, errors, descendant, validate); - }) - } - }); + // if a button or submit was clicked last, include its value + if (internalData.lastButtonClicked) { + var name = getRawAttribute(internalData.lastButtonClicked,"name"); + if (name) { + values[name] = internalData.lastButtonClicked.value; + } } + // include any explicit includes + var includes = findAttributeTargets(elt, "hx-include"); + forEach(includes, function(node) { + processInputValue(processed, values, errors, node, validate); + // if a non-form is included, include any input values within it + if (!matches(node, 'form')) { + forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { + processInputValue(processed, values, errors, descendant, validate); + }) + } + }); + // form values take precedence, overriding the regular values values = mergeObjects(values, formValues); @@ -1795,7 +2107,11 @@ return (function () { if (returnStr !== "") { returnStr += "&"; } - returnStr += encodeURIComponent(name) + "=" + encodeURIComponent(realValue); + if (String(realValue) === "[object Object]") { + realValue = JSON.stringify(realValue); + } + var s = encodeURIComponent(realValue); + returnStr += encodeURIComponent(name) + "=" + s; return returnStr; } @@ -1837,6 +2153,12 @@ return (function () { // Ajax //==================================================================== + /** + * @param {HTMLElement} elt + * @param {HTMLElement} target + * @param {string} prompt + * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification + */ function getHeaders(elt, target, prompt) { var headers = { "HX-Request" : "true", @@ -1849,9 +2171,20 @@ return (function () { if (prompt !== undefined) { headers["HX-Prompt"] = prompt; } + if (getInternalData(elt).boosted) { + headers["HX-Boosted"] = "true"; + } return headers; } + /** + * filterValues takes an object containing form input values + * and returns a new object that only contains keys that are + * specified by the closest "hx-params" attribute + * @param {Object} inputValues + * @param {HTMLElement} elt + * @returns {Object} + */ function filterValues(inputValues, elt) { var paramsValue = getClosestAttributeValue(elt, "hx-params"); if (paramsValue) { @@ -1882,8 +2215,14 @@ return (function () { return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0 } - function getSwapSpecification(elt) { - var swapInfo = getClosestAttributeValue(elt, "hx-swap"); + /** + * + * @param {HTMLElement} elt + * @param {string} swapInfoOverride + * @returns {import("./htmx").HtmxSwapSpecification} + */ + function getSwapSpecification(elt, swapInfoOverride) { + var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap"); var swapSpec = { "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, "swapDelay" : htmx.config.defaultSwapDelay, @@ -1905,10 +2244,24 @@ return (function () { swapSpec["settleDelay"] = parseInterval(modifier.substr(7)); } if (modifier.indexOf("scroll:") === 0) { - swapSpec["scroll"] = modifier.substr(7); + var scrollSpec = modifier.substr(7); + var splitSpec = scrollSpec.split(":"); + var scrollVal = splitSpec.pop(); + var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; + swapSpec["scroll"] = scrollVal; + swapSpec["scrollTarget"] = selectorVal; } if (modifier.indexOf("show:") === 0) { - swapSpec["show"] = modifier.substr(5); + var showSpec = modifier.substr(5); + var splitSpec = showSpec.split(":"); + var showVal = splitSpec.pop(); + var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; + swapSpec["show"] = showVal; + swapSpec["showTarget"] = selectorVal; + } + if (modifier.indexOf("focus-scroll:") === 0) { + var focusScrollVal = modifier.substr("focus-scroll:".length); + swapSpec["focusScroll"] = focusScrollVal == "true"; } } } @@ -1926,7 +2279,8 @@ return (function () { if (encodedParameters != null) { return encodedParameters; } else { - if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data") { + if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || + (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) { return makeFormData(filteredParameters); } else { return urlEncode(filteredParameters); @@ -1934,6 +2288,11 @@ return (function () { } } + /** + * + * @param {Element} target + * @returns {import("./htmx").HtmxSettleInfo} + */ function makeSettleInfo(target) { return {tasks: [], elts: [target]}; } @@ -1942,23 +2301,46 @@ return (function () { var first = content[0]; var last = content[content.length - 1]; if (swapSpec.scroll) { - if (swapSpec.scroll === "top" && first) { - first.scrollTop = 0; + var target = null; + if (swapSpec.scrollTarget) { + target = querySelectorExt(first, swapSpec.scrollTarget); + } + if (swapSpec.scroll === "top" && (first || target)) { + target = target || first; + target.scrollTop = 0; } - if (swapSpec.scroll === "bottom" && last) { - last.scrollTop = last.scrollHeight; + if (swapSpec.scroll === "bottom" && (last || target)) { + target = target || last; + target.scrollTop = target.scrollHeight; } } if (swapSpec.show) { - if (swapSpec.show === "top" && first) { - first.scrollIntoView(true); + var target = null; + if (swapSpec.showTarget) { + var targetStr = swapSpec.showTarget; + if (swapSpec.showTarget === "window") { + targetStr = "body"; + } + target = querySelectorExt(first, targetStr); + } + if (swapSpec.show === "top" && (first || target)) { + target = target || first; + target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior}); } - if (swapSpec.show === "bottom" && last) { - last.scrollIntoView(false); + if (swapSpec.show === "bottom" && (last || target)) { + target = target || last; + target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior}); } } } + /** + * @param {HTMLElement} elt + * @param {string} attr + * @param {boolean=} evalAsDefault + * @param {Object=} values + * @returns {Object} + */ function getValuesForElement(elt, attr, evalAsDefault, values) { if (values == null) { values = {}; @@ -1973,6 +2355,9 @@ return (function () { if (str.indexOf("javascript:") === 0) { str = str.substr(11); evaluateValue = true; + } else if (str.indexOf("js:") === 0) { + str = str.substr(3); + evaluateValue = true; } if (str.indexOf('{') !== 0) { str = "{" + str + "}"; @@ -2003,14 +2388,28 @@ return (function () { } } + /** + * @param {HTMLElement} elt + * @param {*} expressionVars + * @returns + */ function getHXVarsForElement(elt, expressionVars) { return getValuesForElement(elt, "hx-vars", true, expressionVars); } + /** + * @param {HTMLElement} elt + * @param {*} expressionVars + * @returns + */ function getHXValsForElement(elt, expressionVars) { return getValuesForElement(elt, "hx-vals", false, expressionVars); } + /** + * @param {HTMLElement} elt + * @returns {Object} + */ function getExpressionVars(elt) { return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)); } @@ -2044,10 +2443,12 @@ return (function () { } function ajaxHelper(verb, path, context) { + verb = verb.toLowerCase(); if (context) { if (context instanceof Element || isType(context, 'String')) { return issueAjaxRequest(verb, path, null, null, { - targetOverride: resolveTarget(context) + targetOverride: resolveTarget(context), + returnPromise: true }); } else { return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, @@ -2055,11 +2456,15 @@ return (function () { handler : context.handler, headers : context.headers, values : context.values, - targetOverride: resolveTarget(context.target) + targetOverride: resolveTarget(context.target), + swapOverride: context.swap, + returnPromise: true }); } } else { - return issueAjaxRequest(verb, path); + return issueAjaxRequest(verb, path, null, null, { + returnPromise: true + }); } } @@ -2076,7 +2481,7 @@ return (function () { var resolve = null; var reject = null; etc = etc != null ? etc : {}; - if(typeof Promise !== "undefined"){ + if(etc.returnPromise && typeof Promise !== "undefined"){ var promise = new Promise(function (_resolve, _reject) { resolve = _resolve; reject = _reject; @@ -2091,40 +2496,85 @@ return (function () { return; // do not issue requests for elements removed from the DOM } var target = etc.targetOverride || getTarget(elt); - if (target == null) { + if (target == null || target == DUMMY_ELT) { triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); return; } + + var syncElt = elt; var eltData = getInternalData(elt); - if (eltData.requestInFlight) { - var queueStrategy = 'last'; - var eventData = getInternalData(event); - if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { - queueStrategy = eventData.triggerSpec.queue; - } - if (eltData.queuedRequests == null) { - eltData.queuedRequests = []; - } - if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); - } else if (queueStrategy === "all") { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); - } else if (queueStrategy === "last") { - eltData.queuedRequests = []; // dump existing queue - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); + var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); + var queueStrategy = null; + var abortable = false; + if (syncStrategy) { + var syncStrings = syncStrategy.split(":"); + var selector = syncStrings[0].trim(); + if (selector === "this") { + syncElt = findThisElement(elt, 'hx-sync'); + } else { + syncElt = querySelectorExt(elt, selector); + } + // default to the drop strategy + syncStrategy = (syncStrings[1] || 'drop').trim(); + eltData = getInternalData(syncElt); + if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { + return; + } else if (syncStrategy === "abort") { + if (eltData.xhr) { + return; + } else { + abortable = true; + } + } else if (syncStrategy === "replace") { + triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue + } else if (syncStrategy.indexOf("queue") === 0) { + var queueStrArray = syncStrategy.split(" "); + queueStrategy = (queueStrArray[1] || "last").trim(); } - return; - } else { - eltData.requestInFlight = true; } + + if (eltData.xhr) { + if (eltData.abortable) { + triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue + } else { + if(queueStrategy == null){ + if (event) { + var eventData = getInternalData(event); + if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { + queueStrategy = eventData.triggerSpec.queue; + } + } + if (queueStrategy == null) { + queueStrategy = "last"; + } + } + if (eltData.queuedRequests == null) { + eltData.queuedRequests = []; + } + if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } else if (queueStrategy === "all") { + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } else if (queueStrategy === "last") { + eltData.queuedRequests = []; // dump existing queue + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } + return; + } + } + + var xhr = new XMLHttpRequest(); + eltData.xhr = xhr; + eltData.abortable = abortable; var endRequestLock = function(){ - eltData.requestInFlight = false + eltData.xhr = null; + eltData.abortable = false; if (eltData.queuedRequests != null && eltData.queuedRequests.length > 0) { var queuedRequest = eltData.queuedRequests.shift(); @@ -2152,11 +2602,10 @@ return (function () { } } - var xhr = new XMLHttpRequest(); var headers = getHeaders(elt, target, promptResponse); if (etc.headers) { - headers = mergeObjects(headers, etc.values); + headers = mergeObjects(headers, etc.headers); } var results = getInputValues(elt, verb); var errors = results.errors; @@ -2169,7 +2618,7 @@ return (function () { var filteredParameters = filterValues(allParameters, elt); if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null) { - headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; + headers['Content-Type'] = 'application/x-www-form-urlencoded'; } // behavior of anchors w/ empty href is to use the current URL @@ -2177,6 +2626,8 @@ return (function () { path = getDocument().location.href; } + var requestAttrValues = getValuesForElement(elt, 'hx-request'); + var requestConfig = { parameters: filteredParameters, unfilteredParameters: allParameters, @@ -2184,6 +2635,8 @@ return (function () { target:target, verb:verb, errors:errors, + withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, + timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, path:path, triggeringEvent:event }; @@ -2231,17 +2684,22 @@ return (function () { } xhr.overrideMimeType("text/html"); - xhr.withCredentials = htmx.config.withCredentials; + xhr.withCredentials = requestConfig.withCredentials; + xhr.timeout = requestConfig.timeout; // request headers - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - var headerValue = headers[header]; - safelySetHeaderValue(xhr, header, headerValue); + if (requestAttrValues.noHeaders) { + // ignore all headers + } else { + for (var header in headers) { + if (headers.hasOwnProperty(header)) { + var headerValue = headers[header]; + safelySetHeaderValue(xhr, header, headerValue); + } } } - var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, pathInfo:{ + var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, etc:etc, pathInfo:{ path:path, finalPath:finalPathForGet, anchor:anchor } }; @@ -2289,6 +2747,13 @@ return (function () { maybeCall(reject); endRequestLock(); } + xhr.ontimeout = function() { + removeRequestIndicatorClasses(indicators); + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); + triggerErrorEvent(elt, 'htmx:timeout', responseInfo); + maybeCall(reject); + endRequestLock(); + } if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){ maybeCall(resolve); endRequestLock() @@ -2315,6 +2780,7 @@ return (function () { function handleAjaxResponse(elt, responseInfo) { var xhr = responseInfo.xhr; var target = responseInfo.target; + var etc = responseInfo.etc; if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; @@ -2338,123 +2804,162 @@ return (function () { } } - var shouldSaveHistory = shouldPush(elt) || pushedUrl; + if (hasHeader(xhr,/HX-Retarget:/i)) { + responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget")); + } - if (xhr.status >= 200 && xhr.status < 400) { + /** @type {boolean} */ + var shouldSaveHistory + if (pushedUrl == "false") { + shouldSaveHistory = false + } else { + shouldSaveHistory = shouldPush(elt) || pushedUrl; + } + + // by default htmx only swaps on 200 return codes and does not swap + // on 204 'No Content' + // this can be ovverriden by responding to the htmx:beforeSwap event and + // overriding the detail.shouldSwap property + var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; + var serverResponse = xhr.response; + var isError = xhr.status >= 400; + var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo); + if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; + + target = beforeSwapDetails.target; // allow re-targeting + serverResponse = beforeSwapDetails.serverResponse; // allow updating content + isError = beforeSwapDetails.isError; // allow updating error + + responseInfo.failed = isError; // Make failed property available to response events + responseInfo.successful = !isError; // Make successful property available to response events + + if (beforeSwapDetails.shouldSwap) { if (xhr.status === 286) { cancelPolling(elt); } - // don't process 'No Content' - if (xhr.status !== 204) { - if (!triggerEvent(target, 'htmx:beforeSwap', responseInfo)) return; - var serverResponse = xhr.response; - withExtensions(elt, function(extension){ - serverResponse = extension.transformResponse(serverResponse, xhr, elt); - }); + withExtensions(elt, function (extension) { + serverResponse = extension.transformResponse(serverResponse, xhr, elt); + }); - // Save current page - if (shouldSaveHistory) { - saveHistory(); - } + // Save current page + if (shouldSaveHistory) { + saveCurrentPageToHistory(); + } + + var swapOverride = etc.swapOverride; + var swapSpec = getSwapSpecification(elt, swapOverride); - var swapSpec = getSwapSpecification(elt); + target.classList.add(htmx.config.swappingClass); + var doSwap = function () { + try { - target.classList.add(htmx.config.swappingClass); - var doSwap = function () { + var activeElt = document.activeElement; + var selectionInfo = {}; try { + selectionInfo = { + elt: activeElt, + // @ts-ignore + start: activeElt ? activeElt.selectionStart : null, + // @ts-ignore + end: activeElt ? activeElt.selectionEnd : null + }; + } catch (e) { + // safari issue - see https://github.com/microsoft/playwright/issues/5894 + } - var activeElt = document.activeElement; - var selectionInfo = {}; - try { - selectionInfo = { - elt: activeElt, - start: activeElt ? activeElt.selectionStart : null, - end: activeElt ? activeElt.selectionEnd : null - }; - } catch (e) { - // safari issue - see https://github.com/microsoft/playwright/issues/5894 + var settleInfo = makeSettleInfo(target); + selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + + if (selectionInfo.elt && + !bodyContains(selectionInfo.elt) && + selectionInfo.elt.id) { + var newActiveElt = document.getElementById(selectionInfo.elt.id); + var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; + if (newActiveElt) { + // @ts-ignore + if (selectionInfo.start && newActiveElt.setSelectionRange) { + // @ts-ignore + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + } + newActiveElt.focus(focusOptions); } + } - var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + target.classList.remove(htmx.config.swappingClass); + forEach(settleInfo.elts, function (elt) { + if (elt.classList) { + elt.classList.add(htmx.config.settlingClass); + } + triggerEvent(elt, 'htmx:afterSwap', responseInfo); + }); + if (responseInfo.pathInfo.anchor) { + location.hash = responseInfo.pathInfo.anchor; + } - if (selectionInfo.elt && - !bodyContains(selectionInfo.elt) && - selectionInfo.elt.id) { - var newActiveElt = document.getElementById(selectionInfo.elt.id); - if (newActiveElt) { - if (selectionInfo.start && newActiveElt.setSelectionRange) { - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); - } - newActiveElt.focus(); - } + if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { + var finalElt = elt; + if (!bodyContains(elt)) { + finalElt = getDocument().body; } + handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); + } - target.classList.remove(htmx.config.swappingClass); + var doSettle = function () { + forEach(settleInfo.tasks, function (task) { + task.call(); + }); forEach(settleInfo.elts, function (elt) { if (elt.classList) { - elt.classList.add(htmx.config.settlingClass); + elt.classList.remove(htmx.config.settlingClass); } - triggerEvent(elt, 'htmx:afterSwap', responseInfo); + triggerEvent(elt, 'htmx:afterSettle', responseInfo); }); - if (responseInfo.pathInfo.anchor) { - location.hash = responseInfo.pathInfo.anchor; + // push URL and save new page + if (shouldSaveHistory) { + var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; + pushUrlIntoHistory(pathToPush); + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: pathToPush}); } - if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; + if(settleInfo.title) { + var titleElt = find("title"); + if(titleElt) { + titleElt.innerHTML = settleInfo.title; + } else { + window.document.title = settleInfo.title; } - handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); } - var doSettle = function(){ - forEach(settleInfo.tasks, function (task) { - task.call(); - }); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.remove(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSettle', responseInfo); - }); - // push URL and save new page - if (shouldSaveHistory) { - var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; - pushUrlIntoHistory(pathToPush); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path:pathToPush}); - } - updateScrollState(settleInfo.elts, swapSpec); + updateScrollState(settleInfo.elts, swapSpec); - if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); + if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { + var finalElt = elt; + if (!bodyContains(elt)) { + finalElt = getDocument().body; } + handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'htmx:swapError', responseInfo); - throw e; } - }; - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); + if (swapSpec.settleDelay > 0) { + setTimeout(doSettle, swapSpec.settleDelay) + } else { + doSettle(); + } + } catch (e) { + triggerErrorEvent(elt, 'htmx:swapError', responseInfo); + throw e; } + }; + + if (swapSpec.swapDelay > 0) { + setTimeout(doSwap, swapSpec.swapDelay) + } else { + doSwap(); } - } else { + } + if (isError) { triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.path}, responseInfo)); } } @@ -2462,9 +2967,17 @@ return (function () { //==================================================================== // Extensions API //==================================================================== + + /** @type {Object<string, import("./htmx").HtmxExtension>} */ var extensions = {}; + + /** + * extensionBase defines the default functions for all extensions. + * @returns {import("./htmx").HtmxExtension} + */ function extensionBase() { return { + init: function(api) {return null;}, onEvent : function(name, evt) {return true;}, transformResponse : function(text, xhr, elt) {return text;}, isInlineSwap : function(swapStyle) {return false;}, @@ -2473,15 +2986,37 @@ return (function () { } } + /** + * defineExtension initializes the extension and adds it to the htmx registry + * + * @param {string} name + * @param {import("./htmx").HtmxExtension} extension + */ function defineExtension(name, extension) { + if(extension.init) { + extension.init(internalAPI) + } extensions[name] = mergeObjects(extensionBase(), extension); } + /** + * removeExtension removes an extension from the htmx registry + * + * @param {string} name + */ function removeExtension(name) { delete extensions[name]; } - function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + /** + * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element + * + * @param {HTMLElement} elt + * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn + * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore + */ + function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + if (elt == undefined) { return extensionsToReturn; } @@ -2536,6 +3071,7 @@ return (function () { function getMetaConfig() { var element = getDocument().querySelector('meta[name="htmx-config"]'); if (element) { + // @ts-ignore return parseJSON(element.content); } else { return null; @@ -2555,9 +3091,25 @@ return (function () { insertIndicatorStyles(); var body = getDocument().body; processNode(body); + var restoredElts = getDocument().querySelectorAll( + "[hx-trigger='restored'],[data-hx-trigger='restored']" + ); + body.addEventListener("htmx:abort", function (evt) { + var target = evt.target; + var internalData = getInternalData(target); + if (internalData && internalData.xhr) { + internalData.xhr.abort(); + } + }); window.onpopstate = function (event) { if (event.state && event.state.htmx) { restoreHistory(); + forEach(restoredElts, function(elt){ + triggerEvent(elt, 'htmx:restored', { + 'document': getDocument(), + 'triggerEvent': triggerEvent + }); + }); } }; setTimeout(function () { diff --git a/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.min.js b/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.min.js index 57f33b2..998414c 100644 --- a/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.min.js +++ b/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.min.js @@ -1 +1 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var k={onLoad:t,process:rt,on:I,off:M,trigger:lt,ajax:$t,find:w,findAll:S,closest:L,values:function(e,t){var r=Lt(e,t||"post");return r.values},remove:E,addClass:q,removeClass:R,toggleClass:C,takeClass:O,defineExtension:Qt,removeExtension:er,logAll:b,logger:null,useTemplateFragments:false,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,attributesToSettle:["class","style","width","height"],withCredentials:false,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]"},parseInterval:f,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])}};var r=["get","post","put","delete","patch"];var n=r.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function f(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function l(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function D(e,t){return l(e,t)||l(e,"data-"+t)}function c(e){return e.parentElement}function F(){return document}function h(e,t){if(t(e)){return e}else if(c(e)){return h(c(e),t)}else{return null}}function X(e,t){var r=null;h(e,function(e){return r=D(e,t)});return r}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function i(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 o(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=F().createDocumentFragment()}return i}function u(e){if(k.config.useTemplateFragments){var t=o("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=i(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return o("<table>"+e+"</table>",1);case"col":return o("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return o("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return o("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return o("<div>"+e+"</div>",1);default:return o(e,0)}}}function P(e){if(e){e()}}function a(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function v(e){return a(e,"Function")}function g(e){return a(e,"Object")}function U(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function p(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function j(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function m(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function z(e){return F().body.contains(e)}function y(e){return e.trim().split(/\s+/)}function V(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function x(e){try{return JSON.parse(e)}catch(e){ut(e);return null}}function e(e){return Ut(F().body,function(){return eval(e)})}function t(t){var e=k.on("htmx:load",function(e){t(e.detail.elt)});return e}function b(){k.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function w(e,t){if(t){return e.querySelector(t)}else{return w(F(),e)}}function S(e,t){if(t){return e.querySelectorAll(t)}else{return S(F(),e)}}function E(e,t){e=H(e);if(t){setTimeout(function(){E(e)},t)}else{e.parentElement.removeChild(e)}}function q(e,t,r){e=H(e);if(r){setTimeout(function(){q(e,t)},r)}else{e.classList.add(t)}}function R(e,t,r){e=H(e);if(r){setTimeout(function(){R(e,t)},r)}else{e.classList.remove(t)}}function C(e,t){e=H(e);e.classList.toggle(t)}function O(e,t){e=H(e);j(e.parentElement.children,function(e){R(e,t)});q(e,t)}function L(e,t){e=H(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&c(e))}}function A(e,t){if(t.indexOf("closest ")===0){return[L(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[w(e,t.substr(5))]}else{return F().querySelectorAll(t)}}function T(e,t){return A(e,t)[0]}function H(e){if(a(e,"String")){return w(e)}else{return e}}function N(e,t,r){if(v(t)){return{target:F().body,event:e,listener:t}}else{return{target:H(e),event:t,listener:r}}}function I(t,r,n){rr(function(){var e=N(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=v(r);return e?r:n}function M(t,r,n){rr(function(){var e=N(t,r,n);e.target.removeEventListener(e.event,e.listener)});return v(r)?r:n}function _(e){var t=h(e,function(e){return D(e,"hx-target")!==null});if(t){var r=D(t,"hx-target");if(r==="this"){return t}else{return T(e,r)}}else{var n=U(e);if(n.boosted){return F().body}else{return e}}}function B(e){var t=k.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function W(t,r){j(t.attributes,function(e){if(!r.hasAttribute(e.name)&&B(e.name)){t.removeAttribute(e.name)}});j(r.attributes,function(e){if(B(e.name)){t.setAttribute(e.name,e.value)}})}function $(e,t){var r=tr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){ut(e)}}return e==="outerHTML"}function J(e,t,r){var n="#"+t.id;var i="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){i=e.substr(0,e.indexOf(":"));n=e.substr(e.indexOf(":")+1,e.length)}else{i=e}var o=F().querySelector(n);if(o){var a;a=F().createDocumentFragment();a.appendChild(t);if(!$(i,o)){a=t}le(i,o,o,a,r)}else{t.parentNode.removeChild(t);ot(F().body,"htmx:oobErrorNoTarget",{content:t})}return e}function Z(e,r){j(S(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=D(e,"hx-swap-oob");if(t!=null){J(t,e,r)}})}function G(e){j(S(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=D(e,"id");var r=F().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function K(n,e,i){j(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();W(e,t);i.tasks.push(function(){W(e,r)})}}})}function Y(e){return function(){rt(e);Ye(e);Q(e);lt(e,"htmx:load")}}function Q(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ee(e,t,r,n){K(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Y(i))}}}function te(t){var e=U(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}if(e.listenerInfos){j(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){j(t.children,function(e){te(e)})}}function re(e,t,r){if(e.tagName==="BODY"){return se(e,t,r)}else{var n=e.previousSibling;ee(c(e),e,t,r);if(n==null){var i=c(e).firstChild}else{var i=n.nextSibling}U(e).replacedWith=i;r.elts=[];while(i&&i!==e){if(i.nodeType===Node.ELEMENT_NODE){r.elts.push(i)}i=i.nextElementSibling}te(e);c(e).removeChild(e)}}function ne(e,t,r){return ee(e,e.firstChild,t,r)}function ie(e,t,r){return ee(c(e),e,t,r)}function oe(e,t,r){return ee(e,null,t,r)}function ae(e,t,r){return ee(c(e),e.nextSibling,t,r)}function se(e,t,r){var n=e.firstChild;ee(e,n,t,r);if(n){while(n.nextSibling){te(n.nextSibling);e.removeChild(n.nextSibling)}te(n);e.removeChild(n)}}function ue(e,t){var r=X(e,"hx-select");if(r){var n=F().createDocumentFragment();j(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function le(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":re(r,n,i);return;case"afterbegin":ne(r,n,i);return;case"beforebegin":ie(r,n,i);return;case"beforeend":oe(r,n,i);return;case"afterend":ae(r,n,i);return;default:var o=tr(t);for(var a=0;a<o.length;a++){var s=o[a];try{var u=s.handleSwap(e,r,n,i);if(u){if(typeof u.length!=="undefined"){for(var l=0;l<u.length;l++){var f=u[l];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Y(f))}}}return}}catch(e){ut(e)}}se(r,n,i)}}var fe=/<title>([\s\S]+?)<\/title>/im;function ce(e){if(e.indexOf("<title>")>-1&&(e.indexOf("<svg>")==-1||e.indexOf("<title>")<e.indexOf("<svg>"))){var t=fe.exec(e);if(t){return t[1]}}}function he(e,t,r,n,i){var o=ce(n);if(o){var a=w("title");if(a){a.innerHTML=o}else{window.document.title=o}}var s=u(n);if(s){Z(s,i);s=ue(r,s);G(s);return le(e,r,t,s,i)}}function de(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=x(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!g(a)){a={value:a}}lt(r,o,a)}}}else{lt(r,n,[])}}var ve=/\s/;var ge=/[\s,]/;var pe=/[_$a-zA-Z]/;var me=/[_$a-zA-Z0-9]/;var ye=['"',"'","/"];var xe=/[^\s]/;function be(e){var t=[];var r=0;while(r<e.length){if(pe.exec(e.charAt(r))){var n=r;while(me.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(ye.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function we(e,t,r){return pe.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function Se(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Ut(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){ot(F().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(we(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function Ee(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var qe="input, textarea, select";function Re(e){var t=D(e,"hx-trigger");var r=[];if(t){var n=be(t);do{Ee(n,xe);var i=n.length;var o=Ee(n,/[,\[\s]/);if(o!==""){if(o==="every"){var a={trigger:"every"};Ee(n,xe);a.pollInterval=f(Ee(n,ve));r.push(a)}else if(o.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:o.substr(4)})}else{var s={trigger:o};var u=Se(e,n,"event");if(u){s.eventFilter=u}while(n.length>0&&n[0]!==","){Ee(n,xe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=f(Ee(n,ge))}else if(l==="from"&&n[0]===":"){n.shift();s.from=Ee(n,ge)}else if(l==="target"&&n[0]===":"){n.shift();s.target=Ee(n,ge)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=f(Ee(n,ge))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=Ee(n,ge)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=Ee(n,ge)}else{ot(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===i){ot(e,"htmx:syntax:error",{token:n.shift()})}Ee(n,xe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,qe)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ce(e){U(e).cancelled=true}function Oe(e,t,r,n){var i=U(e);i.timeout=setTimeout(function(){if(z(e)&&i.cancelled!==true){Zt(t,r,e);Oe(e,t,D(e,"hx-"+t),n)}},n)}function Le(e){return location.hostname===e.hostname&&l(e,"href")&&l(e,"href").indexOf("#")!==0}function Ae(t,r,e){if(t.tagName==="A"&&Le(t)||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=l(t,"href");r.pushURL=true}else{var o=l(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=l(t,"action")}e.forEach(function(e){Ie(t,n,i,r,e,true)})}}function Te(e){return e.tagName==="FORM"||d(e,'input[type="submit"], button')&&L(e,"form")!==null||e.tagName==="A"&&e.href&&(e.getAttribute("href")==="#"||e.getAttribute("href").indexOf("#")!==0)}function He(e,t){return U(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function Ne(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){ot(F().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Ie(n,i,o,e,a,s){var u=n;if(a.from){u=w(a.from)}var l=function(e){if(!z(n)){u.removeEventListener(a.trigger,l);return}if(He(n,e)){return}if(s||Te(n)){e.preventDefault()}if(Ne(a,e)){return}var t=U(e);t.triggerSpec=a;if(t.handledFor==null){t.handledFor=[]}var r=U(n);if(t.handledFor.indexOf(n)<0){t.handledFor.push(n);if(a.consume){e.stopPropagation()}if(a.target&&e.target){if(!d(e.target,a.target)){return}}if(a.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(a.changed){if(r.lastValue===n.value){return}else{r.lastValue=n.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(a.throttle){if(!r.throttle){Zt(i,o,n,e);r.throttle=setTimeout(function(){r.throttle=null},a.throttle)}}else if(a.delay){r.delayed=setTimeout(function(){Zt(i,o,n,e)},a.delay)}else{Zt(i,o,n,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:a.trigger,listener:l,on:u});u.addEventListener(a.trigger,l)}var Me=false;var ke=null;function De(){if(!ke){ke=function(){Me=true};window.addEventListener("scroll",ke);setInterval(function(){if(Me){Me=false;j(F().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){Fe(e)})}},200)}}function Fe(e){var t=U(e);if(!t.revealed&&m(e)){t.revealed=true;if(t.initialized){Zt(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Zt(t.verb,t.path,e)},{once:true})}}}function Xe(e,t,r){var n=y(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Pe(e,o[1],0)}if(o[0]==="send"){je(e)}}}function Pe(s,r,n){if(!z(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=k.createWebSocket(r);t.onerror=function(e){ot(s,"htmx:wsError",{error:e,socket:t});Ue(s)};t.onclose=function(e){if([1006,1012,1013].includes(e.code)){var t=ze(n);setTimeout(function(){Pe(s,r,n+1)},t)}};t.onopen=function(e){n=0};U(s).webSocket=t;t.addEventListener("message",function(e){if(Ue(s)){return}var t=e.data;st(s,function(e){t=e.transformResponse(t,null,s)});var r=Ft(s);var n=u(t);var i=p(n.children);for(var o=0;o<i.length;o++){var a=i[o];J(D(a,"hx-swap-oob")||"true",a,r)}mt(r.tasks)})}function Ue(e){if(!z(e)){U(e).webSocket.close();return true}}function je(l){var f=h(l,function(e){return U(e).webSocket!=null});if(f){l.addEventListener(Re(l)[0].trigger,function(e){var t=U(f).webSocket;var r=Nt(l,f);var n=Lt(l,"post");var i=n.errors;var o=n.values;var a=Vt(l);var s=V(o,a);var u=It(s,l);u["HEADERS"]=r;if(i&&i.length>0){lt(l,"htmx:validation:halted",i);return}t.send(JSON.stringify(u));if(Te(l)){e.preventDefault()}})}else{ot(l,"htmx:noWebSocketSourceError")}}function ze(e){var t=k.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}ut('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ve(e,t,r){var n=y(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){_e(e,o[1])}if(o[0]==="swap"){Be(e,o[1])}}}function _e(t,e){var r=k.createEventSource(e);r.onerror=function(e){ot(t,"htmx:sseError",{error:e,source:r});$e(t)};U(t).sseEventSource=r}function Be(o,a){var s=h(o,Je);if(s){var u=U(s).sseEventSource;var l=function(e){if($e(s)){u.removeEventListener(a,l);return}var t=e.data;st(o,function(e){t=e.transformResponse(t,null,o)});var r=kt(o);var n=_(o);var i=Ft(o);he(r.swapStyle,o,n,t,i);mt(i.tasks);lt(o,"htmx:sseMessage",e)};U(o).sseListener=l;u.addEventListener(a,l)}else{ot(o,"htmx:noSSESourceError")}}function We(e,t,r,n){var i=h(e,Je);if(i){var o=U(i).sseEventSource;var a=function(){if(!$e(i)){if(z(e)){Zt(t,r,e)}else{o.removeEventListener(n,a)}}};U(e).sseListener=a;o.addEventListener(n,a)}else{ot(e,"htmx:noSSESourceError")}}function $e(e){if(!z(e)){U(e).sseEventSource.close();return true}}function Je(e){return U(e).sseEventSource!=null}function Ze(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Zt(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function Ge(o,a,e){var t=false;j(r,function(n){if(s(o,"hx-"+n)){var i=D(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){We(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){De();Fe(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=T(e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){lt(o,"intersect");break}}},t);r.observe(o);Ie(o,n,i,a,e)}else if(e.trigger==="load"){Ze(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Oe(o,n,i,e.pollInterval)}else{Ie(o,n,i,a,e)}})}});return t}function Ke(e){if(e.type==="text/javascript"||e.type===""){try{Ut(e,function(){(1,eval)(e.innerText)})}catch(e){ut(e)}}}function Ye(e){if(d(e,"script")){Ke(e)}j(S(e,"script"),function(e){Ke(e)})}function Qe(){return document.querySelector("[hx-boost], [data-hx-boost]")}function et(e){if(e.querySelectorAll){var t=Qe()?", a, form":"";var r=e.querySelectorAll(n+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws]");return r}else{return[]}}function tt(e){if(e.closest&&e.closest(k.config.disableSelector)){return}var t=U(e);if(!t.initialized){t.initialized=true;lt(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=Re(e);var n=Ge(e,t,r);if(!n&&X(e,"hx-boost")==="true"){Ae(e,t,r)}var i=D(e,"hx-sse");if(i){Ve(e,t,i)}var o=D(e,"hx-ws");if(o){Xe(e,t,o)}lt(e,"htmx:afterProcessNode")}}function rt(e){e=H(e);tt(e);j(et(e),function(e){tt(e)})}function nt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function it(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=F().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function ot(e,t,r){lt(e,t,V({error:t},r))}function at(e){return e==="htmx:afterProcessNode"}function st(e,t){j(tr(e),function(e){try{t(e)}catch(e){ut(e)}})}function ut(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function lt(e,t,r){e=H(e);if(r==null){r={}}r["elt"]=e;var n=it(t,r);if(k.logger&&!at(t)){k.logger(e,t,r)}if(r.error){ut(r.error);lt(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=nt(t);if(i&&o!==t){var a=it(o,n.detail);i=i&&e.dispatchEvent(a)}st(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var ft=null;function ct(){var e=F().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||F().body}function ht(e,t,r,n){var i=x(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>k.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ot(F().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function dt(e){var t=x(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function vt(e){var t=k.config.requestClass;var r=e.cloneNode(true);j(S(r,"."+t),function(e){R(e,t)});return r.innerHTML}function gt(){var e=ct();var t=ft||location.pathname+location.search;lt(F().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(k.config.historyEnabled)history.replaceState({htmx:true},F().title,window.location.href);ht(t,vt(e),F().title,window.scrollY)}function pt(e){if(k.config.historyEnabled)history.pushState({htmx:true},"",e);ft=e}function mt(e){j(e,function(e){e.call()})}function yt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};lt(F().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){lt(F().body,"htmx:historyCacheMissLoad",i);var e=u(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=ct();var r=Ft(t);se(t,e,r);mt(r.tasks);ft=n;lt(F().body,"htmx:historyRestore",{path:n})}else{ot(F().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function xt(e){gt();e=e||location.pathname+location.search;var t=dt(e);if(t){var r=u(t.content);var n=ct();var i=Ft(n);se(n,r,i);mt(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);ft=e;lt(F().body,"htmx:historyRestore",{path:e})}else{if(k.config.refreshOnHistoryMiss){window.location.reload(true)}else{yt(e)}}}function bt(e){var t=X(e,"hx-push-url");return t&&t!=="false"||U(e).boosted&&U(e).pushURL}function wt(e){var t=X(e,"hx-push-url");return t==="true"||t==="false"?null:t}function St(e){var t=X(e,"hx-indicator");if(t){var r=A(e,t)}else{r=[e]}j(r,function(e){e.classList["add"].call(e.classList,k.config.requestClass)});return r}function Et(e){j(e,function(e){e.classList["remove"].call(e.classList,k.config.requestClass)})}function qt(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Rt(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 Ct(t,r,n,e,i){if(e==null||qt(t,e)){return}else{t.push(e)}if(Rt(e)){var o=l(e,"name");var a=e.value;if(e.multiple){a=p(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=p(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){Ot(e,n)}}if(d(e,"form")){var u=e.elements;j(u,function(e){Ct(t,r,n,e,i)})}}function Ot(e,t){if(e.willValidate){lt(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});lt(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Lt(e,t){var r=[];var n={};var i={};var o=[];var a=d(e,"form")&&e.noValidate!==true;if(t!=="get"){Ct(r,i,o,L(e,"form"),a)}Ct(r,n,o,e,a);var s=X(e,"hx-include");if(s){var u=A(e,s);j(u,function(e){Ct(r,n,o,e,a);if(!d(e,"form")){j(e.querySelectorAll(qe),function(e){Ct(r,n,o,e,a)})}})}n=V(n,i);return{errors:o,values:n}}function At(e,t,r){if(e!==""){e+="&"}e+=encodeURIComponent(t)+"="+encodeURIComponent(r);return e}function Tt(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){j(n,function(e){t=At(t,r,e)})}else{t=At(t,r,n)}}}return t}function Ht(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){j(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Nt(e,t,r){var n={"HX-Request":"true","HX-Trigger":l(e,"id"),"HX-Trigger-Name":l(e,"name"),"HX-Target":D(t,"id"),"HX-Current-URL":F().location.href};Pt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}return n}function It(t,e){var r=X(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){j(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};j(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Mt(e){return l(e,"href")&&l(e,"href").indexOf("#")>=0}function kt(e){var t=X(e,"hx-swap");var r={swapStyle:U(e).boosted?"innerHTML":k.config.defaultSwapStyle,swapDelay:k.config.defaultSwapDelay,settleDelay:k.config.defaultSettleDelay};if(U(e).boosted&&!Mt(e)){r["show"]="top"}if(t){var n=y(t);if(n.length>0){r["swapStyle"]=n[0];for(var i=1;i<n.length;i++){var o=n[i];if(o.indexOf("swap:")===0){r["swapDelay"]=f(o.substr(5))}if(o.indexOf("settle:")===0){r["settleDelay"]=f(o.substr(7))}if(o.indexOf("scroll:")===0){r["scroll"]=o.substr(7)}if(o.indexOf("show:")===0){r["show"]=o.substr(5)}}}}return r}function Dt(t,r,n){var i=null;st(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(X(r,"hx-encoding")==="multipart/form-data"){return Ht(n)}else{return Tt(n)}}}function Ft(e){return{tasks:[],elts:[e]}}function Xt(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){if(t.scroll==="top"&&r){r.scrollTop=0}if(t.scroll==="bottom"&&n){n.scrollTop=n.scrollHeight}}if(t.show){if(t.show==="top"&&r){r.scrollIntoView(true)}if(t.show==="bottom"&&n){n.scrollIntoView(false)}}}function Pt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=D(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Ut(e,function(){return Function("return ("+o+")")()},{})}else{s=x(o)}for(var u in s){if(s.hasOwnProperty(u)){if(n[u]==null){n[u]=s[u]}}}}return Pt(c(e),t,r,n)}function Ut(e,t,r){if(k.config.allowEval){return t()}else{ot(e,"htmx:evalDisallowedError");return r}}function jt(e,t){return Pt(e,"hx-vars",true,t)}function zt(e,t){return Pt(e,"hx-vals",false,t)}function Vt(e){return V(jt(e),zt(e))}function _t(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Bt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ot(F().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Wt(e,t){return e.getAllResponseHeaders().match(t)}function $t(e,t,r){if(r){if(r instanceof Element||a(r,"String")){return Zt(e,t,null,null,{targetOverride:H(r)})}else{return Zt(e,t,H(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:H(r.target)})}}else{return Zt(e,t)}}function Jt(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Zt(e,t,n,r,i){var o=null;var a=null;i=i!=null?i:{};if(typeof Promise!=="undefined"){var s=new Promise(function(e,t){o=e;a=t})}if(n==null){n=F().body}var u=i.handler||Gt;if(!z(n)){return}var l=i.targetOverride||_(n);if(l==null){ot(n,"htmx:targetError",{target:D(n,"hx-target")});return}var f=U(n);if(f.requestInFlight){var c="last";var h=U(r);if(h&&h.triggerSpec&&h.triggerSpec.queue){c=h.triggerSpec.queue}if(f.queuedRequests==null){f.queuedRequests=[]}if(c==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){Zt(e,t,n,r)})}else if(c==="all"){f.queuedRequests.push(function(){Zt(e,t,n,r)})}else if(c==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){Zt(e,t,n,r)})}return}else{f.requestInFlight=true}var d=function(){f.requestInFlight=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var v=X(n,"hx-prompt");if(v){var g=prompt(v);if(g===null||!lt(n,"htmx:prompt",{prompt:g,target:l})){P(o);d();return s}}var p=X(n,"hx-confirm");if(p){if(!confirm(p)){P(o);d();return s}}var m=new XMLHttpRequest;var y=Nt(n,l,g);if(i.headers){y=V(y,i.values)}var x=Lt(n,e);var b=x.errors;var w=x.values;if(i.values){w=V(w,i.values)}var S=Vt(n);var E=V(w,S);var q=It(E,n);if(e!=="get"&&X(n,"hx-encoding")==null){y["Content-Type"]="application/x-www-form-urlencoded; charset=UTF-8"}if(t==null||t===""){t=F().location.href}var R={parameters:q,unfilteredParameters:E,headers:y,target:l,verb:e,errors:b,path:t,triggeringEvent:r};if(!lt(n,"htmx:configRequest",R)){P(o);d();return s}t=R.path;e=R.verb;y=R.headers;q=R.parameters;b=R.errors;if(b&&b.length>0){lt(n,"htmx:validation:halted",R);P(o);d();return s}var C=t.split("#");var O=C[0];var L=C[1];if(e==="get"){var A=O;var T=Object.keys(q).length!==0;if(T){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=Tt(q);if(L){A+="#"+L}}m.open("GET",A,true)}else{m.open(e.toUpperCase(),t,true)}m.overrideMimeType("text/html");m.withCredentials=k.config.withCredentials;for(var H in y){if(y.hasOwnProperty(H)){var N=y[H];_t(m,H,N)}}var I={xhr:m,target:l,requestConfig:R,pathInfo:{path:t,finalPath:A,anchor:L}};m.onload=function(){try{var e=Jt(n);u(n,I);Et(M);lt(n,"htmx:afterRequest",I);lt(n,"htmx:afterOnLoad",I);if(!z(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(z(r)){t=r}}if(t){lt(t,"htmx:afterRequest",I);lt(t,"htmx:afterOnLoad",I)}}P(o);d()}catch(e){ot(n,"htmx:onLoadError",V({error:e},I));throw e}};m.onerror=function(){Et(M);ot(n,"htmx:afterRequest",I);ot(n,"htmx:sendError",I);P(a);d()};m.onabort=function(){Et(M);ot(n,"htmx:afterRequest",I);ot(n,"htmx:sendAbort",I);P(a);d()};if(!lt(n,"htmx:beforeRequest",I)){P(o);d();return s}var M=St(n);j(["loadstart","loadend","progress","abort"],function(t){j([m,m.upload],function(e){e.addEventListener(t,function(e){lt(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});lt(n,"htmx:beforeSend",I);m.send(e==="get"?null:Dt(m,n,q));return s}function Gt(a,s){var u=s.xhr;var l=s.target;if(!lt(a,"htmx:beforeOnLoad",s))return;if(Wt(u,/HX-Trigger:/i)){de(u,"HX-Trigger",a)}if(Wt(u,/HX-Push:/i)){var f=u.getResponseHeader("HX-Push")}if(Wt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Wt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}var c=bt(a)||f;if(u.status>=200&&u.status<400){if(u.status===286){Ce(a)}if(u.status!==204){if(!lt(l,"htmx:beforeSwap",s))return;var h=u.response;st(a,function(e){h=e.transformResponse(h,u,a)});if(c){gt()}var d=kt(a);l.classList.add(k.config.swappingClass);var e=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r=Ft(l);he(d.swapStyle,l,a,h,r);if(t.elt&&!z(t.elt)&&t.elt.id){var n=document.getElementById(t.elt.id);if(n){if(t.start&&n.setSelectionRange){n.setSelectionRange(t.start,t.end)}n.focus()}}l.classList.remove(k.config.swappingClass);j(r.elts,function(e){if(e.classList){e.classList.add(k.config.settlingClass)}lt(e,"htmx:afterSwap",s)});if(s.pathInfo.anchor){location.hash=s.pathInfo.anchor}if(Wt(u,/HX-Trigger-After-Swap:/i)){var i=a;if(!z(a)){i=F().body}de(u,"HX-Trigger-After-Swap",i)}var o=function(){j(r.tasks,function(e){e.call()});j(r.elts,function(e){if(e.classList){e.classList.remove(k.config.settlingClass)}lt(e,"htmx:afterSettle",s)});if(c){var e=f||wt(a)||Bt(u)||s.pathInfo.finalPath||s.pathInfo.path;pt(e);lt(F().body,"htmx:pushedIntoHistory",{path:e})}Xt(r.elts,d);if(Wt(u,/HX-Trigger-After-Settle:/i)){var t=a;if(!z(a)){t=F().body}de(u,"HX-Trigger-After-Settle",t)}};if(d.settleDelay>0){setTimeout(o,d.settleDelay)}else{o()}}catch(e){ot(a,"htmx:swapError",s);throw e}};if(d.swapDelay>0){setTimeout(e,d.swapDelay)}else{e()}}}else{ot(a,"htmx:responseError",V({error:"Response Status Error Code "+u.status+" from "+s.pathInfo.path},s))}}var Kt={};function Yt(){return{onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Qt(e,t){Kt[e]=V(Yt(),t)}function er(e){delete Kt[e]}function tr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=D(e,"hx-ext");if(t){j(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Kt[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return tr(c(e),r,n)}function rr(e){if(F().readyState!=="loading"){e()}else{F().addEventListener("DOMContentLoaded",e)}}function nr(){if(k.config.includeIndicatorStyles!==false){F().head.insertAdjacentHTML("beforeend","<style> ."+k.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+k.config.requestClass+" ."+k.config.indicatorClass+"{opacity:1} ."+k.config.requestClass+"."+k.config.indicatorClass+"{opacity:1} </style>")}}function ir(){var e=F().querySelector('meta[name="htmx-config"]');if(e){return x(e.content)}else{return null}}function or(){var e=ir();if(e){k.config=V(k.config,e)}}rr(function(){or();nr();var e=F().body;rt(e);window.onpopstate=function(e){if(e.state&&e.state.htmx){xt()}};setTimeout(function(){lt(e,"htmx:load",{})},0)});return k}()}); \ No newline at end of file +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(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 l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=k(e);e.classList.toggle(t)}function T(e,t){e=k(e);W(e.parentElement.children,function(e){q(e,t)});L(e,t)}function H(e,t){e=k(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function N(e,t){if(t.indexOf("closest ")===0){return[H(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[C(e,t.substr(5))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return z().querySelectorAll(t)}}function ee(e,t){if(t){return N(e,t)[0]}else{return N(z().body,e)[0]}}function k(e){if(p(e,"String")){return C(e)}else{return e}}function I(e,t,r){if(m(t)){return{target:z().body,event:e,listener:t}}else{return{target:k(e),event:t,listener:r}}}function M(t,r,n){lr(function(){var e=I(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function D(t,r,n){lr(function(){var e=I(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var te=z().createElement("output");function F(e,t){var r=G(e,t);if(r){if(r==="this"){return[re(e,t)]}else{var n=N(e,r);if(n.length===0){pt('The selector "'+r+'" on '+t+" returned no matches!");return[te]}else{return n}}}}function re(e,t){return h(e,function(e){return V(e,t)!=null})}function ne(e){var t=G(e,"hx-target");if(t){if(t==="this"){return re(e,"hx-target")}else{return ee(e,t)}}else{var r=_(e);if(r.boosted){return z().body}else{return e}}}function P(e){var t=U.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function X(t,r){W(t.attributes,function(e){if(!r.hasAttribute(e.name)&&P(e.name)){t.removeAttribute(e.name)}});W(r.attributes,function(e){if(P(e.name)){t.setAttribute(e.name,e.value)}})}function j(e,t){var r=sr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){pt(e)}}return e==="outerHTML"}function B(e,i,o){var t="#"+i.id;var a="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){a=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{a=e}var r=z().querySelectorAll(t);if(r){W(r,function(e){var t;var r=i.cloneNode(true);t=z().createDocumentFragment();t.appendChild(r);if(!j(a,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ye(a,e,e,t,o)}W(o.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(z().body,"htmx:oobErrorNoTarget",{content:i})}return e}function ie(e,r){W(R(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=V(e,"hx-swap-oob");if(t!=null){B(t,e,r)}})}function oe(e){W(R(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=V(e,"id");var r=z().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function ae(n,e,i){W(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();X(e,t);i.tasks.push(function(){X(e,r)})}}})}function se(e){return function(){q(e,U.config.addedClass);ct(e);at(e);le(e);$(e,"htmx:load")}}function le(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ue(e,t,r,n){ae(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(se(i))}}}function fe(t){var e=_(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){W(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){W(t.children,function(e){fe(e)})}}function ce(e,t,r){if(e.tagName==="BODY"){return me(e,t,r)}else{var n;var i=e.previousSibling;ue(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}_(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}fe(e);u(e).removeChild(e)}}function he(e,t,r){return ue(e,e.firstChild,t,r)}function de(e,t,r){return ue(u(e),e,t,r)}function ve(e,t,r){return ue(e,null,t,r)}function ge(e,t,r){return ue(u(e),e.nextSibling,t,r)}function pe(e,t,r){fe(e);return u(e).removeChild(e)}function me(e,t,r){var n=e.firstChild;ue(e,n,t,r);if(n){while(n.nextSibling){fe(n.nextSibling);e.removeChild(n.nextSibling)}fe(n);e.removeChild(n)}}function xe(e,t){var r=G(e,"hx-select");if(r){var n=z().createDocumentFragment();W(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function ye(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":ce(r,n,i);return;case"afterbegin":he(r,n,i);return;case"beforebegin":de(r,n,i);return;case"beforeend":ve(r,n,i);return;case"afterend":ge(r,n,i);return;case"delete":pe(r,n,i);return;default:var o=sr(t);for(var a=0;a<o.length;a++){var f=o[a];try{var s=f.handleSwap(e,r,n,i);if(s){if(typeof s.length!=="undefined"){for(var l=0;l<s.length;l++){var u=s[l];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){i.tasks.push(se(u))}}}return}}catch(e){pt(e)}}if(e==="innerHTML"){me(r,n,i)}else{ye(U.config.defaultSwapStyle,t,r,n,i)}}}function be(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function we(e,t,r,n,i){i.title=be(n);var o=g(n);if(o){ie(o,i);o=xe(r,o);oe(o);return ye(e,r,t,o,i)}}function Se(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!x(a)){a={value:a}}$(r,o,a)}}}else{$(r,n,[])}}var Ee=/\s/;var Ce=/[\s,]/;var Re=/[_$a-zA-Z]/;var Oe=/[_$a-zA-Z0-9]/;var Le=['"',"'","/"];var qe=/[^\s]/;function Ae(e){var t=[];var r=0;while(r<e.length){if(Re.exec(e.charAt(r))){var n=r;while(Oe.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Le.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function Te(e,t,r){return Re.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function He(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Jt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(z().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(Te(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var Ne="input, textarea, select";function ke(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=Ae(t);do{c(n,qe);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var o={trigger:"every"};c(n,qe);o.pollInterval=v(c(n,/[,\[\s]/));c(n,qe);var a=He(e,n,"event");if(a){o.eventFilter=a}r.push(o)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var a=He(e,n,"event");if(a){s.eventFilter=a}while(n.length>0&&n[0]!==","){c(n,qe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Ce))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Ce);if(u==="closest"||u==="find"){n.shift();u+=" "+c(n,Ce)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Ce)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Ce))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Ce)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Ce)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,qe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,Ne)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ie(e){_(e).cancelled=true}function Me(e,t,r,n){var i=_(e);i.timeout=setTimeout(function(){if(Y(e)&&i.cancelled!==true){if(!je(n,dt("hx:poll:trigger",{triggerSpec:n,target:e}))){Z(t,r,e)}Me(e,t,V(e,"hx-"+t),n)}},n.pollInterval)}function De(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&De(t)&&t.target===""||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href");r.pushURL=true}else{var o=f(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=f(t,"action")}e.forEach(function(e){Be(t,n,i,r,e,true)})}}function Pe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&H(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Xe(e,t){return _(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function je(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(z().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Be(o,a,s,e,l,u){var t;if(l.from){t=N(o,l.from)}else{t=[o]}W(t,function(n){var i=function(e){if(!Y(o)){n.removeEventListener(l.trigger,i);return}if(Xe(o,e)){return}if(u||Pe(e,o)){e.preventDefault()}if(je(l,e)){return}var t=_(e);t.triggerSpec=l;if(t.handledFor==null){t.handledFor=[]}var r=_(o);if(t.handledFor.indexOf(o)<0){t.handledFor.push(o);if(l.consume){e.stopPropagation()}if(l.target&&e.target){if(!d(e.target,l.target)){return}}if(l.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(l.changed){if(r.lastValue===o.value){return}else{r.lastValue=o.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(l.throttle){if(!r.throttle){Z(a,s,o,e);r.throttle=setTimeout(function(){r.throttle=null},l.throttle)}}else if(l.delay){r.delayed=setTimeout(function(){Z(a,s,o,e)},l.delay)}else{Z(a,s,o,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:l.trigger,listener:i,on:n});n.addEventListener(l.trigger,i)})}var Ue=false;var Ve=null;function ze(){if(!Ve){Ve=function(){Ue=true};window.addEventListener("scroll",Ve);setInterval(function(){if(Ue){Ue=false;W(z().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){_e(e)})}},200)}}function _e(e){if(!s(e,"data-hx-revealed")&&b(e)){e.setAttribute("data-hx-revealed","true");var t=_(e);if(t.initialized){Z(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Z(t.verb,t.path,e)},{once:true})}}}function We(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Je(e,o[1],0)}if(o[0]==="send"){Ze(e)}}}function Je(s,r,n){if(!Y(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=U.createWebSocket(r);t.onerror=function(e){J(s,"htmx:wsError",{error:e,socket:t});$e(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=Ge(n);setTimeout(function(){Je(s,r,n+1)},t)}};t.onopen=function(e){n=0};_(s).webSocket=t;t.addEventListener("message",function(e){if($e(s)){return}var t=e.data;gt(s,function(e){t=e.transformResponse(t,null,s)});var r=zt(s);var n=g(t);var i=y(n.children);for(var o=0;o<i.length;o++){var a=i[o];B(V(a,"hx-swap-oob")||"true",a,r)}Ct(r.tasks)})}function $e(e){if(!Y(e)){_(e).webSocket.close();return true}}function Ze(u){var f=h(u,function(e){return _(e).webSocket!=null});if(f){u.addEventListener(ke(u)[0].trigger,function(e){var t=_(f).webSocket;var r=Xt(u,f);var n=Mt(u,"post");var i=n.errors;var o=n.values;var a=Gt(u);var s=Q(o,a);var l=jt(s,u);l["HEADERS"]=r;if(i&&i.length>0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Pe(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ge(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}pt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ke(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Ye(e,o[1])}if(o[0]==="swap"){Qe(e,o[1])}}}function Ye(t,e){var r=U.createEventSource(e);r.onerror=function(e){J(t,"htmx:sseError",{error:e,source:r});tt(t)};_(t).sseEventSource=r}function Qe(o,a){var s=h(o,rt);if(s){var l=_(s).sseEventSource;var u=function(e){if(tt(s)){l.removeEventListener(a,u);return}var t=e.data;gt(o,function(e){t=e.transformResponse(t,null,o)});var r=Ut(o);var n=ne(o);var i=zt(o);we(r.swapStyle,o,n,t,i);Ct(i.tasks);$(o,"htmx:sseMessage",e)};_(o).sseListener=u;l.addEventListener(a,u)}else{J(o,"htmx:noSSESourceError")}}function et(e,t,r,n){var i=h(e,rt);if(i){var o=_(i).sseEventSource;var a=function(){if(!tt(i)){if(Y(e)){Z(t,r,e)}else{o.removeEventListener(n,a)}}};_(e).sseListener=a;o.addEventListener(n,a)}else{J(e,"htmx:noSSESourceError")}}function tt(e){if(!Y(e)){_(e).sseEventSource.close();return true}}function rt(e){return _(e).sseEventSource!=null}function nt(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Z(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function it(o,a,e){var t=false;W(n,function(n){if(s(o,"hx-"+n)){var i=V(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){et(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){ze();_e(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=ee(o,e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){$(o,"intersect");break}}},t);r.observe(o);Be(o,n,i,a,e)}else if(e.trigger==="load"){nt(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Me(o,n,i,e)}else{Be(o,n,i,a,e)}})}});return t}function ot(e){if(e.type==="text/javascript"||e.type==="module"||e.type===""){var t=z().createElement("script");W(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(U.config.inlineScriptNonce){t.nonce=U.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){pt(e)}finally{r.removeChild(e)}}}function at(e){if(d(e,"script")){ot(e)}W(R(e,"script"),function(e){ot(e)})}function st(){return document.querySelector("[hx-boost], [data-hx-boost]")}function lt(e){if(e.querySelectorAll){var t=st()?", a, form":"";var r=e.querySelectorAll(i+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [hx-data-ext]");return r}else{return[]}}function ut(r){var e=function(e){if(d(e.target,"button, input[type='submit']")){var t=_(r);t.lastButtonClicked=e.target}};r.addEventListener("click",e);r.addEventListener("focusin",e);r.addEventListener("focusout",function(e){var t=_(r);t.lastButtonClicked=null})}function ft(e){if(e.closest&&e.closest(U.config.disableSelector)){return}var t=_(e);if(!t.initialized){t.initialized=true;$(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=ke(e);var n=it(e,t,r);if(!n&&G(e,"hx-boost")==="true"){Fe(e,t,r)}if(e.tagName==="FORM"){ut(e)}var i=V(e,"hx-sse");if(i){Ke(e,t,i)}var o=V(e,"hx-ws");if(o){We(e,t,o)}$(e,"htmx:afterProcessNode")}}function ct(e){e=k(e);ft(e);W(lt(e),function(e){ft(e)})}function ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function dt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=z().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function J(e,t,r){$(e,t,Q({error:t},r))}function vt(e){return e==="htmx:afterProcessNode"}function gt(e,t){W(sr(e),function(e){try{t(e)}catch(e){pt(e)}})}function pt(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function $(e,t,r){e=k(e);if(r==null){r={}}r["elt"]=e;var n=dt(t,r);if(U.logger&&!vt(t)){U.logger(e,t,r)}if(r.error){pt(r.error);$(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=ht(t);if(i&&o!==t){var a=dt(o,n.detail);i=i&&e.dispatchEvent(a)}gt(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var mt=location.pathname+location.search;function xt(){var e=z().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||z().body}function yt(e,t,r,n){var i=S(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>U.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(z().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function bt(e){var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function wt(e){var t=U.config.requestClass;var r=e.cloneNode(true);W(R(r,"."+t),function(e){q(e,t)});return r.innerHTML}function St(){var e=xt();var t=mt||location.pathname+location.search;$(z().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(U.config.historyEnabled)history.replaceState({htmx:true},z().title,window.location.href);yt(t,wt(e),z().title,window.scrollY)}function Et(e){if(U.config.historyEnabled)history.pushState({htmx:true},"",e);mt=e}function Ct(e){W(e,function(e){e.call()})}function Rt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};$(z().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){$(z().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=xt();var r=zt(t);me(t,e,r);Ct(r.tasks);mt=n;$(z().body,"htmx:historyRestore",{path:n})}else{J(z().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Ot(e){St();e=e||location.pathname+location.search;var t=bt(e);if(t){var r=g(t.content);var n=xt();var i=zt(n);me(n,r,i);Ct(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);mt=e;$(z().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Rt(e)}}}function Lt(e){var t=G(e,"hx-push-url");return t&&t!=="false"||_(e).boosted&&_(e).pushURL}function qt(e){var t=G(e,"hx-push-url");return t==="true"||t==="false"?null:t}function At(e){var t=F(e,"hx-indicator");if(t==null){t=[e]}W(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Tt(e){W(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function Ht(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Nt(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 kt(t,r,n,e,i){if(e==null||Ht(t,e)){return}else{t.push(e)}if(Nt(e)){var o=f(e,"name");var a=e.value;if(e.multiple){a=y(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=y(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){It(e,n)}}if(d(e,"form")){var l=e.elements;W(l,function(e){kt(t,r,n,e,i)})}}function It(e,t){if(e.willValidate){$(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});$(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Mt(e,t){var r=[];var n={};var i={};var o=[];var a=_(e);var s=d(e,"form")&&e.noValidate!==true;if(a.lastButtonClicked){s=s&&a.lastButtonClicked.formNoValidate!==true}if(t!=="get"){kt(r,i,o,H(e,"form"),s)}kt(r,n,o,e,s);if(a.lastButtonClicked){var l=f(a.lastButtonClicked,"name");if(l){n[l]=a.lastButtonClicked.value}}var u=F(e,"hx-include");W(u,function(e){kt(r,n,o,e,s);if(!d(e,"form")){W(e.querySelectorAll(Ne),function(e){kt(r,n,o,e,s)})}});n=Q(n,i);return{errors:o,values:n}}function Dt(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function Ft(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=Dt(t,r,e)})}else{t=Dt(t,r,n)}}}return t}function Pt(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){W(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Xt(e,t,r){var n={"HX-Request":"true","HX-Trigger":f(e,"id"),"HX-Trigger-Name":f(e,"name"),"HX-Target":V(t,"id"),"HX-Current-URL":z().location.href};Wt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(_(e).boosted){n["HX-Boosted"]="true"}return n}function jt(t,e){var r=G(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){W(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};W(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Bt(e){return f(e,"href")&&f(e,"href").indexOf("#")>=0}function Ut(e,t){var r=t?t:G(e,"hx-swap");var n={swapStyle:_(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(_(e).boosted&&!Bt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var o=1;o<i.length;o++){var a=i[o];if(a.indexOf("swap:")===0){n["swapDelay"]=v(a.substr(5))}if(a.indexOf("settle:")===0){n["settleDelay"]=v(a.substr(7))}if(a.indexOf("scroll:")===0){var s=a.substr(7);var l=s.split(":");var f=l.pop();var u=l.length>0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(a.indexOf("show:")===0){var c=a.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(a.indexOf("focus-scroll:")===0){var d=a.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function Vt(t,r,n){var i=null;gt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(G(r,"hx-encoding")==="multipart/form-data"||d(r,"form")&&f(r,"enctype")==="multipart/form-data"){return Pt(n)}else{return Ft(n)}}}function zt(e){return{tasks:[],elts:[e]}}function _t(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ee(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var o=t.showTarget;if(t.showTarget==="window"){o="body"}i=ee(r,o)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function Wt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}else if(o.indexOf("js:")===0){o=o.substr(3);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Jt(e,function(){return Function("return ("+o+")")()},{})}else{s=S(o)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Wt(u(e),t,r,n)}function Jt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function $t(e,t){return Wt(e,"hx-vars",true,t)}function Zt(e,t){return Wt(e,"hx-vals",false,t)}function Gt(e){return Q($t(e),Zt(e))}function Kt(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Yt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(z().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Qt(e,t){return e.getAllResponseHeaders().match(t)}function er(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return Z(e,t,null,null,{targetOverride:k(r),returnPromise:true})}else{return Z(e,t,k(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:k(r.target),swapOverride:r.swap,returnPromise:true})}}else{return Z(e,t,null,null,{returnPromise:true})}}function tr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Z(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=z().body}var v=r.handler||rr;if(!Y(n)){return}var g=r.targetOverride||ne(n);if(g==null||g==te){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=_(n);var o=G(n,"hx-sync");var m=null;var x=false;if(o){var y=o.split(":");var b=y[0].trim();if(b==="this"){p=re(n,"hx-sync")}else{p=ee(n,b)}o=(y[1]||"drop").trim();i=_(p);if(o==="drop"&&i.xhr&&i.abortable!==true){return}else if(o==="abort"){if(i.xhr){return}else{x=true}}else if(o==="replace"){$(p,"htmx:abort")}else if(o.indexOf("queue")===0){var w=o.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=_(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){Z(e,t,n,f,r)})}return}}var a=new XMLHttpRequest;i.xhr=a;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=G(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){K(c);s();return d}}var R=G(n,"hx-confirm");if(R){if(!confirm(R)){K(c);s();return d}}var O=Xt(n,g,C);if(r.headers){O=Q(O,r.headers)}var L=Mt(n,e);var q=L.errors;var A=L.values;if(r.values){A=Q(A,r.values)}var T=Gt(n);var H=Q(A,T);var N=jt(H,n);if(e!=="get"&&G(n,"hx-encoding")==null){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=z().location.href}var k=Wt(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:q,withCredentials:r.credentials||k.credentials||U.config.withCredentials,timeout:r.timeout||k.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){K(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;q=l.errors;if(q&&q.length>0){$(n,"htmx:validation:halted",l);K(c);s();return d}var I=t.split("#");var M=I[0];var D=I[1];if(e==="get"){var F=M;var P=Object.keys(N).length!==0;if(P){if(F.indexOf("?")<0){F+="?"}else{F+="&"}F+=Ft(N);if(D){F+="#"+D}}a.open("GET",F,true)}else{a.open(e.toUpperCase(),t,true)}a.overrideMimeType("text/html");a.withCredentials=l.withCredentials;a.timeout=l.timeout;if(k.noHeaders){}else{for(var X in O){if(O.hasOwnProperty(X)){var j=O[X];Kt(a,X,j)}}}var u={xhr:a,target:g,requestConfig:l,etc:r,pathInfo:{path:t,finalPath:F,anchor:D}};a.onload=function(){try{var e=tr(n);v(n,u);Tt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!Y(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(Y(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}K(c);s()}catch(e){J(n,"htmx:onLoadError",Q({error:e},u));throw e}};a.onerror=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);K(h);s()};a.onabort=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);K(h);s()};a.ontimeout=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);K(h);s()};if(!$(n,"htmx:beforeRequest",u)){K(c);s();return d}var B=At(n);W(["loadstart","loadend","progress","abort"],function(t){W([a,a.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);a.send(e==="get"?null:Vt(a,n,N));return d}function rr(s,l){var u=l.xhr;var f=l.target;var r=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(Qt(u,/HX-Trigger:/i)){Se(u,"HX-Trigger",s)}if(Qt(u,/HX-Push:/i)){var c=u.getResponseHeader("HX-Push")}if(Qt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Qt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(Qt(u,/HX-Retarget:/i)){l.target=z().querySelector(u.getResponseHeader("HX-Retarget"))}var h;if(c=="false"){h=false}else{h=Lt(s)||c}var n=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var e=u.status>=400;var t=Q({shouldSwap:n,serverResponse:d,isError:e},l);if(!$(f,"htmx:beforeSwap",t))return;f=t.target;d=t.serverResponse;e=t.isError;l.failed=e;l.successful=!e;if(t.shouldSwap){if(u.status===286){Ie(s)}gt(s,function(e){d=e.transformResponse(d,u,s)});if(h){St()}var i=r.swapOverride;var v=Ut(s,i);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=zt(f);we(v.swapStyle,f,s,d,n);if(t.elt&&!Y(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);W(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(l.pathInfo.anchor){location.hash=l.pathInfo.anchor}if(Qt(u,/HX-Trigger-After-Swap:/i)){var o=s;if(!Y(s)){o=z().body}Se(u,"HX-Trigger-After-Swap",o)}var a=function(){W(n.tasks,function(e){e.call()});W(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h){var e=c||qt(s)||Yt(u)||l.pathInfo.finalPath||l.pathInfo.path;Et(e);$(z().body,"htmx:pushedIntoHistory",{path:e})}if(n.title){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}_t(n.elts,v);if(Qt(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!Y(s)){r=z().body}Se(u,"HX-Trigger-After-Settle",r)}};if(v.settleDelay>0){setTimeout(a,v.settleDelay)}else{a()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(v.swapDelay>0){setTimeout(o,v.swapDelay)}else{o()}}if(e){J(s,"htmx:responseError",Q({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var nr={};function ir(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function or(e,t){if(t.init){t.init(r)}nr[e]=Q(ir(),t)}function ar(e){delete nr[e]}function sr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){W(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=nr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return sr(u(e),r,n)}function lr(e){if(z().readyState!=="loading"){e()}else{z().addEventListener("DOMContentLoaded",e)}}function ur(){if(U.config.includeIndicatorStyles!==false){z().head.insertAdjacentHTML("beforeend","<style> ."+U.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+U.config.requestClass+" ."+U.config.indicatorClass+"{opacity:1} ."+U.config.requestClass+"."+U.config.indicatorClass+"{opacity:1} </style>")}}function fr(){var e=z().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function cr(){var e=fr();if(e){U.config=Q(U.config,e)}}lr(function(){cr();ur();var e=z().body;ct(e);var t=z().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=_(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){Ot();W(t,function(e){$(e,"htmx:restored",{document:z(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.js b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.js index e38f6ed..27e57bc 100644 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.js +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.js @@ -1,7 +1,9 @@ //AMD insanity (function (root, factory) { + //@ts-ignore if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. + //@ts-ignore define([], factory); } else { // Browser globals @@ -12,6 +14,8 @@ return (function () { 'use strict'; // Public API + //** @type {import("./htmx").HtmxApi} */ + // TODO: list all methods in public API var htmx = { onLoad: onLoadHelper, process: processNode, @@ -35,7 +39,6 @@ return (function () { removeExtension : removeExtension, logAll : logAll, logger : null, - useTemplateFragments: false, config : { historyEnabled:true, historyCacheSize:10, @@ -46,13 +49,19 @@ return (function () { includeIndicatorStyles:true, indicatorClass:'htmx-indicator', requestClass:'htmx-request', + addedClass:'htmx-added', settlingClass:'htmx-settling', swappingClass:'htmx-swapping', allowEval:true, + inlineScriptNonce:'', attributesToSettle:["class", "style", "width", "height"], withCredentials:false, + timeout:0, wsReconnectDelay: 'full-jitter', disableSelector: "[hx-disable], [data-hx-disable]", + useTemplateFragments: false, + scrollBehavior: 'smooth', + defaultFocusScroll: false, }, parseInterval:parseInterval, _:internalEval, @@ -61,9 +70,36 @@ return (function () { }, createWebSocket: function(url){ return new WebSocket(url, []); - } + }, + version: "1.7.0" }; + /** @type {import("./htmx").HtmxInternalApi} */ + var internalAPI = { + bodyContains: bodyContains, + filterValues: filterValues, + hasAttribute: hasAttribute, + getAttributeValue: getAttributeValue, + getClosestMatch: getClosestMatch, + getExpressionVars: getExpressionVars, + getHeaders: getHeaders, + getInputValues: getInputValues, + getInternalData: getInternalData, + getSwapSpecification: getSwapSpecification, + getTriggerSpecs: getTriggerSpecs, + getTarget: getTarget, + makeFragment: makeFragment, + mergeObjects: mergeObjects, + makeSettleInfo: makeSettleInfo, + oobSwap: oobSwap, + selectAndSwap: selectAndSwap, + settleImmediately: settleImmediately, + shouldCancel: shouldCancel, + triggerEvent: triggerEvent, + triggerErrorEvent: triggerErrorEvent, + withExtensions: withExtensions, + } + var VERBS = ['get', 'post', 'put', 'delete', 'patch']; var VERB_SELECTOR = VERBS.map(function(verb){ return "[hx-" + verb + "], [data-hx-" + verb + "]" @@ -73,19 +109,24 @@ return (function () { // Utilities //==================================================================== - function parseInterval(str) { - if (str == undefined) { - return undefined - } - if (str.slice(-2) == "ms") { - return parseFloat(str.slice(0,-2)) || undefined - } - if (str.slice(-1) == "s") { - return (parseFloat(str.slice(0,-1)) * 1000) || undefined - } - return parseFloat(str) || undefined + function parseInterval(str) { + if (str == undefined) { + return undefined + } + if (str.slice(-2) == "ms") { + return parseFloat(str.slice(0,-2)) || undefined + } + if (str.slice(-1) == "s") { + return (parseFloat(str.slice(0,-1)) * 1000) || undefined + } + return parseFloat(str) || undefined } + /** + * @param {HTMLElement} elt + * @param {string} name + * @returns {(string | null)} + */ function getRawAttribute(elt, name) { return elt.getAttribute && elt.getAttribute(name); } @@ -96,18 +137,36 @@ return (function () { elt.hasAttribute("data-" + qualifiedName)); } + /** + * + * @param {HTMLElement} elt + * @param {string} qualifiedName + * @returns {(string | null)} + */ function getAttributeValue(elt, qualifiedName) { return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); } + /** + * @param {HTMLElement} elt + * @returns {HTMLElement | null} + */ function parentElt(elt) { return elt.parentElement; } + /** + * @returns {Document} + */ function getDocument() { return document; } + /** + * @param {HTMLElement} elt + * @param {(e:HTMLElement) => boolean} condition + * @returns {HTMLElement | null} + */ function getClosestMatch(elt, condition) { if (condition(elt)) { return elt; @@ -118,22 +177,47 @@ return (function () { } } + function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ + var attributeValue = getAttributeValue(ancestor, attributeName); + var disinherit = getAttributeValue(ancestor, "hx-disinherit"); + if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) { + return "unset"; + } else { + return attributeValue + } + } + + /** + * @param {HTMLElement} elt + * @param {string} attributeName + * @returns {string | null} + */ function getClosestAttributeValue(elt, attributeName) { var closestAttr = null; getClosestMatch(elt, function (e) { - return closestAttr = getAttributeValue(e, attributeName); + return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName); }); - return closestAttr; + if (closestAttr !== "unset") { + return closestAttr; + } } + /** + * @param {HTMLElement} elt + * @param {string} selector + * @returns {boolean} + */ function matches(elt, selector) { + // @ts-ignore: non-standard properties for browser compatability // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || - elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector - || elt.webkitMatchesSelector || elt.oMatchesSelector; + var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; return matchesFunction && matchesFunction.call(elt, selector); } + /** + * @param {string} str + * @returns {string} + */ function getStartTag(str) { var tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i var match = tagMatcher.exec( str ); @@ -144,23 +228,40 @@ return (function () { } } + /** + * + * @param {string} resp + * @param {number} depth + * @returns {Element} + */ function parseHTML(resp, depth) { var parser = new DOMParser(); var responseDoc = parser.parseFromString(resp, "text/html"); + + /** @type {Element} */ var responseNode = responseDoc.body; while (depth > 0) { depth--; + // @ts-ignore responseNode = responseNode.firstChild; } if (responseNode == null) { + // @ts-ignore responseNode = getDocument().createDocumentFragment(); } return responseNode; } + /** + * + * @param {string} resp + * @returns {Element} + */ function makeFragment(resp) { if (htmx.config.useTemplateFragments) { var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0); + // @ts-ignore type mismatch between DocumentFragment and Element. + // TODO: Are these close enough for htmx to use interchangably? return documentFragment.querySelector('template').content; } else { var startTag = getStartTag(resp); @@ -186,24 +287,45 @@ return (function () { } } + /** + * @param {Function} func + */ function maybeCall(func){ if(func) { func(); } } + /** + * @param {any} o + * @param {string} type + * @returns + */ function isType(o, type) { return Object.prototype.toString.call(o) === "[object " + type + "]"; } + /** + * @param {*} o + * @returns {o is Function} + */ function isFunction(o) { return isType(o, "Function"); } + /** + * @param {*} o + * @returns {o is Object} + */ function isRawObject(o) { return isType(o, "Object"); } + /** + * getInternalData retrieves "private" data stored by htmx within an element + * @param {HTMLElement} elt + * @returns {*} + */ function getInternalData(elt) { var dataProp = 'htmx-internal-data'; var data = elt[dataProp]; @@ -213,6 +335,11 @@ return (function () { return data; } + /** + * toArray converts an ArrayLike object into a real array. + * @param {ArrayLike} arr + * @returns {any[]} + */ function toArray(arr) { var returnArr = []; if (arr) { @@ -238,14 +365,25 @@ return (function () { return elemTop < window.innerHeight && elemBottom >= 0; } - function bodyContains(elt) { - return getDocument().body.contains(elt); - } + function bodyContains(elt) { + if (elt.getRootNode() instanceof ShadowRoot) { + return getDocument().body.contains(elt.getRootNode().host); + } else { + return getDocument().body.contains(elt); + } + } function splitOnWhitespace(trigger) { return trigger.trim().split(/\s+/); } + /** + * mergeObjects takes all of the keys from + * obj2 and duplicates them into obj1 + * @param {Object} obj1 + * @param {Object} obj2 + * @returns {Object} + */ function mergeObjects(obj1, obj2) { for (var key in obj2) { if (obj2.hasOwnProperty(key)) { @@ -319,7 +457,7 @@ return (function () { if (delay) { setTimeout(function(){addClassToElement(elt, clazz);}, delay) } else { - elt.classList.add(clazz); + elt.classList && elt.classList.add(clazz); } } @@ -328,7 +466,13 @@ return (function () { if (delay) { setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) } else { - elt.classList.remove(clazz); + if (elt.classList) { + elt.classList.remove(clazz); + // if there are no classes left, remove the class attribute + if (elt.classList.length === 0) { + elt.removeAttribute("class"); + } + } } } @@ -360,17 +504,25 @@ return (function () { } function querySelectorAllExt(elt, selector) { - if (selector.indexOf("closest ") === 0) { + if (selector.indexOf("closest ") === 0) { return [closest(elt, selector.substr(8))]; } else if (selector.indexOf("find ") === 0) { return [find(elt, selector.substr(5))]; + } else if (selector === 'document') { + return [document]; + } else if (selector === 'window') { + return [window]; } else { return getDocument().querySelectorAll(selector); } } function querySelectorExt(eltOrSelector, selector) { - return querySelectorAllExt(eltOrSelector, selector)[0] + if (selector) { + return querySelectorAllExt(eltOrSelector, selector)[0]; + } else { + return querySelectorAllExt(getDocument().body, eltOrSelector)[0]; + } } function resolveTarget(arg2) { @@ -418,13 +570,36 @@ return (function () { //==================================================================== // Node processing //==================================================================== + + var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors + function findAttributeTargets(elt, attrName) { + var attrTarget = getClosestAttributeValue(elt, attrName); + if (attrTarget) { + if (attrTarget === "this") { + return [findThisElement(elt, attrName)]; + } else { + var result = querySelectorAllExt(elt, attrTarget); + if (result.length === 0) { + logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!"); + return [DUMMY_ELT] + } else { + return result; + } + } + } + } + + function findThisElement(elt, attribute){ + return getClosestMatch(elt, function (elt) { + return getAttributeValue(elt, attribute) != null; + }) + } function getTarget(elt) { - var explicitTarget = getClosestMatch(elt, function(e){return getAttributeValue(e,"hx-target") !== null}); - if (explicitTarget) { - var targetStr = getAttributeValue(explicitTarget, "hx-target"); + var targetStr = getClosestAttributeValue(elt, "hx-target"); + if (targetStr) { if (targetStr === "this") { - return explicitTarget; + return findThisElement(elt,'hx-target'); } else { return querySelectorExt(elt, targetStr) } @@ -476,6 +651,13 @@ return (function () { return swapStyle === "outerHTML"; } + /** + * + * @param {string} oobValue + * @param {HTMLElement} oobElement + * @param {*} settleInfo + * @returns + */ function oobSwap(oobValue, oobElement, settleInfo) { var selector = "#" + oobElement.id; var swapStyle = "outerHTML"; @@ -488,18 +670,35 @@ return (function () { swapStyle = oobValue; } - var target = getDocument().querySelector(selector); - if (target) { - var fragment; - fragment = getDocument().createDocumentFragment(); - fragment.appendChild(oobElement); // pulls the child out of the existing fragment - if (!isInlineSwap(swapStyle, target)) { - fragment = oobElement; // if this is not an inline swap, we use the content of the node, not the node itself - } - swap(swapStyle, target, target, fragment, settleInfo); + var targets = getDocument().querySelectorAll(selector); + if (targets) { + forEach( + targets, + function (target) { + var fragment; + var oobElementClone = oobElement.cloneNode(true); + fragment = getDocument().createDocumentFragment(); + fragment.appendChild(oobElementClone); + if (!isInlineSwap(swapStyle, target)) { + fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself + } + + var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment }; + if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return; + + target = beforeSwapDetails.target; // allow re-targeting + if (beforeSwapDetails['shouldSwap']){ + swap(swapStyle, target, target, fragment, settleInfo); + } + forEach(settleInfo.elts, function (elt) { + triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails); + }); + } + ); + oobElement.parentNode.removeChild(oobElement); } else { oobElement.parentNode.removeChild(oobElement); - triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}) + triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}); } return oobValue; } @@ -540,6 +739,7 @@ return (function () { function makeAjaxLoadTask(child) { return function () { + removeClassFromElement(child, htmx.config.addedClass); processNode(child); processScripts(child); processFocus(child) @@ -559,6 +759,7 @@ return (function () { handleAttributes(parentNode, fragment, settleInfo); while(fragment.childNodes.length > 0){ var child = fragment.firstChild; + addClassToElement(child, htmx.config.addedClass); parentNode.insertBefore(child, insertBefore); if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { settleInfo.tasks.push(makeAjaxLoadTask(child)); @@ -574,6 +775,9 @@ return (function () { if (internalData.sseEventSource) { internalData.sseEventSource.close(); } + + triggerEvent(element, "htmx:beforeCleanupElement") + if (internalData.listenerInfos) { forEach(internalData.listenerInfos, function(info) { if (element !== info.on) { @@ -590,12 +794,14 @@ return (function () { if (target.tagName === "BODY") { return swapInnerHTML(target, fragment, settleInfo); } else { + // @type {HTMLElement} + var newElt var eltBeforeNewContent = target.previousSibling; insertNodesBefore(parentElt(target), target, fragment, settleInfo); if (eltBeforeNewContent == null) { - var newElt = parentElt(target).firstChild; + newElt = parentElt(target).firstChild; } else { - var newElt = eltBeforeNewContent.nextSibling; + newElt = eltBeforeNewContent.nextSibling; } getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later settleInfo.elts = [] // clear existing elements @@ -625,6 +831,10 @@ return (function () { function swapAfterEnd(target, fragment, settleInfo) { return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo); } + function swapDelete(target, fragment, settleInfo) { + cleanUpElement(target); + return parentElt(target).removeChild(target); + } function swapInnerHTML(target, fragment, settleInfo) { var firstChild = target.firstChild; @@ -670,6 +880,9 @@ return (function () { case "afterend": swapAfterEnd(target, fragment, settleInfo); return; + case "delete": + swapDelete(target, fragment, settleInfo); + return; default: var extensions = getExtensions(elt); for (var i = 0; i < extensions.length; i++) { @@ -692,32 +905,27 @@ return (function () { logError(e); } } - swapInnerHTML(target, fragment, settleInfo); + if (swapStyle === "innerHTML") { + swapInnerHTML(target, fragment, settleInfo); + } else { + swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo); + } } } - var TITLE_FINDER = /<title>([\s\S]+?)<\/title>/im; function findTitle(content) { - if(content.indexOf('<title>') > -1 && - (content.indexOf('<svg>') == -1 || - content.indexOf('<title>') < content.indexOf('<svg>'))) { - var result = TITLE_FINDER.exec(content); + if (content.indexOf('<title') > -1) { + var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, ''); + var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im); + if (result) { - return result[1]; + return result[2]; } } } function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) { - var title = findTitle(responseText); - if(title) { - var titleElt = find("title"); - if(titleElt) { - titleElt.innerHTML = title; - } else { - window.document.title = title; - } - } + settleInfo.title = findTitle(responseText); var fragment = makeFragment(responseText); if (fragment) { handleOutOfBandSwaps(fragment, settleInfo); @@ -840,6 +1048,11 @@ return (function () { } var INPUT_SELECTOR = 'input, textarea, select'; + + /** + * @param {HTMLElement} elt + * @returns {import("./htmx").HtmxTriggerSpecification[]} + */ function getTriggerSpecs(elt) { var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); var triggerSpecs = []; @@ -853,7 +1066,12 @@ return (function () { if (trigger === "every") { var every = {trigger: 'every'}; consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, WHITESPACE)); + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); + consumeUntil(tokens, NOT_WHITESPACE); + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + every.eventFilter = eventFilter; + } triggerSpecs.push(every); } else if (trigger.indexOf("sse:") === 0) { triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); @@ -877,7 +1095,17 @@ return (function () { triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); } else if (token === "from" && tokens[0] === ":") { tokens.shift(); - triggerSpec.from = consumeUntil(tokens, WHITESPACE_OR_COMMA); + var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); + if (from_arg === "closest" || from_arg === "find") { + tokens.shift(); + from_arg += + " " + + consumeUntil( + tokens, + WHITESPACE_OR_COMMA + ); + } + triggerSpec.from = from_arg; } else if (token === "target" && tokens[0] === ":") { tokens.shift(); triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA); @@ -919,14 +1147,16 @@ return (function () { getInternalData(elt).cancelled = true; } - function processPolling(elt, verb, path, interval) { + function processPolling(elt, verb, path, spec) { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - issueAjaxRequest(verb, path, elt); - processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), interval); + if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { + issueAjaxRequest(verb, path, elt); + } + processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), spec); } - }, interval); + }, spec.pollInterval); } function isLocalLink(elt) { @@ -936,7 +1166,7 @@ return (function () { } function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt)) || elt.tagName === "FORM") { + if ((elt.tagName === "A" && isLocalLink(elt) && elt.target === "") || elt.tagName === "FORM") { nodeData.boosted = true; var verb, path; if (elt.tagName === "A") { @@ -957,11 +1187,26 @@ return (function () { } } - function shouldCancel(elt) { - return elt.tagName === "FORM" || - (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) || - (elt.tagName === "A" && elt.href && (elt.getAttribute('href') === '#' || - elt.getAttribute('href').indexOf("#") !== 0)); + /** + * + * @param {Event} evt + * @param {HTMLElement} elt + * @returns + */ + function shouldCancel(evt, elt) { + if (evt.type === "submit" || evt.type === "click") { + if (elt.tagName === "FORM") { + return true; + } + if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { + return true; + } + if (elt.tagName === "A" && elt.href && + (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) { + return true; + } + } + return false; } function ignoreBoostedAnchorCtrlClick(elt, evt) { @@ -982,86 +1227,90 @@ return (function () { } function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { - var eltToListenOn = elt; + var eltsToListenOn; if (triggerSpec.from) { - eltToListenOn = find(triggerSpec.from); + eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); + } else { + eltsToListenOn = [elt]; } - var eventListener = function (evt) { - if (!bodyContains(elt)) { - eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); - return; - } - if (ignoreBoostedAnchorCtrlClick(elt, evt)) { - return; - } - if(explicitCancel || shouldCancel(elt)){ - evt.preventDefault(); - } - if (maybeFilterEvent(triggerSpec, evt)) { - return; - } - var eventData = getInternalData(evt); - eventData.triggerSpec = triggerSpec; - if (eventData.handledFor == null) { - eventData.handledFor = []; - } - var elementData = getInternalData(elt); - if (eventData.handledFor.indexOf(elt) < 0) { - eventData.handledFor.push(elt); - if (triggerSpec.consume) { - evt.stopPropagation(); - } - if (triggerSpec.target && evt.target) { - if (!matches(evt.target, triggerSpec.target)) { - return; - } - } - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } + forEach(eltsToListenOn, function (eltToListenOn) { + var eventListener = function (evt) { + if (!bodyContains(elt)) { + eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); + return; } - if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { - return; - } else { - elementData.lastValue = elt.value; - } + if (ignoreBoostedAnchorCtrlClick(elt, evt)) { + return; } - if (elementData.delayed) { - clearTimeout(elementData.delayed); + if (explicitCancel || shouldCancel(evt, elt)) { + evt.preventDefault(); } - if (elementData.throttle) { + if (maybeFilterEvent(triggerSpec, evt)) { return; } + var eventData = getInternalData(evt); + eventData.triggerSpec = triggerSpec; + if (eventData.handledFor == null) { + eventData.handledFor = []; + } + var elementData = getInternalData(elt); + if (eventData.handledFor.indexOf(elt) < 0) { + eventData.handledFor.push(elt); + if (triggerSpec.consume) { + evt.stopPropagation(); + } + if (triggerSpec.target && evt.target) { + if (!matches(evt.target, triggerSpec.target)) { + return; + } + } + 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); + } + if (elementData.throttle) { + return; + } - if (triggerSpec.throttle) { - if(!elementData.throttle) { + if (triggerSpec.throttle) { + if (!elementData.throttle) { + issueAjaxRequest(verb, path, elt, evt); + elementData.throttle = setTimeout(function () { + elementData.throttle = null; + }, triggerSpec.throttle); + } + } else if (triggerSpec.delay) { + elementData.delayed = setTimeout(function () { + issueAjaxRequest(verb, path, elt, evt); + }, triggerSpec.delay); + } else { issueAjaxRequest(verb, path, elt, evt); - elementData.throttle = setTimeout(function(){ - elementData.throttle = null; - }, triggerSpec.throttle); } - } else if (triggerSpec.delay) { - elementData.delayed = setTimeout(function(){ - issueAjaxRequest(verb, path, elt, evt); - }, triggerSpec.delay); - } else { - issueAjaxRequest(verb, path, elt, evt); } - } - }; - if (nodeData.listenerInfos == null) { - nodeData.listenerInfos = []; - } - nodeData.listenerInfos.push({ - trigger: triggerSpec.trigger, - listener: eventListener, - on: eltToListenOn + }; + if (nodeData.listenerInfos == null) { + nodeData.listenerInfos = []; + } + nodeData.listenerInfos.push({ + trigger: triggerSpec.trigger, + listener: eventListener, + on: eltToListenOn + }) + eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); }) - eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); } var windowIsScrolling = false // used by initScrollHandler @@ -1084,9 +1333,9 @@ return (function () { } function maybeReveal(elt) { - var nodeData = getInternalData(elt); - if (!nodeData.revealed && isScrolledIntoView(elt)) { - nodeData.revealed = true; + if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { + elt.setAttribute('data-hx-revealed', 'true'); + var nodeData = getInternalData(elt); if (nodeData.initialized) { issueAjaxRequest(nodeData.verb, nodeData.path, elt); } else { @@ -1099,6 +1348,10 @@ return (function () { } } + //==================================================================== + // Web Sockets + //==================================================================== + function processWebSocketInfo(elt, nodeData, info) { var values = splitOnWhitespace(info); for (var i = 0; i < values.length; i++) { @@ -1132,7 +1385,7 @@ return (function () { }; socket.onclose = function (e) { - if ([1006, 1012, 1013].includes(e.code)) { // Abnormal Closure/Service Restart/Try Again Later + if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later var delay = getWebSocketReconnectDelay(retryCount); setTimeout(function() { ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout @@ -1193,7 +1446,7 @@ return (function () { return; } webSocket.send(JSON.stringify(filteredParameters)); - if(shouldCancel(elt)){ + if(shouldCancel(evt, elt)){ evt.preventDefault(); } }); @@ -1205,6 +1458,7 @@ return (function () { function getWebSocketReconnectDelay(retryCount) { var delay = htmx.config.wsReconnectDelay; if (typeof delay === 'function') { + // @ts-ignore return delay(retryCount); } if (delay === 'full-jitter') { @@ -1340,7 +1594,7 @@ return (function () { } else if (triggerSpec.trigger === "intersect") { var observerOptions = {}; if (triggerSpec.root) { - observerOptions.root = querySelectorExt(triggerSpec.root) + observerOptions.root = querySelectorExt(elt, triggerSpec.root) } if (triggerSpec.threshold) { observerOptions.threshold = parseFloat(triggerSpec.threshold); @@ -1360,7 +1614,7 @@ return (function () { loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); } else if (triggerSpec.pollInterval) { nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec.pollInterval); + processPolling(elt, verb, path, triggerSpec); } else { addEventListener(elt, verb, path, nodeData, triggerSpec); } @@ -1371,14 +1625,24 @@ return (function () { } function evalScript(script) { - if (script.type === "text/javascript" || script.type === "") { + if (script.type === "text/javascript" || script.type === "module" || script.type === "") { + var newScript = getDocument().createElement("script"); + forEach(script.attributes, function (attr) { + newScript.setAttribute(attr.name, attr.value); + }); + newScript.textContent = script.textContent; + newScript.async = false; + if (htmx.config.inlineScriptNonce) { + newScript.nonce = htmx.config.inlineScriptNonce; + } + var parent = script.parentElement; + try { - maybeEval(script, function () { - // wtf - https://stackoverflow.com/questions/9107240/1-evalthis-vs-evalthis-in-javascript - (1, eval)(script.innerText); - }); + parent.insertBefore(newScript, script); } catch (e) { logError(e); + } finally { + parent.removeChild(script); } } } @@ -1392,21 +1656,41 @@ return (function () { }); } - function isBoosted() { + function hasChanceOfBeingBoosted() { return document.querySelector("[hx-boost], [data-hx-boost]"); } function findElementsToProcess(elt) { if (elt.querySelectorAll) { - var boostedElts = isBoosted() ? ", a, form" : ""; + var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws]"); + " [data-hx-ws], [hx-ext], [hx-data-ext]"); return results; } else { return []; } } + function initButtonTracking(form){ + var maybeSetLastButtonClicked = function(evt){ + if (matches(evt.target, "button, input[type='submit']")) { + var internalData = getInternalData(form); + internalData.lastButtonClicked = evt.target; + } + }; + + // need to handle both click and focus in: + // focusin - in case someone tabs in to a button and hits the space bar + // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + + form.addEventListener('click', maybeSetLastButtonClicked) + form.addEventListener('focusin', maybeSetLastButtonClicked) + form.addEventListener('focusout', function(evt){ + var internalData = getInternalData(form); + internalData.lastButtonClicked = null; + }) + } + function initNode(elt) { if (elt.closest && elt.closest(htmx.config.disableSelector)) { return; @@ -1427,6 +1711,10 @@ return (function () { boostElement(elt, nodeData, triggerSpecs); } + if (elt.tagName === "FORM") { + initButtonTracking(elt); + } + var sseInfo = getAttributeValue(elt, 'hx-sse'); if (sseInfo) { processSSEInfo(elt, nodeData, sseInfo); @@ -1473,6 +1761,15 @@ return (function () { return eventName === "htmx:afterProcessNode" } + /** + * `withExtensions` locates all active extensions for a provided element, then + * executes the provided function using each of the active extensions. It should + * be called internally at every extendable execution point in htmx. + * + * @param {HTMLElement} elt + * @param {(extension:import("./htmx").HtmxExtension) => void} toDo + * @returns void + */ function withExtensions(elt, toDo) { forEach(getExtensions(elt), function(extension){ try { @@ -1520,7 +1817,7 @@ return (function () { //==================================================================== // History Support //==================================================================== - var currentPathForHistory = null; + var currentPathForHistory = location.pathname+location.search; function getHistoryElement() { var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]'); @@ -1569,7 +1866,7 @@ return (function () { return clone.innerHTML; } - function saveHistory() { + function saveCurrentPageToHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); @@ -1598,9 +1895,11 @@ return (function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); var fragment = makeFragment(this.response); + // @ts-ignore fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; var historyElement = getHistoryElement(); var settleInfo = makeSettleInfo(historyElement); + // @ts-ignore swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); currentPathForHistory = path; @@ -1613,7 +1912,7 @@ return (function () { } function restoreHistory(path) { - saveHistory(); + saveCurrentPageToHistory(); path = path || location.pathname+location.search; var cached = getCachedHistory(path); if (cached) { @@ -1628,6 +1927,8 @@ return (function () { triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); } else { if (htmx.config.refreshOnHistoryMiss) { + + // @ts-ignore: optional parameter in reload() function throws error window.location.reload(true); } else { loadHistoryFromServer(path); @@ -1647,10 +1948,8 @@ return (function () { } function addRequestIndicatorClasses(elt) { - var indicator = getClosestAttributeValue(elt, 'hx-indicator'); - if (indicator) { - var indicators = querySelectorAllExt(elt, indicator); - } else { + var indicators = findAttributeTargets(elt, 'hx-indicator'); + if (indicators == null) { indicators = [elt]; } forEach(indicators, function (ic) { @@ -1753,14 +2052,22 @@ return (function () { } } + /** + * @param {HTMLElement} elt + * @param {string} verb + */ function getInputValues(elt, verb) { var processed = []; var values = {}; var formValues = {}; var errors = []; + var internalData = getInternalData(elt); - // only validate when form is directly submitted and novalidate is not set + // only validate when form is directly submitted and novalidate or formnovalidate are not set var validate = matches(elt, 'form') && elt.noValidate !== true; + if (internalData.lastButtonClicked) { + validate = validate && internalData.lastButtonClicked.formNoValidate !== true; + } // for a non-GET include the closest form if (verb !== 'get') { @@ -1770,21 +2077,26 @@ return (function () { // include the element itself processInputValue(processed, values, errors, elt, validate); - // include any explicit includes - var includes = getClosestAttributeValue(elt, "hx-include"); - if (includes) { - var nodes = querySelectorAllExt(elt, includes); - forEach(nodes, function(node) { - processInputValue(processed, values, errors, node, validate); - // if a non-form is included, include any input values within it - if (!matches(node, 'form')) { - forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { - processInputValue(processed, values, errors, descendant, validate); - }) - } - }); + // if a button or submit was clicked last, include its value + if (internalData.lastButtonClicked) { + var name = getRawAttribute(internalData.lastButtonClicked,"name"); + if (name) { + values[name] = internalData.lastButtonClicked.value; + } } + // include any explicit includes + var includes = findAttributeTargets(elt, "hx-include"); + forEach(includes, function(node) { + processInputValue(processed, values, errors, node, validate); + // if a non-form is included, include any input values within it + if (!matches(node, 'form')) { + forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { + processInputValue(processed, values, errors, descendant, validate); + }) + } + }); + // form values take precedence, overriding the regular values values = mergeObjects(values, formValues); @@ -1795,7 +2107,11 @@ return (function () { if (returnStr !== "") { returnStr += "&"; } - returnStr += encodeURIComponent(name) + "=" + encodeURIComponent(realValue); + if (String(realValue) === "[object Object]") { + realValue = JSON.stringify(realValue); + } + var s = encodeURIComponent(realValue); + returnStr += encodeURIComponent(name) + "=" + s; return returnStr; } @@ -1837,6 +2153,12 @@ return (function () { // Ajax //==================================================================== + /** + * @param {HTMLElement} elt + * @param {HTMLElement} target + * @param {string} prompt + * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification + */ function getHeaders(elt, target, prompt) { var headers = { "HX-Request" : "true", @@ -1849,9 +2171,20 @@ return (function () { if (prompt !== undefined) { headers["HX-Prompt"] = prompt; } + if (getInternalData(elt).boosted) { + headers["HX-Boosted"] = "true"; + } return headers; } + /** + * filterValues takes an object containing form input values + * and returns a new object that only contains keys that are + * specified by the closest "hx-params" attribute + * @param {Object} inputValues + * @param {HTMLElement} elt + * @returns {Object} + */ function filterValues(inputValues, elt) { var paramsValue = getClosestAttributeValue(elt, "hx-params"); if (paramsValue) { @@ -1882,8 +2215,14 @@ return (function () { return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0 } - function getSwapSpecification(elt) { - var swapInfo = getClosestAttributeValue(elt, "hx-swap"); + /** + * + * @param {HTMLElement} elt + * @param {string} swapInfoOverride + * @returns {import("./htmx").HtmxSwapSpecification} + */ + function getSwapSpecification(elt, swapInfoOverride) { + var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap"); var swapSpec = { "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, "swapDelay" : htmx.config.defaultSwapDelay, @@ -1905,10 +2244,24 @@ return (function () { swapSpec["settleDelay"] = parseInterval(modifier.substr(7)); } if (modifier.indexOf("scroll:") === 0) { - swapSpec["scroll"] = modifier.substr(7); + var scrollSpec = modifier.substr(7); + var splitSpec = scrollSpec.split(":"); + var scrollVal = splitSpec.pop(); + var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; + swapSpec["scroll"] = scrollVal; + swapSpec["scrollTarget"] = selectorVal; } if (modifier.indexOf("show:") === 0) { - swapSpec["show"] = modifier.substr(5); + var showSpec = modifier.substr(5); + var splitSpec = showSpec.split(":"); + var showVal = splitSpec.pop(); + var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; + swapSpec["show"] = showVal; + swapSpec["showTarget"] = selectorVal; + } + if (modifier.indexOf("focus-scroll:") === 0) { + var focusScrollVal = modifier.substr("focus-scroll:".length); + swapSpec["focusScroll"] = focusScrollVal == "true"; } } } @@ -1926,7 +2279,8 @@ return (function () { if (encodedParameters != null) { return encodedParameters; } else { - if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data") { + if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || + (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) { return makeFormData(filteredParameters); } else { return urlEncode(filteredParameters); @@ -1934,6 +2288,11 @@ return (function () { } } + /** + * + * @param {Element} target + * @returns {import("./htmx").HtmxSettleInfo} + */ function makeSettleInfo(target) { return {tasks: [], elts: [target]}; } @@ -1942,23 +2301,46 @@ return (function () { var first = content[0]; var last = content[content.length - 1]; if (swapSpec.scroll) { - if (swapSpec.scroll === "top" && first) { - first.scrollTop = 0; + var target = null; + if (swapSpec.scrollTarget) { + target = querySelectorExt(first, swapSpec.scrollTarget); + } + if (swapSpec.scroll === "top" && (first || target)) { + target = target || first; + target.scrollTop = 0; } - if (swapSpec.scroll === "bottom" && last) { - last.scrollTop = last.scrollHeight; + if (swapSpec.scroll === "bottom" && (last || target)) { + target = target || last; + target.scrollTop = target.scrollHeight; } } if (swapSpec.show) { - if (swapSpec.show === "top" && first) { - first.scrollIntoView(true); + var target = null; + if (swapSpec.showTarget) { + var targetStr = swapSpec.showTarget; + if (swapSpec.showTarget === "window") { + targetStr = "body"; + } + target = querySelectorExt(first, targetStr); + } + if (swapSpec.show === "top" && (first || target)) { + target = target || first; + target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior}); } - if (swapSpec.show === "bottom" && last) { - last.scrollIntoView(false); + if (swapSpec.show === "bottom" && (last || target)) { + target = target || last; + target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior}); } } } + /** + * @param {HTMLElement} elt + * @param {string} attr + * @param {boolean=} evalAsDefault + * @param {Object=} values + * @returns {Object} + */ function getValuesForElement(elt, attr, evalAsDefault, values) { if (values == null) { values = {}; @@ -1973,6 +2355,9 @@ return (function () { if (str.indexOf("javascript:") === 0) { str = str.substr(11); evaluateValue = true; + } else if (str.indexOf("js:") === 0) { + str = str.substr(3); + evaluateValue = true; } if (str.indexOf('{') !== 0) { str = "{" + str + "}"; @@ -2003,14 +2388,28 @@ return (function () { } } + /** + * @param {HTMLElement} elt + * @param {*} expressionVars + * @returns + */ function getHXVarsForElement(elt, expressionVars) { return getValuesForElement(elt, "hx-vars", true, expressionVars); } + /** + * @param {HTMLElement} elt + * @param {*} expressionVars + * @returns + */ function getHXValsForElement(elt, expressionVars) { return getValuesForElement(elt, "hx-vals", false, expressionVars); } + /** + * @param {HTMLElement} elt + * @returns {Object} + */ function getExpressionVars(elt) { return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)); } @@ -2044,10 +2443,12 @@ return (function () { } function ajaxHelper(verb, path, context) { + verb = verb.toLowerCase(); if (context) { if (context instanceof Element || isType(context, 'String')) { return issueAjaxRequest(verb, path, null, null, { - targetOverride: resolveTarget(context) + targetOverride: resolveTarget(context), + returnPromise: true }); } else { return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, @@ -2055,11 +2456,15 @@ return (function () { handler : context.handler, headers : context.headers, values : context.values, - targetOverride: resolveTarget(context.target) + targetOverride: resolveTarget(context.target), + swapOverride: context.swap, + returnPromise: true }); } } else { - return issueAjaxRequest(verb, path); + return issueAjaxRequest(verb, path, null, null, { + returnPromise: true + }); } } @@ -2076,7 +2481,7 @@ return (function () { var resolve = null; var reject = null; etc = etc != null ? etc : {}; - if(typeof Promise !== "undefined"){ + if(etc.returnPromise && typeof Promise !== "undefined"){ var promise = new Promise(function (_resolve, _reject) { resolve = _resolve; reject = _reject; @@ -2091,40 +2496,85 @@ return (function () { return; // do not issue requests for elements removed from the DOM } var target = etc.targetOverride || getTarget(elt); - if (target == null) { + if (target == null || target == DUMMY_ELT) { triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); return; } + + var syncElt = elt; var eltData = getInternalData(elt); - if (eltData.requestInFlight) { - var queueStrategy = 'last'; - var eventData = getInternalData(event); - if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { - queueStrategy = eventData.triggerSpec.queue; - } - if (eltData.queuedRequests == null) { - eltData.queuedRequests = []; - } - if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); - } else if (queueStrategy === "all") { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); - } else if (queueStrategy === "last") { - eltData.queuedRequests = []; // dump existing queue - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); + var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); + var queueStrategy = null; + var abortable = false; + if (syncStrategy) { + var syncStrings = syncStrategy.split(":"); + var selector = syncStrings[0].trim(); + if (selector === "this") { + syncElt = findThisElement(elt, 'hx-sync'); + } else { + syncElt = querySelectorExt(elt, selector); + } + // default to the drop strategy + syncStrategy = (syncStrings[1] || 'drop').trim(); + eltData = getInternalData(syncElt); + if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { + return; + } else if (syncStrategy === "abort") { + if (eltData.xhr) { + return; + } else { + abortable = true; + } + } else if (syncStrategy === "replace") { + triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue + } else if (syncStrategy.indexOf("queue") === 0) { + var queueStrArray = syncStrategy.split(" "); + queueStrategy = (queueStrArray[1] || "last").trim(); } - return; - } else { - eltData.requestInFlight = true; } + + if (eltData.xhr) { + if (eltData.abortable) { + triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue + } else { + if(queueStrategy == null){ + if (event) { + var eventData = getInternalData(event); + if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { + queueStrategy = eventData.triggerSpec.queue; + } + } + if (queueStrategy == null) { + queueStrategy = "last"; + } + } + if (eltData.queuedRequests == null) { + eltData.queuedRequests = []; + } + if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } else if (queueStrategy === "all") { + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } else if (queueStrategy === "last") { + eltData.queuedRequests = []; // dump existing queue + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } + return; + } + } + + var xhr = new XMLHttpRequest(); + eltData.xhr = xhr; + eltData.abortable = abortable; var endRequestLock = function(){ - eltData.requestInFlight = false + eltData.xhr = null; + eltData.abortable = false; if (eltData.queuedRequests != null && eltData.queuedRequests.length > 0) { var queuedRequest = eltData.queuedRequests.shift(); @@ -2152,11 +2602,10 @@ return (function () { } } - var xhr = new XMLHttpRequest(); var headers = getHeaders(elt, target, promptResponse); if (etc.headers) { - headers = mergeObjects(headers, etc.values); + headers = mergeObjects(headers, etc.headers); } var results = getInputValues(elt, verb); var errors = results.errors; @@ -2169,7 +2618,7 @@ return (function () { var filteredParameters = filterValues(allParameters, elt); if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null) { - headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; + headers['Content-Type'] = 'application/x-www-form-urlencoded'; } // behavior of anchors w/ empty href is to use the current URL @@ -2177,6 +2626,8 @@ return (function () { path = getDocument().location.href; } + var requestAttrValues = getValuesForElement(elt, 'hx-request'); + var requestConfig = { parameters: filteredParameters, unfilteredParameters: allParameters, @@ -2184,6 +2635,8 @@ return (function () { target:target, verb:verb, errors:errors, + withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, + timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, path:path, triggeringEvent:event }; @@ -2231,17 +2684,22 @@ return (function () { } xhr.overrideMimeType("text/html"); - xhr.withCredentials = htmx.config.withCredentials; + xhr.withCredentials = requestConfig.withCredentials; + xhr.timeout = requestConfig.timeout; // request headers - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - var headerValue = headers[header]; - safelySetHeaderValue(xhr, header, headerValue); + if (requestAttrValues.noHeaders) { + // ignore all headers + } else { + for (var header in headers) { + if (headers.hasOwnProperty(header)) { + var headerValue = headers[header]; + safelySetHeaderValue(xhr, header, headerValue); + } } } - var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, pathInfo:{ + var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, etc:etc, pathInfo:{ path:path, finalPath:finalPathForGet, anchor:anchor } }; @@ -2289,6 +2747,13 @@ return (function () { maybeCall(reject); endRequestLock(); } + xhr.ontimeout = function() { + removeRequestIndicatorClasses(indicators); + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); + triggerErrorEvent(elt, 'htmx:timeout', responseInfo); + maybeCall(reject); + endRequestLock(); + } if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){ maybeCall(resolve); endRequestLock() @@ -2315,6 +2780,7 @@ return (function () { function handleAjaxResponse(elt, responseInfo) { var xhr = responseInfo.xhr; var target = responseInfo.target; + var etc = responseInfo.etc; if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; @@ -2338,123 +2804,162 @@ return (function () { } } - var shouldSaveHistory = shouldPush(elt) || pushedUrl; + if (hasHeader(xhr,/HX-Retarget:/i)) { + responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget")); + } - if (xhr.status >= 200 && xhr.status < 400) { + /** @type {boolean} */ + var shouldSaveHistory + if (pushedUrl == "false") { + shouldSaveHistory = false + } else { + shouldSaveHistory = shouldPush(elt) || pushedUrl; + } + + // by default htmx only swaps on 200 return codes and does not swap + // on 204 'No Content' + // this can be ovverriden by responding to the htmx:beforeSwap event and + // overriding the detail.shouldSwap property + var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; + var serverResponse = xhr.response; + var isError = xhr.status >= 400; + var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo); + if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; + + target = beforeSwapDetails.target; // allow re-targeting + serverResponse = beforeSwapDetails.serverResponse; // allow updating content + isError = beforeSwapDetails.isError; // allow updating error + + responseInfo.failed = isError; // Make failed property available to response events + responseInfo.successful = !isError; // Make successful property available to response events + + if (beforeSwapDetails.shouldSwap) { if (xhr.status === 286) { cancelPolling(elt); } - // don't process 'No Content' - if (xhr.status !== 204) { - if (!triggerEvent(target, 'htmx:beforeSwap', responseInfo)) return; - var serverResponse = xhr.response; - withExtensions(elt, function(extension){ - serverResponse = extension.transformResponse(serverResponse, xhr, elt); - }); + withExtensions(elt, function (extension) { + serverResponse = extension.transformResponse(serverResponse, xhr, elt); + }); - // Save current page - if (shouldSaveHistory) { - saveHistory(); - } + // Save current page + if (shouldSaveHistory) { + saveCurrentPageToHistory(); + } + + var swapOverride = etc.swapOverride; + var swapSpec = getSwapSpecification(elt, swapOverride); - var swapSpec = getSwapSpecification(elt); + target.classList.add(htmx.config.swappingClass); + var doSwap = function () { + try { - target.classList.add(htmx.config.swappingClass); - var doSwap = function () { + var activeElt = document.activeElement; + var selectionInfo = {}; try { + selectionInfo = { + elt: activeElt, + // @ts-ignore + start: activeElt ? activeElt.selectionStart : null, + // @ts-ignore + end: activeElt ? activeElt.selectionEnd : null + }; + } catch (e) { + // safari issue - see https://github.com/microsoft/playwright/issues/5894 + } - var activeElt = document.activeElement; - var selectionInfo = {}; - try { - selectionInfo = { - elt: activeElt, - start: activeElt ? activeElt.selectionStart : null, - end: activeElt ? activeElt.selectionEnd : null - }; - } catch (e) { - // safari issue - see https://github.com/microsoft/playwright/issues/5894 + var settleInfo = makeSettleInfo(target); + selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + + if (selectionInfo.elt && + !bodyContains(selectionInfo.elt) && + selectionInfo.elt.id) { + var newActiveElt = document.getElementById(selectionInfo.elt.id); + var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; + if (newActiveElt) { + // @ts-ignore + if (selectionInfo.start && newActiveElt.setSelectionRange) { + // @ts-ignore + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + } + newActiveElt.focus(focusOptions); } + } - var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + target.classList.remove(htmx.config.swappingClass); + forEach(settleInfo.elts, function (elt) { + if (elt.classList) { + elt.classList.add(htmx.config.settlingClass); + } + triggerEvent(elt, 'htmx:afterSwap', responseInfo); + }); + if (responseInfo.pathInfo.anchor) { + location.hash = responseInfo.pathInfo.anchor; + } - if (selectionInfo.elt && - !bodyContains(selectionInfo.elt) && - selectionInfo.elt.id) { - var newActiveElt = document.getElementById(selectionInfo.elt.id); - if (newActiveElt) { - if (selectionInfo.start && newActiveElt.setSelectionRange) { - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); - } - newActiveElt.focus(); - } + if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { + var finalElt = elt; + if (!bodyContains(elt)) { + finalElt = getDocument().body; } + handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); + } - target.classList.remove(htmx.config.swappingClass); + var doSettle = function () { + forEach(settleInfo.tasks, function (task) { + task.call(); + }); forEach(settleInfo.elts, function (elt) { if (elt.classList) { - elt.classList.add(htmx.config.settlingClass); + elt.classList.remove(htmx.config.settlingClass); } - triggerEvent(elt, 'htmx:afterSwap', responseInfo); + triggerEvent(elt, 'htmx:afterSettle', responseInfo); }); - if (responseInfo.pathInfo.anchor) { - location.hash = responseInfo.pathInfo.anchor; + // push URL and save new page + if (shouldSaveHistory) { + var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; + pushUrlIntoHistory(pathToPush); + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: pathToPush}); } - if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; + if(settleInfo.title) { + var titleElt = find("title"); + if(titleElt) { + titleElt.innerHTML = settleInfo.title; + } else { + window.document.title = settleInfo.title; } - handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); } - var doSettle = function(){ - forEach(settleInfo.tasks, function (task) { - task.call(); - }); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.remove(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSettle', responseInfo); - }); - // push URL and save new page - if (shouldSaveHistory) { - var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; - pushUrlIntoHistory(pathToPush); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path:pathToPush}); - } - updateScrollState(settleInfo.elts, swapSpec); + updateScrollState(settleInfo.elts, swapSpec); - if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); + if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { + var finalElt = elt; + if (!bodyContains(elt)) { + finalElt = getDocument().body; } + handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'htmx:swapError', responseInfo); - throw e; } - }; - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); + if (swapSpec.settleDelay > 0) { + setTimeout(doSettle, swapSpec.settleDelay) + } else { + doSettle(); + } + } catch (e) { + triggerErrorEvent(elt, 'htmx:swapError', responseInfo); + throw e; } + }; + + if (swapSpec.swapDelay > 0) { + setTimeout(doSwap, swapSpec.swapDelay) + } else { + doSwap(); } - } else { + } + if (isError) { triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.path}, responseInfo)); } } @@ -2462,9 +2967,17 @@ return (function () { //==================================================================== // Extensions API //==================================================================== + + /** @type {Object<string, import("./htmx").HtmxExtension>} */ var extensions = {}; + + /** + * extensionBase defines the default functions for all extensions. + * @returns {import("./htmx").HtmxExtension} + */ function extensionBase() { return { + init: function(api) {return null;}, onEvent : function(name, evt) {return true;}, transformResponse : function(text, xhr, elt) {return text;}, isInlineSwap : function(swapStyle) {return false;}, @@ -2473,15 +2986,37 @@ return (function () { } } + /** + * defineExtension initializes the extension and adds it to the htmx registry + * + * @param {string} name + * @param {import("./htmx").HtmxExtension} extension + */ function defineExtension(name, extension) { + if(extension.init) { + extension.init(internalAPI) + } extensions[name] = mergeObjects(extensionBase(), extension); } + /** + * removeExtension removes an extension from the htmx registry + * + * @param {string} name + */ function removeExtension(name) { delete extensions[name]; } - function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + /** + * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element + * + * @param {HTMLElement} elt + * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn + * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore + */ + function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + if (elt == undefined) { return extensionsToReturn; } @@ -2536,6 +3071,7 @@ return (function () { function getMetaConfig() { var element = getDocument().querySelector('meta[name="htmx-config"]'); if (element) { + // @ts-ignore return parseJSON(element.content); } else { return null; @@ -2555,9 +3091,25 @@ return (function () { insertIndicatorStyles(); var body = getDocument().body; processNode(body); + var restoredElts = getDocument().querySelectorAll( + "[hx-trigger='restored'],[data-hx-trigger='restored']" + ); + body.addEventListener("htmx:abort", function (evt) { + var target = evt.target; + var internalData = getInternalData(target); + if (internalData && internalData.xhr) { + internalData.xhr.abort(); + } + }); window.onpopstate = function (event) { if (event.state && event.state.htmx) { restoreHistory(); + forEach(restoredElts, function(elt){ + triggerEvent(elt, 'htmx:restored', { + 'document': getDocument(), + 'triggerEvent': triggerEvent + }); + }); } }; setTimeout(function () { diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.min.js b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.min.js index 57f33b2..998414c 100644 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.min.js +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.min.js @@ -1 +1 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var k={onLoad:t,process:rt,on:I,off:M,trigger:lt,ajax:$t,find:w,findAll:S,closest:L,values:function(e,t){var r=Lt(e,t||"post");return r.values},remove:E,addClass:q,removeClass:R,toggleClass:C,takeClass:O,defineExtension:Qt,removeExtension:er,logAll:b,logger:null,useTemplateFragments:false,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,attributesToSettle:["class","style","width","height"],withCredentials:false,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]"},parseInterval:f,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])}};var r=["get","post","put","delete","patch"];var n=r.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function f(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function l(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function D(e,t){return l(e,t)||l(e,"data-"+t)}function c(e){return e.parentElement}function F(){return document}function h(e,t){if(t(e)){return e}else if(c(e)){return h(c(e),t)}else{return null}}function X(e,t){var r=null;h(e,function(e){return r=D(e,t)});return r}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function i(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 o(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=F().createDocumentFragment()}return i}function u(e){if(k.config.useTemplateFragments){var t=o("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=i(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return o("<table>"+e+"</table>",1);case"col":return o("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return o("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return o("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return o("<div>"+e+"</div>",1);default:return o(e,0)}}}function P(e){if(e){e()}}function a(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function v(e){return a(e,"Function")}function g(e){return a(e,"Object")}function U(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function p(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function j(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function m(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function z(e){return F().body.contains(e)}function y(e){return e.trim().split(/\s+/)}function V(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function x(e){try{return JSON.parse(e)}catch(e){ut(e);return null}}function e(e){return Ut(F().body,function(){return eval(e)})}function t(t){var e=k.on("htmx:load",function(e){t(e.detail.elt)});return e}function b(){k.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function w(e,t){if(t){return e.querySelector(t)}else{return w(F(),e)}}function S(e,t){if(t){return e.querySelectorAll(t)}else{return S(F(),e)}}function E(e,t){e=H(e);if(t){setTimeout(function(){E(e)},t)}else{e.parentElement.removeChild(e)}}function q(e,t,r){e=H(e);if(r){setTimeout(function(){q(e,t)},r)}else{e.classList.add(t)}}function R(e,t,r){e=H(e);if(r){setTimeout(function(){R(e,t)},r)}else{e.classList.remove(t)}}function C(e,t){e=H(e);e.classList.toggle(t)}function O(e,t){e=H(e);j(e.parentElement.children,function(e){R(e,t)});q(e,t)}function L(e,t){e=H(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&c(e))}}function A(e,t){if(t.indexOf("closest ")===0){return[L(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[w(e,t.substr(5))]}else{return F().querySelectorAll(t)}}function T(e,t){return A(e,t)[0]}function H(e){if(a(e,"String")){return w(e)}else{return e}}function N(e,t,r){if(v(t)){return{target:F().body,event:e,listener:t}}else{return{target:H(e),event:t,listener:r}}}function I(t,r,n){rr(function(){var e=N(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=v(r);return e?r:n}function M(t,r,n){rr(function(){var e=N(t,r,n);e.target.removeEventListener(e.event,e.listener)});return v(r)?r:n}function _(e){var t=h(e,function(e){return D(e,"hx-target")!==null});if(t){var r=D(t,"hx-target");if(r==="this"){return t}else{return T(e,r)}}else{var n=U(e);if(n.boosted){return F().body}else{return e}}}function B(e){var t=k.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function W(t,r){j(t.attributes,function(e){if(!r.hasAttribute(e.name)&&B(e.name)){t.removeAttribute(e.name)}});j(r.attributes,function(e){if(B(e.name)){t.setAttribute(e.name,e.value)}})}function $(e,t){var r=tr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){ut(e)}}return e==="outerHTML"}function J(e,t,r){var n="#"+t.id;var i="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){i=e.substr(0,e.indexOf(":"));n=e.substr(e.indexOf(":")+1,e.length)}else{i=e}var o=F().querySelector(n);if(o){var a;a=F().createDocumentFragment();a.appendChild(t);if(!$(i,o)){a=t}le(i,o,o,a,r)}else{t.parentNode.removeChild(t);ot(F().body,"htmx:oobErrorNoTarget",{content:t})}return e}function Z(e,r){j(S(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=D(e,"hx-swap-oob");if(t!=null){J(t,e,r)}})}function G(e){j(S(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=D(e,"id");var r=F().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function K(n,e,i){j(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();W(e,t);i.tasks.push(function(){W(e,r)})}}})}function Y(e){return function(){rt(e);Ye(e);Q(e);lt(e,"htmx:load")}}function Q(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ee(e,t,r,n){K(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Y(i))}}}function te(t){var e=U(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}if(e.listenerInfos){j(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){j(t.children,function(e){te(e)})}}function re(e,t,r){if(e.tagName==="BODY"){return se(e,t,r)}else{var n=e.previousSibling;ee(c(e),e,t,r);if(n==null){var i=c(e).firstChild}else{var i=n.nextSibling}U(e).replacedWith=i;r.elts=[];while(i&&i!==e){if(i.nodeType===Node.ELEMENT_NODE){r.elts.push(i)}i=i.nextElementSibling}te(e);c(e).removeChild(e)}}function ne(e,t,r){return ee(e,e.firstChild,t,r)}function ie(e,t,r){return ee(c(e),e,t,r)}function oe(e,t,r){return ee(e,null,t,r)}function ae(e,t,r){return ee(c(e),e.nextSibling,t,r)}function se(e,t,r){var n=e.firstChild;ee(e,n,t,r);if(n){while(n.nextSibling){te(n.nextSibling);e.removeChild(n.nextSibling)}te(n);e.removeChild(n)}}function ue(e,t){var r=X(e,"hx-select");if(r){var n=F().createDocumentFragment();j(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function le(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":re(r,n,i);return;case"afterbegin":ne(r,n,i);return;case"beforebegin":ie(r,n,i);return;case"beforeend":oe(r,n,i);return;case"afterend":ae(r,n,i);return;default:var o=tr(t);for(var a=0;a<o.length;a++){var s=o[a];try{var u=s.handleSwap(e,r,n,i);if(u){if(typeof u.length!=="undefined"){for(var l=0;l<u.length;l++){var f=u[l];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Y(f))}}}return}}catch(e){ut(e)}}se(r,n,i)}}var fe=/<title>([\s\S]+?)<\/title>/im;function ce(e){if(e.indexOf("<title>")>-1&&(e.indexOf("<svg>")==-1||e.indexOf("<title>")<e.indexOf("<svg>"))){var t=fe.exec(e);if(t){return t[1]}}}function he(e,t,r,n,i){var o=ce(n);if(o){var a=w("title");if(a){a.innerHTML=o}else{window.document.title=o}}var s=u(n);if(s){Z(s,i);s=ue(r,s);G(s);return le(e,r,t,s,i)}}function de(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=x(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!g(a)){a={value:a}}lt(r,o,a)}}}else{lt(r,n,[])}}var ve=/\s/;var ge=/[\s,]/;var pe=/[_$a-zA-Z]/;var me=/[_$a-zA-Z0-9]/;var ye=['"',"'","/"];var xe=/[^\s]/;function be(e){var t=[];var r=0;while(r<e.length){if(pe.exec(e.charAt(r))){var n=r;while(me.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(ye.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function we(e,t,r){return pe.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function Se(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Ut(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){ot(F().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(we(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function Ee(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var qe="input, textarea, select";function Re(e){var t=D(e,"hx-trigger");var r=[];if(t){var n=be(t);do{Ee(n,xe);var i=n.length;var o=Ee(n,/[,\[\s]/);if(o!==""){if(o==="every"){var a={trigger:"every"};Ee(n,xe);a.pollInterval=f(Ee(n,ve));r.push(a)}else if(o.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:o.substr(4)})}else{var s={trigger:o};var u=Se(e,n,"event");if(u){s.eventFilter=u}while(n.length>0&&n[0]!==","){Ee(n,xe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=f(Ee(n,ge))}else if(l==="from"&&n[0]===":"){n.shift();s.from=Ee(n,ge)}else if(l==="target"&&n[0]===":"){n.shift();s.target=Ee(n,ge)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=f(Ee(n,ge))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=Ee(n,ge)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=Ee(n,ge)}else{ot(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===i){ot(e,"htmx:syntax:error",{token:n.shift()})}Ee(n,xe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,qe)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ce(e){U(e).cancelled=true}function Oe(e,t,r,n){var i=U(e);i.timeout=setTimeout(function(){if(z(e)&&i.cancelled!==true){Zt(t,r,e);Oe(e,t,D(e,"hx-"+t),n)}},n)}function Le(e){return location.hostname===e.hostname&&l(e,"href")&&l(e,"href").indexOf("#")!==0}function Ae(t,r,e){if(t.tagName==="A"&&Le(t)||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=l(t,"href");r.pushURL=true}else{var o=l(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=l(t,"action")}e.forEach(function(e){Ie(t,n,i,r,e,true)})}}function Te(e){return e.tagName==="FORM"||d(e,'input[type="submit"], button')&&L(e,"form")!==null||e.tagName==="A"&&e.href&&(e.getAttribute("href")==="#"||e.getAttribute("href").indexOf("#")!==0)}function He(e,t){return U(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function Ne(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){ot(F().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Ie(n,i,o,e,a,s){var u=n;if(a.from){u=w(a.from)}var l=function(e){if(!z(n)){u.removeEventListener(a.trigger,l);return}if(He(n,e)){return}if(s||Te(n)){e.preventDefault()}if(Ne(a,e)){return}var t=U(e);t.triggerSpec=a;if(t.handledFor==null){t.handledFor=[]}var r=U(n);if(t.handledFor.indexOf(n)<0){t.handledFor.push(n);if(a.consume){e.stopPropagation()}if(a.target&&e.target){if(!d(e.target,a.target)){return}}if(a.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(a.changed){if(r.lastValue===n.value){return}else{r.lastValue=n.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(a.throttle){if(!r.throttle){Zt(i,o,n,e);r.throttle=setTimeout(function(){r.throttle=null},a.throttle)}}else if(a.delay){r.delayed=setTimeout(function(){Zt(i,o,n,e)},a.delay)}else{Zt(i,o,n,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:a.trigger,listener:l,on:u});u.addEventListener(a.trigger,l)}var Me=false;var ke=null;function De(){if(!ke){ke=function(){Me=true};window.addEventListener("scroll",ke);setInterval(function(){if(Me){Me=false;j(F().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){Fe(e)})}},200)}}function Fe(e){var t=U(e);if(!t.revealed&&m(e)){t.revealed=true;if(t.initialized){Zt(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Zt(t.verb,t.path,e)},{once:true})}}}function Xe(e,t,r){var n=y(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Pe(e,o[1],0)}if(o[0]==="send"){je(e)}}}function Pe(s,r,n){if(!z(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=k.createWebSocket(r);t.onerror=function(e){ot(s,"htmx:wsError",{error:e,socket:t});Ue(s)};t.onclose=function(e){if([1006,1012,1013].includes(e.code)){var t=ze(n);setTimeout(function(){Pe(s,r,n+1)},t)}};t.onopen=function(e){n=0};U(s).webSocket=t;t.addEventListener("message",function(e){if(Ue(s)){return}var t=e.data;st(s,function(e){t=e.transformResponse(t,null,s)});var r=Ft(s);var n=u(t);var i=p(n.children);for(var o=0;o<i.length;o++){var a=i[o];J(D(a,"hx-swap-oob")||"true",a,r)}mt(r.tasks)})}function Ue(e){if(!z(e)){U(e).webSocket.close();return true}}function je(l){var f=h(l,function(e){return U(e).webSocket!=null});if(f){l.addEventListener(Re(l)[0].trigger,function(e){var t=U(f).webSocket;var r=Nt(l,f);var n=Lt(l,"post");var i=n.errors;var o=n.values;var a=Vt(l);var s=V(o,a);var u=It(s,l);u["HEADERS"]=r;if(i&&i.length>0){lt(l,"htmx:validation:halted",i);return}t.send(JSON.stringify(u));if(Te(l)){e.preventDefault()}})}else{ot(l,"htmx:noWebSocketSourceError")}}function ze(e){var t=k.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}ut('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ve(e,t,r){var n=y(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){_e(e,o[1])}if(o[0]==="swap"){Be(e,o[1])}}}function _e(t,e){var r=k.createEventSource(e);r.onerror=function(e){ot(t,"htmx:sseError",{error:e,source:r});$e(t)};U(t).sseEventSource=r}function Be(o,a){var s=h(o,Je);if(s){var u=U(s).sseEventSource;var l=function(e){if($e(s)){u.removeEventListener(a,l);return}var t=e.data;st(o,function(e){t=e.transformResponse(t,null,o)});var r=kt(o);var n=_(o);var i=Ft(o);he(r.swapStyle,o,n,t,i);mt(i.tasks);lt(o,"htmx:sseMessage",e)};U(o).sseListener=l;u.addEventListener(a,l)}else{ot(o,"htmx:noSSESourceError")}}function We(e,t,r,n){var i=h(e,Je);if(i){var o=U(i).sseEventSource;var a=function(){if(!$e(i)){if(z(e)){Zt(t,r,e)}else{o.removeEventListener(n,a)}}};U(e).sseListener=a;o.addEventListener(n,a)}else{ot(e,"htmx:noSSESourceError")}}function $e(e){if(!z(e)){U(e).sseEventSource.close();return true}}function Je(e){return U(e).sseEventSource!=null}function Ze(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Zt(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function Ge(o,a,e){var t=false;j(r,function(n){if(s(o,"hx-"+n)){var i=D(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){We(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){De();Fe(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=T(e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){lt(o,"intersect");break}}},t);r.observe(o);Ie(o,n,i,a,e)}else if(e.trigger==="load"){Ze(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Oe(o,n,i,e.pollInterval)}else{Ie(o,n,i,a,e)}})}});return t}function Ke(e){if(e.type==="text/javascript"||e.type===""){try{Ut(e,function(){(1,eval)(e.innerText)})}catch(e){ut(e)}}}function Ye(e){if(d(e,"script")){Ke(e)}j(S(e,"script"),function(e){Ke(e)})}function Qe(){return document.querySelector("[hx-boost], [data-hx-boost]")}function et(e){if(e.querySelectorAll){var t=Qe()?", a, form":"";var r=e.querySelectorAll(n+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws]");return r}else{return[]}}function tt(e){if(e.closest&&e.closest(k.config.disableSelector)){return}var t=U(e);if(!t.initialized){t.initialized=true;lt(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=Re(e);var n=Ge(e,t,r);if(!n&&X(e,"hx-boost")==="true"){Ae(e,t,r)}var i=D(e,"hx-sse");if(i){Ve(e,t,i)}var o=D(e,"hx-ws");if(o){Xe(e,t,o)}lt(e,"htmx:afterProcessNode")}}function rt(e){e=H(e);tt(e);j(et(e),function(e){tt(e)})}function nt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function it(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=F().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function ot(e,t,r){lt(e,t,V({error:t},r))}function at(e){return e==="htmx:afterProcessNode"}function st(e,t){j(tr(e),function(e){try{t(e)}catch(e){ut(e)}})}function ut(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function lt(e,t,r){e=H(e);if(r==null){r={}}r["elt"]=e;var n=it(t,r);if(k.logger&&!at(t)){k.logger(e,t,r)}if(r.error){ut(r.error);lt(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=nt(t);if(i&&o!==t){var a=it(o,n.detail);i=i&&e.dispatchEvent(a)}st(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var ft=null;function ct(){var e=F().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||F().body}function ht(e,t,r,n){var i=x(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>k.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ot(F().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function dt(e){var t=x(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function vt(e){var t=k.config.requestClass;var r=e.cloneNode(true);j(S(r,"."+t),function(e){R(e,t)});return r.innerHTML}function gt(){var e=ct();var t=ft||location.pathname+location.search;lt(F().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(k.config.historyEnabled)history.replaceState({htmx:true},F().title,window.location.href);ht(t,vt(e),F().title,window.scrollY)}function pt(e){if(k.config.historyEnabled)history.pushState({htmx:true},"",e);ft=e}function mt(e){j(e,function(e){e.call()})}function yt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};lt(F().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){lt(F().body,"htmx:historyCacheMissLoad",i);var e=u(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=ct();var r=Ft(t);se(t,e,r);mt(r.tasks);ft=n;lt(F().body,"htmx:historyRestore",{path:n})}else{ot(F().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function xt(e){gt();e=e||location.pathname+location.search;var t=dt(e);if(t){var r=u(t.content);var n=ct();var i=Ft(n);se(n,r,i);mt(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);ft=e;lt(F().body,"htmx:historyRestore",{path:e})}else{if(k.config.refreshOnHistoryMiss){window.location.reload(true)}else{yt(e)}}}function bt(e){var t=X(e,"hx-push-url");return t&&t!=="false"||U(e).boosted&&U(e).pushURL}function wt(e){var t=X(e,"hx-push-url");return t==="true"||t==="false"?null:t}function St(e){var t=X(e,"hx-indicator");if(t){var r=A(e,t)}else{r=[e]}j(r,function(e){e.classList["add"].call(e.classList,k.config.requestClass)});return r}function Et(e){j(e,function(e){e.classList["remove"].call(e.classList,k.config.requestClass)})}function qt(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Rt(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 Ct(t,r,n,e,i){if(e==null||qt(t,e)){return}else{t.push(e)}if(Rt(e)){var o=l(e,"name");var a=e.value;if(e.multiple){a=p(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=p(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){Ot(e,n)}}if(d(e,"form")){var u=e.elements;j(u,function(e){Ct(t,r,n,e,i)})}}function Ot(e,t){if(e.willValidate){lt(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});lt(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Lt(e,t){var r=[];var n={};var i={};var o=[];var a=d(e,"form")&&e.noValidate!==true;if(t!=="get"){Ct(r,i,o,L(e,"form"),a)}Ct(r,n,o,e,a);var s=X(e,"hx-include");if(s){var u=A(e,s);j(u,function(e){Ct(r,n,o,e,a);if(!d(e,"form")){j(e.querySelectorAll(qe),function(e){Ct(r,n,o,e,a)})}})}n=V(n,i);return{errors:o,values:n}}function At(e,t,r){if(e!==""){e+="&"}e+=encodeURIComponent(t)+"="+encodeURIComponent(r);return e}function Tt(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){j(n,function(e){t=At(t,r,e)})}else{t=At(t,r,n)}}}return t}function Ht(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){j(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Nt(e,t,r){var n={"HX-Request":"true","HX-Trigger":l(e,"id"),"HX-Trigger-Name":l(e,"name"),"HX-Target":D(t,"id"),"HX-Current-URL":F().location.href};Pt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}return n}function It(t,e){var r=X(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){j(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};j(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Mt(e){return l(e,"href")&&l(e,"href").indexOf("#")>=0}function kt(e){var t=X(e,"hx-swap");var r={swapStyle:U(e).boosted?"innerHTML":k.config.defaultSwapStyle,swapDelay:k.config.defaultSwapDelay,settleDelay:k.config.defaultSettleDelay};if(U(e).boosted&&!Mt(e)){r["show"]="top"}if(t){var n=y(t);if(n.length>0){r["swapStyle"]=n[0];for(var i=1;i<n.length;i++){var o=n[i];if(o.indexOf("swap:")===0){r["swapDelay"]=f(o.substr(5))}if(o.indexOf("settle:")===0){r["settleDelay"]=f(o.substr(7))}if(o.indexOf("scroll:")===0){r["scroll"]=o.substr(7)}if(o.indexOf("show:")===0){r["show"]=o.substr(5)}}}}return r}function Dt(t,r,n){var i=null;st(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(X(r,"hx-encoding")==="multipart/form-data"){return Ht(n)}else{return Tt(n)}}}function Ft(e){return{tasks:[],elts:[e]}}function Xt(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){if(t.scroll==="top"&&r){r.scrollTop=0}if(t.scroll==="bottom"&&n){n.scrollTop=n.scrollHeight}}if(t.show){if(t.show==="top"&&r){r.scrollIntoView(true)}if(t.show==="bottom"&&n){n.scrollIntoView(false)}}}function Pt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=D(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Ut(e,function(){return Function("return ("+o+")")()},{})}else{s=x(o)}for(var u in s){if(s.hasOwnProperty(u)){if(n[u]==null){n[u]=s[u]}}}}return Pt(c(e),t,r,n)}function Ut(e,t,r){if(k.config.allowEval){return t()}else{ot(e,"htmx:evalDisallowedError");return r}}function jt(e,t){return Pt(e,"hx-vars",true,t)}function zt(e,t){return Pt(e,"hx-vals",false,t)}function Vt(e){return V(jt(e),zt(e))}function _t(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Bt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ot(F().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Wt(e,t){return e.getAllResponseHeaders().match(t)}function $t(e,t,r){if(r){if(r instanceof Element||a(r,"String")){return Zt(e,t,null,null,{targetOverride:H(r)})}else{return Zt(e,t,H(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:H(r.target)})}}else{return Zt(e,t)}}function Jt(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Zt(e,t,n,r,i){var o=null;var a=null;i=i!=null?i:{};if(typeof Promise!=="undefined"){var s=new Promise(function(e,t){o=e;a=t})}if(n==null){n=F().body}var u=i.handler||Gt;if(!z(n)){return}var l=i.targetOverride||_(n);if(l==null){ot(n,"htmx:targetError",{target:D(n,"hx-target")});return}var f=U(n);if(f.requestInFlight){var c="last";var h=U(r);if(h&&h.triggerSpec&&h.triggerSpec.queue){c=h.triggerSpec.queue}if(f.queuedRequests==null){f.queuedRequests=[]}if(c==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){Zt(e,t,n,r)})}else if(c==="all"){f.queuedRequests.push(function(){Zt(e,t,n,r)})}else if(c==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){Zt(e,t,n,r)})}return}else{f.requestInFlight=true}var d=function(){f.requestInFlight=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var v=X(n,"hx-prompt");if(v){var g=prompt(v);if(g===null||!lt(n,"htmx:prompt",{prompt:g,target:l})){P(o);d();return s}}var p=X(n,"hx-confirm");if(p){if(!confirm(p)){P(o);d();return s}}var m=new XMLHttpRequest;var y=Nt(n,l,g);if(i.headers){y=V(y,i.values)}var x=Lt(n,e);var b=x.errors;var w=x.values;if(i.values){w=V(w,i.values)}var S=Vt(n);var E=V(w,S);var q=It(E,n);if(e!=="get"&&X(n,"hx-encoding")==null){y["Content-Type"]="application/x-www-form-urlencoded; charset=UTF-8"}if(t==null||t===""){t=F().location.href}var R={parameters:q,unfilteredParameters:E,headers:y,target:l,verb:e,errors:b,path:t,triggeringEvent:r};if(!lt(n,"htmx:configRequest",R)){P(o);d();return s}t=R.path;e=R.verb;y=R.headers;q=R.parameters;b=R.errors;if(b&&b.length>0){lt(n,"htmx:validation:halted",R);P(o);d();return s}var C=t.split("#");var O=C[0];var L=C[1];if(e==="get"){var A=O;var T=Object.keys(q).length!==0;if(T){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=Tt(q);if(L){A+="#"+L}}m.open("GET",A,true)}else{m.open(e.toUpperCase(),t,true)}m.overrideMimeType("text/html");m.withCredentials=k.config.withCredentials;for(var H in y){if(y.hasOwnProperty(H)){var N=y[H];_t(m,H,N)}}var I={xhr:m,target:l,requestConfig:R,pathInfo:{path:t,finalPath:A,anchor:L}};m.onload=function(){try{var e=Jt(n);u(n,I);Et(M);lt(n,"htmx:afterRequest",I);lt(n,"htmx:afterOnLoad",I);if(!z(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(z(r)){t=r}}if(t){lt(t,"htmx:afterRequest",I);lt(t,"htmx:afterOnLoad",I)}}P(o);d()}catch(e){ot(n,"htmx:onLoadError",V({error:e},I));throw e}};m.onerror=function(){Et(M);ot(n,"htmx:afterRequest",I);ot(n,"htmx:sendError",I);P(a);d()};m.onabort=function(){Et(M);ot(n,"htmx:afterRequest",I);ot(n,"htmx:sendAbort",I);P(a);d()};if(!lt(n,"htmx:beforeRequest",I)){P(o);d();return s}var M=St(n);j(["loadstart","loadend","progress","abort"],function(t){j([m,m.upload],function(e){e.addEventListener(t,function(e){lt(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});lt(n,"htmx:beforeSend",I);m.send(e==="get"?null:Dt(m,n,q));return s}function Gt(a,s){var u=s.xhr;var l=s.target;if(!lt(a,"htmx:beforeOnLoad",s))return;if(Wt(u,/HX-Trigger:/i)){de(u,"HX-Trigger",a)}if(Wt(u,/HX-Push:/i)){var f=u.getResponseHeader("HX-Push")}if(Wt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Wt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}var c=bt(a)||f;if(u.status>=200&&u.status<400){if(u.status===286){Ce(a)}if(u.status!==204){if(!lt(l,"htmx:beforeSwap",s))return;var h=u.response;st(a,function(e){h=e.transformResponse(h,u,a)});if(c){gt()}var d=kt(a);l.classList.add(k.config.swappingClass);var e=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r=Ft(l);he(d.swapStyle,l,a,h,r);if(t.elt&&!z(t.elt)&&t.elt.id){var n=document.getElementById(t.elt.id);if(n){if(t.start&&n.setSelectionRange){n.setSelectionRange(t.start,t.end)}n.focus()}}l.classList.remove(k.config.swappingClass);j(r.elts,function(e){if(e.classList){e.classList.add(k.config.settlingClass)}lt(e,"htmx:afterSwap",s)});if(s.pathInfo.anchor){location.hash=s.pathInfo.anchor}if(Wt(u,/HX-Trigger-After-Swap:/i)){var i=a;if(!z(a)){i=F().body}de(u,"HX-Trigger-After-Swap",i)}var o=function(){j(r.tasks,function(e){e.call()});j(r.elts,function(e){if(e.classList){e.classList.remove(k.config.settlingClass)}lt(e,"htmx:afterSettle",s)});if(c){var e=f||wt(a)||Bt(u)||s.pathInfo.finalPath||s.pathInfo.path;pt(e);lt(F().body,"htmx:pushedIntoHistory",{path:e})}Xt(r.elts,d);if(Wt(u,/HX-Trigger-After-Settle:/i)){var t=a;if(!z(a)){t=F().body}de(u,"HX-Trigger-After-Settle",t)}};if(d.settleDelay>0){setTimeout(o,d.settleDelay)}else{o()}}catch(e){ot(a,"htmx:swapError",s);throw e}};if(d.swapDelay>0){setTimeout(e,d.swapDelay)}else{e()}}}else{ot(a,"htmx:responseError",V({error:"Response Status Error Code "+u.status+" from "+s.pathInfo.path},s))}}var Kt={};function Yt(){return{onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Qt(e,t){Kt[e]=V(Yt(),t)}function er(e){delete Kt[e]}function tr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=D(e,"hx-ext");if(t){j(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Kt[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return tr(c(e),r,n)}function rr(e){if(F().readyState!=="loading"){e()}else{F().addEventListener("DOMContentLoaded",e)}}function nr(){if(k.config.includeIndicatorStyles!==false){F().head.insertAdjacentHTML("beforeend","<style> ."+k.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+k.config.requestClass+" ."+k.config.indicatorClass+"{opacity:1} ."+k.config.requestClass+"."+k.config.indicatorClass+"{opacity:1} </style>")}}function ir(){var e=F().querySelector('meta[name="htmx-config"]');if(e){return x(e.content)}else{return null}}function or(){var e=ir();if(e){k.config=V(k.config,e)}}rr(function(){or();nr();var e=F().body;rt(e);window.onpopstate=function(e){if(e.state&&e.state.htmx){xt()}};setTimeout(function(){lt(e,"htmx:load",{})},0)});return k}()}); \ No newline at end of file +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(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 l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=k(e);e.classList.toggle(t)}function T(e,t){e=k(e);W(e.parentElement.children,function(e){q(e,t)});L(e,t)}function H(e,t){e=k(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function N(e,t){if(t.indexOf("closest ")===0){return[H(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[C(e,t.substr(5))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return z().querySelectorAll(t)}}function ee(e,t){if(t){return N(e,t)[0]}else{return N(z().body,e)[0]}}function k(e){if(p(e,"String")){return C(e)}else{return e}}function I(e,t,r){if(m(t)){return{target:z().body,event:e,listener:t}}else{return{target:k(e),event:t,listener:r}}}function M(t,r,n){lr(function(){var e=I(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function D(t,r,n){lr(function(){var e=I(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var te=z().createElement("output");function F(e,t){var r=G(e,t);if(r){if(r==="this"){return[re(e,t)]}else{var n=N(e,r);if(n.length===0){pt('The selector "'+r+'" on '+t+" returned no matches!");return[te]}else{return n}}}}function re(e,t){return h(e,function(e){return V(e,t)!=null})}function ne(e){var t=G(e,"hx-target");if(t){if(t==="this"){return re(e,"hx-target")}else{return ee(e,t)}}else{var r=_(e);if(r.boosted){return z().body}else{return e}}}function P(e){var t=U.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function X(t,r){W(t.attributes,function(e){if(!r.hasAttribute(e.name)&&P(e.name)){t.removeAttribute(e.name)}});W(r.attributes,function(e){if(P(e.name)){t.setAttribute(e.name,e.value)}})}function j(e,t){var r=sr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){pt(e)}}return e==="outerHTML"}function B(e,i,o){var t="#"+i.id;var a="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){a=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{a=e}var r=z().querySelectorAll(t);if(r){W(r,function(e){var t;var r=i.cloneNode(true);t=z().createDocumentFragment();t.appendChild(r);if(!j(a,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ye(a,e,e,t,o)}W(o.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(z().body,"htmx:oobErrorNoTarget",{content:i})}return e}function ie(e,r){W(R(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=V(e,"hx-swap-oob");if(t!=null){B(t,e,r)}})}function oe(e){W(R(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=V(e,"id");var r=z().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function ae(n,e,i){W(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();X(e,t);i.tasks.push(function(){X(e,r)})}}})}function se(e){return function(){q(e,U.config.addedClass);ct(e);at(e);le(e);$(e,"htmx:load")}}function le(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ue(e,t,r,n){ae(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(se(i))}}}function fe(t){var e=_(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){W(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){W(t.children,function(e){fe(e)})}}function ce(e,t,r){if(e.tagName==="BODY"){return me(e,t,r)}else{var n;var i=e.previousSibling;ue(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}_(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}fe(e);u(e).removeChild(e)}}function he(e,t,r){return ue(e,e.firstChild,t,r)}function de(e,t,r){return ue(u(e),e,t,r)}function ve(e,t,r){return ue(e,null,t,r)}function ge(e,t,r){return ue(u(e),e.nextSibling,t,r)}function pe(e,t,r){fe(e);return u(e).removeChild(e)}function me(e,t,r){var n=e.firstChild;ue(e,n,t,r);if(n){while(n.nextSibling){fe(n.nextSibling);e.removeChild(n.nextSibling)}fe(n);e.removeChild(n)}}function xe(e,t){var r=G(e,"hx-select");if(r){var n=z().createDocumentFragment();W(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function ye(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":ce(r,n,i);return;case"afterbegin":he(r,n,i);return;case"beforebegin":de(r,n,i);return;case"beforeend":ve(r,n,i);return;case"afterend":ge(r,n,i);return;case"delete":pe(r,n,i);return;default:var o=sr(t);for(var a=0;a<o.length;a++){var f=o[a];try{var s=f.handleSwap(e,r,n,i);if(s){if(typeof s.length!=="undefined"){for(var l=0;l<s.length;l++){var u=s[l];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){i.tasks.push(se(u))}}}return}}catch(e){pt(e)}}if(e==="innerHTML"){me(r,n,i)}else{ye(U.config.defaultSwapStyle,t,r,n,i)}}}function be(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function we(e,t,r,n,i){i.title=be(n);var o=g(n);if(o){ie(o,i);o=xe(r,o);oe(o);return ye(e,r,t,o,i)}}function Se(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!x(a)){a={value:a}}$(r,o,a)}}}else{$(r,n,[])}}var Ee=/\s/;var Ce=/[\s,]/;var Re=/[_$a-zA-Z]/;var Oe=/[_$a-zA-Z0-9]/;var Le=['"',"'","/"];var qe=/[^\s]/;function Ae(e){var t=[];var r=0;while(r<e.length){if(Re.exec(e.charAt(r))){var n=r;while(Oe.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Le.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function Te(e,t,r){return Re.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function He(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Jt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(z().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(Te(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var Ne="input, textarea, select";function ke(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=Ae(t);do{c(n,qe);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var o={trigger:"every"};c(n,qe);o.pollInterval=v(c(n,/[,\[\s]/));c(n,qe);var a=He(e,n,"event");if(a){o.eventFilter=a}r.push(o)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var a=He(e,n,"event");if(a){s.eventFilter=a}while(n.length>0&&n[0]!==","){c(n,qe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Ce))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Ce);if(u==="closest"||u==="find"){n.shift();u+=" "+c(n,Ce)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Ce)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Ce))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Ce)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Ce)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,qe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,Ne)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ie(e){_(e).cancelled=true}function Me(e,t,r,n){var i=_(e);i.timeout=setTimeout(function(){if(Y(e)&&i.cancelled!==true){if(!je(n,dt("hx:poll:trigger",{triggerSpec:n,target:e}))){Z(t,r,e)}Me(e,t,V(e,"hx-"+t),n)}},n.pollInterval)}function De(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&De(t)&&t.target===""||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href");r.pushURL=true}else{var o=f(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=f(t,"action")}e.forEach(function(e){Be(t,n,i,r,e,true)})}}function Pe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&H(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Xe(e,t){return _(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function je(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(z().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Be(o,a,s,e,l,u){var t;if(l.from){t=N(o,l.from)}else{t=[o]}W(t,function(n){var i=function(e){if(!Y(o)){n.removeEventListener(l.trigger,i);return}if(Xe(o,e)){return}if(u||Pe(e,o)){e.preventDefault()}if(je(l,e)){return}var t=_(e);t.triggerSpec=l;if(t.handledFor==null){t.handledFor=[]}var r=_(o);if(t.handledFor.indexOf(o)<0){t.handledFor.push(o);if(l.consume){e.stopPropagation()}if(l.target&&e.target){if(!d(e.target,l.target)){return}}if(l.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(l.changed){if(r.lastValue===o.value){return}else{r.lastValue=o.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(l.throttle){if(!r.throttle){Z(a,s,o,e);r.throttle=setTimeout(function(){r.throttle=null},l.throttle)}}else if(l.delay){r.delayed=setTimeout(function(){Z(a,s,o,e)},l.delay)}else{Z(a,s,o,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:l.trigger,listener:i,on:n});n.addEventListener(l.trigger,i)})}var Ue=false;var Ve=null;function ze(){if(!Ve){Ve=function(){Ue=true};window.addEventListener("scroll",Ve);setInterval(function(){if(Ue){Ue=false;W(z().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){_e(e)})}},200)}}function _e(e){if(!s(e,"data-hx-revealed")&&b(e)){e.setAttribute("data-hx-revealed","true");var t=_(e);if(t.initialized){Z(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Z(t.verb,t.path,e)},{once:true})}}}function We(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Je(e,o[1],0)}if(o[0]==="send"){Ze(e)}}}function Je(s,r,n){if(!Y(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=U.createWebSocket(r);t.onerror=function(e){J(s,"htmx:wsError",{error:e,socket:t});$e(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=Ge(n);setTimeout(function(){Je(s,r,n+1)},t)}};t.onopen=function(e){n=0};_(s).webSocket=t;t.addEventListener("message",function(e){if($e(s)){return}var t=e.data;gt(s,function(e){t=e.transformResponse(t,null,s)});var r=zt(s);var n=g(t);var i=y(n.children);for(var o=0;o<i.length;o++){var a=i[o];B(V(a,"hx-swap-oob")||"true",a,r)}Ct(r.tasks)})}function $e(e){if(!Y(e)){_(e).webSocket.close();return true}}function Ze(u){var f=h(u,function(e){return _(e).webSocket!=null});if(f){u.addEventListener(ke(u)[0].trigger,function(e){var t=_(f).webSocket;var r=Xt(u,f);var n=Mt(u,"post");var i=n.errors;var o=n.values;var a=Gt(u);var s=Q(o,a);var l=jt(s,u);l["HEADERS"]=r;if(i&&i.length>0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Pe(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ge(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}pt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ke(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Ye(e,o[1])}if(o[0]==="swap"){Qe(e,o[1])}}}function Ye(t,e){var r=U.createEventSource(e);r.onerror=function(e){J(t,"htmx:sseError",{error:e,source:r});tt(t)};_(t).sseEventSource=r}function Qe(o,a){var s=h(o,rt);if(s){var l=_(s).sseEventSource;var u=function(e){if(tt(s)){l.removeEventListener(a,u);return}var t=e.data;gt(o,function(e){t=e.transformResponse(t,null,o)});var r=Ut(o);var n=ne(o);var i=zt(o);we(r.swapStyle,o,n,t,i);Ct(i.tasks);$(o,"htmx:sseMessage",e)};_(o).sseListener=u;l.addEventListener(a,u)}else{J(o,"htmx:noSSESourceError")}}function et(e,t,r,n){var i=h(e,rt);if(i){var o=_(i).sseEventSource;var a=function(){if(!tt(i)){if(Y(e)){Z(t,r,e)}else{o.removeEventListener(n,a)}}};_(e).sseListener=a;o.addEventListener(n,a)}else{J(e,"htmx:noSSESourceError")}}function tt(e){if(!Y(e)){_(e).sseEventSource.close();return true}}function rt(e){return _(e).sseEventSource!=null}function nt(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Z(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function it(o,a,e){var t=false;W(n,function(n){if(s(o,"hx-"+n)){var i=V(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){et(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){ze();_e(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=ee(o,e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){$(o,"intersect");break}}},t);r.observe(o);Be(o,n,i,a,e)}else if(e.trigger==="load"){nt(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Me(o,n,i,e)}else{Be(o,n,i,a,e)}})}});return t}function ot(e){if(e.type==="text/javascript"||e.type==="module"||e.type===""){var t=z().createElement("script");W(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(U.config.inlineScriptNonce){t.nonce=U.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){pt(e)}finally{r.removeChild(e)}}}function at(e){if(d(e,"script")){ot(e)}W(R(e,"script"),function(e){ot(e)})}function st(){return document.querySelector("[hx-boost], [data-hx-boost]")}function lt(e){if(e.querySelectorAll){var t=st()?", a, form":"";var r=e.querySelectorAll(i+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [hx-data-ext]");return r}else{return[]}}function ut(r){var e=function(e){if(d(e.target,"button, input[type='submit']")){var t=_(r);t.lastButtonClicked=e.target}};r.addEventListener("click",e);r.addEventListener("focusin",e);r.addEventListener("focusout",function(e){var t=_(r);t.lastButtonClicked=null})}function ft(e){if(e.closest&&e.closest(U.config.disableSelector)){return}var t=_(e);if(!t.initialized){t.initialized=true;$(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=ke(e);var n=it(e,t,r);if(!n&&G(e,"hx-boost")==="true"){Fe(e,t,r)}if(e.tagName==="FORM"){ut(e)}var i=V(e,"hx-sse");if(i){Ke(e,t,i)}var o=V(e,"hx-ws");if(o){We(e,t,o)}$(e,"htmx:afterProcessNode")}}function ct(e){e=k(e);ft(e);W(lt(e),function(e){ft(e)})}function ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function dt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=z().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function J(e,t,r){$(e,t,Q({error:t},r))}function vt(e){return e==="htmx:afterProcessNode"}function gt(e,t){W(sr(e),function(e){try{t(e)}catch(e){pt(e)}})}function pt(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function $(e,t,r){e=k(e);if(r==null){r={}}r["elt"]=e;var n=dt(t,r);if(U.logger&&!vt(t)){U.logger(e,t,r)}if(r.error){pt(r.error);$(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=ht(t);if(i&&o!==t){var a=dt(o,n.detail);i=i&&e.dispatchEvent(a)}gt(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var mt=location.pathname+location.search;function xt(){var e=z().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||z().body}function yt(e,t,r,n){var i=S(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>U.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(z().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function bt(e){var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function wt(e){var t=U.config.requestClass;var r=e.cloneNode(true);W(R(r,"."+t),function(e){q(e,t)});return r.innerHTML}function St(){var e=xt();var t=mt||location.pathname+location.search;$(z().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(U.config.historyEnabled)history.replaceState({htmx:true},z().title,window.location.href);yt(t,wt(e),z().title,window.scrollY)}function Et(e){if(U.config.historyEnabled)history.pushState({htmx:true},"",e);mt=e}function Ct(e){W(e,function(e){e.call()})}function Rt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};$(z().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){$(z().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=xt();var r=zt(t);me(t,e,r);Ct(r.tasks);mt=n;$(z().body,"htmx:historyRestore",{path:n})}else{J(z().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Ot(e){St();e=e||location.pathname+location.search;var t=bt(e);if(t){var r=g(t.content);var n=xt();var i=zt(n);me(n,r,i);Ct(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);mt=e;$(z().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Rt(e)}}}function Lt(e){var t=G(e,"hx-push-url");return t&&t!=="false"||_(e).boosted&&_(e).pushURL}function qt(e){var t=G(e,"hx-push-url");return t==="true"||t==="false"?null:t}function At(e){var t=F(e,"hx-indicator");if(t==null){t=[e]}W(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Tt(e){W(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function Ht(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Nt(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 kt(t,r,n,e,i){if(e==null||Ht(t,e)){return}else{t.push(e)}if(Nt(e)){var o=f(e,"name");var a=e.value;if(e.multiple){a=y(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=y(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){It(e,n)}}if(d(e,"form")){var l=e.elements;W(l,function(e){kt(t,r,n,e,i)})}}function It(e,t){if(e.willValidate){$(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});$(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Mt(e,t){var r=[];var n={};var i={};var o=[];var a=_(e);var s=d(e,"form")&&e.noValidate!==true;if(a.lastButtonClicked){s=s&&a.lastButtonClicked.formNoValidate!==true}if(t!=="get"){kt(r,i,o,H(e,"form"),s)}kt(r,n,o,e,s);if(a.lastButtonClicked){var l=f(a.lastButtonClicked,"name");if(l){n[l]=a.lastButtonClicked.value}}var u=F(e,"hx-include");W(u,function(e){kt(r,n,o,e,s);if(!d(e,"form")){W(e.querySelectorAll(Ne),function(e){kt(r,n,o,e,s)})}});n=Q(n,i);return{errors:o,values:n}}function Dt(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function Ft(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=Dt(t,r,e)})}else{t=Dt(t,r,n)}}}return t}function Pt(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){W(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Xt(e,t,r){var n={"HX-Request":"true","HX-Trigger":f(e,"id"),"HX-Trigger-Name":f(e,"name"),"HX-Target":V(t,"id"),"HX-Current-URL":z().location.href};Wt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(_(e).boosted){n["HX-Boosted"]="true"}return n}function jt(t,e){var r=G(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){W(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};W(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Bt(e){return f(e,"href")&&f(e,"href").indexOf("#")>=0}function Ut(e,t){var r=t?t:G(e,"hx-swap");var n={swapStyle:_(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(_(e).boosted&&!Bt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var o=1;o<i.length;o++){var a=i[o];if(a.indexOf("swap:")===0){n["swapDelay"]=v(a.substr(5))}if(a.indexOf("settle:")===0){n["settleDelay"]=v(a.substr(7))}if(a.indexOf("scroll:")===0){var s=a.substr(7);var l=s.split(":");var f=l.pop();var u=l.length>0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(a.indexOf("show:")===0){var c=a.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(a.indexOf("focus-scroll:")===0){var d=a.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function Vt(t,r,n){var i=null;gt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(G(r,"hx-encoding")==="multipart/form-data"||d(r,"form")&&f(r,"enctype")==="multipart/form-data"){return Pt(n)}else{return Ft(n)}}}function zt(e){return{tasks:[],elts:[e]}}function _t(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ee(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var o=t.showTarget;if(t.showTarget==="window"){o="body"}i=ee(r,o)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function Wt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}else if(o.indexOf("js:")===0){o=o.substr(3);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Jt(e,function(){return Function("return ("+o+")")()},{})}else{s=S(o)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Wt(u(e),t,r,n)}function Jt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function $t(e,t){return Wt(e,"hx-vars",true,t)}function Zt(e,t){return Wt(e,"hx-vals",false,t)}function Gt(e){return Q($t(e),Zt(e))}function Kt(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Yt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(z().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Qt(e,t){return e.getAllResponseHeaders().match(t)}function er(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return Z(e,t,null,null,{targetOverride:k(r),returnPromise:true})}else{return Z(e,t,k(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:k(r.target),swapOverride:r.swap,returnPromise:true})}}else{return Z(e,t,null,null,{returnPromise:true})}}function tr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Z(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=z().body}var v=r.handler||rr;if(!Y(n)){return}var g=r.targetOverride||ne(n);if(g==null||g==te){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=_(n);var o=G(n,"hx-sync");var m=null;var x=false;if(o){var y=o.split(":");var b=y[0].trim();if(b==="this"){p=re(n,"hx-sync")}else{p=ee(n,b)}o=(y[1]||"drop").trim();i=_(p);if(o==="drop"&&i.xhr&&i.abortable!==true){return}else if(o==="abort"){if(i.xhr){return}else{x=true}}else if(o==="replace"){$(p,"htmx:abort")}else if(o.indexOf("queue")===0){var w=o.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=_(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){Z(e,t,n,f,r)})}return}}var a=new XMLHttpRequest;i.xhr=a;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=G(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){K(c);s();return d}}var R=G(n,"hx-confirm");if(R){if(!confirm(R)){K(c);s();return d}}var O=Xt(n,g,C);if(r.headers){O=Q(O,r.headers)}var L=Mt(n,e);var q=L.errors;var A=L.values;if(r.values){A=Q(A,r.values)}var T=Gt(n);var H=Q(A,T);var N=jt(H,n);if(e!=="get"&&G(n,"hx-encoding")==null){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=z().location.href}var k=Wt(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:q,withCredentials:r.credentials||k.credentials||U.config.withCredentials,timeout:r.timeout||k.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){K(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;q=l.errors;if(q&&q.length>0){$(n,"htmx:validation:halted",l);K(c);s();return d}var I=t.split("#");var M=I[0];var D=I[1];if(e==="get"){var F=M;var P=Object.keys(N).length!==0;if(P){if(F.indexOf("?")<0){F+="?"}else{F+="&"}F+=Ft(N);if(D){F+="#"+D}}a.open("GET",F,true)}else{a.open(e.toUpperCase(),t,true)}a.overrideMimeType("text/html");a.withCredentials=l.withCredentials;a.timeout=l.timeout;if(k.noHeaders){}else{for(var X in O){if(O.hasOwnProperty(X)){var j=O[X];Kt(a,X,j)}}}var u={xhr:a,target:g,requestConfig:l,etc:r,pathInfo:{path:t,finalPath:F,anchor:D}};a.onload=function(){try{var e=tr(n);v(n,u);Tt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!Y(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(Y(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}K(c);s()}catch(e){J(n,"htmx:onLoadError",Q({error:e},u));throw e}};a.onerror=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);K(h);s()};a.onabort=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);K(h);s()};a.ontimeout=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);K(h);s()};if(!$(n,"htmx:beforeRequest",u)){K(c);s();return d}var B=At(n);W(["loadstart","loadend","progress","abort"],function(t){W([a,a.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);a.send(e==="get"?null:Vt(a,n,N));return d}function rr(s,l){var u=l.xhr;var f=l.target;var r=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(Qt(u,/HX-Trigger:/i)){Se(u,"HX-Trigger",s)}if(Qt(u,/HX-Push:/i)){var c=u.getResponseHeader("HX-Push")}if(Qt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Qt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(Qt(u,/HX-Retarget:/i)){l.target=z().querySelector(u.getResponseHeader("HX-Retarget"))}var h;if(c=="false"){h=false}else{h=Lt(s)||c}var n=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var e=u.status>=400;var t=Q({shouldSwap:n,serverResponse:d,isError:e},l);if(!$(f,"htmx:beforeSwap",t))return;f=t.target;d=t.serverResponse;e=t.isError;l.failed=e;l.successful=!e;if(t.shouldSwap){if(u.status===286){Ie(s)}gt(s,function(e){d=e.transformResponse(d,u,s)});if(h){St()}var i=r.swapOverride;var v=Ut(s,i);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=zt(f);we(v.swapStyle,f,s,d,n);if(t.elt&&!Y(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);W(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(l.pathInfo.anchor){location.hash=l.pathInfo.anchor}if(Qt(u,/HX-Trigger-After-Swap:/i)){var o=s;if(!Y(s)){o=z().body}Se(u,"HX-Trigger-After-Swap",o)}var a=function(){W(n.tasks,function(e){e.call()});W(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h){var e=c||qt(s)||Yt(u)||l.pathInfo.finalPath||l.pathInfo.path;Et(e);$(z().body,"htmx:pushedIntoHistory",{path:e})}if(n.title){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}_t(n.elts,v);if(Qt(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!Y(s)){r=z().body}Se(u,"HX-Trigger-After-Settle",r)}};if(v.settleDelay>0){setTimeout(a,v.settleDelay)}else{a()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(v.swapDelay>0){setTimeout(o,v.swapDelay)}else{o()}}if(e){J(s,"htmx:responseError",Q({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var nr={};function ir(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function or(e,t){if(t.init){t.init(r)}nr[e]=Q(ir(),t)}function ar(e){delete nr[e]}function sr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){W(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=nr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return sr(u(e),r,n)}function lr(e){if(z().readyState!=="loading"){e()}else{z().addEventListener("DOMContentLoaded",e)}}function ur(){if(U.config.includeIndicatorStyles!==false){z().head.insertAdjacentHTML("beforeend","<style> ."+U.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+U.config.requestClass+" ."+U.config.indicatorClass+"{opacity:1} ."+U.config.requestClass+"."+U.config.indicatorClass+"{opacity:1} </style>")}}function fr(){var e=z().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function cr(){var e=fr();if(e){U.config=Q(U.config,e)}}lr(function(){cr();ur();var e=z().body;ct(e);var t=z().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=_(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){Ot();W(t,function(e){$(e,"htmx:restored",{document:z(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.js b/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.js index e38f6ed..27e57bc 100644 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.js +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.js @@ -1,7 +1,9 @@ //AMD insanity (function (root, factory) { + //@ts-ignore if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. + //@ts-ignore define([], factory); } else { // Browser globals @@ -12,6 +14,8 @@ return (function () { 'use strict'; // Public API + //** @type {import("./htmx").HtmxApi} */ + // TODO: list all methods in public API var htmx = { onLoad: onLoadHelper, process: processNode, @@ -35,7 +39,6 @@ return (function () { removeExtension : removeExtension, logAll : logAll, logger : null, - useTemplateFragments: false, config : { historyEnabled:true, historyCacheSize:10, @@ -46,13 +49,19 @@ return (function () { includeIndicatorStyles:true, indicatorClass:'htmx-indicator', requestClass:'htmx-request', + addedClass:'htmx-added', settlingClass:'htmx-settling', swappingClass:'htmx-swapping', allowEval:true, + inlineScriptNonce:'', attributesToSettle:["class", "style", "width", "height"], withCredentials:false, + timeout:0, wsReconnectDelay: 'full-jitter', disableSelector: "[hx-disable], [data-hx-disable]", + useTemplateFragments: false, + scrollBehavior: 'smooth', + defaultFocusScroll: false, }, parseInterval:parseInterval, _:internalEval, @@ -61,9 +70,36 @@ return (function () { }, createWebSocket: function(url){ return new WebSocket(url, []); - } + }, + version: "1.7.0" }; + /** @type {import("./htmx").HtmxInternalApi} */ + var internalAPI = { + bodyContains: bodyContains, + filterValues: filterValues, + hasAttribute: hasAttribute, + getAttributeValue: getAttributeValue, + getClosestMatch: getClosestMatch, + getExpressionVars: getExpressionVars, + getHeaders: getHeaders, + getInputValues: getInputValues, + getInternalData: getInternalData, + getSwapSpecification: getSwapSpecification, + getTriggerSpecs: getTriggerSpecs, + getTarget: getTarget, + makeFragment: makeFragment, + mergeObjects: mergeObjects, + makeSettleInfo: makeSettleInfo, + oobSwap: oobSwap, + selectAndSwap: selectAndSwap, + settleImmediately: settleImmediately, + shouldCancel: shouldCancel, + triggerEvent: triggerEvent, + triggerErrorEvent: triggerErrorEvent, + withExtensions: withExtensions, + } + var VERBS = ['get', 'post', 'put', 'delete', 'patch']; var VERB_SELECTOR = VERBS.map(function(verb){ return "[hx-" + verb + "], [data-hx-" + verb + "]" @@ -73,19 +109,24 @@ return (function () { // Utilities //==================================================================== - function parseInterval(str) { - if (str == undefined) { - return undefined - } - if (str.slice(-2) == "ms") { - return parseFloat(str.slice(0,-2)) || undefined - } - if (str.slice(-1) == "s") { - return (parseFloat(str.slice(0,-1)) * 1000) || undefined - } - return parseFloat(str) || undefined + function parseInterval(str) { + if (str == undefined) { + return undefined + } + if (str.slice(-2) == "ms") { + return parseFloat(str.slice(0,-2)) || undefined + } + if (str.slice(-1) == "s") { + return (parseFloat(str.slice(0,-1)) * 1000) || undefined + } + return parseFloat(str) || undefined } + /** + * @param {HTMLElement} elt + * @param {string} name + * @returns {(string | null)} + */ function getRawAttribute(elt, name) { return elt.getAttribute && elt.getAttribute(name); } @@ -96,18 +137,36 @@ return (function () { elt.hasAttribute("data-" + qualifiedName)); } + /** + * + * @param {HTMLElement} elt + * @param {string} qualifiedName + * @returns {(string | null)} + */ function getAttributeValue(elt, qualifiedName) { return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); } + /** + * @param {HTMLElement} elt + * @returns {HTMLElement | null} + */ function parentElt(elt) { return elt.parentElement; } + /** + * @returns {Document} + */ function getDocument() { return document; } + /** + * @param {HTMLElement} elt + * @param {(e:HTMLElement) => boolean} condition + * @returns {HTMLElement | null} + */ function getClosestMatch(elt, condition) { if (condition(elt)) { return elt; @@ -118,22 +177,47 @@ return (function () { } } + function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ + var attributeValue = getAttributeValue(ancestor, attributeName); + var disinherit = getAttributeValue(ancestor, "hx-disinherit"); + if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) { + return "unset"; + } else { + return attributeValue + } + } + + /** + * @param {HTMLElement} elt + * @param {string} attributeName + * @returns {string | null} + */ function getClosestAttributeValue(elt, attributeName) { var closestAttr = null; getClosestMatch(elt, function (e) { - return closestAttr = getAttributeValue(e, attributeName); + return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName); }); - return closestAttr; + if (closestAttr !== "unset") { + return closestAttr; + } } + /** + * @param {HTMLElement} elt + * @param {string} selector + * @returns {boolean} + */ function matches(elt, selector) { + // @ts-ignore: non-standard properties for browser compatability // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || - elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector - || elt.webkitMatchesSelector || elt.oMatchesSelector; + var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; return matchesFunction && matchesFunction.call(elt, selector); } + /** + * @param {string} str + * @returns {string} + */ function getStartTag(str) { var tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i var match = tagMatcher.exec( str ); @@ -144,23 +228,40 @@ return (function () { } } + /** + * + * @param {string} resp + * @param {number} depth + * @returns {Element} + */ function parseHTML(resp, depth) { var parser = new DOMParser(); var responseDoc = parser.parseFromString(resp, "text/html"); + + /** @type {Element} */ var responseNode = responseDoc.body; while (depth > 0) { depth--; + // @ts-ignore responseNode = responseNode.firstChild; } if (responseNode == null) { + // @ts-ignore responseNode = getDocument().createDocumentFragment(); } return responseNode; } + /** + * + * @param {string} resp + * @returns {Element} + */ function makeFragment(resp) { if (htmx.config.useTemplateFragments) { var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0); + // @ts-ignore type mismatch between DocumentFragment and Element. + // TODO: Are these close enough for htmx to use interchangably? return documentFragment.querySelector('template').content; } else { var startTag = getStartTag(resp); @@ -186,24 +287,45 @@ return (function () { } } + /** + * @param {Function} func + */ function maybeCall(func){ if(func) { func(); } } + /** + * @param {any} o + * @param {string} type + * @returns + */ function isType(o, type) { return Object.prototype.toString.call(o) === "[object " + type + "]"; } + /** + * @param {*} o + * @returns {o is Function} + */ function isFunction(o) { return isType(o, "Function"); } + /** + * @param {*} o + * @returns {o is Object} + */ function isRawObject(o) { return isType(o, "Object"); } + /** + * getInternalData retrieves "private" data stored by htmx within an element + * @param {HTMLElement} elt + * @returns {*} + */ function getInternalData(elt) { var dataProp = 'htmx-internal-data'; var data = elt[dataProp]; @@ -213,6 +335,11 @@ return (function () { return data; } + /** + * toArray converts an ArrayLike object into a real array. + * @param {ArrayLike} arr + * @returns {any[]} + */ function toArray(arr) { var returnArr = []; if (arr) { @@ -238,14 +365,25 @@ return (function () { return elemTop < window.innerHeight && elemBottom >= 0; } - function bodyContains(elt) { - return getDocument().body.contains(elt); - } + function bodyContains(elt) { + if (elt.getRootNode() instanceof ShadowRoot) { + return getDocument().body.contains(elt.getRootNode().host); + } else { + return getDocument().body.contains(elt); + } + } function splitOnWhitespace(trigger) { return trigger.trim().split(/\s+/); } + /** + * mergeObjects takes all of the keys from + * obj2 and duplicates them into obj1 + * @param {Object} obj1 + * @param {Object} obj2 + * @returns {Object} + */ function mergeObjects(obj1, obj2) { for (var key in obj2) { if (obj2.hasOwnProperty(key)) { @@ -319,7 +457,7 @@ return (function () { if (delay) { setTimeout(function(){addClassToElement(elt, clazz);}, delay) } else { - elt.classList.add(clazz); + elt.classList && elt.classList.add(clazz); } } @@ -328,7 +466,13 @@ return (function () { if (delay) { setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) } else { - elt.classList.remove(clazz); + if (elt.classList) { + elt.classList.remove(clazz); + // if there are no classes left, remove the class attribute + if (elt.classList.length === 0) { + elt.removeAttribute("class"); + } + } } } @@ -360,17 +504,25 @@ return (function () { } function querySelectorAllExt(elt, selector) { - if (selector.indexOf("closest ") === 0) { + if (selector.indexOf("closest ") === 0) { return [closest(elt, selector.substr(8))]; } else if (selector.indexOf("find ") === 0) { return [find(elt, selector.substr(5))]; + } else if (selector === 'document') { + return [document]; + } else if (selector === 'window') { + return [window]; } else { return getDocument().querySelectorAll(selector); } } function querySelectorExt(eltOrSelector, selector) { - return querySelectorAllExt(eltOrSelector, selector)[0] + if (selector) { + return querySelectorAllExt(eltOrSelector, selector)[0]; + } else { + return querySelectorAllExt(getDocument().body, eltOrSelector)[0]; + } } function resolveTarget(arg2) { @@ -418,13 +570,36 @@ return (function () { //==================================================================== // Node processing //==================================================================== + + var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors + function findAttributeTargets(elt, attrName) { + var attrTarget = getClosestAttributeValue(elt, attrName); + if (attrTarget) { + if (attrTarget === "this") { + return [findThisElement(elt, attrName)]; + } else { + var result = querySelectorAllExt(elt, attrTarget); + if (result.length === 0) { + logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!"); + return [DUMMY_ELT] + } else { + return result; + } + } + } + } + + function findThisElement(elt, attribute){ + return getClosestMatch(elt, function (elt) { + return getAttributeValue(elt, attribute) != null; + }) + } function getTarget(elt) { - var explicitTarget = getClosestMatch(elt, function(e){return getAttributeValue(e,"hx-target") !== null}); - if (explicitTarget) { - var targetStr = getAttributeValue(explicitTarget, "hx-target"); + var targetStr = getClosestAttributeValue(elt, "hx-target"); + if (targetStr) { if (targetStr === "this") { - return explicitTarget; + return findThisElement(elt,'hx-target'); } else { return querySelectorExt(elt, targetStr) } @@ -476,6 +651,13 @@ return (function () { return swapStyle === "outerHTML"; } + /** + * + * @param {string} oobValue + * @param {HTMLElement} oobElement + * @param {*} settleInfo + * @returns + */ function oobSwap(oobValue, oobElement, settleInfo) { var selector = "#" + oobElement.id; var swapStyle = "outerHTML"; @@ -488,18 +670,35 @@ return (function () { swapStyle = oobValue; } - var target = getDocument().querySelector(selector); - if (target) { - var fragment; - fragment = getDocument().createDocumentFragment(); - fragment.appendChild(oobElement); // pulls the child out of the existing fragment - if (!isInlineSwap(swapStyle, target)) { - fragment = oobElement; // if this is not an inline swap, we use the content of the node, not the node itself - } - swap(swapStyle, target, target, fragment, settleInfo); + var targets = getDocument().querySelectorAll(selector); + if (targets) { + forEach( + targets, + function (target) { + var fragment; + var oobElementClone = oobElement.cloneNode(true); + fragment = getDocument().createDocumentFragment(); + fragment.appendChild(oobElementClone); + if (!isInlineSwap(swapStyle, target)) { + fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself + } + + var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment }; + if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return; + + target = beforeSwapDetails.target; // allow re-targeting + if (beforeSwapDetails['shouldSwap']){ + swap(swapStyle, target, target, fragment, settleInfo); + } + forEach(settleInfo.elts, function (elt) { + triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails); + }); + } + ); + oobElement.parentNode.removeChild(oobElement); } else { oobElement.parentNode.removeChild(oobElement); - triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}) + triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}); } return oobValue; } @@ -540,6 +739,7 @@ return (function () { function makeAjaxLoadTask(child) { return function () { + removeClassFromElement(child, htmx.config.addedClass); processNode(child); processScripts(child); processFocus(child) @@ -559,6 +759,7 @@ return (function () { handleAttributes(parentNode, fragment, settleInfo); while(fragment.childNodes.length > 0){ var child = fragment.firstChild; + addClassToElement(child, htmx.config.addedClass); parentNode.insertBefore(child, insertBefore); if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { settleInfo.tasks.push(makeAjaxLoadTask(child)); @@ -574,6 +775,9 @@ return (function () { if (internalData.sseEventSource) { internalData.sseEventSource.close(); } + + triggerEvent(element, "htmx:beforeCleanupElement") + if (internalData.listenerInfos) { forEach(internalData.listenerInfos, function(info) { if (element !== info.on) { @@ -590,12 +794,14 @@ return (function () { if (target.tagName === "BODY") { return swapInnerHTML(target, fragment, settleInfo); } else { + // @type {HTMLElement} + var newElt var eltBeforeNewContent = target.previousSibling; insertNodesBefore(parentElt(target), target, fragment, settleInfo); if (eltBeforeNewContent == null) { - var newElt = parentElt(target).firstChild; + newElt = parentElt(target).firstChild; } else { - var newElt = eltBeforeNewContent.nextSibling; + newElt = eltBeforeNewContent.nextSibling; } getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later settleInfo.elts = [] // clear existing elements @@ -625,6 +831,10 @@ return (function () { function swapAfterEnd(target, fragment, settleInfo) { return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo); } + function swapDelete(target, fragment, settleInfo) { + cleanUpElement(target); + return parentElt(target).removeChild(target); + } function swapInnerHTML(target, fragment, settleInfo) { var firstChild = target.firstChild; @@ -670,6 +880,9 @@ return (function () { case "afterend": swapAfterEnd(target, fragment, settleInfo); return; + case "delete": + swapDelete(target, fragment, settleInfo); + return; default: var extensions = getExtensions(elt); for (var i = 0; i < extensions.length; i++) { @@ -692,32 +905,27 @@ return (function () { logError(e); } } - swapInnerHTML(target, fragment, settleInfo); + if (swapStyle === "innerHTML") { + swapInnerHTML(target, fragment, settleInfo); + } else { + swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo); + } } } - var TITLE_FINDER = /<title>([\s\S]+?)<\/title>/im; function findTitle(content) { - if(content.indexOf('<title>') > -1 && - (content.indexOf('<svg>') == -1 || - content.indexOf('<title>') < content.indexOf('<svg>'))) { - var result = TITLE_FINDER.exec(content); + if (content.indexOf('<title') > -1) { + var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, ''); + var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im); + if (result) { - return result[1]; + return result[2]; } } } function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) { - var title = findTitle(responseText); - if(title) { - var titleElt = find("title"); - if(titleElt) { - titleElt.innerHTML = title; - } else { - window.document.title = title; - } - } + settleInfo.title = findTitle(responseText); var fragment = makeFragment(responseText); if (fragment) { handleOutOfBandSwaps(fragment, settleInfo); @@ -840,6 +1048,11 @@ return (function () { } var INPUT_SELECTOR = 'input, textarea, select'; + + /** + * @param {HTMLElement} elt + * @returns {import("./htmx").HtmxTriggerSpecification[]} + */ function getTriggerSpecs(elt) { var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); var triggerSpecs = []; @@ -853,7 +1066,12 @@ return (function () { if (trigger === "every") { var every = {trigger: 'every'}; consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, WHITESPACE)); + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); + consumeUntil(tokens, NOT_WHITESPACE); + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + every.eventFilter = eventFilter; + } triggerSpecs.push(every); } else if (trigger.indexOf("sse:") === 0) { triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); @@ -877,7 +1095,17 @@ return (function () { triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); } else if (token === "from" && tokens[0] === ":") { tokens.shift(); - triggerSpec.from = consumeUntil(tokens, WHITESPACE_OR_COMMA); + var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); + if (from_arg === "closest" || from_arg === "find") { + tokens.shift(); + from_arg += + " " + + consumeUntil( + tokens, + WHITESPACE_OR_COMMA + ); + } + triggerSpec.from = from_arg; } else if (token === "target" && tokens[0] === ":") { tokens.shift(); triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA); @@ -919,14 +1147,16 @@ return (function () { getInternalData(elt).cancelled = true; } - function processPolling(elt, verb, path, interval) { + function processPolling(elt, verb, path, spec) { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - issueAjaxRequest(verb, path, elt); - processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), interval); + if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { + issueAjaxRequest(verb, path, elt); + } + processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), spec); } - }, interval); + }, spec.pollInterval); } function isLocalLink(elt) { @@ -936,7 +1166,7 @@ return (function () { } function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt)) || elt.tagName === "FORM") { + if ((elt.tagName === "A" && isLocalLink(elt) && elt.target === "") || elt.tagName === "FORM") { nodeData.boosted = true; var verb, path; if (elt.tagName === "A") { @@ -957,11 +1187,26 @@ return (function () { } } - function shouldCancel(elt) { - return elt.tagName === "FORM" || - (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) || - (elt.tagName === "A" && elt.href && (elt.getAttribute('href') === '#' || - elt.getAttribute('href').indexOf("#") !== 0)); + /** + * + * @param {Event} evt + * @param {HTMLElement} elt + * @returns + */ + function shouldCancel(evt, elt) { + if (evt.type === "submit" || evt.type === "click") { + if (elt.tagName === "FORM") { + return true; + } + if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { + return true; + } + if (elt.tagName === "A" && elt.href && + (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) { + return true; + } + } + return false; } function ignoreBoostedAnchorCtrlClick(elt, evt) { @@ -982,86 +1227,90 @@ return (function () { } function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { - var eltToListenOn = elt; + var eltsToListenOn; if (triggerSpec.from) { - eltToListenOn = find(triggerSpec.from); + eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); + } else { + eltsToListenOn = [elt]; } - var eventListener = function (evt) { - if (!bodyContains(elt)) { - eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); - return; - } - if (ignoreBoostedAnchorCtrlClick(elt, evt)) { - return; - } - if(explicitCancel || shouldCancel(elt)){ - evt.preventDefault(); - } - if (maybeFilterEvent(triggerSpec, evt)) { - return; - } - var eventData = getInternalData(evt); - eventData.triggerSpec = triggerSpec; - if (eventData.handledFor == null) { - eventData.handledFor = []; - } - var elementData = getInternalData(elt); - if (eventData.handledFor.indexOf(elt) < 0) { - eventData.handledFor.push(elt); - if (triggerSpec.consume) { - evt.stopPropagation(); - } - if (triggerSpec.target && evt.target) { - if (!matches(evt.target, triggerSpec.target)) { - return; - } - } - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } + forEach(eltsToListenOn, function (eltToListenOn) { + var eventListener = function (evt) { + if (!bodyContains(elt)) { + eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); + return; } - if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { - return; - } else { - elementData.lastValue = elt.value; - } + if (ignoreBoostedAnchorCtrlClick(elt, evt)) { + return; } - if (elementData.delayed) { - clearTimeout(elementData.delayed); + if (explicitCancel || shouldCancel(evt, elt)) { + evt.preventDefault(); } - if (elementData.throttle) { + if (maybeFilterEvent(triggerSpec, evt)) { return; } + var eventData = getInternalData(evt); + eventData.triggerSpec = triggerSpec; + if (eventData.handledFor == null) { + eventData.handledFor = []; + } + var elementData = getInternalData(elt); + if (eventData.handledFor.indexOf(elt) < 0) { + eventData.handledFor.push(elt); + if (triggerSpec.consume) { + evt.stopPropagation(); + } + if (triggerSpec.target && evt.target) { + if (!matches(evt.target, triggerSpec.target)) { + return; + } + } + 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); + } + if (elementData.throttle) { + return; + } - if (triggerSpec.throttle) { - if(!elementData.throttle) { + if (triggerSpec.throttle) { + if (!elementData.throttle) { + issueAjaxRequest(verb, path, elt, evt); + elementData.throttle = setTimeout(function () { + elementData.throttle = null; + }, triggerSpec.throttle); + } + } else if (triggerSpec.delay) { + elementData.delayed = setTimeout(function () { + issueAjaxRequest(verb, path, elt, evt); + }, triggerSpec.delay); + } else { issueAjaxRequest(verb, path, elt, evt); - elementData.throttle = setTimeout(function(){ - elementData.throttle = null; - }, triggerSpec.throttle); } - } else if (triggerSpec.delay) { - elementData.delayed = setTimeout(function(){ - issueAjaxRequest(verb, path, elt, evt); - }, triggerSpec.delay); - } else { - issueAjaxRequest(verb, path, elt, evt); } - } - }; - if (nodeData.listenerInfos == null) { - nodeData.listenerInfos = []; - } - nodeData.listenerInfos.push({ - trigger: triggerSpec.trigger, - listener: eventListener, - on: eltToListenOn + }; + if (nodeData.listenerInfos == null) { + nodeData.listenerInfos = []; + } + nodeData.listenerInfos.push({ + trigger: triggerSpec.trigger, + listener: eventListener, + on: eltToListenOn + }) + eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); }) - eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); } var windowIsScrolling = false // used by initScrollHandler @@ -1084,9 +1333,9 @@ return (function () { } function maybeReveal(elt) { - var nodeData = getInternalData(elt); - if (!nodeData.revealed && isScrolledIntoView(elt)) { - nodeData.revealed = true; + if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { + elt.setAttribute('data-hx-revealed', 'true'); + var nodeData = getInternalData(elt); if (nodeData.initialized) { issueAjaxRequest(nodeData.verb, nodeData.path, elt); } else { @@ -1099,6 +1348,10 @@ return (function () { } } + //==================================================================== + // Web Sockets + //==================================================================== + function processWebSocketInfo(elt, nodeData, info) { var values = splitOnWhitespace(info); for (var i = 0; i < values.length; i++) { @@ -1132,7 +1385,7 @@ return (function () { }; socket.onclose = function (e) { - if ([1006, 1012, 1013].includes(e.code)) { // Abnormal Closure/Service Restart/Try Again Later + if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later var delay = getWebSocketReconnectDelay(retryCount); setTimeout(function() { ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout @@ -1193,7 +1446,7 @@ return (function () { return; } webSocket.send(JSON.stringify(filteredParameters)); - if(shouldCancel(elt)){ + if(shouldCancel(evt, elt)){ evt.preventDefault(); } }); @@ -1205,6 +1458,7 @@ return (function () { function getWebSocketReconnectDelay(retryCount) { var delay = htmx.config.wsReconnectDelay; if (typeof delay === 'function') { + // @ts-ignore return delay(retryCount); } if (delay === 'full-jitter') { @@ -1340,7 +1594,7 @@ return (function () { } else if (triggerSpec.trigger === "intersect") { var observerOptions = {}; if (triggerSpec.root) { - observerOptions.root = querySelectorExt(triggerSpec.root) + observerOptions.root = querySelectorExt(elt, triggerSpec.root) } if (triggerSpec.threshold) { observerOptions.threshold = parseFloat(triggerSpec.threshold); @@ -1360,7 +1614,7 @@ return (function () { loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); } else if (triggerSpec.pollInterval) { nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec.pollInterval); + processPolling(elt, verb, path, triggerSpec); } else { addEventListener(elt, verb, path, nodeData, triggerSpec); } @@ -1371,14 +1625,24 @@ return (function () { } function evalScript(script) { - if (script.type === "text/javascript" || script.type === "") { + if (script.type === "text/javascript" || script.type === "module" || script.type === "") { + var newScript = getDocument().createElement("script"); + forEach(script.attributes, function (attr) { + newScript.setAttribute(attr.name, attr.value); + }); + newScript.textContent = script.textContent; + newScript.async = false; + if (htmx.config.inlineScriptNonce) { + newScript.nonce = htmx.config.inlineScriptNonce; + } + var parent = script.parentElement; + try { - maybeEval(script, function () { - // wtf - https://stackoverflow.com/questions/9107240/1-evalthis-vs-evalthis-in-javascript - (1, eval)(script.innerText); - }); + parent.insertBefore(newScript, script); } catch (e) { logError(e); + } finally { + parent.removeChild(script); } } } @@ -1392,21 +1656,41 @@ return (function () { }); } - function isBoosted() { + function hasChanceOfBeingBoosted() { return document.querySelector("[hx-boost], [data-hx-boost]"); } function findElementsToProcess(elt) { if (elt.querySelectorAll) { - var boostedElts = isBoosted() ? ", a, form" : ""; + var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws]"); + " [data-hx-ws], [hx-ext], [hx-data-ext]"); return results; } else { return []; } } + function initButtonTracking(form){ + var maybeSetLastButtonClicked = function(evt){ + if (matches(evt.target, "button, input[type='submit']")) { + var internalData = getInternalData(form); + internalData.lastButtonClicked = evt.target; + } + }; + + // need to handle both click and focus in: + // focusin - in case someone tabs in to a button and hits the space bar + // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + + form.addEventListener('click', maybeSetLastButtonClicked) + form.addEventListener('focusin', maybeSetLastButtonClicked) + form.addEventListener('focusout', function(evt){ + var internalData = getInternalData(form); + internalData.lastButtonClicked = null; + }) + } + function initNode(elt) { if (elt.closest && elt.closest(htmx.config.disableSelector)) { return; @@ -1427,6 +1711,10 @@ return (function () { boostElement(elt, nodeData, triggerSpecs); } + if (elt.tagName === "FORM") { + initButtonTracking(elt); + } + var sseInfo = getAttributeValue(elt, 'hx-sse'); if (sseInfo) { processSSEInfo(elt, nodeData, sseInfo); @@ -1473,6 +1761,15 @@ return (function () { return eventName === "htmx:afterProcessNode" } + /** + * `withExtensions` locates all active extensions for a provided element, then + * executes the provided function using each of the active extensions. It should + * be called internally at every extendable execution point in htmx. + * + * @param {HTMLElement} elt + * @param {(extension:import("./htmx").HtmxExtension) => void} toDo + * @returns void + */ function withExtensions(elt, toDo) { forEach(getExtensions(elt), function(extension){ try { @@ -1520,7 +1817,7 @@ return (function () { //==================================================================== // History Support //==================================================================== - var currentPathForHistory = null; + var currentPathForHistory = location.pathname+location.search; function getHistoryElement() { var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]'); @@ -1569,7 +1866,7 @@ return (function () { return clone.innerHTML; } - function saveHistory() { + function saveCurrentPageToHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); @@ -1598,9 +1895,11 @@ return (function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); var fragment = makeFragment(this.response); + // @ts-ignore fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; var historyElement = getHistoryElement(); var settleInfo = makeSettleInfo(historyElement); + // @ts-ignore swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); currentPathForHistory = path; @@ -1613,7 +1912,7 @@ return (function () { } function restoreHistory(path) { - saveHistory(); + saveCurrentPageToHistory(); path = path || location.pathname+location.search; var cached = getCachedHistory(path); if (cached) { @@ -1628,6 +1927,8 @@ return (function () { triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); } else { if (htmx.config.refreshOnHistoryMiss) { + + // @ts-ignore: optional parameter in reload() function throws error window.location.reload(true); } else { loadHistoryFromServer(path); @@ -1647,10 +1948,8 @@ return (function () { } function addRequestIndicatorClasses(elt) { - var indicator = getClosestAttributeValue(elt, 'hx-indicator'); - if (indicator) { - var indicators = querySelectorAllExt(elt, indicator); - } else { + var indicators = findAttributeTargets(elt, 'hx-indicator'); + if (indicators == null) { indicators = [elt]; } forEach(indicators, function (ic) { @@ -1753,14 +2052,22 @@ return (function () { } } + /** + * @param {HTMLElement} elt + * @param {string} verb + */ function getInputValues(elt, verb) { var processed = []; var values = {}; var formValues = {}; var errors = []; + var internalData = getInternalData(elt); - // only validate when form is directly submitted and novalidate is not set + // only validate when form is directly submitted and novalidate or formnovalidate are not set var validate = matches(elt, 'form') && elt.noValidate !== true; + if (internalData.lastButtonClicked) { + validate = validate && internalData.lastButtonClicked.formNoValidate !== true; + } // for a non-GET include the closest form if (verb !== 'get') { @@ -1770,21 +2077,26 @@ return (function () { // include the element itself processInputValue(processed, values, errors, elt, validate); - // include any explicit includes - var includes = getClosestAttributeValue(elt, "hx-include"); - if (includes) { - var nodes = querySelectorAllExt(elt, includes); - forEach(nodes, function(node) { - processInputValue(processed, values, errors, node, validate); - // if a non-form is included, include any input values within it - if (!matches(node, 'form')) { - forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { - processInputValue(processed, values, errors, descendant, validate); - }) - } - }); + // if a button or submit was clicked last, include its value + if (internalData.lastButtonClicked) { + var name = getRawAttribute(internalData.lastButtonClicked,"name"); + if (name) { + values[name] = internalData.lastButtonClicked.value; + } } + // include any explicit includes + var includes = findAttributeTargets(elt, "hx-include"); + forEach(includes, function(node) { + processInputValue(processed, values, errors, node, validate); + // if a non-form is included, include any input values within it + if (!matches(node, 'form')) { + forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { + processInputValue(processed, values, errors, descendant, validate); + }) + } + }); + // form values take precedence, overriding the regular values values = mergeObjects(values, formValues); @@ -1795,7 +2107,11 @@ return (function () { if (returnStr !== "") { returnStr += "&"; } - returnStr += encodeURIComponent(name) + "=" + encodeURIComponent(realValue); + if (String(realValue) === "[object Object]") { + realValue = JSON.stringify(realValue); + } + var s = encodeURIComponent(realValue); + returnStr += encodeURIComponent(name) + "=" + s; return returnStr; } @@ -1837,6 +2153,12 @@ return (function () { // Ajax //==================================================================== + /** + * @param {HTMLElement} elt + * @param {HTMLElement} target + * @param {string} prompt + * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification + */ function getHeaders(elt, target, prompt) { var headers = { "HX-Request" : "true", @@ -1849,9 +2171,20 @@ return (function () { if (prompt !== undefined) { headers["HX-Prompt"] = prompt; } + if (getInternalData(elt).boosted) { + headers["HX-Boosted"] = "true"; + } return headers; } + /** + * filterValues takes an object containing form input values + * and returns a new object that only contains keys that are + * specified by the closest "hx-params" attribute + * @param {Object} inputValues + * @param {HTMLElement} elt + * @returns {Object} + */ function filterValues(inputValues, elt) { var paramsValue = getClosestAttributeValue(elt, "hx-params"); if (paramsValue) { @@ -1882,8 +2215,14 @@ return (function () { return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0 } - function getSwapSpecification(elt) { - var swapInfo = getClosestAttributeValue(elt, "hx-swap"); + /** + * + * @param {HTMLElement} elt + * @param {string} swapInfoOverride + * @returns {import("./htmx").HtmxSwapSpecification} + */ + function getSwapSpecification(elt, swapInfoOverride) { + var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap"); var swapSpec = { "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, "swapDelay" : htmx.config.defaultSwapDelay, @@ -1905,10 +2244,24 @@ return (function () { swapSpec["settleDelay"] = parseInterval(modifier.substr(7)); } if (modifier.indexOf("scroll:") === 0) { - swapSpec["scroll"] = modifier.substr(7); + var scrollSpec = modifier.substr(7); + var splitSpec = scrollSpec.split(":"); + var scrollVal = splitSpec.pop(); + var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; + swapSpec["scroll"] = scrollVal; + swapSpec["scrollTarget"] = selectorVal; } if (modifier.indexOf("show:") === 0) { - swapSpec["show"] = modifier.substr(5); + var showSpec = modifier.substr(5); + var splitSpec = showSpec.split(":"); + var showVal = splitSpec.pop(); + var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; + swapSpec["show"] = showVal; + swapSpec["showTarget"] = selectorVal; + } + if (modifier.indexOf("focus-scroll:") === 0) { + var focusScrollVal = modifier.substr("focus-scroll:".length); + swapSpec["focusScroll"] = focusScrollVal == "true"; } } } @@ -1926,7 +2279,8 @@ return (function () { if (encodedParameters != null) { return encodedParameters; } else { - if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data") { + if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || + (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) { return makeFormData(filteredParameters); } else { return urlEncode(filteredParameters); @@ -1934,6 +2288,11 @@ return (function () { } } + /** + * + * @param {Element} target + * @returns {import("./htmx").HtmxSettleInfo} + */ function makeSettleInfo(target) { return {tasks: [], elts: [target]}; } @@ -1942,23 +2301,46 @@ return (function () { var first = content[0]; var last = content[content.length - 1]; if (swapSpec.scroll) { - if (swapSpec.scroll === "top" && first) { - first.scrollTop = 0; + var target = null; + if (swapSpec.scrollTarget) { + target = querySelectorExt(first, swapSpec.scrollTarget); + } + if (swapSpec.scroll === "top" && (first || target)) { + target = target || first; + target.scrollTop = 0; } - if (swapSpec.scroll === "bottom" && last) { - last.scrollTop = last.scrollHeight; + if (swapSpec.scroll === "bottom" && (last || target)) { + target = target || last; + target.scrollTop = target.scrollHeight; } } if (swapSpec.show) { - if (swapSpec.show === "top" && first) { - first.scrollIntoView(true); + var target = null; + if (swapSpec.showTarget) { + var targetStr = swapSpec.showTarget; + if (swapSpec.showTarget === "window") { + targetStr = "body"; + } + target = querySelectorExt(first, targetStr); + } + if (swapSpec.show === "top" && (first || target)) { + target = target || first; + target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior}); } - if (swapSpec.show === "bottom" && last) { - last.scrollIntoView(false); + if (swapSpec.show === "bottom" && (last || target)) { + target = target || last; + target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior}); } } } + /** + * @param {HTMLElement} elt + * @param {string} attr + * @param {boolean=} evalAsDefault + * @param {Object=} values + * @returns {Object} + */ function getValuesForElement(elt, attr, evalAsDefault, values) { if (values == null) { values = {}; @@ -1973,6 +2355,9 @@ return (function () { if (str.indexOf("javascript:") === 0) { str = str.substr(11); evaluateValue = true; + } else if (str.indexOf("js:") === 0) { + str = str.substr(3); + evaluateValue = true; } if (str.indexOf('{') !== 0) { str = "{" + str + "}"; @@ -2003,14 +2388,28 @@ return (function () { } } + /** + * @param {HTMLElement} elt + * @param {*} expressionVars + * @returns + */ function getHXVarsForElement(elt, expressionVars) { return getValuesForElement(elt, "hx-vars", true, expressionVars); } + /** + * @param {HTMLElement} elt + * @param {*} expressionVars + * @returns + */ function getHXValsForElement(elt, expressionVars) { return getValuesForElement(elt, "hx-vals", false, expressionVars); } + /** + * @param {HTMLElement} elt + * @returns {Object} + */ function getExpressionVars(elt) { return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)); } @@ -2044,10 +2443,12 @@ return (function () { } function ajaxHelper(verb, path, context) { + verb = verb.toLowerCase(); if (context) { if (context instanceof Element || isType(context, 'String')) { return issueAjaxRequest(verb, path, null, null, { - targetOverride: resolveTarget(context) + targetOverride: resolveTarget(context), + returnPromise: true }); } else { return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, @@ -2055,11 +2456,15 @@ return (function () { handler : context.handler, headers : context.headers, values : context.values, - targetOverride: resolveTarget(context.target) + targetOverride: resolveTarget(context.target), + swapOverride: context.swap, + returnPromise: true }); } } else { - return issueAjaxRequest(verb, path); + return issueAjaxRequest(verb, path, null, null, { + returnPromise: true + }); } } @@ -2076,7 +2481,7 @@ return (function () { var resolve = null; var reject = null; etc = etc != null ? etc : {}; - if(typeof Promise !== "undefined"){ + if(etc.returnPromise && typeof Promise !== "undefined"){ var promise = new Promise(function (_resolve, _reject) { resolve = _resolve; reject = _reject; @@ -2091,40 +2496,85 @@ return (function () { return; // do not issue requests for elements removed from the DOM } var target = etc.targetOverride || getTarget(elt); - if (target == null) { + if (target == null || target == DUMMY_ELT) { triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); return; } + + var syncElt = elt; var eltData = getInternalData(elt); - if (eltData.requestInFlight) { - var queueStrategy = 'last'; - var eventData = getInternalData(event); - if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { - queueStrategy = eventData.triggerSpec.queue; - } - if (eltData.queuedRequests == null) { - eltData.queuedRequests = []; - } - if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); - } else if (queueStrategy === "all") { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); - } else if (queueStrategy === "last") { - eltData.queuedRequests = []; // dump existing queue - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); + var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); + var queueStrategy = null; + var abortable = false; + if (syncStrategy) { + var syncStrings = syncStrategy.split(":"); + var selector = syncStrings[0].trim(); + if (selector === "this") { + syncElt = findThisElement(elt, 'hx-sync'); + } else { + syncElt = querySelectorExt(elt, selector); + } + // default to the drop strategy + syncStrategy = (syncStrings[1] || 'drop').trim(); + eltData = getInternalData(syncElt); + if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { + return; + } else if (syncStrategy === "abort") { + if (eltData.xhr) { + return; + } else { + abortable = true; + } + } else if (syncStrategy === "replace") { + triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue + } else if (syncStrategy.indexOf("queue") === 0) { + var queueStrArray = syncStrategy.split(" "); + queueStrategy = (queueStrArray[1] || "last").trim(); } - return; - } else { - eltData.requestInFlight = true; } + + if (eltData.xhr) { + if (eltData.abortable) { + triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue + } else { + if(queueStrategy == null){ + if (event) { + var eventData = getInternalData(event); + if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { + queueStrategy = eventData.triggerSpec.queue; + } + } + if (queueStrategy == null) { + queueStrategy = "last"; + } + } + if (eltData.queuedRequests == null) { + eltData.queuedRequests = []; + } + if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } else if (queueStrategy === "all") { + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } else if (queueStrategy === "last") { + eltData.queuedRequests = []; // dump existing queue + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } + return; + } + } + + var xhr = new XMLHttpRequest(); + eltData.xhr = xhr; + eltData.abortable = abortable; var endRequestLock = function(){ - eltData.requestInFlight = false + eltData.xhr = null; + eltData.abortable = false; if (eltData.queuedRequests != null && eltData.queuedRequests.length > 0) { var queuedRequest = eltData.queuedRequests.shift(); @@ -2152,11 +2602,10 @@ return (function () { } } - var xhr = new XMLHttpRequest(); var headers = getHeaders(elt, target, promptResponse); if (etc.headers) { - headers = mergeObjects(headers, etc.values); + headers = mergeObjects(headers, etc.headers); } var results = getInputValues(elt, verb); var errors = results.errors; @@ -2169,7 +2618,7 @@ return (function () { var filteredParameters = filterValues(allParameters, elt); if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null) { - headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; + headers['Content-Type'] = 'application/x-www-form-urlencoded'; } // behavior of anchors w/ empty href is to use the current URL @@ -2177,6 +2626,8 @@ return (function () { path = getDocument().location.href; } + var requestAttrValues = getValuesForElement(elt, 'hx-request'); + var requestConfig = { parameters: filteredParameters, unfilteredParameters: allParameters, @@ -2184,6 +2635,8 @@ return (function () { target:target, verb:verb, errors:errors, + withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, + timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, path:path, triggeringEvent:event }; @@ -2231,17 +2684,22 @@ return (function () { } xhr.overrideMimeType("text/html"); - xhr.withCredentials = htmx.config.withCredentials; + xhr.withCredentials = requestConfig.withCredentials; + xhr.timeout = requestConfig.timeout; // request headers - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - var headerValue = headers[header]; - safelySetHeaderValue(xhr, header, headerValue); + if (requestAttrValues.noHeaders) { + // ignore all headers + } else { + for (var header in headers) { + if (headers.hasOwnProperty(header)) { + var headerValue = headers[header]; + safelySetHeaderValue(xhr, header, headerValue); + } } } - var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, pathInfo:{ + var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, etc:etc, pathInfo:{ path:path, finalPath:finalPathForGet, anchor:anchor } }; @@ -2289,6 +2747,13 @@ return (function () { maybeCall(reject); endRequestLock(); } + xhr.ontimeout = function() { + removeRequestIndicatorClasses(indicators); + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); + triggerErrorEvent(elt, 'htmx:timeout', responseInfo); + maybeCall(reject); + endRequestLock(); + } if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){ maybeCall(resolve); endRequestLock() @@ -2315,6 +2780,7 @@ return (function () { function handleAjaxResponse(elt, responseInfo) { var xhr = responseInfo.xhr; var target = responseInfo.target; + var etc = responseInfo.etc; if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; @@ -2338,123 +2804,162 @@ return (function () { } } - var shouldSaveHistory = shouldPush(elt) || pushedUrl; + if (hasHeader(xhr,/HX-Retarget:/i)) { + responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget")); + } - if (xhr.status >= 200 && xhr.status < 400) { + /** @type {boolean} */ + var shouldSaveHistory + if (pushedUrl == "false") { + shouldSaveHistory = false + } else { + shouldSaveHistory = shouldPush(elt) || pushedUrl; + } + + // by default htmx only swaps on 200 return codes and does not swap + // on 204 'No Content' + // this can be ovverriden by responding to the htmx:beforeSwap event and + // overriding the detail.shouldSwap property + var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; + var serverResponse = xhr.response; + var isError = xhr.status >= 400; + var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo); + if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; + + target = beforeSwapDetails.target; // allow re-targeting + serverResponse = beforeSwapDetails.serverResponse; // allow updating content + isError = beforeSwapDetails.isError; // allow updating error + + responseInfo.failed = isError; // Make failed property available to response events + responseInfo.successful = !isError; // Make successful property available to response events + + if (beforeSwapDetails.shouldSwap) { if (xhr.status === 286) { cancelPolling(elt); } - // don't process 'No Content' - if (xhr.status !== 204) { - if (!triggerEvent(target, 'htmx:beforeSwap', responseInfo)) return; - var serverResponse = xhr.response; - withExtensions(elt, function(extension){ - serverResponse = extension.transformResponse(serverResponse, xhr, elt); - }); + withExtensions(elt, function (extension) { + serverResponse = extension.transformResponse(serverResponse, xhr, elt); + }); - // Save current page - if (shouldSaveHistory) { - saveHistory(); - } + // Save current page + if (shouldSaveHistory) { + saveCurrentPageToHistory(); + } + + var swapOverride = etc.swapOverride; + var swapSpec = getSwapSpecification(elt, swapOverride); - var swapSpec = getSwapSpecification(elt); + target.classList.add(htmx.config.swappingClass); + var doSwap = function () { + try { - target.classList.add(htmx.config.swappingClass); - var doSwap = function () { + var activeElt = document.activeElement; + var selectionInfo = {}; try { + selectionInfo = { + elt: activeElt, + // @ts-ignore + start: activeElt ? activeElt.selectionStart : null, + // @ts-ignore + end: activeElt ? activeElt.selectionEnd : null + }; + } catch (e) { + // safari issue - see https://github.com/microsoft/playwright/issues/5894 + } - var activeElt = document.activeElement; - var selectionInfo = {}; - try { - selectionInfo = { - elt: activeElt, - start: activeElt ? activeElt.selectionStart : null, - end: activeElt ? activeElt.selectionEnd : null - }; - } catch (e) { - // safari issue - see https://github.com/microsoft/playwright/issues/5894 + var settleInfo = makeSettleInfo(target); + selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + + if (selectionInfo.elt && + !bodyContains(selectionInfo.elt) && + selectionInfo.elt.id) { + var newActiveElt = document.getElementById(selectionInfo.elt.id); + var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; + if (newActiveElt) { + // @ts-ignore + if (selectionInfo.start && newActiveElt.setSelectionRange) { + // @ts-ignore + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + } + newActiveElt.focus(focusOptions); } + } - var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + target.classList.remove(htmx.config.swappingClass); + forEach(settleInfo.elts, function (elt) { + if (elt.classList) { + elt.classList.add(htmx.config.settlingClass); + } + triggerEvent(elt, 'htmx:afterSwap', responseInfo); + }); + if (responseInfo.pathInfo.anchor) { + location.hash = responseInfo.pathInfo.anchor; + } - if (selectionInfo.elt && - !bodyContains(selectionInfo.elt) && - selectionInfo.elt.id) { - var newActiveElt = document.getElementById(selectionInfo.elt.id); - if (newActiveElt) { - if (selectionInfo.start && newActiveElt.setSelectionRange) { - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); - } - newActiveElt.focus(); - } + if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { + var finalElt = elt; + if (!bodyContains(elt)) { + finalElt = getDocument().body; } + handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); + } - target.classList.remove(htmx.config.swappingClass); + var doSettle = function () { + forEach(settleInfo.tasks, function (task) { + task.call(); + }); forEach(settleInfo.elts, function (elt) { if (elt.classList) { - elt.classList.add(htmx.config.settlingClass); + elt.classList.remove(htmx.config.settlingClass); } - triggerEvent(elt, 'htmx:afterSwap', responseInfo); + triggerEvent(elt, 'htmx:afterSettle', responseInfo); }); - if (responseInfo.pathInfo.anchor) { - location.hash = responseInfo.pathInfo.anchor; + // push URL and save new page + if (shouldSaveHistory) { + var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; + pushUrlIntoHistory(pathToPush); + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: pathToPush}); } - if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; + if(settleInfo.title) { + var titleElt = find("title"); + if(titleElt) { + titleElt.innerHTML = settleInfo.title; + } else { + window.document.title = settleInfo.title; } - handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); } - var doSettle = function(){ - forEach(settleInfo.tasks, function (task) { - task.call(); - }); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.remove(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSettle', responseInfo); - }); - // push URL and save new page - if (shouldSaveHistory) { - var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; - pushUrlIntoHistory(pathToPush); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path:pathToPush}); - } - updateScrollState(settleInfo.elts, swapSpec); + updateScrollState(settleInfo.elts, swapSpec); - if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); + if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { + var finalElt = elt; + if (!bodyContains(elt)) { + finalElt = getDocument().body; } + handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'htmx:swapError', responseInfo); - throw e; } - }; - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); + if (swapSpec.settleDelay > 0) { + setTimeout(doSettle, swapSpec.settleDelay) + } else { + doSettle(); + } + } catch (e) { + triggerErrorEvent(elt, 'htmx:swapError', responseInfo); + throw e; } + }; + + if (swapSpec.swapDelay > 0) { + setTimeout(doSwap, swapSpec.swapDelay) + } else { + doSwap(); } - } else { + } + if (isError) { triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.path}, responseInfo)); } } @@ -2462,9 +2967,17 @@ return (function () { //==================================================================== // Extensions API //==================================================================== + + /** @type {Object<string, import("./htmx").HtmxExtension>} */ var extensions = {}; + + /** + * extensionBase defines the default functions for all extensions. + * @returns {import("./htmx").HtmxExtension} + */ function extensionBase() { return { + init: function(api) {return null;}, onEvent : function(name, evt) {return true;}, transformResponse : function(text, xhr, elt) {return text;}, isInlineSwap : function(swapStyle) {return false;}, @@ -2473,15 +2986,37 @@ return (function () { } } + /** + * defineExtension initializes the extension and adds it to the htmx registry + * + * @param {string} name + * @param {import("./htmx").HtmxExtension} extension + */ function defineExtension(name, extension) { + if(extension.init) { + extension.init(internalAPI) + } extensions[name] = mergeObjects(extensionBase(), extension); } + /** + * removeExtension removes an extension from the htmx registry + * + * @param {string} name + */ function removeExtension(name) { delete extensions[name]; } - function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + /** + * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element + * + * @param {HTMLElement} elt + * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn + * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore + */ + function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + if (elt == undefined) { return extensionsToReturn; } @@ -2536,6 +3071,7 @@ return (function () { function getMetaConfig() { var element = getDocument().querySelector('meta[name="htmx-config"]'); if (element) { + // @ts-ignore return parseJSON(element.content); } else { return null; @@ -2555,9 +3091,25 @@ return (function () { insertIndicatorStyles(); var body = getDocument().body; processNode(body); + var restoredElts = getDocument().querySelectorAll( + "[hx-trigger='restored'],[data-hx-trigger='restored']" + ); + body.addEventListener("htmx:abort", function (evt) { + var target = evt.target; + var internalData = getInternalData(target); + if (internalData && internalData.xhr) { + internalData.xhr.abort(); + } + }); window.onpopstate = function (event) { if (event.state && event.state.htmx) { restoreHistory(); + forEach(restoredElts, function(elt){ + triggerEvent(elt, 'htmx:restored', { + 'document': getDocument(), + 'triggerEvent': triggerEvent + }); + }); } }; setTimeout(function () { diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.min.js b/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.min.js index 57f33b2..998414c 100644 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.min.js +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.min.js @@ -1 +1 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var k={onLoad:t,process:rt,on:I,off:M,trigger:lt,ajax:$t,find:w,findAll:S,closest:L,values:function(e,t){var r=Lt(e,t||"post");return r.values},remove:E,addClass:q,removeClass:R,toggleClass:C,takeClass:O,defineExtension:Qt,removeExtension:er,logAll:b,logger:null,useTemplateFragments:false,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,attributesToSettle:["class","style","width","height"],withCredentials:false,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]"},parseInterval:f,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])}};var r=["get","post","put","delete","patch"];var n=r.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function f(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function l(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function D(e,t){return l(e,t)||l(e,"data-"+t)}function c(e){return e.parentElement}function F(){return document}function h(e,t){if(t(e)){return e}else if(c(e)){return h(c(e),t)}else{return null}}function X(e,t){var r=null;h(e,function(e){return r=D(e,t)});return r}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function i(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 o(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=F().createDocumentFragment()}return i}function u(e){if(k.config.useTemplateFragments){var t=o("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=i(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return o("<table>"+e+"</table>",1);case"col":return o("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return o("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return o("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return o("<div>"+e+"</div>",1);default:return o(e,0)}}}function P(e){if(e){e()}}function a(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function v(e){return a(e,"Function")}function g(e){return a(e,"Object")}function U(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function p(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function j(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function m(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function z(e){return F().body.contains(e)}function y(e){return e.trim().split(/\s+/)}function V(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function x(e){try{return JSON.parse(e)}catch(e){ut(e);return null}}function e(e){return Ut(F().body,function(){return eval(e)})}function t(t){var e=k.on("htmx:load",function(e){t(e.detail.elt)});return e}function b(){k.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function w(e,t){if(t){return e.querySelector(t)}else{return w(F(),e)}}function S(e,t){if(t){return e.querySelectorAll(t)}else{return S(F(),e)}}function E(e,t){e=H(e);if(t){setTimeout(function(){E(e)},t)}else{e.parentElement.removeChild(e)}}function q(e,t,r){e=H(e);if(r){setTimeout(function(){q(e,t)},r)}else{e.classList.add(t)}}function R(e,t,r){e=H(e);if(r){setTimeout(function(){R(e,t)},r)}else{e.classList.remove(t)}}function C(e,t){e=H(e);e.classList.toggle(t)}function O(e,t){e=H(e);j(e.parentElement.children,function(e){R(e,t)});q(e,t)}function L(e,t){e=H(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&c(e))}}function A(e,t){if(t.indexOf("closest ")===0){return[L(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[w(e,t.substr(5))]}else{return F().querySelectorAll(t)}}function T(e,t){return A(e,t)[0]}function H(e){if(a(e,"String")){return w(e)}else{return e}}function N(e,t,r){if(v(t)){return{target:F().body,event:e,listener:t}}else{return{target:H(e),event:t,listener:r}}}function I(t,r,n){rr(function(){var e=N(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=v(r);return e?r:n}function M(t,r,n){rr(function(){var e=N(t,r,n);e.target.removeEventListener(e.event,e.listener)});return v(r)?r:n}function _(e){var t=h(e,function(e){return D(e,"hx-target")!==null});if(t){var r=D(t,"hx-target");if(r==="this"){return t}else{return T(e,r)}}else{var n=U(e);if(n.boosted){return F().body}else{return e}}}function B(e){var t=k.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function W(t,r){j(t.attributes,function(e){if(!r.hasAttribute(e.name)&&B(e.name)){t.removeAttribute(e.name)}});j(r.attributes,function(e){if(B(e.name)){t.setAttribute(e.name,e.value)}})}function $(e,t){var r=tr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){ut(e)}}return e==="outerHTML"}function J(e,t,r){var n="#"+t.id;var i="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){i=e.substr(0,e.indexOf(":"));n=e.substr(e.indexOf(":")+1,e.length)}else{i=e}var o=F().querySelector(n);if(o){var a;a=F().createDocumentFragment();a.appendChild(t);if(!$(i,o)){a=t}le(i,o,o,a,r)}else{t.parentNode.removeChild(t);ot(F().body,"htmx:oobErrorNoTarget",{content:t})}return e}function Z(e,r){j(S(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=D(e,"hx-swap-oob");if(t!=null){J(t,e,r)}})}function G(e){j(S(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=D(e,"id");var r=F().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function K(n,e,i){j(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();W(e,t);i.tasks.push(function(){W(e,r)})}}})}function Y(e){return function(){rt(e);Ye(e);Q(e);lt(e,"htmx:load")}}function Q(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ee(e,t,r,n){K(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Y(i))}}}function te(t){var e=U(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}if(e.listenerInfos){j(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){j(t.children,function(e){te(e)})}}function re(e,t,r){if(e.tagName==="BODY"){return se(e,t,r)}else{var n=e.previousSibling;ee(c(e),e,t,r);if(n==null){var i=c(e).firstChild}else{var i=n.nextSibling}U(e).replacedWith=i;r.elts=[];while(i&&i!==e){if(i.nodeType===Node.ELEMENT_NODE){r.elts.push(i)}i=i.nextElementSibling}te(e);c(e).removeChild(e)}}function ne(e,t,r){return ee(e,e.firstChild,t,r)}function ie(e,t,r){return ee(c(e),e,t,r)}function oe(e,t,r){return ee(e,null,t,r)}function ae(e,t,r){return ee(c(e),e.nextSibling,t,r)}function se(e,t,r){var n=e.firstChild;ee(e,n,t,r);if(n){while(n.nextSibling){te(n.nextSibling);e.removeChild(n.nextSibling)}te(n);e.removeChild(n)}}function ue(e,t){var r=X(e,"hx-select");if(r){var n=F().createDocumentFragment();j(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function le(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":re(r,n,i);return;case"afterbegin":ne(r,n,i);return;case"beforebegin":ie(r,n,i);return;case"beforeend":oe(r,n,i);return;case"afterend":ae(r,n,i);return;default:var o=tr(t);for(var a=0;a<o.length;a++){var s=o[a];try{var u=s.handleSwap(e,r,n,i);if(u){if(typeof u.length!=="undefined"){for(var l=0;l<u.length;l++){var f=u[l];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Y(f))}}}return}}catch(e){ut(e)}}se(r,n,i)}}var fe=/<title>([\s\S]+?)<\/title>/im;function ce(e){if(e.indexOf("<title>")>-1&&(e.indexOf("<svg>")==-1||e.indexOf("<title>")<e.indexOf("<svg>"))){var t=fe.exec(e);if(t){return t[1]}}}function he(e,t,r,n,i){var o=ce(n);if(o){var a=w("title");if(a){a.innerHTML=o}else{window.document.title=o}}var s=u(n);if(s){Z(s,i);s=ue(r,s);G(s);return le(e,r,t,s,i)}}function de(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=x(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!g(a)){a={value:a}}lt(r,o,a)}}}else{lt(r,n,[])}}var ve=/\s/;var ge=/[\s,]/;var pe=/[_$a-zA-Z]/;var me=/[_$a-zA-Z0-9]/;var ye=['"',"'","/"];var xe=/[^\s]/;function be(e){var t=[];var r=0;while(r<e.length){if(pe.exec(e.charAt(r))){var n=r;while(me.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(ye.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function we(e,t,r){return pe.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function Se(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Ut(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){ot(F().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(we(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function Ee(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var qe="input, textarea, select";function Re(e){var t=D(e,"hx-trigger");var r=[];if(t){var n=be(t);do{Ee(n,xe);var i=n.length;var o=Ee(n,/[,\[\s]/);if(o!==""){if(o==="every"){var a={trigger:"every"};Ee(n,xe);a.pollInterval=f(Ee(n,ve));r.push(a)}else if(o.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:o.substr(4)})}else{var s={trigger:o};var u=Se(e,n,"event");if(u){s.eventFilter=u}while(n.length>0&&n[0]!==","){Ee(n,xe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=f(Ee(n,ge))}else if(l==="from"&&n[0]===":"){n.shift();s.from=Ee(n,ge)}else if(l==="target"&&n[0]===":"){n.shift();s.target=Ee(n,ge)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=f(Ee(n,ge))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=Ee(n,ge)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=Ee(n,ge)}else{ot(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===i){ot(e,"htmx:syntax:error",{token:n.shift()})}Ee(n,xe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,qe)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ce(e){U(e).cancelled=true}function Oe(e,t,r,n){var i=U(e);i.timeout=setTimeout(function(){if(z(e)&&i.cancelled!==true){Zt(t,r,e);Oe(e,t,D(e,"hx-"+t),n)}},n)}function Le(e){return location.hostname===e.hostname&&l(e,"href")&&l(e,"href").indexOf("#")!==0}function Ae(t,r,e){if(t.tagName==="A"&&Le(t)||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=l(t,"href");r.pushURL=true}else{var o=l(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=l(t,"action")}e.forEach(function(e){Ie(t,n,i,r,e,true)})}}function Te(e){return e.tagName==="FORM"||d(e,'input[type="submit"], button')&&L(e,"form")!==null||e.tagName==="A"&&e.href&&(e.getAttribute("href")==="#"||e.getAttribute("href").indexOf("#")!==0)}function He(e,t){return U(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function Ne(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){ot(F().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Ie(n,i,o,e,a,s){var u=n;if(a.from){u=w(a.from)}var l=function(e){if(!z(n)){u.removeEventListener(a.trigger,l);return}if(He(n,e)){return}if(s||Te(n)){e.preventDefault()}if(Ne(a,e)){return}var t=U(e);t.triggerSpec=a;if(t.handledFor==null){t.handledFor=[]}var r=U(n);if(t.handledFor.indexOf(n)<0){t.handledFor.push(n);if(a.consume){e.stopPropagation()}if(a.target&&e.target){if(!d(e.target,a.target)){return}}if(a.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(a.changed){if(r.lastValue===n.value){return}else{r.lastValue=n.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(a.throttle){if(!r.throttle){Zt(i,o,n,e);r.throttle=setTimeout(function(){r.throttle=null},a.throttle)}}else if(a.delay){r.delayed=setTimeout(function(){Zt(i,o,n,e)},a.delay)}else{Zt(i,o,n,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:a.trigger,listener:l,on:u});u.addEventListener(a.trigger,l)}var Me=false;var ke=null;function De(){if(!ke){ke=function(){Me=true};window.addEventListener("scroll",ke);setInterval(function(){if(Me){Me=false;j(F().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){Fe(e)})}},200)}}function Fe(e){var t=U(e);if(!t.revealed&&m(e)){t.revealed=true;if(t.initialized){Zt(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Zt(t.verb,t.path,e)},{once:true})}}}function Xe(e,t,r){var n=y(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Pe(e,o[1],0)}if(o[0]==="send"){je(e)}}}function Pe(s,r,n){if(!z(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=k.createWebSocket(r);t.onerror=function(e){ot(s,"htmx:wsError",{error:e,socket:t});Ue(s)};t.onclose=function(e){if([1006,1012,1013].includes(e.code)){var t=ze(n);setTimeout(function(){Pe(s,r,n+1)},t)}};t.onopen=function(e){n=0};U(s).webSocket=t;t.addEventListener("message",function(e){if(Ue(s)){return}var t=e.data;st(s,function(e){t=e.transformResponse(t,null,s)});var r=Ft(s);var n=u(t);var i=p(n.children);for(var o=0;o<i.length;o++){var a=i[o];J(D(a,"hx-swap-oob")||"true",a,r)}mt(r.tasks)})}function Ue(e){if(!z(e)){U(e).webSocket.close();return true}}function je(l){var f=h(l,function(e){return U(e).webSocket!=null});if(f){l.addEventListener(Re(l)[0].trigger,function(e){var t=U(f).webSocket;var r=Nt(l,f);var n=Lt(l,"post");var i=n.errors;var o=n.values;var a=Vt(l);var s=V(o,a);var u=It(s,l);u["HEADERS"]=r;if(i&&i.length>0){lt(l,"htmx:validation:halted",i);return}t.send(JSON.stringify(u));if(Te(l)){e.preventDefault()}})}else{ot(l,"htmx:noWebSocketSourceError")}}function ze(e){var t=k.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}ut('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ve(e,t,r){var n=y(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){_e(e,o[1])}if(o[0]==="swap"){Be(e,o[1])}}}function _e(t,e){var r=k.createEventSource(e);r.onerror=function(e){ot(t,"htmx:sseError",{error:e,source:r});$e(t)};U(t).sseEventSource=r}function Be(o,a){var s=h(o,Je);if(s){var u=U(s).sseEventSource;var l=function(e){if($e(s)){u.removeEventListener(a,l);return}var t=e.data;st(o,function(e){t=e.transformResponse(t,null,o)});var r=kt(o);var n=_(o);var i=Ft(o);he(r.swapStyle,o,n,t,i);mt(i.tasks);lt(o,"htmx:sseMessage",e)};U(o).sseListener=l;u.addEventListener(a,l)}else{ot(o,"htmx:noSSESourceError")}}function We(e,t,r,n){var i=h(e,Je);if(i){var o=U(i).sseEventSource;var a=function(){if(!$e(i)){if(z(e)){Zt(t,r,e)}else{o.removeEventListener(n,a)}}};U(e).sseListener=a;o.addEventListener(n,a)}else{ot(e,"htmx:noSSESourceError")}}function $e(e){if(!z(e)){U(e).sseEventSource.close();return true}}function Je(e){return U(e).sseEventSource!=null}function Ze(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Zt(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function Ge(o,a,e){var t=false;j(r,function(n){if(s(o,"hx-"+n)){var i=D(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){We(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){De();Fe(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=T(e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){lt(o,"intersect");break}}},t);r.observe(o);Ie(o,n,i,a,e)}else if(e.trigger==="load"){Ze(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Oe(o,n,i,e.pollInterval)}else{Ie(o,n,i,a,e)}})}});return t}function Ke(e){if(e.type==="text/javascript"||e.type===""){try{Ut(e,function(){(1,eval)(e.innerText)})}catch(e){ut(e)}}}function Ye(e){if(d(e,"script")){Ke(e)}j(S(e,"script"),function(e){Ke(e)})}function Qe(){return document.querySelector("[hx-boost], [data-hx-boost]")}function et(e){if(e.querySelectorAll){var t=Qe()?", a, form":"";var r=e.querySelectorAll(n+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws]");return r}else{return[]}}function tt(e){if(e.closest&&e.closest(k.config.disableSelector)){return}var t=U(e);if(!t.initialized){t.initialized=true;lt(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=Re(e);var n=Ge(e,t,r);if(!n&&X(e,"hx-boost")==="true"){Ae(e,t,r)}var i=D(e,"hx-sse");if(i){Ve(e,t,i)}var o=D(e,"hx-ws");if(o){Xe(e,t,o)}lt(e,"htmx:afterProcessNode")}}function rt(e){e=H(e);tt(e);j(et(e),function(e){tt(e)})}function nt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function it(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=F().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function ot(e,t,r){lt(e,t,V({error:t},r))}function at(e){return e==="htmx:afterProcessNode"}function st(e,t){j(tr(e),function(e){try{t(e)}catch(e){ut(e)}})}function ut(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function lt(e,t,r){e=H(e);if(r==null){r={}}r["elt"]=e;var n=it(t,r);if(k.logger&&!at(t)){k.logger(e,t,r)}if(r.error){ut(r.error);lt(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=nt(t);if(i&&o!==t){var a=it(o,n.detail);i=i&&e.dispatchEvent(a)}st(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var ft=null;function ct(){var e=F().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||F().body}function ht(e,t,r,n){var i=x(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>k.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ot(F().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function dt(e){var t=x(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function vt(e){var t=k.config.requestClass;var r=e.cloneNode(true);j(S(r,"."+t),function(e){R(e,t)});return r.innerHTML}function gt(){var e=ct();var t=ft||location.pathname+location.search;lt(F().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(k.config.historyEnabled)history.replaceState({htmx:true},F().title,window.location.href);ht(t,vt(e),F().title,window.scrollY)}function pt(e){if(k.config.historyEnabled)history.pushState({htmx:true},"",e);ft=e}function mt(e){j(e,function(e){e.call()})}function yt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};lt(F().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){lt(F().body,"htmx:historyCacheMissLoad",i);var e=u(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=ct();var r=Ft(t);se(t,e,r);mt(r.tasks);ft=n;lt(F().body,"htmx:historyRestore",{path:n})}else{ot(F().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function xt(e){gt();e=e||location.pathname+location.search;var t=dt(e);if(t){var r=u(t.content);var n=ct();var i=Ft(n);se(n,r,i);mt(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);ft=e;lt(F().body,"htmx:historyRestore",{path:e})}else{if(k.config.refreshOnHistoryMiss){window.location.reload(true)}else{yt(e)}}}function bt(e){var t=X(e,"hx-push-url");return t&&t!=="false"||U(e).boosted&&U(e).pushURL}function wt(e){var t=X(e,"hx-push-url");return t==="true"||t==="false"?null:t}function St(e){var t=X(e,"hx-indicator");if(t){var r=A(e,t)}else{r=[e]}j(r,function(e){e.classList["add"].call(e.classList,k.config.requestClass)});return r}function Et(e){j(e,function(e){e.classList["remove"].call(e.classList,k.config.requestClass)})}function qt(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Rt(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 Ct(t,r,n,e,i){if(e==null||qt(t,e)){return}else{t.push(e)}if(Rt(e)){var o=l(e,"name");var a=e.value;if(e.multiple){a=p(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=p(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){Ot(e,n)}}if(d(e,"form")){var u=e.elements;j(u,function(e){Ct(t,r,n,e,i)})}}function Ot(e,t){if(e.willValidate){lt(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});lt(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Lt(e,t){var r=[];var n={};var i={};var o=[];var a=d(e,"form")&&e.noValidate!==true;if(t!=="get"){Ct(r,i,o,L(e,"form"),a)}Ct(r,n,o,e,a);var s=X(e,"hx-include");if(s){var u=A(e,s);j(u,function(e){Ct(r,n,o,e,a);if(!d(e,"form")){j(e.querySelectorAll(qe),function(e){Ct(r,n,o,e,a)})}})}n=V(n,i);return{errors:o,values:n}}function At(e,t,r){if(e!==""){e+="&"}e+=encodeURIComponent(t)+"="+encodeURIComponent(r);return e}function Tt(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){j(n,function(e){t=At(t,r,e)})}else{t=At(t,r,n)}}}return t}function Ht(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){j(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Nt(e,t,r){var n={"HX-Request":"true","HX-Trigger":l(e,"id"),"HX-Trigger-Name":l(e,"name"),"HX-Target":D(t,"id"),"HX-Current-URL":F().location.href};Pt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}return n}function It(t,e){var r=X(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){j(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};j(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Mt(e){return l(e,"href")&&l(e,"href").indexOf("#")>=0}function kt(e){var t=X(e,"hx-swap");var r={swapStyle:U(e).boosted?"innerHTML":k.config.defaultSwapStyle,swapDelay:k.config.defaultSwapDelay,settleDelay:k.config.defaultSettleDelay};if(U(e).boosted&&!Mt(e)){r["show"]="top"}if(t){var n=y(t);if(n.length>0){r["swapStyle"]=n[0];for(var i=1;i<n.length;i++){var o=n[i];if(o.indexOf("swap:")===0){r["swapDelay"]=f(o.substr(5))}if(o.indexOf("settle:")===0){r["settleDelay"]=f(o.substr(7))}if(o.indexOf("scroll:")===0){r["scroll"]=o.substr(7)}if(o.indexOf("show:")===0){r["show"]=o.substr(5)}}}}return r}function Dt(t,r,n){var i=null;st(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(X(r,"hx-encoding")==="multipart/form-data"){return Ht(n)}else{return Tt(n)}}}function Ft(e){return{tasks:[],elts:[e]}}function Xt(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){if(t.scroll==="top"&&r){r.scrollTop=0}if(t.scroll==="bottom"&&n){n.scrollTop=n.scrollHeight}}if(t.show){if(t.show==="top"&&r){r.scrollIntoView(true)}if(t.show==="bottom"&&n){n.scrollIntoView(false)}}}function Pt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=D(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Ut(e,function(){return Function("return ("+o+")")()},{})}else{s=x(o)}for(var u in s){if(s.hasOwnProperty(u)){if(n[u]==null){n[u]=s[u]}}}}return Pt(c(e),t,r,n)}function Ut(e,t,r){if(k.config.allowEval){return t()}else{ot(e,"htmx:evalDisallowedError");return r}}function jt(e,t){return Pt(e,"hx-vars",true,t)}function zt(e,t){return Pt(e,"hx-vals",false,t)}function Vt(e){return V(jt(e),zt(e))}function _t(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Bt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ot(F().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Wt(e,t){return e.getAllResponseHeaders().match(t)}function $t(e,t,r){if(r){if(r instanceof Element||a(r,"String")){return Zt(e,t,null,null,{targetOverride:H(r)})}else{return Zt(e,t,H(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:H(r.target)})}}else{return Zt(e,t)}}function Jt(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Zt(e,t,n,r,i){var o=null;var a=null;i=i!=null?i:{};if(typeof Promise!=="undefined"){var s=new Promise(function(e,t){o=e;a=t})}if(n==null){n=F().body}var u=i.handler||Gt;if(!z(n)){return}var l=i.targetOverride||_(n);if(l==null){ot(n,"htmx:targetError",{target:D(n,"hx-target")});return}var f=U(n);if(f.requestInFlight){var c="last";var h=U(r);if(h&&h.triggerSpec&&h.triggerSpec.queue){c=h.triggerSpec.queue}if(f.queuedRequests==null){f.queuedRequests=[]}if(c==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){Zt(e,t,n,r)})}else if(c==="all"){f.queuedRequests.push(function(){Zt(e,t,n,r)})}else if(c==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){Zt(e,t,n,r)})}return}else{f.requestInFlight=true}var d=function(){f.requestInFlight=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var v=X(n,"hx-prompt");if(v){var g=prompt(v);if(g===null||!lt(n,"htmx:prompt",{prompt:g,target:l})){P(o);d();return s}}var p=X(n,"hx-confirm");if(p){if(!confirm(p)){P(o);d();return s}}var m=new XMLHttpRequest;var y=Nt(n,l,g);if(i.headers){y=V(y,i.values)}var x=Lt(n,e);var b=x.errors;var w=x.values;if(i.values){w=V(w,i.values)}var S=Vt(n);var E=V(w,S);var q=It(E,n);if(e!=="get"&&X(n,"hx-encoding")==null){y["Content-Type"]="application/x-www-form-urlencoded; charset=UTF-8"}if(t==null||t===""){t=F().location.href}var R={parameters:q,unfilteredParameters:E,headers:y,target:l,verb:e,errors:b,path:t,triggeringEvent:r};if(!lt(n,"htmx:configRequest",R)){P(o);d();return s}t=R.path;e=R.verb;y=R.headers;q=R.parameters;b=R.errors;if(b&&b.length>0){lt(n,"htmx:validation:halted",R);P(o);d();return s}var C=t.split("#");var O=C[0];var L=C[1];if(e==="get"){var A=O;var T=Object.keys(q).length!==0;if(T){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=Tt(q);if(L){A+="#"+L}}m.open("GET",A,true)}else{m.open(e.toUpperCase(),t,true)}m.overrideMimeType("text/html");m.withCredentials=k.config.withCredentials;for(var H in y){if(y.hasOwnProperty(H)){var N=y[H];_t(m,H,N)}}var I={xhr:m,target:l,requestConfig:R,pathInfo:{path:t,finalPath:A,anchor:L}};m.onload=function(){try{var e=Jt(n);u(n,I);Et(M);lt(n,"htmx:afterRequest",I);lt(n,"htmx:afterOnLoad",I);if(!z(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(z(r)){t=r}}if(t){lt(t,"htmx:afterRequest",I);lt(t,"htmx:afterOnLoad",I)}}P(o);d()}catch(e){ot(n,"htmx:onLoadError",V({error:e},I));throw e}};m.onerror=function(){Et(M);ot(n,"htmx:afterRequest",I);ot(n,"htmx:sendError",I);P(a);d()};m.onabort=function(){Et(M);ot(n,"htmx:afterRequest",I);ot(n,"htmx:sendAbort",I);P(a);d()};if(!lt(n,"htmx:beforeRequest",I)){P(o);d();return s}var M=St(n);j(["loadstart","loadend","progress","abort"],function(t){j([m,m.upload],function(e){e.addEventListener(t,function(e){lt(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});lt(n,"htmx:beforeSend",I);m.send(e==="get"?null:Dt(m,n,q));return s}function Gt(a,s){var u=s.xhr;var l=s.target;if(!lt(a,"htmx:beforeOnLoad",s))return;if(Wt(u,/HX-Trigger:/i)){de(u,"HX-Trigger",a)}if(Wt(u,/HX-Push:/i)){var f=u.getResponseHeader("HX-Push")}if(Wt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Wt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}var c=bt(a)||f;if(u.status>=200&&u.status<400){if(u.status===286){Ce(a)}if(u.status!==204){if(!lt(l,"htmx:beforeSwap",s))return;var h=u.response;st(a,function(e){h=e.transformResponse(h,u,a)});if(c){gt()}var d=kt(a);l.classList.add(k.config.swappingClass);var e=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r=Ft(l);he(d.swapStyle,l,a,h,r);if(t.elt&&!z(t.elt)&&t.elt.id){var n=document.getElementById(t.elt.id);if(n){if(t.start&&n.setSelectionRange){n.setSelectionRange(t.start,t.end)}n.focus()}}l.classList.remove(k.config.swappingClass);j(r.elts,function(e){if(e.classList){e.classList.add(k.config.settlingClass)}lt(e,"htmx:afterSwap",s)});if(s.pathInfo.anchor){location.hash=s.pathInfo.anchor}if(Wt(u,/HX-Trigger-After-Swap:/i)){var i=a;if(!z(a)){i=F().body}de(u,"HX-Trigger-After-Swap",i)}var o=function(){j(r.tasks,function(e){e.call()});j(r.elts,function(e){if(e.classList){e.classList.remove(k.config.settlingClass)}lt(e,"htmx:afterSettle",s)});if(c){var e=f||wt(a)||Bt(u)||s.pathInfo.finalPath||s.pathInfo.path;pt(e);lt(F().body,"htmx:pushedIntoHistory",{path:e})}Xt(r.elts,d);if(Wt(u,/HX-Trigger-After-Settle:/i)){var t=a;if(!z(a)){t=F().body}de(u,"HX-Trigger-After-Settle",t)}};if(d.settleDelay>0){setTimeout(o,d.settleDelay)}else{o()}}catch(e){ot(a,"htmx:swapError",s);throw e}};if(d.swapDelay>0){setTimeout(e,d.swapDelay)}else{e()}}}else{ot(a,"htmx:responseError",V({error:"Response Status Error Code "+u.status+" from "+s.pathInfo.path},s))}}var Kt={};function Yt(){return{onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Qt(e,t){Kt[e]=V(Yt(),t)}function er(e){delete Kt[e]}function tr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=D(e,"hx-ext");if(t){j(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Kt[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return tr(c(e),r,n)}function rr(e){if(F().readyState!=="loading"){e()}else{F().addEventListener("DOMContentLoaded",e)}}function nr(){if(k.config.includeIndicatorStyles!==false){F().head.insertAdjacentHTML("beforeend","<style> ."+k.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+k.config.requestClass+" ."+k.config.indicatorClass+"{opacity:1} ."+k.config.requestClass+"."+k.config.indicatorClass+"{opacity:1} </style>")}}function ir(){var e=F().querySelector('meta[name="htmx-config"]');if(e){return x(e.content)}else{return null}}function or(){var e=ir();if(e){k.config=V(k.config,e)}}rr(function(){or();nr();var e=F().body;rt(e);window.onpopstate=function(e){if(e.state&&e.state.htmx){xt()}};setTimeout(function(){lt(e,"htmx:load",{})},0)});return k}()}); \ No newline at end of file +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(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 l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=k(e);e.classList.toggle(t)}function T(e,t){e=k(e);W(e.parentElement.children,function(e){q(e,t)});L(e,t)}function H(e,t){e=k(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function N(e,t){if(t.indexOf("closest ")===0){return[H(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[C(e,t.substr(5))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return z().querySelectorAll(t)}}function ee(e,t){if(t){return N(e,t)[0]}else{return N(z().body,e)[0]}}function k(e){if(p(e,"String")){return C(e)}else{return e}}function I(e,t,r){if(m(t)){return{target:z().body,event:e,listener:t}}else{return{target:k(e),event:t,listener:r}}}function M(t,r,n){lr(function(){var e=I(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function D(t,r,n){lr(function(){var e=I(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var te=z().createElement("output");function F(e,t){var r=G(e,t);if(r){if(r==="this"){return[re(e,t)]}else{var n=N(e,r);if(n.length===0){pt('The selector "'+r+'" on '+t+" returned no matches!");return[te]}else{return n}}}}function re(e,t){return h(e,function(e){return V(e,t)!=null})}function ne(e){var t=G(e,"hx-target");if(t){if(t==="this"){return re(e,"hx-target")}else{return ee(e,t)}}else{var r=_(e);if(r.boosted){return z().body}else{return e}}}function P(e){var t=U.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function X(t,r){W(t.attributes,function(e){if(!r.hasAttribute(e.name)&&P(e.name)){t.removeAttribute(e.name)}});W(r.attributes,function(e){if(P(e.name)){t.setAttribute(e.name,e.value)}})}function j(e,t){var r=sr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){pt(e)}}return e==="outerHTML"}function B(e,i,o){var t="#"+i.id;var a="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){a=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{a=e}var r=z().querySelectorAll(t);if(r){W(r,function(e){var t;var r=i.cloneNode(true);t=z().createDocumentFragment();t.appendChild(r);if(!j(a,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ye(a,e,e,t,o)}W(o.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(z().body,"htmx:oobErrorNoTarget",{content:i})}return e}function ie(e,r){W(R(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=V(e,"hx-swap-oob");if(t!=null){B(t,e,r)}})}function oe(e){W(R(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=V(e,"id");var r=z().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function ae(n,e,i){W(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();X(e,t);i.tasks.push(function(){X(e,r)})}}})}function se(e){return function(){q(e,U.config.addedClass);ct(e);at(e);le(e);$(e,"htmx:load")}}function le(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ue(e,t,r,n){ae(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(se(i))}}}function fe(t){var e=_(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){W(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){W(t.children,function(e){fe(e)})}}function ce(e,t,r){if(e.tagName==="BODY"){return me(e,t,r)}else{var n;var i=e.previousSibling;ue(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}_(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}fe(e);u(e).removeChild(e)}}function he(e,t,r){return ue(e,e.firstChild,t,r)}function de(e,t,r){return ue(u(e),e,t,r)}function ve(e,t,r){return ue(e,null,t,r)}function ge(e,t,r){return ue(u(e),e.nextSibling,t,r)}function pe(e,t,r){fe(e);return u(e).removeChild(e)}function me(e,t,r){var n=e.firstChild;ue(e,n,t,r);if(n){while(n.nextSibling){fe(n.nextSibling);e.removeChild(n.nextSibling)}fe(n);e.removeChild(n)}}function xe(e,t){var r=G(e,"hx-select");if(r){var n=z().createDocumentFragment();W(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function ye(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":ce(r,n,i);return;case"afterbegin":he(r,n,i);return;case"beforebegin":de(r,n,i);return;case"beforeend":ve(r,n,i);return;case"afterend":ge(r,n,i);return;case"delete":pe(r,n,i);return;default:var o=sr(t);for(var a=0;a<o.length;a++){var f=o[a];try{var s=f.handleSwap(e,r,n,i);if(s){if(typeof s.length!=="undefined"){for(var l=0;l<s.length;l++){var u=s[l];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){i.tasks.push(se(u))}}}return}}catch(e){pt(e)}}if(e==="innerHTML"){me(r,n,i)}else{ye(U.config.defaultSwapStyle,t,r,n,i)}}}function be(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function we(e,t,r,n,i){i.title=be(n);var o=g(n);if(o){ie(o,i);o=xe(r,o);oe(o);return ye(e,r,t,o,i)}}function Se(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!x(a)){a={value:a}}$(r,o,a)}}}else{$(r,n,[])}}var Ee=/\s/;var Ce=/[\s,]/;var Re=/[_$a-zA-Z]/;var Oe=/[_$a-zA-Z0-9]/;var Le=['"',"'","/"];var qe=/[^\s]/;function Ae(e){var t=[];var r=0;while(r<e.length){if(Re.exec(e.charAt(r))){var n=r;while(Oe.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Le.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function Te(e,t,r){return Re.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function He(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Jt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(z().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(Te(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var Ne="input, textarea, select";function ke(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=Ae(t);do{c(n,qe);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var o={trigger:"every"};c(n,qe);o.pollInterval=v(c(n,/[,\[\s]/));c(n,qe);var a=He(e,n,"event");if(a){o.eventFilter=a}r.push(o)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var a=He(e,n,"event");if(a){s.eventFilter=a}while(n.length>0&&n[0]!==","){c(n,qe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Ce))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Ce);if(u==="closest"||u==="find"){n.shift();u+=" "+c(n,Ce)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Ce)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Ce))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Ce)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Ce)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,qe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,Ne)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ie(e){_(e).cancelled=true}function Me(e,t,r,n){var i=_(e);i.timeout=setTimeout(function(){if(Y(e)&&i.cancelled!==true){if(!je(n,dt("hx:poll:trigger",{triggerSpec:n,target:e}))){Z(t,r,e)}Me(e,t,V(e,"hx-"+t),n)}},n.pollInterval)}function De(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&De(t)&&t.target===""||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href");r.pushURL=true}else{var o=f(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=f(t,"action")}e.forEach(function(e){Be(t,n,i,r,e,true)})}}function Pe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&H(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Xe(e,t){return _(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function je(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(z().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Be(o,a,s,e,l,u){var t;if(l.from){t=N(o,l.from)}else{t=[o]}W(t,function(n){var i=function(e){if(!Y(o)){n.removeEventListener(l.trigger,i);return}if(Xe(o,e)){return}if(u||Pe(e,o)){e.preventDefault()}if(je(l,e)){return}var t=_(e);t.triggerSpec=l;if(t.handledFor==null){t.handledFor=[]}var r=_(o);if(t.handledFor.indexOf(o)<0){t.handledFor.push(o);if(l.consume){e.stopPropagation()}if(l.target&&e.target){if(!d(e.target,l.target)){return}}if(l.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(l.changed){if(r.lastValue===o.value){return}else{r.lastValue=o.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(l.throttle){if(!r.throttle){Z(a,s,o,e);r.throttle=setTimeout(function(){r.throttle=null},l.throttle)}}else if(l.delay){r.delayed=setTimeout(function(){Z(a,s,o,e)},l.delay)}else{Z(a,s,o,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:l.trigger,listener:i,on:n});n.addEventListener(l.trigger,i)})}var Ue=false;var Ve=null;function ze(){if(!Ve){Ve=function(){Ue=true};window.addEventListener("scroll",Ve);setInterval(function(){if(Ue){Ue=false;W(z().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){_e(e)})}},200)}}function _e(e){if(!s(e,"data-hx-revealed")&&b(e)){e.setAttribute("data-hx-revealed","true");var t=_(e);if(t.initialized){Z(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Z(t.verb,t.path,e)},{once:true})}}}function We(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Je(e,o[1],0)}if(o[0]==="send"){Ze(e)}}}function Je(s,r,n){if(!Y(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=U.createWebSocket(r);t.onerror=function(e){J(s,"htmx:wsError",{error:e,socket:t});$e(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=Ge(n);setTimeout(function(){Je(s,r,n+1)},t)}};t.onopen=function(e){n=0};_(s).webSocket=t;t.addEventListener("message",function(e){if($e(s)){return}var t=e.data;gt(s,function(e){t=e.transformResponse(t,null,s)});var r=zt(s);var n=g(t);var i=y(n.children);for(var o=0;o<i.length;o++){var a=i[o];B(V(a,"hx-swap-oob")||"true",a,r)}Ct(r.tasks)})}function $e(e){if(!Y(e)){_(e).webSocket.close();return true}}function Ze(u){var f=h(u,function(e){return _(e).webSocket!=null});if(f){u.addEventListener(ke(u)[0].trigger,function(e){var t=_(f).webSocket;var r=Xt(u,f);var n=Mt(u,"post");var i=n.errors;var o=n.values;var a=Gt(u);var s=Q(o,a);var l=jt(s,u);l["HEADERS"]=r;if(i&&i.length>0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Pe(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ge(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}pt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ke(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Ye(e,o[1])}if(o[0]==="swap"){Qe(e,o[1])}}}function Ye(t,e){var r=U.createEventSource(e);r.onerror=function(e){J(t,"htmx:sseError",{error:e,source:r});tt(t)};_(t).sseEventSource=r}function Qe(o,a){var s=h(o,rt);if(s){var l=_(s).sseEventSource;var u=function(e){if(tt(s)){l.removeEventListener(a,u);return}var t=e.data;gt(o,function(e){t=e.transformResponse(t,null,o)});var r=Ut(o);var n=ne(o);var i=zt(o);we(r.swapStyle,o,n,t,i);Ct(i.tasks);$(o,"htmx:sseMessage",e)};_(o).sseListener=u;l.addEventListener(a,u)}else{J(o,"htmx:noSSESourceError")}}function et(e,t,r,n){var i=h(e,rt);if(i){var o=_(i).sseEventSource;var a=function(){if(!tt(i)){if(Y(e)){Z(t,r,e)}else{o.removeEventListener(n,a)}}};_(e).sseListener=a;o.addEventListener(n,a)}else{J(e,"htmx:noSSESourceError")}}function tt(e){if(!Y(e)){_(e).sseEventSource.close();return true}}function rt(e){return _(e).sseEventSource!=null}function nt(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Z(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function it(o,a,e){var t=false;W(n,function(n){if(s(o,"hx-"+n)){var i=V(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){et(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){ze();_e(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=ee(o,e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){$(o,"intersect");break}}},t);r.observe(o);Be(o,n,i,a,e)}else if(e.trigger==="load"){nt(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Me(o,n,i,e)}else{Be(o,n,i,a,e)}})}});return t}function ot(e){if(e.type==="text/javascript"||e.type==="module"||e.type===""){var t=z().createElement("script");W(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(U.config.inlineScriptNonce){t.nonce=U.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){pt(e)}finally{r.removeChild(e)}}}function at(e){if(d(e,"script")){ot(e)}W(R(e,"script"),function(e){ot(e)})}function st(){return document.querySelector("[hx-boost], [data-hx-boost]")}function lt(e){if(e.querySelectorAll){var t=st()?", a, form":"";var r=e.querySelectorAll(i+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [hx-data-ext]");return r}else{return[]}}function ut(r){var e=function(e){if(d(e.target,"button, input[type='submit']")){var t=_(r);t.lastButtonClicked=e.target}};r.addEventListener("click",e);r.addEventListener("focusin",e);r.addEventListener("focusout",function(e){var t=_(r);t.lastButtonClicked=null})}function ft(e){if(e.closest&&e.closest(U.config.disableSelector)){return}var t=_(e);if(!t.initialized){t.initialized=true;$(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=ke(e);var n=it(e,t,r);if(!n&&G(e,"hx-boost")==="true"){Fe(e,t,r)}if(e.tagName==="FORM"){ut(e)}var i=V(e,"hx-sse");if(i){Ke(e,t,i)}var o=V(e,"hx-ws");if(o){We(e,t,o)}$(e,"htmx:afterProcessNode")}}function ct(e){e=k(e);ft(e);W(lt(e),function(e){ft(e)})}function ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function dt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=z().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function J(e,t,r){$(e,t,Q({error:t},r))}function vt(e){return e==="htmx:afterProcessNode"}function gt(e,t){W(sr(e),function(e){try{t(e)}catch(e){pt(e)}})}function pt(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function $(e,t,r){e=k(e);if(r==null){r={}}r["elt"]=e;var n=dt(t,r);if(U.logger&&!vt(t)){U.logger(e,t,r)}if(r.error){pt(r.error);$(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=ht(t);if(i&&o!==t){var a=dt(o,n.detail);i=i&&e.dispatchEvent(a)}gt(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var mt=location.pathname+location.search;function xt(){var e=z().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||z().body}function yt(e,t,r,n){var i=S(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>U.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(z().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function bt(e){var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function wt(e){var t=U.config.requestClass;var r=e.cloneNode(true);W(R(r,"."+t),function(e){q(e,t)});return r.innerHTML}function St(){var e=xt();var t=mt||location.pathname+location.search;$(z().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(U.config.historyEnabled)history.replaceState({htmx:true},z().title,window.location.href);yt(t,wt(e),z().title,window.scrollY)}function Et(e){if(U.config.historyEnabled)history.pushState({htmx:true},"",e);mt=e}function Ct(e){W(e,function(e){e.call()})}function Rt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};$(z().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){$(z().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=xt();var r=zt(t);me(t,e,r);Ct(r.tasks);mt=n;$(z().body,"htmx:historyRestore",{path:n})}else{J(z().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Ot(e){St();e=e||location.pathname+location.search;var t=bt(e);if(t){var r=g(t.content);var n=xt();var i=zt(n);me(n,r,i);Ct(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);mt=e;$(z().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Rt(e)}}}function Lt(e){var t=G(e,"hx-push-url");return t&&t!=="false"||_(e).boosted&&_(e).pushURL}function qt(e){var t=G(e,"hx-push-url");return t==="true"||t==="false"?null:t}function At(e){var t=F(e,"hx-indicator");if(t==null){t=[e]}W(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Tt(e){W(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function Ht(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Nt(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 kt(t,r,n,e,i){if(e==null||Ht(t,e)){return}else{t.push(e)}if(Nt(e)){var o=f(e,"name");var a=e.value;if(e.multiple){a=y(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=y(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){It(e,n)}}if(d(e,"form")){var l=e.elements;W(l,function(e){kt(t,r,n,e,i)})}}function It(e,t){if(e.willValidate){$(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});$(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Mt(e,t){var r=[];var n={};var i={};var o=[];var a=_(e);var s=d(e,"form")&&e.noValidate!==true;if(a.lastButtonClicked){s=s&&a.lastButtonClicked.formNoValidate!==true}if(t!=="get"){kt(r,i,o,H(e,"form"),s)}kt(r,n,o,e,s);if(a.lastButtonClicked){var l=f(a.lastButtonClicked,"name");if(l){n[l]=a.lastButtonClicked.value}}var u=F(e,"hx-include");W(u,function(e){kt(r,n,o,e,s);if(!d(e,"form")){W(e.querySelectorAll(Ne),function(e){kt(r,n,o,e,s)})}});n=Q(n,i);return{errors:o,values:n}}function Dt(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function Ft(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=Dt(t,r,e)})}else{t=Dt(t,r,n)}}}return t}function Pt(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){W(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Xt(e,t,r){var n={"HX-Request":"true","HX-Trigger":f(e,"id"),"HX-Trigger-Name":f(e,"name"),"HX-Target":V(t,"id"),"HX-Current-URL":z().location.href};Wt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(_(e).boosted){n["HX-Boosted"]="true"}return n}function jt(t,e){var r=G(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){W(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};W(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Bt(e){return f(e,"href")&&f(e,"href").indexOf("#")>=0}function Ut(e,t){var r=t?t:G(e,"hx-swap");var n={swapStyle:_(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(_(e).boosted&&!Bt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var o=1;o<i.length;o++){var a=i[o];if(a.indexOf("swap:")===0){n["swapDelay"]=v(a.substr(5))}if(a.indexOf("settle:")===0){n["settleDelay"]=v(a.substr(7))}if(a.indexOf("scroll:")===0){var s=a.substr(7);var l=s.split(":");var f=l.pop();var u=l.length>0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(a.indexOf("show:")===0){var c=a.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(a.indexOf("focus-scroll:")===0){var d=a.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function Vt(t,r,n){var i=null;gt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(G(r,"hx-encoding")==="multipart/form-data"||d(r,"form")&&f(r,"enctype")==="multipart/form-data"){return Pt(n)}else{return Ft(n)}}}function zt(e){return{tasks:[],elts:[e]}}function _t(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ee(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var o=t.showTarget;if(t.showTarget==="window"){o="body"}i=ee(r,o)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function Wt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}else if(o.indexOf("js:")===0){o=o.substr(3);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Jt(e,function(){return Function("return ("+o+")")()},{})}else{s=S(o)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Wt(u(e),t,r,n)}function Jt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function $t(e,t){return Wt(e,"hx-vars",true,t)}function Zt(e,t){return Wt(e,"hx-vals",false,t)}function Gt(e){return Q($t(e),Zt(e))}function Kt(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Yt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(z().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Qt(e,t){return e.getAllResponseHeaders().match(t)}function er(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return Z(e,t,null,null,{targetOverride:k(r),returnPromise:true})}else{return Z(e,t,k(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:k(r.target),swapOverride:r.swap,returnPromise:true})}}else{return Z(e,t,null,null,{returnPromise:true})}}function tr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Z(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=z().body}var v=r.handler||rr;if(!Y(n)){return}var g=r.targetOverride||ne(n);if(g==null||g==te){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=_(n);var o=G(n,"hx-sync");var m=null;var x=false;if(o){var y=o.split(":");var b=y[0].trim();if(b==="this"){p=re(n,"hx-sync")}else{p=ee(n,b)}o=(y[1]||"drop").trim();i=_(p);if(o==="drop"&&i.xhr&&i.abortable!==true){return}else if(o==="abort"){if(i.xhr){return}else{x=true}}else if(o==="replace"){$(p,"htmx:abort")}else if(o.indexOf("queue")===0){var w=o.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=_(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){Z(e,t,n,f,r)})}return}}var a=new XMLHttpRequest;i.xhr=a;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=G(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){K(c);s();return d}}var R=G(n,"hx-confirm");if(R){if(!confirm(R)){K(c);s();return d}}var O=Xt(n,g,C);if(r.headers){O=Q(O,r.headers)}var L=Mt(n,e);var q=L.errors;var A=L.values;if(r.values){A=Q(A,r.values)}var T=Gt(n);var H=Q(A,T);var N=jt(H,n);if(e!=="get"&&G(n,"hx-encoding")==null){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=z().location.href}var k=Wt(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:q,withCredentials:r.credentials||k.credentials||U.config.withCredentials,timeout:r.timeout||k.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){K(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;q=l.errors;if(q&&q.length>0){$(n,"htmx:validation:halted",l);K(c);s();return d}var I=t.split("#");var M=I[0];var D=I[1];if(e==="get"){var F=M;var P=Object.keys(N).length!==0;if(P){if(F.indexOf("?")<0){F+="?"}else{F+="&"}F+=Ft(N);if(D){F+="#"+D}}a.open("GET",F,true)}else{a.open(e.toUpperCase(),t,true)}a.overrideMimeType("text/html");a.withCredentials=l.withCredentials;a.timeout=l.timeout;if(k.noHeaders){}else{for(var X in O){if(O.hasOwnProperty(X)){var j=O[X];Kt(a,X,j)}}}var u={xhr:a,target:g,requestConfig:l,etc:r,pathInfo:{path:t,finalPath:F,anchor:D}};a.onload=function(){try{var e=tr(n);v(n,u);Tt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!Y(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(Y(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}K(c);s()}catch(e){J(n,"htmx:onLoadError",Q({error:e},u));throw e}};a.onerror=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);K(h);s()};a.onabort=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);K(h);s()};a.ontimeout=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);K(h);s()};if(!$(n,"htmx:beforeRequest",u)){K(c);s();return d}var B=At(n);W(["loadstart","loadend","progress","abort"],function(t){W([a,a.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);a.send(e==="get"?null:Vt(a,n,N));return d}function rr(s,l){var u=l.xhr;var f=l.target;var r=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(Qt(u,/HX-Trigger:/i)){Se(u,"HX-Trigger",s)}if(Qt(u,/HX-Push:/i)){var c=u.getResponseHeader("HX-Push")}if(Qt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Qt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(Qt(u,/HX-Retarget:/i)){l.target=z().querySelector(u.getResponseHeader("HX-Retarget"))}var h;if(c=="false"){h=false}else{h=Lt(s)||c}var n=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var e=u.status>=400;var t=Q({shouldSwap:n,serverResponse:d,isError:e},l);if(!$(f,"htmx:beforeSwap",t))return;f=t.target;d=t.serverResponse;e=t.isError;l.failed=e;l.successful=!e;if(t.shouldSwap){if(u.status===286){Ie(s)}gt(s,function(e){d=e.transformResponse(d,u,s)});if(h){St()}var i=r.swapOverride;var v=Ut(s,i);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=zt(f);we(v.swapStyle,f,s,d,n);if(t.elt&&!Y(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);W(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(l.pathInfo.anchor){location.hash=l.pathInfo.anchor}if(Qt(u,/HX-Trigger-After-Swap:/i)){var o=s;if(!Y(s)){o=z().body}Se(u,"HX-Trigger-After-Swap",o)}var a=function(){W(n.tasks,function(e){e.call()});W(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h){var e=c||qt(s)||Yt(u)||l.pathInfo.finalPath||l.pathInfo.path;Et(e);$(z().body,"htmx:pushedIntoHistory",{path:e})}if(n.title){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}_t(n.elts,v);if(Qt(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!Y(s)){r=z().body}Se(u,"HX-Trigger-After-Settle",r)}};if(v.settleDelay>0){setTimeout(a,v.settleDelay)}else{a()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(v.swapDelay>0){setTimeout(o,v.swapDelay)}else{o()}}if(e){J(s,"htmx:responseError",Q({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var nr={};function ir(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function or(e,t){if(t.init){t.init(r)}nr[e]=Q(ir(),t)}function ar(e){delete nr[e]}function sr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){W(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=nr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return sr(u(e),r,n)}function lr(e){if(z().readyState!=="loading"){e()}else{z().addEventListener("DOMContentLoaded",e)}}function ur(){if(U.config.includeIndicatorStyles!==false){z().head.insertAdjacentHTML("beforeend","<style> ."+U.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+U.config.requestClass+" ."+U.config.indicatorClass+"{opacity:1} ."+U.config.requestClass+"."+U.config.indicatorClass+"{opacity:1} </style>")}}function fr(){var e=z().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function cr(){var e=fr();if(e){U.config=Q(U.config,e)}}lr(function(){cr();ur();var e=z().body;ct(e);var t=z().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=_(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){Ot();W(t,function(e){$(e,"htmx:restored",{document:z(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file diff --git a/code/starter_video_collector/static/js/htmx.js b/code/starter_video_collector/static/js/htmx.js index e38f6ed..27e57bc 100644 --- a/code/starter_video_collector/static/js/htmx.js +++ b/code/starter_video_collector/static/js/htmx.js @@ -1,7 +1,9 @@ //AMD insanity (function (root, factory) { + //@ts-ignore if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. + //@ts-ignore define([], factory); } else { // Browser globals @@ -12,6 +14,8 @@ return (function () { 'use strict'; // Public API + //** @type {import("./htmx").HtmxApi} */ + // TODO: list all methods in public API var htmx = { onLoad: onLoadHelper, process: processNode, @@ -35,7 +39,6 @@ return (function () { removeExtension : removeExtension, logAll : logAll, logger : null, - useTemplateFragments: false, config : { historyEnabled:true, historyCacheSize:10, @@ -46,13 +49,19 @@ return (function () { includeIndicatorStyles:true, indicatorClass:'htmx-indicator', requestClass:'htmx-request', + addedClass:'htmx-added', settlingClass:'htmx-settling', swappingClass:'htmx-swapping', allowEval:true, + inlineScriptNonce:'', attributesToSettle:["class", "style", "width", "height"], withCredentials:false, + timeout:0, wsReconnectDelay: 'full-jitter', disableSelector: "[hx-disable], [data-hx-disable]", + useTemplateFragments: false, + scrollBehavior: 'smooth', + defaultFocusScroll: false, }, parseInterval:parseInterval, _:internalEval, @@ -61,9 +70,36 @@ return (function () { }, createWebSocket: function(url){ return new WebSocket(url, []); - } + }, + version: "1.7.0" }; + /** @type {import("./htmx").HtmxInternalApi} */ + var internalAPI = { + bodyContains: bodyContains, + filterValues: filterValues, + hasAttribute: hasAttribute, + getAttributeValue: getAttributeValue, + getClosestMatch: getClosestMatch, + getExpressionVars: getExpressionVars, + getHeaders: getHeaders, + getInputValues: getInputValues, + getInternalData: getInternalData, + getSwapSpecification: getSwapSpecification, + getTriggerSpecs: getTriggerSpecs, + getTarget: getTarget, + makeFragment: makeFragment, + mergeObjects: mergeObjects, + makeSettleInfo: makeSettleInfo, + oobSwap: oobSwap, + selectAndSwap: selectAndSwap, + settleImmediately: settleImmediately, + shouldCancel: shouldCancel, + triggerEvent: triggerEvent, + triggerErrorEvent: triggerErrorEvent, + withExtensions: withExtensions, + } + var VERBS = ['get', 'post', 'put', 'delete', 'patch']; var VERB_SELECTOR = VERBS.map(function(verb){ return "[hx-" + verb + "], [data-hx-" + verb + "]" @@ -73,19 +109,24 @@ return (function () { // Utilities //==================================================================== - function parseInterval(str) { - if (str == undefined) { - return undefined - } - if (str.slice(-2) == "ms") { - return parseFloat(str.slice(0,-2)) || undefined - } - if (str.slice(-1) == "s") { - return (parseFloat(str.slice(0,-1)) * 1000) || undefined - } - return parseFloat(str) || undefined + function parseInterval(str) { + if (str == undefined) { + return undefined + } + if (str.slice(-2) == "ms") { + return parseFloat(str.slice(0,-2)) || undefined + } + if (str.slice(-1) == "s") { + return (parseFloat(str.slice(0,-1)) * 1000) || undefined + } + return parseFloat(str) || undefined } + /** + * @param {HTMLElement} elt + * @param {string} name + * @returns {(string | null)} + */ function getRawAttribute(elt, name) { return elt.getAttribute && elt.getAttribute(name); } @@ -96,18 +137,36 @@ return (function () { elt.hasAttribute("data-" + qualifiedName)); } + /** + * + * @param {HTMLElement} elt + * @param {string} qualifiedName + * @returns {(string | null)} + */ function getAttributeValue(elt, qualifiedName) { return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); } + /** + * @param {HTMLElement} elt + * @returns {HTMLElement | null} + */ function parentElt(elt) { return elt.parentElement; } + /** + * @returns {Document} + */ function getDocument() { return document; } + /** + * @param {HTMLElement} elt + * @param {(e:HTMLElement) => boolean} condition + * @returns {HTMLElement | null} + */ function getClosestMatch(elt, condition) { if (condition(elt)) { return elt; @@ -118,22 +177,47 @@ return (function () { } } + function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ + var attributeValue = getAttributeValue(ancestor, attributeName); + var disinherit = getAttributeValue(ancestor, "hx-disinherit"); + if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) { + return "unset"; + } else { + return attributeValue + } + } + + /** + * @param {HTMLElement} elt + * @param {string} attributeName + * @returns {string | null} + */ function getClosestAttributeValue(elt, attributeName) { var closestAttr = null; getClosestMatch(elt, function (e) { - return closestAttr = getAttributeValue(e, attributeName); + return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName); }); - return closestAttr; + if (closestAttr !== "unset") { + return closestAttr; + } } + /** + * @param {HTMLElement} elt + * @param {string} selector + * @returns {boolean} + */ function matches(elt, selector) { + // @ts-ignore: non-standard properties for browser compatability // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || - elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector - || elt.webkitMatchesSelector || elt.oMatchesSelector; + var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; return matchesFunction && matchesFunction.call(elt, selector); } + /** + * @param {string} str + * @returns {string} + */ function getStartTag(str) { var tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i var match = tagMatcher.exec( str ); @@ -144,23 +228,40 @@ return (function () { } } + /** + * + * @param {string} resp + * @param {number} depth + * @returns {Element} + */ function parseHTML(resp, depth) { var parser = new DOMParser(); var responseDoc = parser.parseFromString(resp, "text/html"); + + /** @type {Element} */ var responseNode = responseDoc.body; while (depth > 0) { depth--; + // @ts-ignore responseNode = responseNode.firstChild; } if (responseNode == null) { + // @ts-ignore responseNode = getDocument().createDocumentFragment(); } return responseNode; } + /** + * + * @param {string} resp + * @returns {Element} + */ function makeFragment(resp) { if (htmx.config.useTemplateFragments) { var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0); + // @ts-ignore type mismatch between DocumentFragment and Element. + // TODO: Are these close enough for htmx to use interchangably? return documentFragment.querySelector('template').content; } else { var startTag = getStartTag(resp); @@ -186,24 +287,45 @@ return (function () { } } + /** + * @param {Function} func + */ function maybeCall(func){ if(func) { func(); } } + /** + * @param {any} o + * @param {string} type + * @returns + */ function isType(o, type) { return Object.prototype.toString.call(o) === "[object " + type + "]"; } + /** + * @param {*} o + * @returns {o is Function} + */ function isFunction(o) { return isType(o, "Function"); } + /** + * @param {*} o + * @returns {o is Object} + */ function isRawObject(o) { return isType(o, "Object"); } + /** + * getInternalData retrieves "private" data stored by htmx within an element + * @param {HTMLElement} elt + * @returns {*} + */ function getInternalData(elt) { var dataProp = 'htmx-internal-data'; var data = elt[dataProp]; @@ -213,6 +335,11 @@ return (function () { return data; } + /** + * toArray converts an ArrayLike object into a real array. + * @param {ArrayLike} arr + * @returns {any[]} + */ function toArray(arr) { var returnArr = []; if (arr) { @@ -238,14 +365,25 @@ return (function () { return elemTop < window.innerHeight && elemBottom >= 0; } - function bodyContains(elt) { - return getDocument().body.contains(elt); - } + function bodyContains(elt) { + if (elt.getRootNode() instanceof ShadowRoot) { + return getDocument().body.contains(elt.getRootNode().host); + } else { + return getDocument().body.contains(elt); + } + } function splitOnWhitespace(trigger) { return trigger.trim().split(/\s+/); } + /** + * mergeObjects takes all of the keys from + * obj2 and duplicates them into obj1 + * @param {Object} obj1 + * @param {Object} obj2 + * @returns {Object} + */ function mergeObjects(obj1, obj2) { for (var key in obj2) { if (obj2.hasOwnProperty(key)) { @@ -319,7 +457,7 @@ return (function () { if (delay) { setTimeout(function(){addClassToElement(elt, clazz);}, delay) } else { - elt.classList.add(clazz); + elt.classList && elt.classList.add(clazz); } } @@ -328,7 +466,13 @@ return (function () { if (delay) { setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) } else { - elt.classList.remove(clazz); + if (elt.classList) { + elt.classList.remove(clazz); + // if there are no classes left, remove the class attribute + if (elt.classList.length === 0) { + elt.removeAttribute("class"); + } + } } } @@ -360,17 +504,25 @@ return (function () { } function querySelectorAllExt(elt, selector) { - if (selector.indexOf("closest ") === 0) { + if (selector.indexOf("closest ") === 0) { return [closest(elt, selector.substr(8))]; } else if (selector.indexOf("find ") === 0) { return [find(elt, selector.substr(5))]; + } else if (selector === 'document') { + return [document]; + } else if (selector === 'window') { + return [window]; } else { return getDocument().querySelectorAll(selector); } } function querySelectorExt(eltOrSelector, selector) { - return querySelectorAllExt(eltOrSelector, selector)[0] + if (selector) { + return querySelectorAllExt(eltOrSelector, selector)[0]; + } else { + return querySelectorAllExt(getDocument().body, eltOrSelector)[0]; + } } function resolveTarget(arg2) { @@ -418,13 +570,36 @@ return (function () { //==================================================================== // Node processing //==================================================================== + + var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors + function findAttributeTargets(elt, attrName) { + var attrTarget = getClosestAttributeValue(elt, attrName); + if (attrTarget) { + if (attrTarget === "this") { + return [findThisElement(elt, attrName)]; + } else { + var result = querySelectorAllExt(elt, attrTarget); + if (result.length === 0) { + logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!"); + return [DUMMY_ELT] + } else { + return result; + } + } + } + } + + function findThisElement(elt, attribute){ + return getClosestMatch(elt, function (elt) { + return getAttributeValue(elt, attribute) != null; + }) + } function getTarget(elt) { - var explicitTarget = getClosestMatch(elt, function(e){return getAttributeValue(e,"hx-target") !== null}); - if (explicitTarget) { - var targetStr = getAttributeValue(explicitTarget, "hx-target"); + var targetStr = getClosestAttributeValue(elt, "hx-target"); + if (targetStr) { if (targetStr === "this") { - return explicitTarget; + return findThisElement(elt,'hx-target'); } else { return querySelectorExt(elt, targetStr) } @@ -476,6 +651,13 @@ return (function () { return swapStyle === "outerHTML"; } + /** + * + * @param {string} oobValue + * @param {HTMLElement} oobElement + * @param {*} settleInfo + * @returns + */ function oobSwap(oobValue, oobElement, settleInfo) { var selector = "#" + oobElement.id; var swapStyle = "outerHTML"; @@ -488,18 +670,35 @@ return (function () { swapStyle = oobValue; } - var target = getDocument().querySelector(selector); - if (target) { - var fragment; - fragment = getDocument().createDocumentFragment(); - fragment.appendChild(oobElement); // pulls the child out of the existing fragment - if (!isInlineSwap(swapStyle, target)) { - fragment = oobElement; // if this is not an inline swap, we use the content of the node, not the node itself - } - swap(swapStyle, target, target, fragment, settleInfo); + var targets = getDocument().querySelectorAll(selector); + if (targets) { + forEach( + targets, + function (target) { + var fragment; + var oobElementClone = oobElement.cloneNode(true); + fragment = getDocument().createDocumentFragment(); + fragment.appendChild(oobElementClone); + if (!isInlineSwap(swapStyle, target)) { + fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself + } + + var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment }; + if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return; + + target = beforeSwapDetails.target; // allow re-targeting + if (beforeSwapDetails['shouldSwap']){ + swap(swapStyle, target, target, fragment, settleInfo); + } + forEach(settleInfo.elts, function (elt) { + triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails); + }); + } + ); + oobElement.parentNode.removeChild(oobElement); } else { oobElement.parentNode.removeChild(oobElement); - triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}) + triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}); } return oobValue; } @@ -540,6 +739,7 @@ return (function () { function makeAjaxLoadTask(child) { return function () { + removeClassFromElement(child, htmx.config.addedClass); processNode(child); processScripts(child); processFocus(child) @@ -559,6 +759,7 @@ return (function () { handleAttributes(parentNode, fragment, settleInfo); while(fragment.childNodes.length > 0){ var child = fragment.firstChild; + addClassToElement(child, htmx.config.addedClass); parentNode.insertBefore(child, insertBefore); if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { settleInfo.tasks.push(makeAjaxLoadTask(child)); @@ -574,6 +775,9 @@ return (function () { if (internalData.sseEventSource) { internalData.sseEventSource.close(); } + + triggerEvent(element, "htmx:beforeCleanupElement") + if (internalData.listenerInfos) { forEach(internalData.listenerInfos, function(info) { if (element !== info.on) { @@ -590,12 +794,14 @@ return (function () { if (target.tagName === "BODY") { return swapInnerHTML(target, fragment, settleInfo); } else { + // @type {HTMLElement} + var newElt var eltBeforeNewContent = target.previousSibling; insertNodesBefore(parentElt(target), target, fragment, settleInfo); if (eltBeforeNewContent == null) { - var newElt = parentElt(target).firstChild; + newElt = parentElt(target).firstChild; } else { - var newElt = eltBeforeNewContent.nextSibling; + newElt = eltBeforeNewContent.nextSibling; } getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later settleInfo.elts = [] // clear existing elements @@ -625,6 +831,10 @@ return (function () { function swapAfterEnd(target, fragment, settleInfo) { return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo); } + function swapDelete(target, fragment, settleInfo) { + cleanUpElement(target); + return parentElt(target).removeChild(target); + } function swapInnerHTML(target, fragment, settleInfo) { var firstChild = target.firstChild; @@ -670,6 +880,9 @@ return (function () { case "afterend": swapAfterEnd(target, fragment, settleInfo); return; + case "delete": + swapDelete(target, fragment, settleInfo); + return; default: var extensions = getExtensions(elt); for (var i = 0; i < extensions.length; i++) { @@ -692,32 +905,27 @@ return (function () { logError(e); } } - swapInnerHTML(target, fragment, settleInfo); + if (swapStyle === "innerHTML") { + swapInnerHTML(target, fragment, settleInfo); + } else { + swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo); + } } } - var TITLE_FINDER = /<title>([\s\S]+?)<\/title>/im; function findTitle(content) { - if(content.indexOf('<title>') > -1 && - (content.indexOf('<svg>') == -1 || - content.indexOf('<title>') < content.indexOf('<svg>'))) { - var result = TITLE_FINDER.exec(content); + if (content.indexOf('<title') > -1) { + var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, ''); + var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im); + if (result) { - return result[1]; + return result[2]; } } } function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) { - var title = findTitle(responseText); - if(title) { - var titleElt = find("title"); - if(titleElt) { - titleElt.innerHTML = title; - } else { - window.document.title = title; - } - } + settleInfo.title = findTitle(responseText); var fragment = makeFragment(responseText); if (fragment) { handleOutOfBandSwaps(fragment, settleInfo); @@ -840,6 +1048,11 @@ return (function () { } var INPUT_SELECTOR = 'input, textarea, select'; + + /** + * @param {HTMLElement} elt + * @returns {import("./htmx").HtmxTriggerSpecification[]} + */ function getTriggerSpecs(elt) { var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); var triggerSpecs = []; @@ -853,7 +1066,12 @@ return (function () { if (trigger === "every") { var every = {trigger: 'every'}; consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, WHITESPACE)); + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); + consumeUntil(tokens, NOT_WHITESPACE); + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + every.eventFilter = eventFilter; + } triggerSpecs.push(every); } else if (trigger.indexOf("sse:") === 0) { triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); @@ -877,7 +1095,17 @@ return (function () { triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); } else if (token === "from" && tokens[0] === ":") { tokens.shift(); - triggerSpec.from = consumeUntil(tokens, WHITESPACE_OR_COMMA); + var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); + if (from_arg === "closest" || from_arg === "find") { + tokens.shift(); + from_arg += + " " + + consumeUntil( + tokens, + WHITESPACE_OR_COMMA + ); + } + triggerSpec.from = from_arg; } else if (token === "target" && tokens[0] === ":") { tokens.shift(); triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA); @@ -919,14 +1147,16 @@ return (function () { getInternalData(elt).cancelled = true; } - function processPolling(elt, verb, path, interval) { + function processPolling(elt, verb, path, spec) { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - issueAjaxRequest(verb, path, elt); - processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), interval); + if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { + issueAjaxRequest(verb, path, elt); + } + processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), spec); } - }, interval); + }, spec.pollInterval); } function isLocalLink(elt) { @@ -936,7 +1166,7 @@ return (function () { } function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt)) || elt.tagName === "FORM") { + if ((elt.tagName === "A" && isLocalLink(elt) && elt.target === "") || elt.tagName === "FORM") { nodeData.boosted = true; var verb, path; if (elt.tagName === "A") { @@ -957,11 +1187,26 @@ return (function () { } } - function shouldCancel(elt) { - return elt.tagName === "FORM" || - (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) || - (elt.tagName === "A" && elt.href && (elt.getAttribute('href') === '#' || - elt.getAttribute('href').indexOf("#") !== 0)); + /** + * + * @param {Event} evt + * @param {HTMLElement} elt + * @returns + */ + function shouldCancel(evt, elt) { + if (evt.type === "submit" || evt.type === "click") { + if (elt.tagName === "FORM") { + return true; + } + if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { + return true; + } + if (elt.tagName === "A" && elt.href && + (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) { + return true; + } + } + return false; } function ignoreBoostedAnchorCtrlClick(elt, evt) { @@ -982,86 +1227,90 @@ return (function () { } function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { - var eltToListenOn = elt; + var eltsToListenOn; if (triggerSpec.from) { - eltToListenOn = find(triggerSpec.from); + eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); + } else { + eltsToListenOn = [elt]; } - var eventListener = function (evt) { - if (!bodyContains(elt)) { - eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); - return; - } - if (ignoreBoostedAnchorCtrlClick(elt, evt)) { - return; - } - if(explicitCancel || shouldCancel(elt)){ - evt.preventDefault(); - } - if (maybeFilterEvent(triggerSpec, evt)) { - return; - } - var eventData = getInternalData(evt); - eventData.triggerSpec = triggerSpec; - if (eventData.handledFor == null) { - eventData.handledFor = []; - } - var elementData = getInternalData(elt); - if (eventData.handledFor.indexOf(elt) < 0) { - eventData.handledFor.push(elt); - if (triggerSpec.consume) { - evt.stopPropagation(); - } - if (triggerSpec.target && evt.target) { - if (!matches(evt.target, triggerSpec.target)) { - return; - } - } - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } + forEach(eltsToListenOn, function (eltToListenOn) { + var eventListener = function (evt) { + if (!bodyContains(elt)) { + eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); + return; } - if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { - return; - } else { - elementData.lastValue = elt.value; - } + if (ignoreBoostedAnchorCtrlClick(elt, evt)) { + return; } - if (elementData.delayed) { - clearTimeout(elementData.delayed); + if (explicitCancel || shouldCancel(evt, elt)) { + evt.preventDefault(); } - if (elementData.throttle) { + if (maybeFilterEvent(triggerSpec, evt)) { return; } + var eventData = getInternalData(evt); + eventData.triggerSpec = triggerSpec; + if (eventData.handledFor == null) { + eventData.handledFor = []; + } + var elementData = getInternalData(elt); + if (eventData.handledFor.indexOf(elt) < 0) { + eventData.handledFor.push(elt); + if (triggerSpec.consume) { + evt.stopPropagation(); + } + if (triggerSpec.target && evt.target) { + if (!matches(evt.target, triggerSpec.target)) { + return; + } + } + 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); + } + if (elementData.throttle) { + return; + } - if (triggerSpec.throttle) { - if(!elementData.throttle) { + if (triggerSpec.throttle) { + if (!elementData.throttle) { + issueAjaxRequest(verb, path, elt, evt); + elementData.throttle = setTimeout(function () { + elementData.throttle = null; + }, triggerSpec.throttle); + } + } else if (triggerSpec.delay) { + elementData.delayed = setTimeout(function () { + issueAjaxRequest(verb, path, elt, evt); + }, triggerSpec.delay); + } else { issueAjaxRequest(verb, path, elt, evt); - elementData.throttle = setTimeout(function(){ - elementData.throttle = null; - }, triggerSpec.throttle); } - } else if (triggerSpec.delay) { - elementData.delayed = setTimeout(function(){ - issueAjaxRequest(verb, path, elt, evt); - }, triggerSpec.delay); - } else { - issueAjaxRequest(verb, path, elt, evt); } - } - }; - if (nodeData.listenerInfos == null) { - nodeData.listenerInfos = []; - } - nodeData.listenerInfos.push({ - trigger: triggerSpec.trigger, - listener: eventListener, - on: eltToListenOn + }; + if (nodeData.listenerInfos == null) { + nodeData.listenerInfos = []; + } + nodeData.listenerInfos.push({ + trigger: triggerSpec.trigger, + listener: eventListener, + on: eltToListenOn + }) + eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); }) - eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); } var windowIsScrolling = false // used by initScrollHandler @@ -1084,9 +1333,9 @@ return (function () { } function maybeReveal(elt) { - var nodeData = getInternalData(elt); - if (!nodeData.revealed && isScrolledIntoView(elt)) { - nodeData.revealed = true; + if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { + elt.setAttribute('data-hx-revealed', 'true'); + var nodeData = getInternalData(elt); if (nodeData.initialized) { issueAjaxRequest(nodeData.verb, nodeData.path, elt); } else { @@ -1099,6 +1348,10 @@ return (function () { } } + //==================================================================== + // Web Sockets + //==================================================================== + function processWebSocketInfo(elt, nodeData, info) { var values = splitOnWhitespace(info); for (var i = 0; i < values.length; i++) { @@ -1132,7 +1385,7 @@ return (function () { }; socket.onclose = function (e) { - if ([1006, 1012, 1013].includes(e.code)) { // Abnormal Closure/Service Restart/Try Again Later + if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later var delay = getWebSocketReconnectDelay(retryCount); setTimeout(function() { ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout @@ -1193,7 +1446,7 @@ return (function () { return; } webSocket.send(JSON.stringify(filteredParameters)); - if(shouldCancel(elt)){ + if(shouldCancel(evt, elt)){ evt.preventDefault(); } }); @@ -1205,6 +1458,7 @@ return (function () { function getWebSocketReconnectDelay(retryCount) { var delay = htmx.config.wsReconnectDelay; if (typeof delay === 'function') { + // @ts-ignore return delay(retryCount); } if (delay === 'full-jitter') { @@ -1340,7 +1594,7 @@ return (function () { } else if (triggerSpec.trigger === "intersect") { var observerOptions = {}; if (triggerSpec.root) { - observerOptions.root = querySelectorExt(triggerSpec.root) + observerOptions.root = querySelectorExt(elt, triggerSpec.root) } if (triggerSpec.threshold) { observerOptions.threshold = parseFloat(triggerSpec.threshold); @@ -1360,7 +1614,7 @@ return (function () { loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); } else if (triggerSpec.pollInterval) { nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec.pollInterval); + processPolling(elt, verb, path, triggerSpec); } else { addEventListener(elt, verb, path, nodeData, triggerSpec); } @@ -1371,14 +1625,24 @@ return (function () { } function evalScript(script) { - if (script.type === "text/javascript" || script.type === "") { + if (script.type === "text/javascript" || script.type === "module" || script.type === "") { + var newScript = getDocument().createElement("script"); + forEach(script.attributes, function (attr) { + newScript.setAttribute(attr.name, attr.value); + }); + newScript.textContent = script.textContent; + newScript.async = false; + if (htmx.config.inlineScriptNonce) { + newScript.nonce = htmx.config.inlineScriptNonce; + } + var parent = script.parentElement; + try { - maybeEval(script, function () { - // wtf - https://stackoverflow.com/questions/9107240/1-evalthis-vs-evalthis-in-javascript - (1, eval)(script.innerText); - }); + parent.insertBefore(newScript, script); } catch (e) { logError(e); + } finally { + parent.removeChild(script); } } } @@ -1392,21 +1656,41 @@ return (function () { }); } - function isBoosted() { + function hasChanceOfBeingBoosted() { return document.querySelector("[hx-boost], [data-hx-boost]"); } function findElementsToProcess(elt) { if (elt.querySelectorAll) { - var boostedElts = isBoosted() ? ", a, form" : ""; + var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws]"); + " [data-hx-ws], [hx-ext], [hx-data-ext]"); return results; } else { return []; } } + function initButtonTracking(form){ + var maybeSetLastButtonClicked = function(evt){ + if (matches(evt.target, "button, input[type='submit']")) { + var internalData = getInternalData(form); + internalData.lastButtonClicked = evt.target; + } + }; + + // need to handle both click and focus in: + // focusin - in case someone tabs in to a button and hits the space bar + // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + + form.addEventListener('click', maybeSetLastButtonClicked) + form.addEventListener('focusin', maybeSetLastButtonClicked) + form.addEventListener('focusout', function(evt){ + var internalData = getInternalData(form); + internalData.lastButtonClicked = null; + }) + } + function initNode(elt) { if (elt.closest && elt.closest(htmx.config.disableSelector)) { return; @@ -1427,6 +1711,10 @@ return (function () { boostElement(elt, nodeData, triggerSpecs); } + if (elt.tagName === "FORM") { + initButtonTracking(elt); + } + var sseInfo = getAttributeValue(elt, 'hx-sse'); if (sseInfo) { processSSEInfo(elt, nodeData, sseInfo); @@ -1473,6 +1761,15 @@ return (function () { return eventName === "htmx:afterProcessNode" } + /** + * `withExtensions` locates all active extensions for a provided element, then + * executes the provided function using each of the active extensions. It should + * be called internally at every extendable execution point in htmx. + * + * @param {HTMLElement} elt + * @param {(extension:import("./htmx").HtmxExtension) => void} toDo + * @returns void + */ function withExtensions(elt, toDo) { forEach(getExtensions(elt), function(extension){ try { @@ -1520,7 +1817,7 @@ return (function () { //==================================================================== // History Support //==================================================================== - var currentPathForHistory = null; + var currentPathForHistory = location.pathname+location.search; function getHistoryElement() { var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]'); @@ -1569,7 +1866,7 @@ return (function () { return clone.innerHTML; } - function saveHistory() { + function saveCurrentPageToHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); @@ -1598,9 +1895,11 @@ return (function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); var fragment = makeFragment(this.response); + // @ts-ignore fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; var historyElement = getHistoryElement(); var settleInfo = makeSettleInfo(historyElement); + // @ts-ignore swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); currentPathForHistory = path; @@ -1613,7 +1912,7 @@ return (function () { } function restoreHistory(path) { - saveHistory(); + saveCurrentPageToHistory(); path = path || location.pathname+location.search; var cached = getCachedHistory(path); if (cached) { @@ -1628,6 +1927,8 @@ return (function () { triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); } else { if (htmx.config.refreshOnHistoryMiss) { + + // @ts-ignore: optional parameter in reload() function throws error window.location.reload(true); } else { loadHistoryFromServer(path); @@ -1647,10 +1948,8 @@ return (function () { } function addRequestIndicatorClasses(elt) { - var indicator = getClosestAttributeValue(elt, 'hx-indicator'); - if (indicator) { - var indicators = querySelectorAllExt(elt, indicator); - } else { + var indicators = findAttributeTargets(elt, 'hx-indicator'); + if (indicators == null) { indicators = [elt]; } forEach(indicators, function (ic) { @@ -1753,14 +2052,22 @@ return (function () { } } + /** + * @param {HTMLElement} elt + * @param {string} verb + */ function getInputValues(elt, verb) { var processed = []; var values = {}; var formValues = {}; var errors = []; + var internalData = getInternalData(elt); - // only validate when form is directly submitted and novalidate is not set + // only validate when form is directly submitted and novalidate or formnovalidate are not set var validate = matches(elt, 'form') && elt.noValidate !== true; + if (internalData.lastButtonClicked) { + validate = validate && internalData.lastButtonClicked.formNoValidate !== true; + } // for a non-GET include the closest form if (verb !== 'get') { @@ -1770,21 +2077,26 @@ return (function () { // include the element itself processInputValue(processed, values, errors, elt, validate); - // include any explicit includes - var includes = getClosestAttributeValue(elt, "hx-include"); - if (includes) { - var nodes = querySelectorAllExt(elt, includes); - forEach(nodes, function(node) { - processInputValue(processed, values, errors, node, validate); - // if a non-form is included, include any input values within it - if (!matches(node, 'form')) { - forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { - processInputValue(processed, values, errors, descendant, validate); - }) - } - }); + // if a button or submit was clicked last, include its value + if (internalData.lastButtonClicked) { + var name = getRawAttribute(internalData.lastButtonClicked,"name"); + if (name) { + values[name] = internalData.lastButtonClicked.value; + } } + // include any explicit includes + var includes = findAttributeTargets(elt, "hx-include"); + forEach(includes, function(node) { + processInputValue(processed, values, errors, node, validate); + // if a non-form is included, include any input values within it + if (!matches(node, 'form')) { + forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { + processInputValue(processed, values, errors, descendant, validate); + }) + } + }); + // form values take precedence, overriding the regular values values = mergeObjects(values, formValues); @@ -1795,7 +2107,11 @@ return (function () { if (returnStr !== "") { returnStr += "&"; } - returnStr += encodeURIComponent(name) + "=" + encodeURIComponent(realValue); + if (String(realValue) === "[object Object]") { + realValue = JSON.stringify(realValue); + } + var s = encodeURIComponent(realValue); + returnStr += encodeURIComponent(name) + "=" + s; return returnStr; } @@ -1837,6 +2153,12 @@ return (function () { // Ajax //==================================================================== + /** + * @param {HTMLElement} elt + * @param {HTMLElement} target + * @param {string} prompt + * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification + */ function getHeaders(elt, target, prompt) { var headers = { "HX-Request" : "true", @@ -1849,9 +2171,20 @@ return (function () { if (prompt !== undefined) { headers["HX-Prompt"] = prompt; } + if (getInternalData(elt).boosted) { + headers["HX-Boosted"] = "true"; + } return headers; } + /** + * filterValues takes an object containing form input values + * and returns a new object that only contains keys that are + * specified by the closest "hx-params" attribute + * @param {Object} inputValues + * @param {HTMLElement} elt + * @returns {Object} + */ function filterValues(inputValues, elt) { var paramsValue = getClosestAttributeValue(elt, "hx-params"); if (paramsValue) { @@ -1882,8 +2215,14 @@ return (function () { return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0 } - function getSwapSpecification(elt) { - var swapInfo = getClosestAttributeValue(elt, "hx-swap"); + /** + * + * @param {HTMLElement} elt + * @param {string} swapInfoOverride + * @returns {import("./htmx").HtmxSwapSpecification} + */ + function getSwapSpecification(elt, swapInfoOverride) { + var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap"); var swapSpec = { "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, "swapDelay" : htmx.config.defaultSwapDelay, @@ -1905,10 +2244,24 @@ return (function () { swapSpec["settleDelay"] = parseInterval(modifier.substr(7)); } if (modifier.indexOf("scroll:") === 0) { - swapSpec["scroll"] = modifier.substr(7); + var scrollSpec = modifier.substr(7); + var splitSpec = scrollSpec.split(":"); + var scrollVal = splitSpec.pop(); + var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; + swapSpec["scroll"] = scrollVal; + swapSpec["scrollTarget"] = selectorVal; } if (modifier.indexOf("show:") === 0) { - swapSpec["show"] = modifier.substr(5); + var showSpec = modifier.substr(5); + var splitSpec = showSpec.split(":"); + var showVal = splitSpec.pop(); + var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; + swapSpec["show"] = showVal; + swapSpec["showTarget"] = selectorVal; + } + if (modifier.indexOf("focus-scroll:") === 0) { + var focusScrollVal = modifier.substr("focus-scroll:".length); + swapSpec["focusScroll"] = focusScrollVal == "true"; } } } @@ -1926,7 +2279,8 @@ return (function () { if (encodedParameters != null) { return encodedParameters; } else { - if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data") { + if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || + (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) { return makeFormData(filteredParameters); } else { return urlEncode(filteredParameters); @@ -1934,6 +2288,11 @@ return (function () { } } + /** + * + * @param {Element} target + * @returns {import("./htmx").HtmxSettleInfo} + */ function makeSettleInfo(target) { return {tasks: [], elts: [target]}; } @@ -1942,23 +2301,46 @@ return (function () { var first = content[0]; var last = content[content.length - 1]; if (swapSpec.scroll) { - if (swapSpec.scroll === "top" && first) { - first.scrollTop = 0; + var target = null; + if (swapSpec.scrollTarget) { + target = querySelectorExt(first, swapSpec.scrollTarget); + } + if (swapSpec.scroll === "top" && (first || target)) { + target = target || first; + target.scrollTop = 0; } - if (swapSpec.scroll === "bottom" && last) { - last.scrollTop = last.scrollHeight; + if (swapSpec.scroll === "bottom" && (last || target)) { + target = target || last; + target.scrollTop = target.scrollHeight; } } if (swapSpec.show) { - if (swapSpec.show === "top" && first) { - first.scrollIntoView(true); + var target = null; + if (swapSpec.showTarget) { + var targetStr = swapSpec.showTarget; + if (swapSpec.showTarget === "window") { + targetStr = "body"; + } + target = querySelectorExt(first, targetStr); + } + if (swapSpec.show === "top" && (first || target)) { + target = target || first; + target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior}); } - if (swapSpec.show === "bottom" && last) { - last.scrollIntoView(false); + if (swapSpec.show === "bottom" && (last || target)) { + target = target || last; + target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior}); } } } + /** + * @param {HTMLElement} elt + * @param {string} attr + * @param {boolean=} evalAsDefault + * @param {Object=} values + * @returns {Object} + */ function getValuesForElement(elt, attr, evalAsDefault, values) { if (values == null) { values = {}; @@ -1973,6 +2355,9 @@ return (function () { if (str.indexOf("javascript:") === 0) { str = str.substr(11); evaluateValue = true; + } else if (str.indexOf("js:") === 0) { + str = str.substr(3); + evaluateValue = true; } if (str.indexOf('{') !== 0) { str = "{" + str + "}"; @@ -2003,14 +2388,28 @@ return (function () { } } + /** + * @param {HTMLElement} elt + * @param {*} expressionVars + * @returns + */ function getHXVarsForElement(elt, expressionVars) { return getValuesForElement(elt, "hx-vars", true, expressionVars); } + /** + * @param {HTMLElement} elt + * @param {*} expressionVars + * @returns + */ function getHXValsForElement(elt, expressionVars) { return getValuesForElement(elt, "hx-vals", false, expressionVars); } + /** + * @param {HTMLElement} elt + * @returns {Object} + */ function getExpressionVars(elt) { return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)); } @@ -2044,10 +2443,12 @@ return (function () { } function ajaxHelper(verb, path, context) { + verb = verb.toLowerCase(); if (context) { if (context instanceof Element || isType(context, 'String')) { return issueAjaxRequest(verb, path, null, null, { - targetOverride: resolveTarget(context) + targetOverride: resolveTarget(context), + returnPromise: true }); } else { return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, @@ -2055,11 +2456,15 @@ return (function () { handler : context.handler, headers : context.headers, values : context.values, - targetOverride: resolveTarget(context.target) + targetOverride: resolveTarget(context.target), + swapOverride: context.swap, + returnPromise: true }); } } else { - return issueAjaxRequest(verb, path); + return issueAjaxRequest(verb, path, null, null, { + returnPromise: true + }); } } @@ -2076,7 +2481,7 @@ return (function () { var resolve = null; var reject = null; etc = etc != null ? etc : {}; - if(typeof Promise !== "undefined"){ + if(etc.returnPromise && typeof Promise !== "undefined"){ var promise = new Promise(function (_resolve, _reject) { resolve = _resolve; reject = _reject; @@ -2091,40 +2496,85 @@ return (function () { return; // do not issue requests for elements removed from the DOM } var target = etc.targetOverride || getTarget(elt); - if (target == null) { + if (target == null || target == DUMMY_ELT) { triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); return; } + + var syncElt = elt; var eltData = getInternalData(elt); - if (eltData.requestInFlight) { - var queueStrategy = 'last'; - var eventData = getInternalData(event); - if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { - queueStrategy = eventData.triggerSpec.queue; - } - if (eltData.queuedRequests == null) { - eltData.queuedRequests = []; - } - if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); - } else if (queueStrategy === "all") { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); - } else if (queueStrategy === "last") { - eltData.queuedRequests = []; // dump existing queue - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event) - }); + var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); + var queueStrategy = null; + var abortable = false; + if (syncStrategy) { + var syncStrings = syncStrategy.split(":"); + var selector = syncStrings[0].trim(); + if (selector === "this") { + syncElt = findThisElement(elt, 'hx-sync'); + } else { + syncElt = querySelectorExt(elt, selector); + } + // default to the drop strategy + syncStrategy = (syncStrings[1] || 'drop').trim(); + eltData = getInternalData(syncElt); + if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { + return; + } else if (syncStrategy === "abort") { + if (eltData.xhr) { + return; + } else { + abortable = true; + } + } else if (syncStrategy === "replace") { + triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue + } else if (syncStrategy.indexOf("queue") === 0) { + var queueStrArray = syncStrategy.split(" "); + queueStrategy = (queueStrArray[1] || "last").trim(); } - return; - } else { - eltData.requestInFlight = true; } + + if (eltData.xhr) { + if (eltData.abortable) { + triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue + } else { + if(queueStrategy == null){ + if (event) { + var eventData = getInternalData(event); + if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { + queueStrategy = eventData.triggerSpec.queue; + } + } + if (queueStrategy == null) { + queueStrategy = "last"; + } + } + if (eltData.queuedRequests == null) { + eltData.queuedRequests = []; + } + if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } else if (queueStrategy === "all") { + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } else if (queueStrategy === "last") { + eltData.queuedRequests = []; // dump existing queue + eltData.queuedRequests.push(function () { + issueAjaxRequest(verb, path, elt, event, etc) + }); + } + return; + } + } + + var xhr = new XMLHttpRequest(); + eltData.xhr = xhr; + eltData.abortable = abortable; var endRequestLock = function(){ - eltData.requestInFlight = false + eltData.xhr = null; + eltData.abortable = false; if (eltData.queuedRequests != null && eltData.queuedRequests.length > 0) { var queuedRequest = eltData.queuedRequests.shift(); @@ -2152,11 +2602,10 @@ return (function () { } } - var xhr = new XMLHttpRequest(); var headers = getHeaders(elt, target, promptResponse); if (etc.headers) { - headers = mergeObjects(headers, etc.values); + headers = mergeObjects(headers, etc.headers); } var results = getInputValues(elt, verb); var errors = results.errors; @@ -2169,7 +2618,7 @@ return (function () { var filteredParameters = filterValues(allParameters, elt); if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null) { - headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; + headers['Content-Type'] = 'application/x-www-form-urlencoded'; } // behavior of anchors w/ empty href is to use the current URL @@ -2177,6 +2626,8 @@ return (function () { path = getDocument().location.href; } + var requestAttrValues = getValuesForElement(elt, 'hx-request'); + var requestConfig = { parameters: filteredParameters, unfilteredParameters: allParameters, @@ -2184,6 +2635,8 @@ return (function () { target:target, verb:verb, errors:errors, + withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, + timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, path:path, triggeringEvent:event }; @@ -2231,17 +2684,22 @@ return (function () { } xhr.overrideMimeType("text/html"); - xhr.withCredentials = htmx.config.withCredentials; + xhr.withCredentials = requestConfig.withCredentials; + xhr.timeout = requestConfig.timeout; // request headers - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - var headerValue = headers[header]; - safelySetHeaderValue(xhr, header, headerValue); + if (requestAttrValues.noHeaders) { + // ignore all headers + } else { + for (var header in headers) { + if (headers.hasOwnProperty(header)) { + var headerValue = headers[header]; + safelySetHeaderValue(xhr, header, headerValue); + } } } - var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, pathInfo:{ + var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, etc:etc, pathInfo:{ path:path, finalPath:finalPathForGet, anchor:anchor } }; @@ -2289,6 +2747,13 @@ return (function () { maybeCall(reject); endRequestLock(); } + xhr.ontimeout = function() { + removeRequestIndicatorClasses(indicators); + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); + triggerErrorEvent(elt, 'htmx:timeout', responseInfo); + maybeCall(reject); + endRequestLock(); + } if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){ maybeCall(resolve); endRequestLock() @@ -2315,6 +2780,7 @@ return (function () { function handleAjaxResponse(elt, responseInfo) { var xhr = responseInfo.xhr; var target = responseInfo.target; + var etc = responseInfo.etc; if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; @@ -2338,123 +2804,162 @@ return (function () { } } - var shouldSaveHistory = shouldPush(elt) || pushedUrl; + if (hasHeader(xhr,/HX-Retarget:/i)) { + responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget")); + } - if (xhr.status >= 200 && xhr.status < 400) { + /** @type {boolean} */ + var shouldSaveHistory + if (pushedUrl == "false") { + shouldSaveHistory = false + } else { + shouldSaveHistory = shouldPush(elt) || pushedUrl; + } + + // by default htmx only swaps on 200 return codes and does not swap + // on 204 'No Content' + // this can be ovverriden by responding to the htmx:beforeSwap event and + // overriding the detail.shouldSwap property + var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; + var serverResponse = xhr.response; + var isError = xhr.status >= 400; + var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo); + if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; + + target = beforeSwapDetails.target; // allow re-targeting + serverResponse = beforeSwapDetails.serverResponse; // allow updating content + isError = beforeSwapDetails.isError; // allow updating error + + responseInfo.failed = isError; // Make failed property available to response events + responseInfo.successful = !isError; // Make successful property available to response events + + if (beforeSwapDetails.shouldSwap) { if (xhr.status === 286) { cancelPolling(elt); } - // don't process 'No Content' - if (xhr.status !== 204) { - if (!triggerEvent(target, 'htmx:beforeSwap', responseInfo)) return; - var serverResponse = xhr.response; - withExtensions(elt, function(extension){ - serverResponse = extension.transformResponse(serverResponse, xhr, elt); - }); + withExtensions(elt, function (extension) { + serverResponse = extension.transformResponse(serverResponse, xhr, elt); + }); - // Save current page - if (shouldSaveHistory) { - saveHistory(); - } + // Save current page + if (shouldSaveHistory) { + saveCurrentPageToHistory(); + } + + var swapOverride = etc.swapOverride; + var swapSpec = getSwapSpecification(elt, swapOverride); - var swapSpec = getSwapSpecification(elt); + target.classList.add(htmx.config.swappingClass); + var doSwap = function () { + try { - target.classList.add(htmx.config.swappingClass); - var doSwap = function () { + var activeElt = document.activeElement; + var selectionInfo = {}; try { + selectionInfo = { + elt: activeElt, + // @ts-ignore + start: activeElt ? activeElt.selectionStart : null, + // @ts-ignore + end: activeElt ? activeElt.selectionEnd : null + }; + } catch (e) { + // safari issue - see https://github.com/microsoft/playwright/issues/5894 + } - var activeElt = document.activeElement; - var selectionInfo = {}; - try { - selectionInfo = { - elt: activeElt, - start: activeElt ? activeElt.selectionStart : null, - end: activeElt ? activeElt.selectionEnd : null - }; - } catch (e) { - // safari issue - see https://github.com/microsoft/playwright/issues/5894 + var settleInfo = makeSettleInfo(target); + selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + + if (selectionInfo.elt && + !bodyContains(selectionInfo.elt) && + selectionInfo.elt.id) { + var newActiveElt = document.getElementById(selectionInfo.elt.id); + var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; + if (newActiveElt) { + // @ts-ignore + if (selectionInfo.start && newActiveElt.setSelectionRange) { + // @ts-ignore + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + } + newActiveElt.focus(focusOptions); } + } - var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + target.classList.remove(htmx.config.swappingClass); + forEach(settleInfo.elts, function (elt) { + if (elt.classList) { + elt.classList.add(htmx.config.settlingClass); + } + triggerEvent(elt, 'htmx:afterSwap', responseInfo); + }); + if (responseInfo.pathInfo.anchor) { + location.hash = responseInfo.pathInfo.anchor; + } - if (selectionInfo.elt && - !bodyContains(selectionInfo.elt) && - selectionInfo.elt.id) { - var newActiveElt = document.getElementById(selectionInfo.elt.id); - if (newActiveElt) { - if (selectionInfo.start && newActiveElt.setSelectionRange) { - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); - } - newActiveElt.focus(); - } + if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { + var finalElt = elt; + if (!bodyContains(elt)) { + finalElt = getDocument().body; } + handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); + } - target.classList.remove(htmx.config.swappingClass); + var doSettle = function () { + forEach(settleInfo.tasks, function (task) { + task.call(); + }); forEach(settleInfo.elts, function (elt) { if (elt.classList) { - elt.classList.add(htmx.config.settlingClass); + elt.classList.remove(htmx.config.settlingClass); } - triggerEvent(elt, 'htmx:afterSwap', responseInfo); + triggerEvent(elt, 'htmx:afterSettle', responseInfo); }); - if (responseInfo.pathInfo.anchor) { - location.hash = responseInfo.pathInfo.anchor; + // push URL and save new page + if (shouldSaveHistory) { + var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; + pushUrlIntoHistory(pathToPush); + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: pathToPush}); } - if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; + if(settleInfo.title) { + var titleElt = find("title"); + if(titleElt) { + titleElt.innerHTML = settleInfo.title; + } else { + window.document.title = settleInfo.title; } - handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); } - var doSettle = function(){ - forEach(settleInfo.tasks, function (task) { - task.call(); - }); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.remove(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSettle', responseInfo); - }); - // push URL and save new page - if (shouldSaveHistory) { - var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; - pushUrlIntoHistory(pathToPush); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path:pathToPush}); - } - updateScrollState(settleInfo.elts, swapSpec); + updateScrollState(settleInfo.elts, swapSpec); - if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); + if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { + var finalElt = elt; + if (!bodyContains(elt)) { + finalElt = getDocument().body; } + handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'htmx:swapError', responseInfo); - throw e; } - }; - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); + if (swapSpec.settleDelay > 0) { + setTimeout(doSettle, swapSpec.settleDelay) + } else { + doSettle(); + } + } catch (e) { + triggerErrorEvent(elt, 'htmx:swapError', responseInfo); + throw e; } + }; + + if (swapSpec.swapDelay > 0) { + setTimeout(doSwap, swapSpec.swapDelay) + } else { + doSwap(); } - } else { + } + if (isError) { triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.path}, responseInfo)); } } @@ -2462,9 +2967,17 @@ return (function () { //==================================================================== // Extensions API //==================================================================== + + /** @type {Object<string, import("./htmx").HtmxExtension>} */ var extensions = {}; + + /** + * extensionBase defines the default functions for all extensions. + * @returns {import("./htmx").HtmxExtension} + */ function extensionBase() { return { + init: function(api) {return null;}, onEvent : function(name, evt) {return true;}, transformResponse : function(text, xhr, elt) {return text;}, isInlineSwap : function(swapStyle) {return false;}, @@ -2473,15 +2986,37 @@ return (function () { } } + /** + * defineExtension initializes the extension and adds it to the htmx registry + * + * @param {string} name + * @param {import("./htmx").HtmxExtension} extension + */ function defineExtension(name, extension) { + if(extension.init) { + extension.init(internalAPI) + } extensions[name] = mergeObjects(extensionBase(), extension); } + /** + * removeExtension removes an extension from the htmx registry + * + * @param {string} name + */ function removeExtension(name) { delete extensions[name]; } - function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + /** + * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element + * + * @param {HTMLElement} elt + * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn + * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore + */ + function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + if (elt == undefined) { return extensionsToReturn; } @@ -2536,6 +3071,7 @@ return (function () { function getMetaConfig() { var element = getDocument().querySelector('meta[name="htmx-config"]'); if (element) { + // @ts-ignore return parseJSON(element.content); } else { return null; @@ -2555,9 +3091,25 @@ return (function () { insertIndicatorStyles(); var body = getDocument().body; processNode(body); + var restoredElts = getDocument().querySelectorAll( + "[hx-trigger='restored'],[data-hx-trigger='restored']" + ); + body.addEventListener("htmx:abort", function (evt) { + var target = evt.target; + var internalData = getInternalData(target); + if (internalData && internalData.xhr) { + internalData.xhr.abort(); + } + }); window.onpopstate = function (event) { if (event.state && event.state.htmx) { restoreHistory(); + forEach(restoredElts, function(elt){ + triggerEvent(elt, 'htmx:restored', { + 'document': getDocument(), + 'triggerEvent': triggerEvent + }); + }); } }; setTimeout(function () { diff --git a/code/starter_video_collector/static/js/htmx.min.js b/code/starter_video_collector/static/js/htmx.min.js index 57f33b2..998414c 100644 --- a/code/starter_video_collector/static/js/htmx.min.js +++ b/code/starter_video_collector/static/js/htmx.min.js @@ -1 +1 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var k={onLoad:t,process:rt,on:I,off:M,trigger:lt,ajax:$t,find:w,findAll:S,closest:L,values:function(e,t){var r=Lt(e,t||"post");return r.values},remove:E,addClass:q,removeClass:R,toggleClass:C,takeClass:O,defineExtension:Qt,removeExtension:er,logAll:b,logger:null,useTemplateFragments:false,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,attributesToSettle:["class","style","width","height"],withCredentials:false,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]"},parseInterval:f,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])}};var r=["get","post","put","delete","patch"];var n=r.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function f(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function l(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function D(e,t){return l(e,t)||l(e,"data-"+t)}function c(e){return e.parentElement}function F(){return document}function h(e,t){if(t(e)){return e}else if(c(e)){return h(c(e),t)}else{return null}}function X(e,t){var r=null;h(e,function(e){return r=D(e,t)});return r}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function i(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 o(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=F().createDocumentFragment()}return i}function u(e){if(k.config.useTemplateFragments){var t=o("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=i(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return o("<table>"+e+"</table>",1);case"col":return o("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return o("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return o("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return o("<div>"+e+"</div>",1);default:return o(e,0)}}}function P(e){if(e){e()}}function a(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function v(e){return a(e,"Function")}function g(e){return a(e,"Object")}function U(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function p(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function j(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function m(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function z(e){return F().body.contains(e)}function y(e){return e.trim().split(/\s+/)}function V(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function x(e){try{return JSON.parse(e)}catch(e){ut(e);return null}}function e(e){return Ut(F().body,function(){return eval(e)})}function t(t){var e=k.on("htmx:load",function(e){t(e.detail.elt)});return e}function b(){k.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function w(e,t){if(t){return e.querySelector(t)}else{return w(F(),e)}}function S(e,t){if(t){return e.querySelectorAll(t)}else{return S(F(),e)}}function E(e,t){e=H(e);if(t){setTimeout(function(){E(e)},t)}else{e.parentElement.removeChild(e)}}function q(e,t,r){e=H(e);if(r){setTimeout(function(){q(e,t)},r)}else{e.classList.add(t)}}function R(e,t,r){e=H(e);if(r){setTimeout(function(){R(e,t)},r)}else{e.classList.remove(t)}}function C(e,t){e=H(e);e.classList.toggle(t)}function O(e,t){e=H(e);j(e.parentElement.children,function(e){R(e,t)});q(e,t)}function L(e,t){e=H(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&c(e))}}function A(e,t){if(t.indexOf("closest ")===0){return[L(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[w(e,t.substr(5))]}else{return F().querySelectorAll(t)}}function T(e,t){return A(e,t)[0]}function H(e){if(a(e,"String")){return w(e)}else{return e}}function N(e,t,r){if(v(t)){return{target:F().body,event:e,listener:t}}else{return{target:H(e),event:t,listener:r}}}function I(t,r,n){rr(function(){var e=N(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=v(r);return e?r:n}function M(t,r,n){rr(function(){var e=N(t,r,n);e.target.removeEventListener(e.event,e.listener)});return v(r)?r:n}function _(e){var t=h(e,function(e){return D(e,"hx-target")!==null});if(t){var r=D(t,"hx-target");if(r==="this"){return t}else{return T(e,r)}}else{var n=U(e);if(n.boosted){return F().body}else{return e}}}function B(e){var t=k.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function W(t,r){j(t.attributes,function(e){if(!r.hasAttribute(e.name)&&B(e.name)){t.removeAttribute(e.name)}});j(r.attributes,function(e){if(B(e.name)){t.setAttribute(e.name,e.value)}})}function $(e,t){var r=tr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){ut(e)}}return e==="outerHTML"}function J(e,t,r){var n="#"+t.id;var i="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){i=e.substr(0,e.indexOf(":"));n=e.substr(e.indexOf(":")+1,e.length)}else{i=e}var o=F().querySelector(n);if(o){var a;a=F().createDocumentFragment();a.appendChild(t);if(!$(i,o)){a=t}le(i,o,o,a,r)}else{t.parentNode.removeChild(t);ot(F().body,"htmx:oobErrorNoTarget",{content:t})}return e}function Z(e,r){j(S(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=D(e,"hx-swap-oob");if(t!=null){J(t,e,r)}})}function G(e){j(S(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=D(e,"id");var r=F().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function K(n,e,i){j(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();W(e,t);i.tasks.push(function(){W(e,r)})}}})}function Y(e){return function(){rt(e);Ye(e);Q(e);lt(e,"htmx:load")}}function Q(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ee(e,t,r,n){K(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Y(i))}}}function te(t){var e=U(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}if(e.listenerInfos){j(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){j(t.children,function(e){te(e)})}}function re(e,t,r){if(e.tagName==="BODY"){return se(e,t,r)}else{var n=e.previousSibling;ee(c(e),e,t,r);if(n==null){var i=c(e).firstChild}else{var i=n.nextSibling}U(e).replacedWith=i;r.elts=[];while(i&&i!==e){if(i.nodeType===Node.ELEMENT_NODE){r.elts.push(i)}i=i.nextElementSibling}te(e);c(e).removeChild(e)}}function ne(e,t,r){return ee(e,e.firstChild,t,r)}function ie(e,t,r){return ee(c(e),e,t,r)}function oe(e,t,r){return ee(e,null,t,r)}function ae(e,t,r){return ee(c(e),e.nextSibling,t,r)}function se(e,t,r){var n=e.firstChild;ee(e,n,t,r);if(n){while(n.nextSibling){te(n.nextSibling);e.removeChild(n.nextSibling)}te(n);e.removeChild(n)}}function ue(e,t){var r=X(e,"hx-select");if(r){var n=F().createDocumentFragment();j(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function le(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":re(r,n,i);return;case"afterbegin":ne(r,n,i);return;case"beforebegin":ie(r,n,i);return;case"beforeend":oe(r,n,i);return;case"afterend":ae(r,n,i);return;default:var o=tr(t);for(var a=0;a<o.length;a++){var s=o[a];try{var u=s.handleSwap(e,r,n,i);if(u){if(typeof u.length!=="undefined"){for(var l=0;l<u.length;l++){var f=u[l];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Y(f))}}}return}}catch(e){ut(e)}}se(r,n,i)}}var fe=/<title>([\s\S]+?)<\/title>/im;function ce(e){if(e.indexOf("<title>")>-1&&(e.indexOf("<svg>")==-1||e.indexOf("<title>")<e.indexOf("<svg>"))){var t=fe.exec(e);if(t){return t[1]}}}function he(e,t,r,n,i){var o=ce(n);if(o){var a=w("title");if(a){a.innerHTML=o}else{window.document.title=o}}var s=u(n);if(s){Z(s,i);s=ue(r,s);G(s);return le(e,r,t,s,i)}}function de(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=x(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!g(a)){a={value:a}}lt(r,o,a)}}}else{lt(r,n,[])}}var ve=/\s/;var ge=/[\s,]/;var pe=/[_$a-zA-Z]/;var me=/[_$a-zA-Z0-9]/;var ye=['"',"'","/"];var xe=/[^\s]/;function be(e){var t=[];var r=0;while(r<e.length){if(pe.exec(e.charAt(r))){var n=r;while(me.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(ye.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function we(e,t,r){return pe.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function Se(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Ut(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){ot(F().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(we(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function Ee(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var qe="input, textarea, select";function Re(e){var t=D(e,"hx-trigger");var r=[];if(t){var n=be(t);do{Ee(n,xe);var i=n.length;var o=Ee(n,/[,\[\s]/);if(o!==""){if(o==="every"){var a={trigger:"every"};Ee(n,xe);a.pollInterval=f(Ee(n,ve));r.push(a)}else if(o.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:o.substr(4)})}else{var s={trigger:o};var u=Se(e,n,"event");if(u){s.eventFilter=u}while(n.length>0&&n[0]!==","){Ee(n,xe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=f(Ee(n,ge))}else if(l==="from"&&n[0]===":"){n.shift();s.from=Ee(n,ge)}else if(l==="target"&&n[0]===":"){n.shift();s.target=Ee(n,ge)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=f(Ee(n,ge))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=Ee(n,ge)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=Ee(n,ge)}else{ot(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===i){ot(e,"htmx:syntax:error",{token:n.shift()})}Ee(n,xe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,qe)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ce(e){U(e).cancelled=true}function Oe(e,t,r,n){var i=U(e);i.timeout=setTimeout(function(){if(z(e)&&i.cancelled!==true){Zt(t,r,e);Oe(e,t,D(e,"hx-"+t),n)}},n)}function Le(e){return location.hostname===e.hostname&&l(e,"href")&&l(e,"href").indexOf("#")!==0}function Ae(t,r,e){if(t.tagName==="A"&&Le(t)||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=l(t,"href");r.pushURL=true}else{var o=l(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=l(t,"action")}e.forEach(function(e){Ie(t,n,i,r,e,true)})}}function Te(e){return e.tagName==="FORM"||d(e,'input[type="submit"], button')&&L(e,"form")!==null||e.tagName==="A"&&e.href&&(e.getAttribute("href")==="#"||e.getAttribute("href").indexOf("#")!==0)}function He(e,t){return U(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function Ne(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){ot(F().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Ie(n,i,o,e,a,s){var u=n;if(a.from){u=w(a.from)}var l=function(e){if(!z(n)){u.removeEventListener(a.trigger,l);return}if(He(n,e)){return}if(s||Te(n)){e.preventDefault()}if(Ne(a,e)){return}var t=U(e);t.triggerSpec=a;if(t.handledFor==null){t.handledFor=[]}var r=U(n);if(t.handledFor.indexOf(n)<0){t.handledFor.push(n);if(a.consume){e.stopPropagation()}if(a.target&&e.target){if(!d(e.target,a.target)){return}}if(a.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(a.changed){if(r.lastValue===n.value){return}else{r.lastValue=n.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(a.throttle){if(!r.throttle){Zt(i,o,n,e);r.throttle=setTimeout(function(){r.throttle=null},a.throttle)}}else if(a.delay){r.delayed=setTimeout(function(){Zt(i,o,n,e)},a.delay)}else{Zt(i,o,n,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:a.trigger,listener:l,on:u});u.addEventListener(a.trigger,l)}var Me=false;var ke=null;function De(){if(!ke){ke=function(){Me=true};window.addEventListener("scroll",ke);setInterval(function(){if(Me){Me=false;j(F().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){Fe(e)})}},200)}}function Fe(e){var t=U(e);if(!t.revealed&&m(e)){t.revealed=true;if(t.initialized){Zt(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Zt(t.verb,t.path,e)},{once:true})}}}function Xe(e,t,r){var n=y(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Pe(e,o[1],0)}if(o[0]==="send"){je(e)}}}function Pe(s,r,n){if(!z(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=k.createWebSocket(r);t.onerror=function(e){ot(s,"htmx:wsError",{error:e,socket:t});Ue(s)};t.onclose=function(e){if([1006,1012,1013].includes(e.code)){var t=ze(n);setTimeout(function(){Pe(s,r,n+1)},t)}};t.onopen=function(e){n=0};U(s).webSocket=t;t.addEventListener("message",function(e){if(Ue(s)){return}var t=e.data;st(s,function(e){t=e.transformResponse(t,null,s)});var r=Ft(s);var n=u(t);var i=p(n.children);for(var o=0;o<i.length;o++){var a=i[o];J(D(a,"hx-swap-oob")||"true",a,r)}mt(r.tasks)})}function Ue(e){if(!z(e)){U(e).webSocket.close();return true}}function je(l){var f=h(l,function(e){return U(e).webSocket!=null});if(f){l.addEventListener(Re(l)[0].trigger,function(e){var t=U(f).webSocket;var r=Nt(l,f);var n=Lt(l,"post");var i=n.errors;var o=n.values;var a=Vt(l);var s=V(o,a);var u=It(s,l);u["HEADERS"]=r;if(i&&i.length>0){lt(l,"htmx:validation:halted",i);return}t.send(JSON.stringify(u));if(Te(l)){e.preventDefault()}})}else{ot(l,"htmx:noWebSocketSourceError")}}function ze(e){var t=k.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}ut('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ve(e,t,r){var n=y(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){_e(e,o[1])}if(o[0]==="swap"){Be(e,o[1])}}}function _e(t,e){var r=k.createEventSource(e);r.onerror=function(e){ot(t,"htmx:sseError",{error:e,source:r});$e(t)};U(t).sseEventSource=r}function Be(o,a){var s=h(o,Je);if(s){var u=U(s).sseEventSource;var l=function(e){if($e(s)){u.removeEventListener(a,l);return}var t=e.data;st(o,function(e){t=e.transformResponse(t,null,o)});var r=kt(o);var n=_(o);var i=Ft(o);he(r.swapStyle,o,n,t,i);mt(i.tasks);lt(o,"htmx:sseMessage",e)};U(o).sseListener=l;u.addEventListener(a,l)}else{ot(o,"htmx:noSSESourceError")}}function We(e,t,r,n){var i=h(e,Je);if(i){var o=U(i).sseEventSource;var a=function(){if(!$e(i)){if(z(e)){Zt(t,r,e)}else{o.removeEventListener(n,a)}}};U(e).sseListener=a;o.addEventListener(n,a)}else{ot(e,"htmx:noSSESourceError")}}function $e(e){if(!z(e)){U(e).sseEventSource.close();return true}}function Je(e){return U(e).sseEventSource!=null}function Ze(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Zt(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function Ge(o,a,e){var t=false;j(r,function(n){if(s(o,"hx-"+n)){var i=D(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){We(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){De();Fe(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=T(e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){lt(o,"intersect");break}}},t);r.observe(o);Ie(o,n,i,a,e)}else if(e.trigger==="load"){Ze(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Oe(o,n,i,e.pollInterval)}else{Ie(o,n,i,a,e)}})}});return t}function Ke(e){if(e.type==="text/javascript"||e.type===""){try{Ut(e,function(){(1,eval)(e.innerText)})}catch(e){ut(e)}}}function Ye(e){if(d(e,"script")){Ke(e)}j(S(e,"script"),function(e){Ke(e)})}function Qe(){return document.querySelector("[hx-boost], [data-hx-boost]")}function et(e){if(e.querySelectorAll){var t=Qe()?", a, form":"";var r=e.querySelectorAll(n+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws]");return r}else{return[]}}function tt(e){if(e.closest&&e.closest(k.config.disableSelector)){return}var t=U(e);if(!t.initialized){t.initialized=true;lt(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=Re(e);var n=Ge(e,t,r);if(!n&&X(e,"hx-boost")==="true"){Ae(e,t,r)}var i=D(e,"hx-sse");if(i){Ve(e,t,i)}var o=D(e,"hx-ws");if(o){Xe(e,t,o)}lt(e,"htmx:afterProcessNode")}}function rt(e){e=H(e);tt(e);j(et(e),function(e){tt(e)})}function nt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function it(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=F().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function ot(e,t,r){lt(e,t,V({error:t},r))}function at(e){return e==="htmx:afterProcessNode"}function st(e,t){j(tr(e),function(e){try{t(e)}catch(e){ut(e)}})}function ut(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function lt(e,t,r){e=H(e);if(r==null){r={}}r["elt"]=e;var n=it(t,r);if(k.logger&&!at(t)){k.logger(e,t,r)}if(r.error){ut(r.error);lt(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=nt(t);if(i&&o!==t){var a=it(o,n.detail);i=i&&e.dispatchEvent(a)}st(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var ft=null;function ct(){var e=F().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||F().body}function ht(e,t,r,n){var i=x(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>k.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ot(F().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function dt(e){var t=x(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function vt(e){var t=k.config.requestClass;var r=e.cloneNode(true);j(S(r,"."+t),function(e){R(e,t)});return r.innerHTML}function gt(){var e=ct();var t=ft||location.pathname+location.search;lt(F().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(k.config.historyEnabled)history.replaceState({htmx:true},F().title,window.location.href);ht(t,vt(e),F().title,window.scrollY)}function pt(e){if(k.config.historyEnabled)history.pushState({htmx:true},"",e);ft=e}function mt(e){j(e,function(e){e.call()})}function yt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};lt(F().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){lt(F().body,"htmx:historyCacheMissLoad",i);var e=u(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=ct();var r=Ft(t);se(t,e,r);mt(r.tasks);ft=n;lt(F().body,"htmx:historyRestore",{path:n})}else{ot(F().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function xt(e){gt();e=e||location.pathname+location.search;var t=dt(e);if(t){var r=u(t.content);var n=ct();var i=Ft(n);se(n,r,i);mt(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);ft=e;lt(F().body,"htmx:historyRestore",{path:e})}else{if(k.config.refreshOnHistoryMiss){window.location.reload(true)}else{yt(e)}}}function bt(e){var t=X(e,"hx-push-url");return t&&t!=="false"||U(e).boosted&&U(e).pushURL}function wt(e){var t=X(e,"hx-push-url");return t==="true"||t==="false"?null:t}function St(e){var t=X(e,"hx-indicator");if(t){var r=A(e,t)}else{r=[e]}j(r,function(e){e.classList["add"].call(e.classList,k.config.requestClass)});return r}function Et(e){j(e,function(e){e.classList["remove"].call(e.classList,k.config.requestClass)})}function qt(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Rt(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 Ct(t,r,n,e,i){if(e==null||qt(t,e)){return}else{t.push(e)}if(Rt(e)){var o=l(e,"name");var a=e.value;if(e.multiple){a=p(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=p(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){Ot(e,n)}}if(d(e,"form")){var u=e.elements;j(u,function(e){Ct(t,r,n,e,i)})}}function Ot(e,t){if(e.willValidate){lt(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});lt(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Lt(e,t){var r=[];var n={};var i={};var o=[];var a=d(e,"form")&&e.noValidate!==true;if(t!=="get"){Ct(r,i,o,L(e,"form"),a)}Ct(r,n,o,e,a);var s=X(e,"hx-include");if(s){var u=A(e,s);j(u,function(e){Ct(r,n,o,e,a);if(!d(e,"form")){j(e.querySelectorAll(qe),function(e){Ct(r,n,o,e,a)})}})}n=V(n,i);return{errors:o,values:n}}function At(e,t,r){if(e!==""){e+="&"}e+=encodeURIComponent(t)+"="+encodeURIComponent(r);return e}function Tt(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){j(n,function(e){t=At(t,r,e)})}else{t=At(t,r,n)}}}return t}function Ht(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){j(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Nt(e,t,r){var n={"HX-Request":"true","HX-Trigger":l(e,"id"),"HX-Trigger-Name":l(e,"name"),"HX-Target":D(t,"id"),"HX-Current-URL":F().location.href};Pt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}return n}function It(t,e){var r=X(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){j(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};j(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Mt(e){return l(e,"href")&&l(e,"href").indexOf("#")>=0}function kt(e){var t=X(e,"hx-swap");var r={swapStyle:U(e).boosted?"innerHTML":k.config.defaultSwapStyle,swapDelay:k.config.defaultSwapDelay,settleDelay:k.config.defaultSettleDelay};if(U(e).boosted&&!Mt(e)){r["show"]="top"}if(t){var n=y(t);if(n.length>0){r["swapStyle"]=n[0];for(var i=1;i<n.length;i++){var o=n[i];if(o.indexOf("swap:")===0){r["swapDelay"]=f(o.substr(5))}if(o.indexOf("settle:")===0){r["settleDelay"]=f(o.substr(7))}if(o.indexOf("scroll:")===0){r["scroll"]=o.substr(7)}if(o.indexOf("show:")===0){r["show"]=o.substr(5)}}}}return r}function Dt(t,r,n){var i=null;st(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(X(r,"hx-encoding")==="multipart/form-data"){return Ht(n)}else{return Tt(n)}}}function Ft(e){return{tasks:[],elts:[e]}}function Xt(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){if(t.scroll==="top"&&r){r.scrollTop=0}if(t.scroll==="bottom"&&n){n.scrollTop=n.scrollHeight}}if(t.show){if(t.show==="top"&&r){r.scrollIntoView(true)}if(t.show==="bottom"&&n){n.scrollIntoView(false)}}}function Pt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=D(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Ut(e,function(){return Function("return ("+o+")")()},{})}else{s=x(o)}for(var u in s){if(s.hasOwnProperty(u)){if(n[u]==null){n[u]=s[u]}}}}return Pt(c(e),t,r,n)}function Ut(e,t,r){if(k.config.allowEval){return t()}else{ot(e,"htmx:evalDisallowedError");return r}}function jt(e,t){return Pt(e,"hx-vars",true,t)}function zt(e,t){return Pt(e,"hx-vals",false,t)}function Vt(e){return V(jt(e),zt(e))}function _t(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Bt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ot(F().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Wt(e,t){return e.getAllResponseHeaders().match(t)}function $t(e,t,r){if(r){if(r instanceof Element||a(r,"String")){return Zt(e,t,null,null,{targetOverride:H(r)})}else{return Zt(e,t,H(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:H(r.target)})}}else{return Zt(e,t)}}function Jt(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Zt(e,t,n,r,i){var o=null;var a=null;i=i!=null?i:{};if(typeof Promise!=="undefined"){var s=new Promise(function(e,t){o=e;a=t})}if(n==null){n=F().body}var u=i.handler||Gt;if(!z(n)){return}var l=i.targetOverride||_(n);if(l==null){ot(n,"htmx:targetError",{target:D(n,"hx-target")});return}var f=U(n);if(f.requestInFlight){var c="last";var h=U(r);if(h&&h.triggerSpec&&h.triggerSpec.queue){c=h.triggerSpec.queue}if(f.queuedRequests==null){f.queuedRequests=[]}if(c==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){Zt(e,t,n,r)})}else if(c==="all"){f.queuedRequests.push(function(){Zt(e,t,n,r)})}else if(c==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){Zt(e,t,n,r)})}return}else{f.requestInFlight=true}var d=function(){f.requestInFlight=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var v=X(n,"hx-prompt");if(v){var g=prompt(v);if(g===null||!lt(n,"htmx:prompt",{prompt:g,target:l})){P(o);d();return s}}var p=X(n,"hx-confirm");if(p){if(!confirm(p)){P(o);d();return s}}var m=new XMLHttpRequest;var y=Nt(n,l,g);if(i.headers){y=V(y,i.values)}var x=Lt(n,e);var b=x.errors;var w=x.values;if(i.values){w=V(w,i.values)}var S=Vt(n);var E=V(w,S);var q=It(E,n);if(e!=="get"&&X(n,"hx-encoding")==null){y["Content-Type"]="application/x-www-form-urlencoded; charset=UTF-8"}if(t==null||t===""){t=F().location.href}var R={parameters:q,unfilteredParameters:E,headers:y,target:l,verb:e,errors:b,path:t,triggeringEvent:r};if(!lt(n,"htmx:configRequest",R)){P(o);d();return s}t=R.path;e=R.verb;y=R.headers;q=R.parameters;b=R.errors;if(b&&b.length>0){lt(n,"htmx:validation:halted",R);P(o);d();return s}var C=t.split("#");var O=C[0];var L=C[1];if(e==="get"){var A=O;var T=Object.keys(q).length!==0;if(T){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=Tt(q);if(L){A+="#"+L}}m.open("GET",A,true)}else{m.open(e.toUpperCase(),t,true)}m.overrideMimeType("text/html");m.withCredentials=k.config.withCredentials;for(var H in y){if(y.hasOwnProperty(H)){var N=y[H];_t(m,H,N)}}var I={xhr:m,target:l,requestConfig:R,pathInfo:{path:t,finalPath:A,anchor:L}};m.onload=function(){try{var e=Jt(n);u(n,I);Et(M);lt(n,"htmx:afterRequest",I);lt(n,"htmx:afterOnLoad",I);if(!z(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(z(r)){t=r}}if(t){lt(t,"htmx:afterRequest",I);lt(t,"htmx:afterOnLoad",I)}}P(o);d()}catch(e){ot(n,"htmx:onLoadError",V({error:e},I));throw e}};m.onerror=function(){Et(M);ot(n,"htmx:afterRequest",I);ot(n,"htmx:sendError",I);P(a);d()};m.onabort=function(){Et(M);ot(n,"htmx:afterRequest",I);ot(n,"htmx:sendAbort",I);P(a);d()};if(!lt(n,"htmx:beforeRequest",I)){P(o);d();return s}var M=St(n);j(["loadstart","loadend","progress","abort"],function(t){j([m,m.upload],function(e){e.addEventListener(t,function(e){lt(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});lt(n,"htmx:beforeSend",I);m.send(e==="get"?null:Dt(m,n,q));return s}function Gt(a,s){var u=s.xhr;var l=s.target;if(!lt(a,"htmx:beforeOnLoad",s))return;if(Wt(u,/HX-Trigger:/i)){de(u,"HX-Trigger",a)}if(Wt(u,/HX-Push:/i)){var f=u.getResponseHeader("HX-Push")}if(Wt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Wt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}var c=bt(a)||f;if(u.status>=200&&u.status<400){if(u.status===286){Ce(a)}if(u.status!==204){if(!lt(l,"htmx:beforeSwap",s))return;var h=u.response;st(a,function(e){h=e.transformResponse(h,u,a)});if(c){gt()}var d=kt(a);l.classList.add(k.config.swappingClass);var e=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r=Ft(l);he(d.swapStyle,l,a,h,r);if(t.elt&&!z(t.elt)&&t.elt.id){var n=document.getElementById(t.elt.id);if(n){if(t.start&&n.setSelectionRange){n.setSelectionRange(t.start,t.end)}n.focus()}}l.classList.remove(k.config.swappingClass);j(r.elts,function(e){if(e.classList){e.classList.add(k.config.settlingClass)}lt(e,"htmx:afterSwap",s)});if(s.pathInfo.anchor){location.hash=s.pathInfo.anchor}if(Wt(u,/HX-Trigger-After-Swap:/i)){var i=a;if(!z(a)){i=F().body}de(u,"HX-Trigger-After-Swap",i)}var o=function(){j(r.tasks,function(e){e.call()});j(r.elts,function(e){if(e.classList){e.classList.remove(k.config.settlingClass)}lt(e,"htmx:afterSettle",s)});if(c){var e=f||wt(a)||Bt(u)||s.pathInfo.finalPath||s.pathInfo.path;pt(e);lt(F().body,"htmx:pushedIntoHistory",{path:e})}Xt(r.elts,d);if(Wt(u,/HX-Trigger-After-Settle:/i)){var t=a;if(!z(a)){t=F().body}de(u,"HX-Trigger-After-Settle",t)}};if(d.settleDelay>0){setTimeout(o,d.settleDelay)}else{o()}}catch(e){ot(a,"htmx:swapError",s);throw e}};if(d.swapDelay>0){setTimeout(e,d.swapDelay)}else{e()}}}else{ot(a,"htmx:responseError",V({error:"Response Status Error Code "+u.status+" from "+s.pathInfo.path},s))}}var Kt={};function Yt(){return{onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Qt(e,t){Kt[e]=V(Yt(),t)}function er(e){delete Kt[e]}function tr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=D(e,"hx-ext");if(t){j(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Kt[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return tr(c(e),r,n)}function rr(e){if(F().readyState!=="loading"){e()}else{F().addEventListener("DOMContentLoaded",e)}}function nr(){if(k.config.includeIndicatorStyles!==false){F().head.insertAdjacentHTML("beforeend","<style> ."+k.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+k.config.requestClass+" ."+k.config.indicatorClass+"{opacity:1} ."+k.config.requestClass+"."+k.config.indicatorClass+"{opacity:1} </style>")}}function ir(){var e=F().querySelector('meta[name="htmx-config"]');if(e){return x(e.content)}else{return null}}function or(){var e=ir();if(e){k.config=V(k.config,e)}}rr(function(){or();nr();var e=F().body;rt(e);window.onpopstate=function(e){if(e.state&&e.state.htmx){xt()}};setTimeout(function(){lt(e,"htmx:load",{})},0)});return k}()}); \ No newline at end of file +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(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 l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=k(e);e.classList.toggle(t)}function T(e,t){e=k(e);W(e.parentElement.children,function(e){q(e,t)});L(e,t)}function H(e,t){e=k(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function N(e,t){if(t.indexOf("closest ")===0){return[H(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[C(e,t.substr(5))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return z().querySelectorAll(t)}}function ee(e,t){if(t){return N(e,t)[0]}else{return N(z().body,e)[0]}}function k(e){if(p(e,"String")){return C(e)}else{return e}}function I(e,t,r){if(m(t)){return{target:z().body,event:e,listener:t}}else{return{target:k(e),event:t,listener:r}}}function M(t,r,n){lr(function(){var e=I(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function D(t,r,n){lr(function(){var e=I(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var te=z().createElement("output");function F(e,t){var r=G(e,t);if(r){if(r==="this"){return[re(e,t)]}else{var n=N(e,r);if(n.length===0){pt('The selector "'+r+'" on '+t+" returned no matches!");return[te]}else{return n}}}}function re(e,t){return h(e,function(e){return V(e,t)!=null})}function ne(e){var t=G(e,"hx-target");if(t){if(t==="this"){return re(e,"hx-target")}else{return ee(e,t)}}else{var r=_(e);if(r.boosted){return z().body}else{return e}}}function P(e){var t=U.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function X(t,r){W(t.attributes,function(e){if(!r.hasAttribute(e.name)&&P(e.name)){t.removeAttribute(e.name)}});W(r.attributes,function(e){if(P(e.name)){t.setAttribute(e.name,e.value)}})}function j(e,t){var r=sr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){pt(e)}}return e==="outerHTML"}function B(e,i,o){var t="#"+i.id;var a="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){a=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{a=e}var r=z().querySelectorAll(t);if(r){W(r,function(e){var t;var r=i.cloneNode(true);t=z().createDocumentFragment();t.appendChild(r);if(!j(a,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ye(a,e,e,t,o)}W(o.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(z().body,"htmx:oobErrorNoTarget",{content:i})}return e}function ie(e,r){W(R(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=V(e,"hx-swap-oob");if(t!=null){B(t,e,r)}})}function oe(e){W(R(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=V(e,"id");var r=z().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function ae(n,e,i){W(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();X(e,t);i.tasks.push(function(){X(e,r)})}}})}function se(e){return function(){q(e,U.config.addedClass);ct(e);at(e);le(e);$(e,"htmx:load")}}function le(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ue(e,t,r,n){ae(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(se(i))}}}function fe(t){var e=_(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){W(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){W(t.children,function(e){fe(e)})}}function ce(e,t,r){if(e.tagName==="BODY"){return me(e,t,r)}else{var n;var i=e.previousSibling;ue(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}_(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}fe(e);u(e).removeChild(e)}}function he(e,t,r){return ue(e,e.firstChild,t,r)}function de(e,t,r){return ue(u(e),e,t,r)}function ve(e,t,r){return ue(e,null,t,r)}function ge(e,t,r){return ue(u(e),e.nextSibling,t,r)}function pe(e,t,r){fe(e);return u(e).removeChild(e)}function me(e,t,r){var n=e.firstChild;ue(e,n,t,r);if(n){while(n.nextSibling){fe(n.nextSibling);e.removeChild(n.nextSibling)}fe(n);e.removeChild(n)}}function xe(e,t){var r=G(e,"hx-select");if(r){var n=z().createDocumentFragment();W(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function ye(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":ce(r,n,i);return;case"afterbegin":he(r,n,i);return;case"beforebegin":de(r,n,i);return;case"beforeend":ve(r,n,i);return;case"afterend":ge(r,n,i);return;case"delete":pe(r,n,i);return;default:var o=sr(t);for(var a=0;a<o.length;a++){var f=o[a];try{var s=f.handleSwap(e,r,n,i);if(s){if(typeof s.length!=="undefined"){for(var l=0;l<s.length;l++){var u=s[l];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){i.tasks.push(se(u))}}}return}}catch(e){pt(e)}}if(e==="innerHTML"){me(r,n,i)}else{ye(U.config.defaultSwapStyle,t,r,n,i)}}}function be(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function we(e,t,r,n,i){i.title=be(n);var o=g(n);if(o){ie(o,i);o=xe(r,o);oe(o);return ye(e,r,t,o,i)}}function Se(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!x(a)){a={value:a}}$(r,o,a)}}}else{$(r,n,[])}}var Ee=/\s/;var Ce=/[\s,]/;var Re=/[_$a-zA-Z]/;var Oe=/[_$a-zA-Z0-9]/;var Le=['"',"'","/"];var qe=/[^\s]/;function Ae(e){var t=[];var r=0;while(r<e.length){if(Re.exec(e.charAt(r))){var n=r;while(Oe.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Le.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function Te(e,t,r){return Re.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function He(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Jt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(z().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(Te(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var Ne="input, textarea, select";function ke(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=Ae(t);do{c(n,qe);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var o={trigger:"every"};c(n,qe);o.pollInterval=v(c(n,/[,\[\s]/));c(n,qe);var a=He(e,n,"event");if(a){o.eventFilter=a}r.push(o)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var a=He(e,n,"event");if(a){s.eventFilter=a}while(n.length>0&&n[0]!==","){c(n,qe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Ce))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Ce);if(u==="closest"||u==="find"){n.shift();u+=" "+c(n,Ce)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Ce)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Ce))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Ce)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Ce)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,qe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,Ne)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ie(e){_(e).cancelled=true}function Me(e,t,r,n){var i=_(e);i.timeout=setTimeout(function(){if(Y(e)&&i.cancelled!==true){if(!je(n,dt("hx:poll:trigger",{triggerSpec:n,target:e}))){Z(t,r,e)}Me(e,t,V(e,"hx-"+t),n)}},n.pollInterval)}function De(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&De(t)&&t.target===""||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href");r.pushURL=true}else{var o=f(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=f(t,"action")}e.forEach(function(e){Be(t,n,i,r,e,true)})}}function Pe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&H(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Xe(e,t){return _(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function je(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(z().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Be(o,a,s,e,l,u){var t;if(l.from){t=N(o,l.from)}else{t=[o]}W(t,function(n){var i=function(e){if(!Y(o)){n.removeEventListener(l.trigger,i);return}if(Xe(o,e)){return}if(u||Pe(e,o)){e.preventDefault()}if(je(l,e)){return}var t=_(e);t.triggerSpec=l;if(t.handledFor==null){t.handledFor=[]}var r=_(o);if(t.handledFor.indexOf(o)<0){t.handledFor.push(o);if(l.consume){e.stopPropagation()}if(l.target&&e.target){if(!d(e.target,l.target)){return}}if(l.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(l.changed){if(r.lastValue===o.value){return}else{r.lastValue=o.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(l.throttle){if(!r.throttle){Z(a,s,o,e);r.throttle=setTimeout(function(){r.throttle=null},l.throttle)}}else if(l.delay){r.delayed=setTimeout(function(){Z(a,s,o,e)},l.delay)}else{Z(a,s,o,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:l.trigger,listener:i,on:n});n.addEventListener(l.trigger,i)})}var Ue=false;var Ve=null;function ze(){if(!Ve){Ve=function(){Ue=true};window.addEventListener("scroll",Ve);setInterval(function(){if(Ue){Ue=false;W(z().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){_e(e)})}},200)}}function _e(e){if(!s(e,"data-hx-revealed")&&b(e)){e.setAttribute("data-hx-revealed","true");var t=_(e);if(t.initialized){Z(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Z(t.verb,t.path,e)},{once:true})}}}function We(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Je(e,o[1],0)}if(o[0]==="send"){Ze(e)}}}function Je(s,r,n){if(!Y(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=U.createWebSocket(r);t.onerror=function(e){J(s,"htmx:wsError",{error:e,socket:t});$e(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=Ge(n);setTimeout(function(){Je(s,r,n+1)},t)}};t.onopen=function(e){n=0};_(s).webSocket=t;t.addEventListener("message",function(e){if($e(s)){return}var t=e.data;gt(s,function(e){t=e.transformResponse(t,null,s)});var r=zt(s);var n=g(t);var i=y(n.children);for(var o=0;o<i.length;o++){var a=i[o];B(V(a,"hx-swap-oob")||"true",a,r)}Ct(r.tasks)})}function $e(e){if(!Y(e)){_(e).webSocket.close();return true}}function Ze(u){var f=h(u,function(e){return _(e).webSocket!=null});if(f){u.addEventListener(ke(u)[0].trigger,function(e){var t=_(f).webSocket;var r=Xt(u,f);var n=Mt(u,"post");var i=n.errors;var o=n.values;var a=Gt(u);var s=Q(o,a);var l=jt(s,u);l["HEADERS"]=r;if(i&&i.length>0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Pe(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ge(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}pt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ke(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Ye(e,o[1])}if(o[0]==="swap"){Qe(e,o[1])}}}function Ye(t,e){var r=U.createEventSource(e);r.onerror=function(e){J(t,"htmx:sseError",{error:e,source:r});tt(t)};_(t).sseEventSource=r}function Qe(o,a){var s=h(o,rt);if(s){var l=_(s).sseEventSource;var u=function(e){if(tt(s)){l.removeEventListener(a,u);return}var t=e.data;gt(o,function(e){t=e.transformResponse(t,null,o)});var r=Ut(o);var n=ne(o);var i=zt(o);we(r.swapStyle,o,n,t,i);Ct(i.tasks);$(o,"htmx:sseMessage",e)};_(o).sseListener=u;l.addEventListener(a,u)}else{J(o,"htmx:noSSESourceError")}}function et(e,t,r,n){var i=h(e,rt);if(i){var o=_(i).sseEventSource;var a=function(){if(!tt(i)){if(Y(e)){Z(t,r,e)}else{o.removeEventListener(n,a)}}};_(e).sseListener=a;o.addEventListener(n,a)}else{J(e,"htmx:noSSESourceError")}}function tt(e){if(!Y(e)){_(e).sseEventSource.close();return true}}function rt(e){return _(e).sseEventSource!=null}function nt(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Z(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function it(o,a,e){var t=false;W(n,function(n){if(s(o,"hx-"+n)){var i=V(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){et(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){ze();_e(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=ee(o,e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){$(o,"intersect");break}}},t);r.observe(o);Be(o,n,i,a,e)}else if(e.trigger==="load"){nt(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Me(o,n,i,e)}else{Be(o,n,i,a,e)}})}});return t}function ot(e){if(e.type==="text/javascript"||e.type==="module"||e.type===""){var t=z().createElement("script");W(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(U.config.inlineScriptNonce){t.nonce=U.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){pt(e)}finally{r.removeChild(e)}}}function at(e){if(d(e,"script")){ot(e)}W(R(e,"script"),function(e){ot(e)})}function st(){return document.querySelector("[hx-boost], [data-hx-boost]")}function lt(e){if(e.querySelectorAll){var t=st()?", a, form":"";var r=e.querySelectorAll(i+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [hx-data-ext]");return r}else{return[]}}function ut(r){var e=function(e){if(d(e.target,"button, input[type='submit']")){var t=_(r);t.lastButtonClicked=e.target}};r.addEventListener("click",e);r.addEventListener("focusin",e);r.addEventListener("focusout",function(e){var t=_(r);t.lastButtonClicked=null})}function ft(e){if(e.closest&&e.closest(U.config.disableSelector)){return}var t=_(e);if(!t.initialized){t.initialized=true;$(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=ke(e);var n=it(e,t,r);if(!n&&G(e,"hx-boost")==="true"){Fe(e,t,r)}if(e.tagName==="FORM"){ut(e)}var i=V(e,"hx-sse");if(i){Ke(e,t,i)}var o=V(e,"hx-ws");if(o){We(e,t,o)}$(e,"htmx:afterProcessNode")}}function ct(e){e=k(e);ft(e);W(lt(e),function(e){ft(e)})}function ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function dt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=z().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function J(e,t,r){$(e,t,Q({error:t},r))}function vt(e){return e==="htmx:afterProcessNode"}function gt(e,t){W(sr(e),function(e){try{t(e)}catch(e){pt(e)}})}function pt(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function $(e,t,r){e=k(e);if(r==null){r={}}r["elt"]=e;var n=dt(t,r);if(U.logger&&!vt(t)){U.logger(e,t,r)}if(r.error){pt(r.error);$(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=ht(t);if(i&&o!==t){var a=dt(o,n.detail);i=i&&e.dispatchEvent(a)}gt(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var mt=location.pathname+location.search;function xt(){var e=z().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||z().body}function yt(e,t,r,n){var i=S(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>U.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(z().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function bt(e){var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function wt(e){var t=U.config.requestClass;var r=e.cloneNode(true);W(R(r,"."+t),function(e){q(e,t)});return r.innerHTML}function St(){var e=xt();var t=mt||location.pathname+location.search;$(z().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(U.config.historyEnabled)history.replaceState({htmx:true},z().title,window.location.href);yt(t,wt(e),z().title,window.scrollY)}function Et(e){if(U.config.historyEnabled)history.pushState({htmx:true},"",e);mt=e}function Ct(e){W(e,function(e){e.call()})}function Rt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};$(z().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){$(z().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=xt();var r=zt(t);me(t,e,r);Ct(r.tasks);mt=n;$(z().body,"htmx:historyRestore",{path:n})}else{J(z().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Ot(e){St();e=e||location.pathname+location.search;var t=bt(e);if(t){var r=g(t.content);var n=xt();var i=zt(n);me(n,r,i);Ct(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);mt=e;$(z().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Rt(e)}}}function Lt(e){var t=G(e,"hx-push-url");return t&&t!=="false"||_(e).boosted&&_(e).pushURL}function qt(e){var t=G(e,"hx-push-url");return t==="true"||t==="false"?null:t}function At(e){var t=F(e,"hx-indicator");if(t==null){t=[e]}W(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Tt(e){W(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function Ht(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Nt(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 kt(t,r,n,e,i){if(e==null||Ht(t,e)){return}else{t.push(e)}if(Nt(e)){var o=f(e,"name");var a=e.value;if(e.multiple){a=y(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=y(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){It(e,n)}}if(d(e,"form")){var l=e.elements;W(l,function(e){kt(t,r,n,e,i)})}}function It(e,t){if(e.willValidate){$(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});$(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Mt(e,t){var r=[];var n={};var i={};var o=[];var a=_(e);var s=d(e,"form")&&e.noValidate!==true;if(a.lastButtonClicked){s=s&&a.lastButtonClicked.formNoValidate!==true}if(t!=="get"){kt(r,i,o,H(e,"form"),s)}kt(r,n,o,e,s);if(a.lastButtonClicked){var l=f(a.lastButtonClicked,"name");if(l){n[l]=a.lastButtonClicked.value}}var u=F(e,"hx-include");W(u,function(e){kt(r,n,o,e,s);if(!d(e,"form")){W(e.querySelectorAll(Ne),function(e){kt(r,n,o,e,s)})}});n=Q(n,i);return{errors:o,values:n}}function Dt(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function Ft(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=Dt(t,r,e)})}else{t=Dt(t,r,n)}}}return t}function Pt(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){W(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Xt(e,t,r){var n={"HX-Request":"true","HX-Trigger":f(e,"id"),"HX-Trigger-Name":f(e,"name"),"HX-Target":V(t,"id"),"HX-Current-URL":z().location.href};Wt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(_(e).boosted){n["HX-Boosted"]="true"}return n}function jt(t,e){var r=G(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){W(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};W(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Bt(e){return f(e,"href")&&f(e,"href").indexOf("#")>=0}function Ut(e,t){var r=t?t:G(e,"hx-swap");var n={swapStyle:_(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(_(e).boosted&&!Bt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var o=1;o<i.length;o++){var a=i[o];if(a.indexOf("swap:")===0){n["swapDelay"]=v(a.substr(5))}if(a.indexOf("settle:")===0){n["settleDelay"]=v(a.substr(7))}if(a.indexOf("scroll:")===0){var s=a.substr(7);var l=s.split(":");var f=l.pop();var u=l.length>0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(a.indexOf("show:")===0){var c=a.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(a.indexOf("focus-scroll:")===0){var d=a.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function Vt(t,r,n){var i=null;gt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(G(r,"hx-encoding")==="multipart/form-data"||d(r,"form")&&f(r,"enctype")==="multipart/form-data"){return Pt(n)}else{return Ft(n)}}}function zt(e){return{tasks:[],elts:[e]}}function _t(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ee(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var o=t.showTarget;if(t.showTarget==="window"){o="body"}i=ee(r,o)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function Wt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}else if(o.indexOf("js:")===0){o=o.substr(3);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Jt(e,function(){return Function("return ("+o+")")()},{})}else{s=S(o)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Wt(u(e),t,r,n)}function Jt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function $t(e,t){return Wt(e,"hx-vars",true,t)}function Zt(e,t){return Wt(e,"hx-vals",false,t)}function Gt(e){return Q($t(e),Zt(e))}function Kt(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Yt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(z().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Qt(e,t){return e.getAllResponseHeaders().match(t)}function er(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return Z(e,t,null,null,{targetOverride:k(r),returnPromise:true})}else{return Z(e,t,k(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:k(r.target),swapOverride:r.swap,returnPromise:true})}}else{return Z(e,t,null,null,{returnPromise:true})}}function tr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Z(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=z().body}var v=r.handler||rr;if(!Y(n)){return}var g=r.targetOverride||ne(n);if(g==null||g==te){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=_(n);var o=G(n,"hx-sync");var m=null;var x=false;if(o){var y=o.split(":");var b=y[0].trim();if(b==="this"){p=re(n,"hx-sync")}else{p=ee(n,b)}o=(y[1]||"drop").trim();i=_(p);if(o==="drop"&&i.xhr&&i.abortable!==true){return}else if(o==="abort"){if(i.xhr){return}else{x=true}}else if(o==="replace"){$(p,"htmx:abort")}else if(o.indexOf("queue")===0){var w=o.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=_(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){Z(e,t,n,f,r)})}return}}var a=new XMLHttpRequest;i.xhr=a;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=G(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){K(c);s();return d}}var R=G(n,"hx-confirm");if(R){if(!confirm(R)){K(c);s();return d}}var O=Xt(n,g,C);if(r.headers){O=Q(O,r.headers)}var L=Mt(n,e);var q=L.errors;var A=L.values;if(r.values){A=Q(A,r.values)}var T=Gt(n);var H=Q(A,T);var N=jt(H,n);if(e!=="get"&&G(n,"hx-encoding")==null){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=z().location.href}var k=Wt(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:q,withCredentials:r.credentials||k.credentials||U.config.withCredentials,timeout:r.timeout||k.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){K(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;q=l.errors;if(q&&q.length>0){$(n,"htmx:validation:halted",l);K(c);s();return d}var I=t.split("#");var M=I[0];var D=I[1];if(e==="get"){var F=M;var P=Object.keys(N).length!==0;if(P){if(F.indexOf("?")<0){F+="?"}else{F+="&"}F+=Ft(N);if(D){F+="#"+D}}a.open("GET",F,true)}else{a.open(e.toUpperCase(),t,true)}a.overrideMimeType("text/html");a.withCredentials=l.withCredentials;a.timeout=l.timeout;if(k.noHeaders){}else{for(var X in O){if(O.hasOwnProperty(X)){var j=O[X];Kt(a,X,j)}}}var u={xhr:a,target:g,requestConfig:l,etc:r,pathInfo:{path:t,finalPath:F,anchor:D}};a.onload=function(){try{var e=tr(n);v(n,u);Tt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!Y(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(Y(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}K(c);s()}catch(e){J(n,"htmx:onLoadError",Q({error:e},u));throw e}};a.onerror=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);K(h);s()};a.onabort=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);K(h);s()};a.ontimeout=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);K(h);s()};if(!$(n,"htmx:beforeRequest",u)){K(c);s();return d}var B=At(n);W(["loadstart","loadend","progress","abort"],function(t){W([a,a.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);a.send(e==="get"?null:Vt(a,n,N));return d}function rr(s,l){var u=l.xhr;var f=l.target;var r=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(Qt(u,/HX-Trigger:/i)){Se(u,"HX-Trigger",s)}if(Qt(u,/HX-Push:/i)){var c=u.getResponseHeader("HX-Push")}if(Qt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Qt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(Qt(u,/HX-Retarget:/i)){l.target=z().querySelector(u.getResponseHeader("HX-Retarget"))}var h;if(c=="false"){h=false}else{h=Lt(s)||c}var n=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var e=u.status>=400;var t=Q({shouldSwap:n,serverResponse:d,isError:e},l);if(!$(f,"htmx:beforeSwap",t))return;f=t.target;d=t.serverResponse;e=t.isError;l.failed=e;l.successful=!e;if(t.shouldSwap){if(u.status===286){Ie(s)}gt(s,function(e){d=e.transformResponse(d,u,s)});if(h){St()}var i=r.swapOverride;var v=Ut(s,i);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=zt(f);we(v.swapStyle,f,s,d,n);if(t.elt&&!Y(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);W(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(l.pathInfo.anchor){location.hash=l.pathInfo.anchor}if(Qt(u,/HX-Trigger-After-Swap:/i)){var o=s;if(!Y(s)){o=z().body}Se(u,"HX-Trigger-After-Swap",o)}var a=function(){W(n.tasks,function(e){e.call()});W(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h){var e=c||qt(s)||Yt(u)||l.pathInfo.finalPath||l.pathInfo.path;Et(e);$(z().body,"htmx:pushedIntoHistory",{path:e})}if(n.title){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}_t(n.elts,v);if(Qt(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!Y(s)){r=z().body}Se(u,"HX-Trigger-After-Settle",r)}};if(v.settleDelay>0){setTimeout(a,v.settleDelay)}else{a()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(v.swapDelay>0){setTimeout(o,v.swapDelay)}else{o()}}if(e){J(s,"htmx:responseError",Q({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var nr={};function ir(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function or(e,t){if(t.init){t.init(r)}nr[e]=Q(ir(),t)}function ar(e){delete nr[e]}function sr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){W(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=nr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return sr(u(e),r,n)}function lr(e){if(z().readyState!=="loading"){e()}else{z().addEventListener("DOMContentLoaded",e)}}function ur(){if(U.config.includeIndicatorStyles!==false){z().head.insertAdjacentHTML("beforeend","<style> ."+U.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+U.config.requestClass+" ."+U.config.indicatorClass+"{opacity:1} ."+U.config.requestClass+"."+U.config.indicatorClass+"{opacity:1} </style>")}}function fr(){var e=z().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function cr(){var e=fr();if(e){U.config=Q(U.config,e)}}lr(function(){cr();ur();var e=z().body;ct(e);var t=z().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=_(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){Ot();W(t,function(e){$(e,"htmx:restored",{document:z(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file From 31fc36b3430d804e835ede2b936df46fef51467e Mon Sep 17 00:00:00 2001 From: Michael Kennedy <mikeckennedy@gmail.com> Date: Wed, 28 Dec 2022 10:31:48 -0800 Subject: [PATCH 06/21] Clean up .idea folder in assorted places. --- .gitignore | 17 +++-------------- .../ch4_final_video_collector/.idea/.gitignore | 8 -------- .../ch4_final_video_collector/.idea/.name | 1 - .../ch5_starter_video_collector/.idea/.name | 1 - .../ch6_final_video_collector/.idea/.name | 1 - .../ch6_starter_video_collector/.idea/.name | 1 - .../ch7_final_video_collector/.idea/.name | 1 - .../ch7_starter_video_collector/.idea/.name | 1 - code/starter_video_collector/.idea/.name | 1 - 9 files changed, 3 insertions(+), 29 deletions(-) delete mode 100644 code/ch4_app/ch4_final_video_collector/.idea/.gitignore delete mode 100644 code/ch4_app/ch4_final_video_collector/.idea/.name delete mode 100644 code/ch5_partials/ch5_starter_video_collector/.idea/.name delete mode 100644 code/ch6_active_search/ch6_final_video_collector/.idea/.name delete mode 100644 code/ch6_active_search/ch6_starter_video_collector/.idea/.name delete mode 100644 code/ch7_infinite_scroll/ch7_final_video_collector/.idea/.name delete mode 100644 code/ch7_infinite_scroll/ch7_starter_video_collector/.idea/.name delete mode 100644 code/starter_video_collector/.idea/.name diff --git a/.gitignore b/.gitignore index a529c48..9960643 100644 --- a/.gitignore +++ b/.gitignore @@ -127,17 +127,6 @@ dmypy.json # Pyre type checker .pyre/ -code/starter_video_collector/.idea/.gitignore -code/starter_video_collector/.idea/misc.xml -code/starter_video_collector/.idea/modules.xml -code/starter_video_collector/.idea/starter_video_collector.iml -code/starter_video_collector/.idea/vcs.xml -code/starter_video_collector/.idea/inspectionProfiles/profiles_settings.xml -code/starter_video_collector/.idea/inspectionProfiles/Project_Default.xml -code/ch4_app/ch4_final_video_collector/.idea/ch4_final_video_collector.iml -code/ch4_app/ch4_final_video_collector/.idea/modules.xml -code/ch4_app/ch4_final_video_collector/.idea/* -code/starter_video_collector/.idea/* -code/ch4_app/ch4_final_video_collector/.idea/* -code/starter_video_collector/.idea/* -code/ch7_infinite_scroll/ch7_final_video_collector/.idea + +# Pycharm project folder +.idea/* diff --git a/code/ch4_app/ch4_final_video_collector/.idea/.gitignore b/code/ch4_app/ch4_final_video_collector/.idea/.gitignore deleted file mode 100644 index 13566b8..0000000 --- a/code/ch4_app/ch4_final_video_collector/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/code/ch4_app/ch4_final_video_collector/.idea/.name b/code/ch4_app/ch4_final_video_collector/.idea/.name deleted file mode 100644 index f50865d..0000000 --- a/code/ch4_app/ch4_final_video_collector/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -HTMX Video Collector [ch4] \ No newline at end of file diff --git a/code/ch5_partials/ch5_starter_video_collector/.idea/.name b/code/ch5_partials/ch5_starter_video_collector/.idea/.name deleted file mode 100644 index 2b6ae51..0000000 --- a/code/ch5_partials/ch5_starter_video_collector/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -HTMX Video Collector [ch5] \ No newline at end of file diff --git a/code/ch6_active_search/ch6_final_video_collector/.idea/.name b/code/ch6_active_search/ch6_final_video_collector/.idea/.name deleted file mode 100644 index c341c0d..0000000 --- a/code/ch6_active_search/ch6_final_video_collector/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -HTMX Video Collector [ch6] \ No newline at end of file diff --git a/code/ch6_active_search/ch6_starter_video_collector/.idea/.name b/code/ch6_active_search/ch6_starter_video_collector/.idea/.name deleted file mode 100644 index c341c0d..0000000 --- a/code/ch6_active_search/ch6_starter_video_collector/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -HTMX Video Collector [ch6] \ No newline at end of file diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/.idea/.name b/code/ch7_infinite_scroll/ch7_final_video_collector/.idea/.name deleted file mode 100644 index edbb527..0000000 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -HTMX Video Collector [ch7] \ No newline at end of file diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/.idea/.name b/code/ch7_infinite_scroll/ch7_starter_video_collector/.idea/.name deleted file mode 100644 index edbb527..0000000 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -HTMX Video Collector [ch7] \ No newline at end of file diff --git a/code/starter_video_collector/.idea/.name b/code/starter_video_collector/.idea/.name deleted file mode 100644 index b25f2ca..0000000 --- a/code/starter_video_collector/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -HTMX Video Collector [starter project] \ No newline at end of file From fbaf0234d8619601bf7a44ed201a5ebdb0ec83dc Mon Sep 17 00:00:00 2001 From: Michael Kennedy <mikeckennedy@gmail.com> Date: Wed, 28 Dec 2022 10:32:14 -0800 Subject: [PATCH 07/21] Use pip-tools to create pinned requirements for each chapter's projects for greater stability. --- .../ch4_final_video_collector/requirements.in | 6 +++ .../requirements.txt | 37 ++++++++++++++--- .../requirements.in | 6 +++ .../requirements.txt | 37 ++++++++++++++--- .../ch5_final_video_collector/requirements.in | 7 ++++ .../requirements.txt | 41 +++++++++++++++---- .../requirements.in | 6 +++ .../requirements.txt | 37 ++++++++++++++--- .../ch6_final_video_collector/requirements.in | 7 ++++ .../requirements.txt | 41 +++++++++++++++---- .../requirements.in | 7 ++++ .../requirements.txt | 41 +++++++++++++++---- .../ch7_final_video_collector/requirements.in | 7 ++++ .../requirements.txt | 41 +++++++++++++++---- .../requirements.in | 7 ++++ .../requirements.txt | 41 +++++++++++++++---- code/starter_video_collector/requirements.in | 6 +++ code/starter_video_collector/requirements.txt | 37 ++++++++++++++--- requirements.txt | 34 +++++++++++++++ 19 files changed, 387 insertions(+), 59 deletions(-) create mode 100644 code/ch4_app/ch4_final_video_collector/requirements.in create mode 100644 code/ch4_app/ch4_starter_video_collector/requirements.in create mode 100644 code/ch5_partials/ch5_final_video_collector/requirements.in create mode 100644 code/ch5_partials/ch5_starter_video_collector/requirements.in create mode 100644 code/ch6_active_search/ch6_final_video_collector/requirements.in create mode 100644 code/ch6_active_search/ch6_starter_video_collector/requirements.in create mode 100644 code/ch7_infinite_scroll/ch7_final_video_collector/requirements.in create mode 100644 code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.in create mode 100644 code/starter_video_collector/requirements.in create mode 100644 requirements.txt diff --git a/code/ch4_app/ch4_final_video_collector/requirements.in b/code/ch4_app/ch4_final_video_collector/requirements.in new file mode 100644 index 0000000..f2e5eba --- /dev/null +++ b/code/ch4_app/ch4_final_video_collector/requirements.in @@ -0,0 +1,6 @@ +flask +Werkzeug +pydantic +more_itertools +MarkupSafe +Jinja2 diff --git a/code/ch4_app/ch4_final_video_collector/requirements.txt b/code/ch4_app/ch4_final_video_collector/requirements.txt index f2e5eba..ed68e16 100644 --- a/code/ch4_app/ch4_final_video_collector/requirements.txt +++ b/code/ch4_app/ch4_final_video_collector/requirements.txt @@ -1,6 +1,31 @@ -flask -Werkzeug -pydantic -more_itertools -MarkupSafe -Jinja2 +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile +# +click==8.1.3 + # via flask +flask==2.2.2 + # via -r requirements.in +itsdangerous==2.1.2 + # via flask +jinja2==3.1.2 + # via + # -r requirements.in + # flask +markupsafe==2.1.1 + # via + # -r requirements.in + # jinja2 + # werkzeug +more-itertools==9.0.0 + # via -r requirements.in +pydantic==1.10.2 + # via -r requirements.in +typing-extensions==4.4.0 + # via pydantic +werkzeug==2.2.2 + # via + # -r requirements.in + # flask diff --git a/code/ch4_app/ch4_starter_video_collector/requirements.in b/code/ch4_app/ch4_starter_video_collector/requirements.in new file mode 100644 index 0000000..f2e5eba --- /dev/null +++ b/code/ch4_app/ch4_starter_video_collector/requirements.in @@ -0,0 +1,6 @@ +flask +Werkzeug +pydantic +more_itertools +MarkupSafe +Jinja2 diff --git a/code/ch4_app/ch4_starter_video_collector/requirements.txt b/code/ch4_app/ch4_starter_video_collector/requirements.txt index f2e5eba..ed68e16 100644 --- a/code/ch4_app/ch4_starter_video_collector/requirements.txt +++ b/code/ch4_app/ch4_starter_video_collector/requirements.txt @@ -1,6 +1,31 @@ -flask -Werkzeug -pydantic -more_itertools -MarkupSafe -Jinja2 +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile +# +click==8.1.3 + # via flask +flask==2.2.2 + # via -r requirements.in +itsdangerous==2.1.2 + # via flask +jinja2==3.1.2 + # via + # -r requirements.in + # flask +markupsafe==2.1.1 + # via + # -r requirements.in + # jinja2 + # werkzeug +more-itertools==9.0.0 + # via -r requirements.in +pydantic==1.10.2 + # via -r requirements.in +typing-extensions==4.4.0 + # via pydantic +werkzeug==2.2.2 + # via + # -r requirements.in + # flask diff --git a/code/ch5_partials/ch5_final_video_collector/requirements.in b/code/ch5_partials/ch5_final_video_collector/requirements.in new file mode 100644 index 0000000..6ec68a8 --- /dev/null +++ b/code/ch5_partials/ch5_final_video_collector/requirements.in @@ -0,0 +1,7 @@ +flask +Werkzeug +pydantic +more_itertools +MarkupSafe +Jinja2 +jinja-partials diff --git a/code/ch5_partials/ch5_final_video_collector/requirements.txt b/code/ch5_partials/ch5_final_video_collector/requirements.txt index 6ec68a8..0cd62ed 100644 --- a/code/ch5_partials/ch5_final_video_collector/requirements.txt +++ b/code/ch5_partials/ch5_final_video_collector/requirements.txt @@ -1,7 +1,34 @@ -flask -Werkzeug -pydantic -more_itertools -MarkupSafe -Jinja2 -jinja-partials +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile +# +click==8.1.3 + # via flask +flask==2.2.2 + # via -r requirements.in +itsdangerous==2.1.2 + # via flask +jinja-partials==0.1.1 + # via -r requirements.in +jinja2==3.1.2 + # via + # -r requirements.in + # flask + # jinja-partials +markupsafe==2.1.1 + # via + # -r requirements.in + # jinja2 + # werkzeug +more-itertools==9.0.0 + # via -r requirements.in +pydantic==1.10.2 + # via -r requirements.in +typing-extensions==4.4.0 + # via pydantic +werkzeug==2.2.2 + # via + # -r requirements.in + # flask diff --git a/code/ch5_partials/ch5_starter_video_collector/requirements.in b/code/ch5_partials/ch5_starter_video_collector/requirements.in new file mode 100644 index 0000000..f2e5eba --- /dev/null +++ b/code/ch5_partials/ch5_starter_video_collector/requirements.in @@ -0,0 +1,6 @@ +flask +Werkzeug +pydantic +more_itertools +MarkupSafe +Jinja2 diff --git a/code/ch5_partials/ch5_starter_video_collector/requirements.txt b/code/ch5_partials/ch5_starter_video_collector/requirements.txt index f2e5eba..ed68e16 100644 --- a/code/ch5_partials/ch5_starter_video_collector/requirements.txt +++ b/code/ch5_partials/ch5_starter_video_collector/requirements.txt @@ -1,6 +1,31 @@ -flask -Werkzeug -pydantic -more_itertools -MarkupSafe -Jinja2 +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile +# +click==8.1.3 + # via flask +flask==2.2.2 + # via -r requirements.in +itsdangerous==2.1.2 + # via flask +jinja2==3.1.2 + # via + # -r requirements.in + # flask +markupsafe==2.1.1 + # via + # -r requirements.in + # jinja2 + # werkzeug +more-itertools==9.0.0 + # via -r requirements.in +pydantic==1.10.2 + # via -r requirements.in +typing-extensions==4.4.0 + # via pydantic +werkzeug==2.2.2 + # via + # -r requirements.in + # flask diff --git a/code/ch6_active_search/ch6_final_video_collector/requirements.in b/code/ch6_active_search/ch6_final_video_collector/requirements.in new file mode 100644 index 0000000..6ec68a8 --- /dev/null +++ b/code/ch6_active_search/ch6_final_video_collector/requirements.in @@ -0,0 +1,7 @@ +flask +Werkzeug +pydantic +more_itertools +MarkupSafe +Jinja2 +jinja-partials diff --git a/code/ch6_active_search/ch6_final_video_collector/requirements.txt b/code/ch6_active_search/ch6_final_video_collector/requirements.txt index 6ec68a8..0cd62ed 100644 --- a/code/ch6_active_search/ch6_final_video_collector/requirements.txt +++ b/code/ch6_active_search/ch6_final_video_collector/requirements.txt @@ -1,7 +1,34 @@ -flask -Werkzeug -pydantic -more_itertools -MarkupSafe -Jinja2 -jinja-partials +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile +# +click==8.1.3 + # via flask +flask==2.2.2 + # via -r requirements.in +itsdangerous==2.1.2 + # via flask +jinja-partials==0.1.1 + # via -r requirements.in +jinja2==3.1.2 + # via + # -r requirements.in + # flask + # jinja-partials +markupsafe==2.1.1 + # via + # -r requirements.in + # jinja2 + # werkzeug +more-itertools==9.0.0 + # via -r requirements.in +pydantic==1.10.2 + # via -r requirements.in +typing-extensions==4.4.0 + # via pydantic +werkzeug==2.2.2 + # via + # -r requirements.in + # flask diff --git a/code/ch6_active_search/ch6_starter_video_collector/requirements.in b/code/ch6_active_search/ch6_starter_video_collector/requirements.in new file mode 100644 index 0000000..6ec68a8 --- /dev/null +++ b/code/ch6_active_search/ch6_starter_video_collector/requirements.in @@ -0,0 +1,7 @@ +flask +Werkzeug +pydantic +more_itertools +MarkupSafe +Jinja2 +jinja-partials diff --git a/code/ch6_active_search/ch6_starter_video_collector/requirements.txt b/code/ch6_active_search/ch6_starter_video_collector/requirements.txt index 6ec68a8..0cd62ed 100644 --- a/code/ch6_active_search/ch6_starter_video_collector/requirements.txt +++ b/code/ch6_active_search/ch6_starter_video_collector/requirements.txt @@ -1,7 +1,34 @@ -flask -Werkzeug -pydantic -more_itertools -MarkupSafe -Jinja2 -jinja-partials +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile +# +click==8.1.3 + # via flask +flask==2.2.2 + # via -r requirements.in +itsdangerous==2.1.2 + # via flask +jinja-partials==0.1.1 + # via -r requirements.in +jinja2==3.1.2 + # via + # -r requirements.in + # flask + # jinja-partials +markupsafe==2.1.1 + # via + # -r requirements.in + # jinja2 + # werkzeug +more-itertools==9.0.0 + # via -r requirements.in +pydantic==1.10.2 + # via -r requirements.in +typing-extensions==4.4.0 + # via pydantic +werkzeug==2.2.2 + # via + # -r requirements.in + # flask diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.in b/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.in new file mode 100644 index 0000000..6ec68a8 --- /dev/null +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.in @@ -0,0 +1,7 @@ +flask +Werkzeug +pydantic +more_itertools +MarkupSafe +Jinja2 +jinja-partials diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt b/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt index 6ec68a8..0cd62ed 100644 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt @@ -1,7 +1,34 @@ -flask -Werkzeug -pydantic -more_itertools -MarkupSafe -Jinja2 -jinja-partials +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile +# +click==8.1.3 + # via flask +flask==2.2.2 + # via -r requirements.in +itsdangerous==2.1.2 + # via flask +jinja-partials==0.1.1 + # via -r requirements.in +jinja2==3.1.2 + # via + # -r requirements.in + # flask + # jinja-partials +markupsafe==2.1.1 + # via + # -r requirements.in + # jinja2 + # werkzeug +more-itertools==9.0.0 + # via -r requirements.in +pydantic==1.10.2 + # via -r requirements.in +typing-extensions==4.4.0 + # via pydantic +werkzeug==2.2.2 + # via + # -r requirements.in + # flask diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.in b/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.in new file mode 100644 index 0000000..6ec68a8 --- /dev/null +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.in @@ -0,0 +1,7 @@ +flask +Werkzeug +pydantic +more_itertools +MarkupSafe +Jinja2 +jinja-partials diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt b/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt index 6ec68a8..0cd62ed 100644 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt @@ -1,7 +1,34 @@ -flask -Werkzeug -pydantic -more_itertools -MarkupSafe -Jinja2 -jinja-partials +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile +# +click==8.1.3 + # via flask +flask==2.2.2 + # via -r requirements.in +itsdangerous==2.1.2 + # via flask +jinja-partials==0.1.1 + # via -r requirements.in +jinja2==3.1.2 + # via + # -r requirements.in + # flask + # jinja-partials +markupsafe==2.1.1 + # via + # -r requirements.in + # jinja2 + # werkzeug +more-itertools==9.0.0 + # via -r requirements.in +pydantic==1.10.2 + # via -r requirements.in +typing-extensions==4.4.0 + # via pydantic +werkzeug==2.2.2 + # via + # -r requirements.in + # flask diff --git a/code/starter_video_collector/requirements.in b/code/starter_video_collector/requirements.in new file mode 100644 index 0000000..f2e5eba --- /dev/null +++ b/code/starter_video_collector/requirements.in @@ -0,0 +1,6 @@ +flask +Werkzeug +pydantic +more_itertools +MarkupSafe +Jinja2 diff --git a/code/starter_video_collector/requirements.txt b/code/starter_video_collector/requirements.txt index f2e5eba..ed68e16 100644 --- a/code/starter_video_collector/requirements.txt +++ b/code/starter_video_collector/requirements.txt @@ -1,6 +1,31 @@ -flask -Werkzeug -pydantic -more_itertools -MarkupSafe -Jinja2 +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile +# +click==8.1.3 + # via flask +flask==2.2.2 + # via -r requirements.in +itsdangerous==2.1.2 + # via flask +jinja2==3.1.2 + # via + # -r requirements.in + # flask +markupsafe==2.1.1 + # via + # -r requirements.in + # jinja2 + # werkzeug +more-itertools==9.0.0 + # via -r requirements.in +pydantic==1.10.2 + # via -r requirements.in +typing-extensions==4.4.0 + # via pydantic +werkzeug==2.2.2 + # via + # -r requirements.in + # flask diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..0cd62ed --- /dev/null +++ b/requirements.txt @@ -0,0 +1,34 @@ +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile +# +click==8.1.3 + # via flask +flask==2.2.2 + # via -r requirements.in +itsdangerous==2.1.2 + # via flask +jinja-partials==0.1.1 + # via -r requirements.in +jinja2==3.1.2 + # via + # -r requirements.in + # flask + # jinja-partials +markupsafe==2.1.1 + # via + # -r requirements.in + # jinja2 + # werkzeug +more-itertools==9.0.0 + # via -r requirements.in +pydantic==1.10.2 + # via -r requirements.in +typing-extensions==4.4.0 + # via pydantic +werkzeug==2.2.2 + # via + # -r requirements.in + # flask From ce9c5bf5caf8a5f907279c7b6718eca8696e4c76 Mon Sep 17 00:00:00 2001 From: Michael Kennedy <mikeckennedy@gmail.com> Date: Thu, 29 Dec 2022 21:06:42 -0800 Subject: [PATCH 08/21] ignore pycharm files --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9960643..6deed5a 100644 --- a/.gitignore +++ b/.gitignore @@ -129,4 +129,5 @@ dmypy.json .pyre/ # Pycharm project folder -.idea/* +.idea/ +.idea From 58c3979d6082a9d2e0d5e88dfd0a73ac9874f936 Mon Sep 17 00:00:00 2001 From: Michael Kennedy <mikeckennedy@gmail.com> Date: Mon, 16 Jan 2023 09:37:31 -0800 Subject: [PATCH 09/21] Fix bug which didn't (or always) transforms the form dictionary in request dict. Fixes #4 --- .../infrastructure/request_dict.py | 10 +++++----- .../infrastructure/request_dict.py | 10 +++++----- .../infrastructure/request_dict.py | 10 +++++----- .../infrastructure/request_dict.py | 10 +++++----- .../infrastructure/request_dict.py | 10 +++++----- .../infrastructure/request_dict.py | 10 +++++----- .../infrastructure/request_dict.py | 10 +++++----- .../ch7_final_video_collector/requirements.txt | 8 ++++---- .../infrastructure/request_dict.py | 10 +++++----- .../infrastructure/request_dict.py | 10 +++++----- 10 files changed, 49 insertions(+), 49 deletions(-) diff --git a/code/ch4_app/ch4_final_video_collector/infrastructure/request_dict.py b/code/ch4_app/ch4_final_video_collector/infrastructure/request_dict.py index d7ab10d..4098c1b 100644 --- a/code/ch4_app/ch4_final_video_collector/infrastructure/request_dict.py +++ b/code/ch4_app/ch4_final_video_collector/infrastructure/request_dict.py @@ -14,16 +14,16 @@ def __getattr__(self, key): def create(default_val=None, **route_args) -> RequestDictionary: request = flask.request - # Adding this retro actively. Some folks are experiencing issues where they + # Adding this retroactively. Some folks are experiencing issues where they # are getting a list rather than plain dict. I think it's from multiple # entries in the multidict. This should fix it. args = request.args - if isinstance(request.args, MultiDict): - args = request.args.to_dict() + if isinstance(args, MultiDict): + args = args.to_dict() form = request.form - if isinstance(request.args, MultiDict): - form = request.form.to_dict() + if isinstance(form, MultiDict): + form = form.to_dict() data = { **args, # The key/value pairs in the URL query string diff --git a/code/ch4_app/ch4_starter_video_collector/infrastructure/request_dict.py b/code/ch4_app/ch4_starter_video_collector/infrastructure/request_dict.py index d7ab10d..4098c1b 100644 --- a/code/ch4_app/ch4_starter_video_collector/infrastructure/request_dict.py +++ b/code/ch4_app/ch4_starter_video_collector/infrastructure/request_dict.py @@ -14,16 +14,16 @@ def __getattr__(self, key): def create(default_val=None, **route_args) -> RequestDictionary: request = flask.request - # Adding this retro actively. Some folks are experiencing issues where they + # Adding this retroactively. Some folks are experiencing issues where they # are getting a list rather than plain dict. I think it's from multiple # entries in the multidict. This should fix it. args = request.args - if isinstance(request.args, MultiDict): - args = request.args.to_dict() + if isinstance(args, MultiDict): + args = args.to_dict() form = request.form - if isinstance(request.args, MultiDict): - form = request.form.to_dict() + if isinstance(form, MultiDict): + form = form.to_dict() data = { **args, # The key/value pairs in the URL query string diff --git a/code/ch5_partials/ch5_final_video_collector/infrastructure/request_dict.py b/code/ch5_partials/ch5_final_video_collector/infrastructure/request_dict.py index d7ab10d..4098c1b 100644 --- a/code/ch5_partials/ch5_final_video_collector/infrastructure/request_dict.py +++ b/code/ch5_partials/ch5_final_video_collector/infrastructure/request_dict.py @@ -14,16 +14,16 @@ def __getattr__(self, key): def create(default_val=None, **route_args) -> RequestDictionary: request = flask.request - # Adding this retro actively. Some folks are experiencing issues where they + # Adding this retroactively. Some folks are experiencing issues where they # are getting a list rather than plain dict. I think it's from multiple # entries in the multidict. This should fix it. args = request.args - if isinstance(request.args, MultiDict): - args = request.args.to_dict() + if isinstance(args, MultiDict): + args = args.to_dict() form = request.form - if isinstance(request.args, MultiDict): - form = request.form.to_dict() + if isinstance(form, MultiDict): + form = form.to_dict() data = { **args, # The key/value pairs in the URL query string diff --git a/code/ch5_partials/ch5_starter_video_collector/infrastructure/request_dict.py b/code/ch5_partials/ch5_starter_video_collector/infrastructure/request_dict.py index d7ab10d..4098c1b 100644 --- a/code/ch5_partials/ch5_starter_video_collector/infrastructure/request_dict.py +++ b/code/ch5_partials/ch5_starter_video_collector/infrastructure/request_dict.py @@ -14,16 +14,16 @@ def __getattr__(self, key): def create(default_val=None, **route_args) -> RequestDictionary: request = flask.request - # Adding this retro actively. Some folks are experiencing issues where they + # Adding this retroactively. Some folks are experiencing issues where they # are getting a list rather than plain dict. I think it's from multiple # entries in the multidict. This should fix it. args = request.args - if isinstance(request.args, MultiDict): - args = request.args.to_dict() + if isinstance(args, MultiDict): + args = args.to_dict() form = request.form - if isinstance(request.args, MultiDict): - form = request.form.to_dict() + if isinstance(form, MultiDict): + form = form.to_dict() data = { **args, # The key/value pairs in the URL query string diff --git a/code/ch6_active_search/ch6_final_video_collector/infrastructure/request_dict.py b/code/ch6_active_search/ch6_final_video_collector/infrastructure/request_dict.py index d7ab10d..4098c1b 100644 --- a/code/ch6_active_search/ch6_final_video_collector/infrastructure/request_dict.py +++ b/code/ch6_active_search/ch6_final_video_collector/infrastructure/request_dict.py @@ -14,16 +14,16 @@ def __getattr__(self, key): def create(default_val=None, **route_args) -> RequestDictionary: request = flask.request - # Adding this retro actively. Some folks are experiencing issues where they + # Adding this retroactively. Some folks are experiencing issues where they # are getting a list rather than plain dict. I think it's from multiple # entries in the multidict. This should fix it. args = request.args - if isinstance(request.args, MultiDict): - args = request.args.to_dict() + if isinstance(args, MultiDict): + args = args.to_dict() form = request.form - if isinstance(request.args, MultiDict): - form = request.form.to_dict() + if isinstance(form, MultiDict): + form = form.to_dict() data = { **args, # The key/value pairs in the URL query string diff --git a/code/ch6_active_search/ch6_starter_video_collector/infrastructure/request_dict.py b/code/ch6_active_search/ch6_starter_video_collector/infrastructure/request_dict.py index d7ab10d..4098c1b 100644 --- a/code/ch6_active_search/ch6_starter_video_collector/infrastructure/request_dict.py +++ b/code/ch6_active_search/ch6_starter_video_collector/infrastructure/request_dict.py @@ -14,16 +14,16 @@ def __getattr__(self, key): def create(default_val=None, **route_args) -> RequestDictionary: request = flask.request - # Adding this retro actively. Some folks are experiencing issues where they + # Adding this retroactively. Some folks are experiencing issues where they # are getting a list rather than plain dict. I think it's from multiple # entries in the multidict. This should fix it. args = request.args - if isinstance(request.args, MultiDict): - args = request.args.to_dict() + if isinstance(args, MultiDict): + args = args.to_dict() form = request.form - if isinstance(request.args, MultiDict): - form = request.form.to_dict() + if isinstance(form, MultiDict): + form = form.to_dict() data = { **args, # The key/value pairs in the URL query string diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/infrastructure/request_dict.py b/code/ch7_infinite_scroll/ch7_final_video_collector/infrastructure/request_dict.py index d7ab10d..4098c1b 100644 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/infrastructure/request_dict.py +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/infrastructure/request_dict.py @@ -14,16 +14,16 @@ def __getattr__(self, key): def create(default_val=None, **route_args) -> RequestDictionary: request = flask.request - # Adding this retro actively. Some folks are experiencing issues where they + # Adding this retroactively. Some folks are experiencing issues where they # are getting a list rather than plain dict. I think it's from multiple # entries in the multidict. This should fix it. args = request.args - if isinstance(request.args, MultiDict): - args = request.args.to_dict() + if isinstance(args, MultiDict): + args = args.to_dict() form = request.form - if isinstance(request.args, MultiDict): - form = request.form.to_dict() + if isinstance(form, MultiDict): + form = form.to_dict() data = { **args, # The key/value pairs in the URL query string diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt b/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt index 0cd62ed..acac8f1 100644 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt @@ -1,8 +1,8 @@ # -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: +# This file is autogenerated by pip-compile with python 3.10 +# To update, run: # -# pip-compile +# pip-compile requirements.in # click==8.1.3 # via flask @@ -24,7 +24,7 @@ markupsafe==2.1.1 # werkzeug more-itertools==9.0.0 # via -r requirements.in -pydantic==1.10.2 +pydantic==1.10.4 # via -r requirements.in typing-extensions==4.4.0 # via pydantic diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/infrastructure/request_dict.py b/code/ch7_infinite_scroll/ch7_starter_video_collector/infrastructure/request_dict.py index d7ab10d..4098c1b 100644 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/infrastructure/request_dict.py +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/infrastructure/request_dict.py @@ -14,16 +14,16 @@ def __getattr__(self, key): def create(default_val=None, **route_args) -> RequestDictionary: request = flask.request - # Adding this retro actively. Some folks are experiencing issues where they + # Adding this retroactively. Some folks are experiencing issues where they # are getting a list rather than plain dict. I think it's from multiple # entries in the multidict. This should fix it. args = request.args - if isinstance(request.args, MultiDict): - args = request.args.to_dict() + if isinstance(args, MultiDict): + args = args.to_dict() form = request.form - if isinstance(request.args, MultiDict): - form = request.form.to_dict() + if isinstance(form, MultiDict): + form = form.to_dict() data = { **args, # The key/value pairs in the URL query string diff --git a/code/starter_video_collector/infrastructure/request_dict.py b/code/starter_video_collector/infrastructure/request_dict.py index d7ab10d..4098c1b 100644 --- a/code/starter_video_collector/infrastructure/request_dict.py +++ b/code/starter_video_collector/infrastructure/request_dict.py @@ -14,16 +14,16 @@ def __getattr__(self, key): def create(default_val=None, **route_args) -> RequestDictionary: request = flask.request - # Adding this retro actively. Some folks are experiencing issues where they + # Adding this retroactively. Some folks are experiencing issues where they # are getting a list rather than plain dict. I think it's from multiple # entries in the multidict. This should fix it. args = request.args - if isinstance(request.args, MultiDict): - args = request.args.to_dict() + if isinstance(args, MultiDict): + args = args.to_dict() form = request.form - if isinstance(request.args, MultiDict): - form = request.form.to_dict() + if isinstance(form, MultiDict): + form = form.to_dict() data = { **args, # The key/value pairs in the URL query string From 93bd13acad177804e14e38dca01297ca44f3be8f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Feb 2023 18:08:07 +0000 Subject: [PATCH 10/21] Bump werkzeug in /code/ch7_infinite_scroll/ch7_starter_video_collector Bumps [werkzeug](https://github.com/pallets/werkzeug) from 2.2.2 to 2.2.3. - [Release notes](https://github.com/pallets/werkzeug/releases) - [Changelog](https://github.com/pallets/werkzeug/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/werkzeug/compare/2.2.2...2.2.3) --- updated-dependencies: - dependency-name: werkzeug dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> --- .../ch7_starter_video_collector/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt b/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt index 0cd62ed..0763adc 100644 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt @@ -28,7 +28,7 @@ pydantic==1.10.2 # via -r requirements.in typing-extensions==4.4.0 # via pydantic -werkzeug==2.2.2 +werkzeug==2.2.3 # via # -r requirements.in # flask From b83af1fc74b148969f624ecc8360ce455d02c3b5 Mon Sep 17 00:00:00 2001 From: Michael Kennedy <mikeckennedy@gmail.com> Date: Fri, 24 Feb 2023 10:10:54 -0800 Subject: [PATCH 11/21] bump dependencies (werkzeug had an issue). --- .../ch7_final_video_collector/requirements.txt | 14 +++++++------- .../ch7_starter_video_collector/requirements.txt | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt b/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt index acac8f1..366e3db 100644 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt @@ -1,12 +1,12 @@ # -# This file is autogenerated by pip-compile with python 3.10 -# To update, run: +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: # # pip-compile requirements.in # click==8.1.3 # via flask -flask==2.2.2 +flask==2.2.3 # via -r requirements.in itsdangerous==2.1.2 # via flask @@ -17,18 +17,18 @@ jinja2==3.1.2 # -r requirements.in # flask # jinja-partials -markupsafe==2.1.1 +markupsafe==2.1.2 # via # -r requirements.in # jinja2 # werkzeug more-itertools==9.0.0 # via -r requirements.in -pydantic==1.10.4 +pydantic==1.10.5 # via -r requirements.in -typing-extensions==4.4.0 +typing-extensions==4.5.0 # via pydantic -werkzeug==2.2.2 +werkzeug==2.2.3 # via # -r requirements.in # flask diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt b/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt index 0cd62ed..366e3db 100644 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt @@ -2,11 +2,11 @@ # This file is autogenerated by pip-compile with Python 3.11 # by the following command: # -# pip-compile +# pip-compile requirements.in # click==8.1.3 # via flask -flask==2.2.2 +flask==2.2.3 # via -r requirements.in itsdangerous==2.1.2 # via flask @@ -17,18 +17,18 @@ jinja2==3.1.2 # -r requirements.in # flask # jinja-partials -markupsafe==2.1.1 +markupsafe==2.1.2 # via # -r requirements.in # jinja2 # werkzeug more-itertools==9.0.0 # via -r requirements.in -pydantic==1.10.2 +pydantic==1.10.5 # via -r requirements.in -typing-extensions==4.4.0 +typing-extensions==4.5.0 # via pydantic -werkzeug==2.2.2 +werkzeug==2.2.3 # via # -r requirements.in # flask From 8ff7f65d916f6b8d2453f94d103a31cf2824ba01 Mon Sep 17 00:00:00 2001 From: Michael Kennedy <mikeckennedy@gmail.com> Date: Fri, 24 Feb 2023 10:13:52 -0800 Subject: [PATCH 12/21] Bump a few versions due to minor security issues. --- .../ch4_final_video_collector/requirements.txt | 12 ++++++------ .../ch4_starter_video_collector/requirements.txt | 12 ++++++------ .../ch5_final_video_collector/requirements.txt | 12 ++++++------ .../ch5_starter_video_collector/requirements.txt | 12 ++++++------ .../ch6_final_video_collector/requirements.txt | 12 ++++++------ .../ch6_starter_video_collector/requirements.txt | 12 ++++++------ code/starter_video_collector/requirements.txt | 12 ++++++------ 7 files changed, 42 insertions(+), 42 deletions(-) diff --git a/code/ch4_app/ch4_final_video_collector/requirements.txt b/code/ch4_app/ch4_final_video_collector/requirements.txt index ed68e16..112b1af 100644 --- a/code/ch4_app/ch4_final_video_collector/requirements.txt +++ b/code/ch4_app/ch4_final_video_collector/requirements.txt @@ -2,11 +2,11 @@ # This file is autogenerated by pip-compile with Python 3.11 # by the following command: # -# pip-compile +# pip-compile requirements.in # click==8.1.3 # via flask -flask==2.2.2 +flask==2.2.3 # via -r requirements.in itsdangerous==2.1.2 # via flask @@ -14,18 +14,18 @@ jinja2==3.1.2 # via # -r requirements.in # flask -markupsafe==2.1.1 +markupsafe==2.1.2 # via # -r requirements.in # jinja2 # werkzeug more-itertools==9.0.0 # via -r requirements.in -pydantic==1.10.2 +pydantic==1.10.5 # via -r requirements.in -typing-extensions==4.4.0 +typing-extensions==4.5.0 # via pydantic -werkzeug==2.2.2 +werkzeug==2.2.3 # via # -r requirements.in # flask diff --git a/code/ch4_app/ch4_starter_video_collector/requirements.txt b/code/ch4_app/ch4_starter_video_collector/requirements.txt index ed68e16..112b1af 100644 --- a/code/ch4_app/ch4_starter_video_collector/requirements.txt +++ b/code/ch4_app/ch4_starter_video_collector/requirements.txt @@ -2,11 +2,11 @@ # This file is autogenerated by pip-compile with Python 3.11 # by the following command: # -# pip-compile +# pip-compile requirements.in # click==8.1.3 # via flask -flask==2.2.2 +flask==2.2.3 # via -r requirements.in itsdangerous==2.1.2 # via flask @@ -14,18 +14,18 @@ jinja2==3.1.2 # via # -r requirements.in # flask -markupsafe==2.1.1 +markupsafe==2.1.2 # via # -r requirements.in # jinja2 # werkzeug more-itertools==9.0.0 # via -r requirements.in -pydantic==1.10.2 +pydantic==1.10.5 # via -r requirements.in -typing-extensions==4.4.0 +typing-extensions==4.5.0 # via pydantic -werkzeug==2.2.2 +werkzeug==2.2.3 # via # -r requirements.in # flask diff --git a/code/ch5_partials/ch5_final_video_collector/requirements.txt b/code/ch5_partials/ch5_final_video_collector/requirements.txt index 0cd62ed..366e3db 100644 --- a/code/ch5_partials/ch5_final_video_collector/requirements.txt +++ b/code/ch5_partials/ch5_final_video_collector/requirements.txt @@ -2,11 +2,11 @@ # This file is autogenerated by pip-compile with Python 3.11 # by the following command: # -# pip-compile +# pip-compile requirements.in # click==8.1.3 # via flask -flask==2.2.2 +flask==2.2.3 # via -r requirements.in itsdangerous==2.1.2 # via flask @@ -17,18 +17,18 @@ jinja2==3.1.2 # -r requirements.in # flask # jinja-partials -markupsafe==2.1.1 +markupsafe==2.1.2 # via # -r requirements.in # jinja2 # werkzeug more-itertools==9.0.0 # via -r requirements.in -pydantic==1.10.2 +pydantic==1.10.5 # via -r requirements.in -typing-extensions==4.4.0 +typing-extensions==4.5.0 # via pydantic -werkzeug==2.2.2 +werkzeug==2.2.3 # via # -r requirements.in # flask diff --git a/code/ch5_partials/ch5_starter_video_collector/requirements.txt b/code/ch5_partials/ch5_starter_video_collector/requirements.txt index ed68e16..112b1af 100644 --- a/code/ch5_partials/ch5_starter_video_collector/requirements.txt +++ b/code/ch5_partials/ch5_starter_video_collector/requirements.txt @@ -2,11 +2,11 @@ # This file is autogenerated by pip-compile with Python 3.11 # by the following command: # -# pip-compile +# pip-compile requirements.in # click==8.1.3 # via flask -flask==2.2.2 +flask==2.2.3 # via -r requirements.in itsdangerous==2.1.2 # via flask @@ -14,18 +14,18 @@ jinja2==3.1.2 # via # -r requirements.in # flask -markupsafe==2.1.1 +markupsafe==2.1.2 # via # -r requirements.in # jinja2 # werkzeug more-itertools==9.0.0 # via -r requirements.in -pydantic==1.10.2 +pydantic==1.10.5 # via -r requirements.in -typing-extensions==4.4.0 +typing-extensions==4.5.0 # via pydantic -werkzeug==2.2.2 +werkzeug==2.2.3 # via # -r requirements.in # flask diff --git a/code/ch6_active_search/ch6_final_video_collector/requirements.txt b/code/ch6_active_search/ch6_final_video_collector/requirements.txt index 0cd62ed..366e3db 100644 --- a/code/ch6_active_search/ch6_final_video_collector/requirements.txt +++ b/code/ch6_active_search/ch6_final_video_collector/requirements.txt @@ -2,11 +2,11 @@ # This file is autogenerated by pip-compile with Python 3.11 # by the following command: # -# pip-compile +# pip-compile requirements.in # click==8.1.3 # via flask -flask==2.2.2 +flask==2.2.3 # via -r requirements.in itsdangerous==2.1.2 # via flask @@ -17,18 +17,18 @@ jinja2==3.1.2 # -r requirements.in # flask # jinja-partials -markupsafe==2.1.1 +markupsafe==2.1.2 # via # -r requirements.in # jinja2 # werkzeug more-itertools==9.0.0 # via -r requirements.in -pydantic==1.10.2 +pydantic==1.10.5 # via -r requirements.in -typing-extensions==4.4.0 +typing-extensions==4.5.0 # via pydantic -werkzeug==2.2.2 +werkzeug==2.2.3 # via # -r requirements.in # flask diff --git a/code/ch6_active_search/ch6_starter_video_collector/requirements.txt b/code/ch6_active_search/ch6_starter_video_collector/requirements.txt index 0cd62ed..366e3db 100644 --- a/code/ch6_active_search/ch6_starter_video_collector/requirements.txt +++ b/code/ch6_active_search/ch6_starter_video_collector/requirements.txt @@ -2,11 +2,11 @@ # This file is autogenerated by pip-compile with Python 3.11 # by the following command: # -# pip-compile +# pip-compile requirements.in # click==8.1.3 # via flask -flask==2.2.2 +flask==2.2.3 # via -r requirements.in itsdangerous==2.1.2 # via flask @@ -17,18 +17,18 @@ jinja2==3.1.2 # -r requirements.in # flask # jinja-partials -markupsafe==2.1.1 +markupsafe==2.1.2 # via # -r requirements.in # jinja2 # werkzeug more-itertools==9.0.0 # via -r requirements.in -pydantic==1.10.2 +pydantic==1.10.5 # via -r requirements.in -typing-extensions==4.4.0 +typing-extensions==4.5.0 # via pydantic -werkzeug==2.2.2 +werkzeug==2.2.3 # via # -r requirements.in # flask diff --git a/code/starter_video_collector/requirements.txt b/code/starter_video_collector/requirements.txt index ed68e16..112b1af 100644 --- a/code/starter_video_collector/requirements.txt +++ b/code/starter_video_collector/requirements.txt @@ -2,11 +2,11 @@ # This file is autogenerated by pip-compile with Python 3.11 # by the following command: # -# pip-compile +# pip-compile requirements.in # click==8.1.3 # via flask -flask==2.2.2 +flask==2.2.3 # via -r requirements.in itsdangerous==2.1.2 # via flask @@ -14,18 +14,18 @@ jinja2==3.1.2 # via # -r requirements.in # flask -markupsafe==2.1.1 +markupsafe==2.1.2 # via # -r requirements.in # jinja2 # werkzeug more-itertools==9.0.0 # via -r requirements.in -pydantic==1.10.2 +pydantic==1.10.5 # via -r requirements.in -typing-extensions==4.4.0 +typing-extensions==4.5.0 # via pydantic -werkzeug==2.2.2 +werkzeug==2.2.3 # via # -r requirements.in # flask From 5111f233b8172125f04661df087ccd03afa8a024 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Feb 2023 18:15:17 +0000 Subject: [PATCH 13/21] Bump werkzeug from 2.2.2 to 2.2.3 Bumps [werkzeug](https://github.com/pallets/werkzeug) from 2.2.2 to 2.2.3. - [Release notes](https://github.com/pallets/werkzeug/releases) - [Changelog](https://github.com/pallets/werkzeug/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/werkzeug/compare/2.2.2...2.2.3) --- updated-dependencies: - dependency-name: werkzeug dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 0cd62ed..0763adc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,7 +28,7 @@ pydantic==1.10.2 # via -r requirements.in typing-extensions==4.4.0 # via pydantic -werkzeug==2.2.2 +werkzeug==2.2.3 # via # -r requirements.in # flask From d9cc19e8d898787cbbfa4b820339708a8350f923 Mon Sep 17 00:00:00 2001 From: Michael Kennedy <michael@talkpython.fm> Date: Mon, 28 Aug 2023 09:17:53 -0700 Subject: [PATCH 14/21] Upgrade to be compatible with Pydantic v2. --- .../models/video_model.py | 2 +- .../requirements.txt | 22 ++++++++++------ .../models/video_model.py | 2 +- .../requirements.txt | 22 ++++++++++------ .../models/video_model.py | 2 +- .../requirements.txt | 22 ++++++++++------ .../models/video_model.py | 2 +- .../requirements.txt | 22 ++++++++++------ .../models/video_model.py | 2 +- .../requirements.txt | 22 ++++++++++------ .../models/video_model.py | 2 +- .../requirements.txt | 22 ++++++++++------ .../models/video_model.py | 2 +- .../requirements.txt | 22 ++++++++++------ .../models/video_model.py | 2 +- .../requirements.txt | 22 ++++++++++------ .../models/video_model.py | 2 +- code/starter_video_collector/requirements.txt | 25 +++++++++++++------ requirements.in | 7 ++++++ requirements.txt | 24 ++++++++++++------ 20 files changed, 170 insertions(+), 80 deletions(-) create mode 100644 requirements.in diff --git a/code/ch4_app/ch4_final_video_collector/models/video_model.py b/code/ch4_app/ch4_final_video_collector/models/video_model.py index 4de5b4e..25908c0 100644 --- a/code/ch4_app/ch4_final_video_collector/models/video_model.py +++ b/code/ch4_app/ch4_final_video_collector/models/video_model.py @@ -9,4 +9,4 @@ class Video(BaseModel): url: str author: str views: int - category: Optional[str] + category: Optional[str] = None diff --git a/code/ch4_app/ch4_final_video_collector/requirements.txt b/code/ch4_app/ch4_final_video_collector/requirements.txt index 112b1af..71e7465 100644 --- a/code/ch4_app/ch4_final_video_collector/requirements.txt +++ b/code/ch4_app/ch4_final_video_collector/requirements.txt @@ -4,9 +4,13 @@ # # pip-compile requirements.in # -click==8.1.3 +annotated-types==0.5.0 + # via pydantic +blinker==1.6.2 + # via flask +click==8.1.7 # via flask -flask==2.2.3 +flask==2.3.3 # via -r requirements.in itsdangerous==2.1.2 # via flask @@ -14,18 +18,22 @@ jinja2==3.1.2 # via # -r requirements.in # flask -markupsafe==2.1.2 +markupsafe==2.1.3 # via # -r requirements.in # jinja2 # werkzeug -more-itertools==9.0.0 +more-itertools==10.1.0 # via -r requirements.in -pydantic==1.10.5 +pydantic==2.3.0 # via -r requirements.in -typing-extensions==4.5.0 +pydantic-core==2.6.3 # via pydantic -werkzeug==2.2.3 +typing-extensions==4.7.1 + # via + # pydantic + # pydantic-core +werkzeug==2.3.7 # via # -r requirements.in # flask diff --git a/code/ch4_app/ch4_starter_video_collector/models/video_model.py b/code/ch4_app/ch4_starter_video_collector/models/video_model.py index 4de5b4e..25908c0 100644 --- a/code/ch4_app/ch4_starter_video_collector/models/video_model.py +++ b/code/ch4_app/ch4_starter_video_collector/models/video_model.py @@ -9,4 +9,4 @@ class Video(BaseModel): url: str author: str views: int - category: Optional[str] + category: Optional[str] = None diff --git a/code/ch4_app/ch4_starter_video_collector/requirements.txt b/code/ch4_app/ch4_starter_video_collector/requirements.txt index 112b1af..71e7465 100644 --- a/code/ch4_app/ch4_starter_video_collector/requirements.txt +++ b/code/ch4_app/ch4_starter_video_collector/requirements.txt @@ -4,9 +4,13 @@ # # pip-compile requirements.in # -click==8.1.3 +annotated-types==0.5.0 + # via pydantic +blinker==1.6.2 + # via flask +click==8.1.7 # via flask -flask==2.2.3 +flask==2.3.3 # via -r requirements.in itsdangerous==2.1.2 # via flask @@ -14,18 +18,22 @@ jinja2==3.1.2 # via # -r requirements.in # flask -markupsafe==2.1.2 +markupsafe==2.1.3 # via # -r requirements.in # jinja2 # werkzeug -more-itertools==9.0.0 +more-itertools==10.1.0 # via -r requirements.in -pydantic==1.10.5 +pydantic==2.3.0 # via -r requirements.in -typing-extensions==4.5.0 +pydantic-core==2.6.3 # via pydantic -werkzeug==2.2.3 +typing-extensions==4.7.1 + # via + # pydantic + # pydantic-core +werkzeug==2.3.7 # via # -r requirements.in # flask diff --git a/code/ch5_partials/ch5_final_video_collector/models/video_model.py b/code/ch5_partials/ch5_final_video_collector/models/video_model.py index 4de5b4e..25908c0 100644 --- a/code/ch5_partials/ch5_final_video_collector/models/video_model.py +++ b/code/ch5_partials/ch5_final_video_collector/models/video_model.py @@ -9,4 +9,4 @@ class Video(BaseModel): url: str author: str views: int - category: Optional[str] + category: Optional[str] = None diff --git a/code/ch5_partials/ch5_final_video_collector/requirements.txt b/code/ch5_partials/ch5_final_video_collector/requirements.txt index 366e3db..f636e74 100644 --- a/code/ch5_partials/ch5_final_video_collector/requirements.txt +++ b/code/ch5_partials/ch5_final_video_collector/requirements.txt @@ -4,9 +4,13 @@ # # pip-compile requirements.in # -click==8.1.3 +annotated-types==0.5.0 + # via pydantic +blinker==1.6.2 + # via flask +click==8.1.7 # via flask -flask==2.2.3 +flask==2.3.3 # via -r requirements.in itsdangerous==2.1.2 # via flask @@ -17,18 +21,22 @@ jinja2==3.1.2 # -r requirements.in # flask # jinja-partials -markupsafe==2.1.2 +markupsafe==2.1.3 # via # -r requirements.in # jinja2 # werkzeug -more-itertools==9.0.0 +more-itertools==10.1.0 # via -r requirements.in -pydantic==1.10.5 +pydantic==2.3.0 # via -r requirements.in -typing-extensions==4.5.0 +pydantic-core==2.6.3 # via pydantic -werkzeug==2.2.3 +typing-extensions==4.7.1 + # via + # pydantic + # pydantic-core +werkzeug==2.3.7 # via # -r requirements.in # flask diff --git a/code/ch5_partials/ch5_starter_video_collector/models/video_model.py b/code/ch5_partials/ch5_starter_video_collector/models/video_model.py index 4de5b4e..25908c0 100644 --- a/code/ch5_partials/ch5_starter_video_collector/models/video_model.py +++ b/code/ch5_partials/ch5_starter_video_collector/models/video_model.py @@ -9,4 +9,4 @@ class Video(BaseModel): url: str author: str views: int - category: Optional[str] + category: Optional[str] = None diff --git a/code/ch5_partials/ch5_starter_video_collector/requirements.txt b/code/ch5_partials/ch5_starter_video_collector/requirements.txt index 112b1af..71e7465 100644 --- a/code/ch5_partials/ch5_starter_video_collector/requirements.txt +++ b/code/ch5_partials/ch5_starter_video_collector/requirements.txt @@ -4,9 +4,13 @@ # # pip-compile requirements.in # -click==8.1.3 +annotated-types==0.5.0 + # via pydantic +blinker==1.6.2 + # via flask +click==8.1.7 # via flask -flask==2.2.3 +flask==2.3.3 # via -r requirements.in itsdangerous==2.1.2 # via flask @@ -14,18 +18,22 @@ jinja2==3.1.2 # via # -r requirements.in # flask -markupsafe==2.1.2 +markupsafe==2.1.3 # via # -r requirements.in # jinja2 # werkzeug -more-itertools==9.0.0 +more-itertools==10.1.0 # via -r requirements.in -pydantic==1.10.5 +pydantic==2.3.0 # via -r requirements.in -typing-extensions==4.5.0 +pydantic-core==2.6.3 # via pydantic -werkzeug==2.2.3 +typing-extensions==4.7.1 + # via + # pydantic + # pydantic-core +werkzeug==2.3.7 # via # -r requirements.in # flask diff --git a/code/ch6_active_search/ch6_final_video_collector/models/video_model.py b/code/ch6_active_search/ch6_final_video_collector/models/video_model.py index 4de5b4e..25908c0 100644 --- a/code/ch6_active_search/ch6_final_video_collector/models/video_model.py +++ b/code/ch6_active_search/ch6_final_video_collector/models/video_model.py @@ -9,4 +9,4 @@ class Video(BaseModel): url: str author: str views: int - category: Optional[str] + category: Optional[str] = None diff --git a/code/ch6_active_search/ch6_final_video_collector/requirements.txt b/code/ch6_active_search/ch6_final_video_collector/requirements.txt index 366e3db..f636e74 100644 --- a/code/ch6_active_search/ch6_final_video_collector/requirements.txt +++ b/code/ch6_active_search/ch6_final_video_collector/requirements.txt @@ -4,9 +4,13 @@ # # pip-compile requirements.in # -click==8.1.3 +annotated-types==0.5.0 + # via pydantic +blinker==1.6.2 + # via flask +click==8.1.7 # via flask -flask==2.2.3 +flask==2.3.3 # via -r requirements.in itsdangerous==2.1.2 # via flask @@ -17,18 +21,22 @@ jinja2==3.1.2 # -r requirements.in # flask # jinja-partials -markupsafe==2.1.2 +markupsafe==2.1.3 # via # -r requirements.in # jinja2 # werkzeug -more-itertools==9.0.0 +more-itertools==10.1.0 # via -r requirements.in -pydantic==1.10.5 +pydantic==2.3.0 # via -r requirements.in -typing-extensions==4.5.0 +pydantic-core==2.6.3 # via pydantic -werkzeug==2.2.3 +typing-extensions==4.7.1 + # via + # pydantic + # pydantic-core +werkzeug==2.3.7 # via # -r requirements.in # flask diff --git a/code/ch6_active_search/ch6_starter_video_collector/models/video_model.py b/code/ch6_active_search/ch6_starter_video_collector/models/video_model.py index 4de5b4e..25908c0 100644 --- a/code/ch6_active_search/ch6_starter_video_collector/models/video_model.py +++ b/code/ch6_active_search/ch6_starter_video_collector/models/video_model.py @@ -9,4 +9,4 @@ class Video(BaseModel): url: str author: str views: int - category: Optional[str] + category: Optional[str] = None diff --git a/code/ch6_active_search/ch6_starter_video_collector/requirements.txt b/code/ch6_active_search/ch6_starter_video_collector/requirements.txt index 366e3db..f636e74 100644 --- a/code/ch6_active_search/ch6_starter_video_collector/requirements.txt +++ b/code/ch6_active_search/ch6_starter_video_collector/requirements.txt @@ -4,9 +4,13 @@ # # pip-compile requirements.in # -click==8.1.3 +annotated-types==0.5.0 + # via pydantic +blinker==1.6.2 + # via flask +click==8.1.7 # via flask -flask==2.2.3 +flask==2.3.3 # via -r requirements.in itsdangerous==2.1.2 # via flask @@ -17,18 +21,22 @@ jinja2==3.1.2 # -r requirements.in # flask # jinja-partials -markupsafe==2.1.2 +markupsafe==2.1.3 # via # -r requirements.in # jinja2 # werkzeug -more-itertools==9.0.0 +more-itertools==10.1.0 # via -r requirements.in -pydantic==1.10.5 +pydantic==2.3.0 # via -r requirements.in -typing-extensions==4.5.0 +pydantic-core==2.6.3 # via pydantic -werkzeug==2.2.3 +typing-extensions==4.7.1 + # via + # pydantic + # pydantic-core +werkzeug==2.3.7 # via # -r requirements.in # flask diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/models/video_model.py b/code/ch7_infinite_scroll/ch7_final_video_collector/models/video_model.py index 4de5b4e..25908c0 100644 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/models/video_model.py +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/models/video_model.py @@ -9,4 +9,4 @@ class Video(BaseModel): url: str author: str views: int - category: Optional[str] + category: Optional[str] = None diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt b/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt index 366e3db..f636e74 100644 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt @@ -4,9 +4,13 @@ # # pip-compile requirements.in # -click==8.1.3 +annotated-types==0.5.0 + # via pydantic +blinker==1.6.2 + # via flask +click==8.1.7 # via flask -flask==2.2.3 +flask==2.3.3 # via -r requirements.in itsdangerous==2.1.2 # via flask @@ -17,18 +21,22 @@ jinja2==3.1.2 # -r requirements.in # flask # jinja-partials -markupsafe==2.1.2 +markupsafe==2.1.3 # via # -r requirements.in # jinja2 # werkzeug -more-itertools==9.0.0 +more-itertools==10.1.0 # via -r requirements.in -pydantic==1.10.5 +pydantic==2.3.0 # via -r requirements.in -typing-extensions==4.5.0 +pydantic-core==2.6.3 # via pydantic -werkzeug==2.2.3 +typing-extensions==4.7.1 + # via + # pydantic + # pydantic-core +werkzeug==2.3.7 # via # -r requirements.in # flask diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/models/video_model.py b/code/ch7_infinite_scroll/ch7_starter_video_collector/models/video_model.py index 4de5b4e..25908c0 100644 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/models/video_model.py +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/models/video_model.py @@ -9,4 +9,4 @@ class Video(BaseModel): url: str author: str views: int - category: Optional[str] + category: Optional[str] = None diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt b/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt index 366e3db..f636e74 100644 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt @@ -4,9 +4,13 @@ # # pip-compile requirements.in # -click==8.1.3 +annotated-types==0.5.0 + # via pydantic +blinker==1.6.2 + # via flask +click==8.1.7 # via flask -flask==2.2.3 +flask==2.3.3 # via -r requirements.in itsdangerous==2.1.2 # via flask @@ -17,18 +21,22 @@ jinja2==3.1.2 # -r requirements.in # flask # jinja-partials -markupsafe==2.1.2 +markupsafe==2.1.3 # via # -r requirements.in # jinja2 # werkzeug -more-itertools==9.0.0 +more-itertools==10.1.0 # via -r requirements.in -pydantic==1.10.5 +pydantic==2.3.0 # via -r requirements.in -typing-extensions==4.5.0 +pydantic-core==2.6.3 # via pydantic -werkzeug==2.2.3 +typing-extensions==4.7.1 + # via + # pydantic + # pydantic-core +werkzeug==2.3.7 # via # -r requirements.in # flask diff --git a/code/starter_video_collector/models/video_model.py b/code/starter_video_collector/models/video_model.py index 4de5b4e..25908c0 100644 --- a/code/starter_video_collector/models/video_model.py +++ b/code/starter_video_collector/models/video_model.py @@ -9,4 +9,4 @@ class Video(BaseModel): url: str author: str views: int - category: Optional[str] + category: Optional[str] = None diff --git a/code/starter_video_collector/requirements.txt b/code/starter_video_collector/requirements.txt index 112b1af..f636e74 100644 --- a/code/starter_video_collector/requirements.txt +++ b/code/starter_video_collector/requirements.txt @@ -4,28 +4,39 @@ # # pip-compile requirements.in # -click==8.1.3 +annotated-types==0.5.0 + # via pydantic +blinker==1.6.2 + # via flask +click==8.1.7 # via flask -flask==2.2.3 +flask==2.3.3 # via -r requirements.in itsdangerous==2.1.2 # via flask +jinja-partials==0.1.1 + # via -r requirements.in jinja2==3.1.2 # via # -r requirements.in # flask -markupsafe==2.1.2 + # jinja-partials +markupsafe==2.1.3 # via # -r requirements.in # jinja2 # werkzeug -more-itertools==9.0.0 +more-itertools==10.1.0 # via -r requirements.in -pydantic==1.10.5 +pydantic==2.3.0 # via -r requirements.in -typing-extensions==4.5.0 +pydantic-core==2.6.3 # via pydantic -werkzeug==2.2.3 +typing-extensions==4.7.1 + # via + # pydantic + # pydantic-core +werkzeug==2.3.7 # via # -r requirements.in # flask diff --git a/requirements.in b/requirements.in new file mode 100644 index 0000000..6ec68a8 --- /dev/null +++ b/requirements.in @@ -0,0 +1,7 @@ +flask +Werkzeug +pydantic +more_itertools +MarkupSafe +Jinja2 +jinja-partials diff --git a/requirements.txt b/requirements.txt index 0763adc..f636e74 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,11 +2,15 @@ # This file is autogenerated by pip-compile with Python 3.11 # by the following command: # -# pip-compile +# pip-compile requirements.in # -click==8.1.3 +annotated-types==0.5.0 + # via pydantic +blinker==1.6.2 + # via flask +click==8.1.7 # via flask -flask==2.2.2 +flask==2.3.3 # via -r requirements.in itsdangerous==2.1.2 # via flask @@ -17,18 +21,22 @@ jinja2==3.1.2 # -r requirements.in # flask # jinja-partials -markupsafe==2.1.1 +markupsafe==2.1.3 # via # -r requirements.in # jinja2 # werkzeug -more-itertools==9.0.0 +more-itertools==10.1.0 # via -r requirements.in -pydantic==1.10.2 +pydantic==2.3.0 # via -r requirements.in -typing-extensions==4.4.0 +pydantic-core==2.6.3 # via pydantic -werkzeug==2.2.3 +typing-extensions==4.7.1 + # via + # pydantic + # pydantic-core +werkzeug==2.3.7 # via # -r requirements.in # flask From 38c9f739b9cb503dcfed508406603a2fa6ca2e27 Mon Sep 17 00:00:00 2001 From: Michael Kennedy <michael@talkpython.fm> Date: Mon, 11 Mar 2024 16:26:23 -0700 Subject: [PATCH 15/21] Update the code to use the latest external packages. --- ...{requirements.in => requirements.piptools} | 0 .../requirements.txt | 40 ++++++----------- ...{requirements.in => requirements.piptools} | 0 .../requirements.txt | 40 ++++++----------- ...{requirements.in => requirements.piptools} | 0 .../requirements.txt | 40 ++++++----------- ...{requirements.in => requirements.piptools} | 0 .../requirements.txt | 40 ++++++----------- ...{requirements.in => requirements.piptools} | 0 .../requirements.txt | 40 ++++++----------- ...{requirements.in => requirements.piptools} | 0 .../requirements.txt | 40 ++++++----------- ...{requirements.in => requirements.piptools} | 0 .../requirements.txt | 40 ++++++----------- ...{requirements.in => requirements.piptools} | 0 .../requirements.txt | 40 ++++++----------- ...{requirements.in => requirements.piptools} | 0 code/starter_video_collector/requirements.txt | 43 ++++++------------- requirements.in => requirements.piptools | 0 requirements.txt | 40 ++++++----------- 20 files changed, 140 insertions(+), 263 deletions(-) rename code/ch4_app/ch4_final_video_collector/{requirements.in => requirements.piptools} (100%) rename code/ch4_app/ch4_starter_video_collector/{requirements.in => requirements.piptools} (100%) rename code/ch5_partials/ch5_final_video_collector/{requirements.in => requirements.piptools} (100%) rename code/ch5_partials/ch5_starter_video_collector/{requirements.in => requirements.piptools} (100%) rename code/ch6_active_search/ch6_final_video_collector/{requirements.in => requirements.piptools} (100%) rename code/ch6_active_search/ch6_starter_video_collector/{requirements.in => requirements.piptools} (100%) rename code/ch7_infinite_scroll/ch7_final_video_collector/{requirements.in => requirements.piptools} (100%) rename code/ch7_infinite_scroll/ch7_starter_video_collector/{requirements.in => requirements.piptools} (100%) rename code/starter_video_collector/{requirements.in => requirements.piptools} (100%) rename requirements.in => requirements.piptools (100%) diff --git a/code/ch4_app/ch4_final_video_collector/requirements.in b/code/ch4_app/ch4_final_video_collector/requirements.piptools similarity index 100% rename from code/ch4_app/ch4_final_video_collector/requirements.in rename to code/ch4_app/ch4_final_video_collector/requirements.piptools diff --git a/code/ch4_app/ch4_final_video_collector/requirements.txt b/code/ch4_app/ch4_final_video_collector/requirements.txt index 71e7465..19fcb66 100644 --- a/code/ch4_app/ch4_final_video_collector/requirements.txt +++ b/code/ch4_app/ch4_final_video_collector/requirements.txt @@ -1,39 +1,27 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile requirements.in -# -annotated-types==0.5.0 +# This file was autogenerated by uv via the following command: +# uv pip compile requirements.piptools --output-file requirements.txt +annotated-types==0.6.0 # via pydantic -blinker==1.6.2 +blinker==1.7.0 # via flask click==8.1.7 # via flask -flask==2.3.3 - # via -r requirements.in +flask==3.0.2 itsdangerous==2.1.2 # via flask -jinja2==3.1.2 - # via - # -r requirements.in - # flask -markupsafe==2.1.3 +jinja2==3.1.3 + # via flask +markupsafe==2.1.5 # via - # -r requirements.in # jinja2 # werkzeug -more-itertools==10.1.0 - # via -r requirements.in -pydantic==2.3.0 - # via -r requirements.in -pydantic-core==2.6.3 +more-itertools==10.2.0 +pydantic==2.6.3 +pydantic-core==2.16.3 # via pydantic -typing-extensions==4.7.1 +typing-extensions==4.10.0 # via # pydantic # pydantic-core -werkzeug==2.3.7 - # via - # -r requirements.in - # flask +werkzeug==3.0.1 + # via flask diff --git a/code/ch4_app/ch4_starter_video_collector/requirements.in b/code/ch4_app/ch4_starter_video_collector/requirements.piptools similarity index 100% rename from code/ch4_app/ch4_starter_video_collector/requirements.in rename to code/ch4_app/ch4_starter_video_collector/requirements.piptools diff --git a/code/ch4_app/ch4_starter_video_collector/requirements.txt b/code/ch4_app/ch4_starter_video_collector/requirements.txt index 71e7465..19fcb66 100644 --- a/code/ch4_app/ch4_starter_video_collector/requirements.txt +++ b/code/ch4_app/ch4_starter_video_collector/requirements.txt @@ -1,39 +1,27 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile requirements.in -# -annotated-types==0.5.0 +# This file was autogenerated by uv via the following command: +# uv pip compile requirements.piptools --output-file requirements.txt +annotated-types==0.6.0 # via pydantic -blinker==1.6.2 +blinker==1.7.0 # via flask click==8.1.7 # via flask -flask==2.3.3 - # via -r requirements.in +flask==3.0.2 itsdangerous==2.1.2 # via flask -jinja2==3.1.2 - # via - # -r requirements.in - # flask -markupsafe==2.1.3 +jinja2==3.1.3 + # via flask +markupsafe==2.1.5 # via - # -r requirements.in # jinja2 # werkzeug -more-itertools==10.1.0 - # via -r requirements.in -pydantic==2.3.0 - # via -r requirements.in -pydantic-core==2.6.3 +more-itertools==10.2.0 +pydantic==2.6.3 +pydantic-core==2.16.3 # via pydantic -typing-extensions==4.7.1 +typing-extensions==4.10.0 # via # pydantic # pydantic-core -werkzeug==2.3.7 - # via - # -r requirements.in - # flask +werkzeug==3.0.1 + # via flask diff --git a/code/ch5_partials/ch5_final_video_collector/requirements.in b/code/ch5_partials/ch5_final_video_collector/requirements.piptools similarity index 100% rename from code/ch5_partials/ch5_final_video_collector/requirements.in rename to code/ch5_partials/ch5_final_video_collector/requirements.piptools diff --git a/code/ch5_partials/ch5_final_video_collector/requirements.txt b/code/ch5_partials/ch5_final_video_collector/requirements.txt index f636e74..959604b 100644 --- a/code/ch5_partials/ch5_final_video_collector/requirements.txt +++ b/code/ch5_partials/ch5_final_video_collector/requirements.txt @@ -1,42 +1,30 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile requirements.in -# -annotated-types==0.5.0 +# This file was autogenerated by uv via the following command: +# uv pip compile requirements.piptools --output-file requirements.txt +annotated-types==0.6.0 # via pydantic -blinker==1.6.2 +blinker==1.7.0 # via flask click==8.1.7 # via flask -flask==2.3.3 - # via -r requirements.in +flask==3.0.2 itsdangerous==2.1.2 # via flask -jinja-partials==0.1.1 - # via -r requirements.in -jinja2==3.1.2 +jinja-partials==0.2.0 +jinja2==3.1.3 # via - # -r requirements.in # flask # jinja-partials -markupsafe==2.1.3 +markupsafe==2.1.5 # via - # -r requirements.in # jinja2 # werkzeug -more-itertools==10.1.0 - # via -r requirements.in -pydantic==2.3.0 - # via -r requirements.in -pydantic-core==2.6.3 +more-itertools==10.2.0 +pydantic==2.6.3 +pydantic-core==2.16.3 # via pydantic -typing-extensions==4.7.1 +typing-extensions==4.10.0 # via # pydantic # pydantic-core -werkzeug==2.3.7 - # via - # -r requirements.in - # flask +werkzeug==3.0.1 + # via flask diff --git a/code/ch5_partials/ch5_starter_video_collector/requirements.in b/code/ch5_partials/ch5_starter_video_collector/requirements.piptools similarity index 100% rename from code/ch5_partials/ch5_starter_video_collector/requirements.in rename to code/ch5_partials/ch5_starter_video_collector/requirements.piptools diff --git a/code/ch5_partials/ch5_starter_video_collector/requirements.txt b/code/ch5_partials/ch5_starter_video_collector/requirements.txt index 71e7465..19fcb66 100644 --- a/code/ch5_partials/ch5_starter_video_collector/requirements.txt +++ b/code/ch5_partials/ch5_starter_video_collector/requirements.txt @@ -1,39 +1,27 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile requirements.in -# -annotated-types==0.5.0 +# This file was autogenerated by uv via the following command: +# uv pip compile requirements.piptools --output-file requirements.txt +annotated-types==0.6.0 # via pydantic -blinker==1.6.2 +blinker==1.7.0 # via flask click==8.1.7 # via flask -flask==2.3.3 - # via -r requirements.in +flask==3.0.2 itsdangerous==2.1.2 # via flask -jinja2==3.1.2 - # via - # -r requirements.in - # flask -markupsafe==2.1.3 +jinja2==3.1.3 + # via flask +markupsafe==2.1.5 # via - # -r requirements.in # jinja2 # werkzeug -more-itertools==10.1.0 - # via -r requirements.in -pydantic==2.3.0 - # via -r requirements.in -pydantic-core==2.6.3 +more-itertools==10.2.0 +pydantic==2.6.3 +pydantic-core==2.16.3 # via pydantic -typing-extensions==4.7.1 +typing-extensions==4.10.0 # via # pydantic # pydantic-core -werkzeug==2.3.7 - # via - # -r requirements.in - # flask +werkzeug==3.0.1 + # via flask diff --git a/code/ch6_active_search/ch6_final_video_collector/requirements.in b/code/ch6_active_search/ch6_final_video_collector/requirements.piptools similarity index 100% rename from code/ch6_active_search/ch6_final_video_collector/requirements.in rename to code/ch6_active_search/ch6_final_video_collector/requirements.piptools diff --git a/code/ch6_active_search/ch6_final_video_collector/requirements.txt b/code/ch6_active_search/ch6_final_video_collector/requirements.txt index f636e74..959604b 100644 --- a/code/ch6_active_search/ch6_final_video_collector/requirements.txt +++ b/code/ch6_active_search/ch6_final_video_collector/requirements.txt @@ -1,42 +1,30 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile requirements.in -# -annotated-types==0.5.0 +# This file was autogenerated by uv via the following command: +# uv pip compile requirements.piptools --output-file requirements.txt +annotated-types==0.6.0 # via pydantic -blinker==1.6.2 +blinker==1.7.0 # via flask click==8.1.7 # via flask -flask==2.3.3 - # via -r requirements.in +flask==3.0.2 itsdangerous==2.1.2 # via flask -jinja-partials==0.1.1 - # via -r requirements.in -jinja2==3.1.2 +jinja-partials==0.2.0 +jinja2==3.1.3 # via - # -r requirements.in # flask # jinja-partials -markupsafe==2.1.3 +markupsafe==2.1.5 # via - # -r requirements.in # jinja2 # werkzeug -more-itertools==10.1.0 - # via -r requirements.in -pydantic==2.3.0 - # via -r requirements.in -pydantic-core==2.6.3 +more-itertools==10.2.0 +pydantic==2.6.3 +pydantic-core==2.16.3 # via pydantic -typing-extensions==4.7.1 +typing-extensions==4.10.0 # via # pydantic # pydantic-core -werkzeug==2.3.7 - # via - # -r requirements.in - # flask +werkzeug==3.0.1 + # via flask diff --git a/code/ch6_active_search/ch6_starter_video_collector/requirements.in b/code/ch6_active_search/ch6_starter_video_collector/requirements.piptools similarity index 100% rename from code/ch6_active_search/ch6_starter_video_collector/requirements.in rename to code/ch6_active_search/ch6_starter_video_collector/requirements.piptools diff --git a/code/ch6_active_search/ch6_starter_video_collector/requirements.txt b/code/ch6_active_search/ch6_starter_video_collector/requirements.txt index f636e74..959604b 100644 --- a/code/ch6_active_search/ch6_starter_video_collector/requirements.txt +++ b/code/ch6_active_search/ch6_starter_video_collector/requirements.txt @@ -1,42 +1,30 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile requirements.in -# -annotated-types==0.5.0 +# This file was autogenerated by uv via the following command: +# uv pip compile requirements.piptools --output-file requirements.txt +annotated-types==0.6.0 # via pydantic -blinker==1.6.2 +blinker==1.7.0 # via flask click==8.1.7 # via flask -flask==2.3.3 - # via -r requirements.in +flask==3.0.2 itsdangerous==2.1.2 # via flask -jinja-partials==0.1.1 - # via -r requirements.in -jinja2==3.1.2 +jinja-partials==0.2.0 +jinja2==3.1.3 # via - # -r requirements.in # flask # jinja-partials -markupsafe==2.1.3 +markupsafe==2.1.5 # via - # -r requirements.in # jinja2 # werkzeug -more-itertools==10.1.0 - # via -r requirements.in -pydantic==2.3.0 - # via -r requirements.in -pydantic-core==2.6.3 +more-itertools==10.2.0 +pydantic==2.6.3 +pydantic-core==2.16.3 # via pydantic -typing-extensions==4.7.1 +typing-extensions==4.10.0 # via # pydantic # pydantic-core -werkzeug==2.3.7 - # via - # -r requirements.in - # flask +werkzeug==3.0.1 + # via flask diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.in b/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.piptools similarity index 100% rename from code/ch7_infinite_scroll/ch7_final_video_collector/requirements.in rename to code/ch7_infinite_scroll/ch7_final_video_collector/requirements.piptools diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt b/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt index f636e74..959604b 100644 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt @@ -1,42 +1,30 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile requirements.in -# -annotated-types==0.5.0 +# This file was autogenerated by uv via the following command: +# uv pip compile requirements.piptools --output-file requirements.txt +annotated-types==0.6.0 # via pydantic -blinker==1.6.2 +blinker==1.7.0 # via flask click==8.1.7 # via flask -flask==2.3.3 - # via -r requirements.in +flask==3.0.2 itsdangerous==2.1.2 # via flask -jinja-partials==0.1.1 - # via -r requirements.in -jinja2==3.1.2 +jinja-partials==0.2.0 +jinja2==3.1.3 # via - # -r requirements.in # flask # jinja-partials -markupsafe==2.1.3 +markupsafe==2.1.5 # via - # -r requirements.in # jinja2 # werkzeug -more-itertools==10.1.0 - # via -r requirements.in -pydantic==2.3.0 - # via -r requirements.in -pydantic-core==2.6.3 +more-itertools==10.2.0 +pydantic==2.6.3 +pydantic-core==2.16.3 # via pydantic -typing-extensions==4.7.1 +typing-extensions==4.10.0 # via # pydantic # pydantic-core -werkzeug==2.3.7 - # via - # -r requirements.in - # flask +werkzeug==3.0.1 + # via flask diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.in b/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.piptools similarity index 100% rename from code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.in rename to code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.piptools diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt b/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt index f636e74..959604b 100644 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt @@ -1,42 +1,30 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile requirements.in -# -annotated-types==0.5.0 +# This file was autogenerated by uv via the following command: +# uv pip compile requirements.piptools --output-file requirements.txt +annotated-types==0.6.0 # via pydantic -blinker==1.6.2 +blinker==1.7.0 # via flask click==8.1.7 # via flask -flask==2.3.3 - # via -r requirements.in +flask==3.0.2 itsdangerous==2.1.2 # via flask -jinja-partials==0.1.1 - # via -r requirements.in -jinja2==3.1.2 +jinja-partials==0.2.0 +jinja2==3.1.3 # via - # -r requirements.in # flask # jinja-partials -markupsafe==2.1.3 +markupsafe==2.1.5 # via - # -r requirements.in # jinja2 # werkzeug -more-itertools==10.1.0 - # via -r requirements.in -pydantic==2.3.0 - # via -r requirements.in -pydantic-core==2.6.3 +more-itertools==10.2.0 +pydantic==2.6.3 +pydantic-core==2.16.3 # via pydantic -typing-extensions==4.7.1 +typing-extensions==4.10.0 # via # pydantic # pydantic-core -werkzeug==2.3.7 - # via - # -r requirements.in - # flask +werkzeug==3.0.1 + # via flask diff --git a/code/starter_video_collector/requirements.in b/code/starter_video_collector/requirements.piptools similarity index 100% rename from code/starter_video_collector/requirements.in rename to code/starter_video_collector/requirements.piptools diff --git a/code/starter_video_collector/requirements.txt b/code/starter_video_collector/requirements.txt index f636e74..19fcb66 100644 --- a/code/starter_video_collector/requirements.txt +++ b/code/starter_video_collector/requirements.txt @@ -1,42 +1,27 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile requirements.in -# -annotated-types==0.5.0 +# This file was autogenerated by uv via the following command: +# uv pip compile requirements.piptools --output-file requirements.txt +annotated-types==0.6.0 # via pydantic -blinker==1.6.2 +blinker==1.7.0 # via flask click==8.1.7 # via flask -flask==2.3.3 - # via -r requirements.in +flask==3.0.2 itsdangerous==2.1.2 # via flask -jinja-partials==0.1.1 - # via -r requirements.in -jinja2==3.1.2 - # via - # -r requirements.in - # flask - # jinja-partials -markupsafe==2.1.3 +jinja2==3.1.3 + # via flask +markupsafe==2.1.5 # via - # -r requirements.in # jinja2 # werkzeug -more-itertools==10.1.0 - # via -r requirements.in -pydantic==2.3.0 - # via -r requirements.in -pydantic-core==2.6.3 +more-itertools==10.2.0 +pydantic==2.6.3 +pydantic-core==2.16.3 # via pydantic -typing-extensions==4.7.1 +typing-extensions==4.10.0 # via # pydantic # pydantic-core -werkzeug==2.3.7 - # via - # -r requirements.in - # flask +werkzeug==3.0.1 + # via flask diff --git a/requirements.in b/requirements.piptools similarity index 100% rename from requirements.in rename to requirements.piptools diff --git a/requirements.txt b/requirements.txt index f636e74..959604b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,42 +1,30 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile requirements.in -# -annotated-types==0.5.0 +# This file was autogenerated by uv via the following command: +# uv pip compile requirements.piptools --output-file requirements.txt +annotated-types==0.6.0 # via pydantic -blinker==1.6.2 +blinker==1.7.0 # via flask click==8.1.7 # via flask -flask==2.3.3 - # via -r requirements.in +flask==3.0.2 itsdangerous==2.1.2 # via flask -jinja-partials==0.1.1 - # via -r requirements.in -jinja2==3.1.2 +jinja-partials==0.2.0 +jinja2==3.1.3 # via - # -r requirements.in # flask # jinja-partials -markupsafe==2.1.3 +markupsafe==2.1.5 # via - # -r requirements.in # jinja2 # werkzeug -more-itertools==10.1.0 - # via -r requirements.in -pydantic==2.3.0 - # via -r requirements.in -pydantic-core==2.6.3 +more-itertools==10.2.0 +pydantic==2.6.3 +pydantic-core==2.16.3 # via pydantic -typing-extensions==4.7.1 +typing-extensions==4.10.0 # via # pydantic # pydantic-core -werkzeug==2.3.7 - # via - # -r requirements.in - # flask +werkzeug==3.0.1 + # via flask From 8eeb307dbd3aa191d32e835064ac9dc3592ece1c Mon Sep 17 00:00:00 2001 From: Michael Kennedy <michael@talkpython.fm> Date: Mon, 11 Mar 2024 16:28:08 -0700 Subject: [PATCH 16/21] Update to the latest htmx, v1.9.10 --- .../static/js/htmx.js | 1564 +++++++++++++---- .../static/js/htmx.min.js | 5 +- .../static/js/htmx.js | 1564 +++++++++++++---- .../static/js/htmx.min.js | 5 +- .../static/js/htmx.js | 1564 +++++++++++++---- .../static/js/htmx.min.js | 5 +- .../static/js/htmx.js | 1564 +++++++++++++---- .../static/js/htmx.min.js | 5 +- .../static/js/htmx.js | 1564 +++++++++++++---- .../static/js/htmx.min.js | 5 +- .../static/js/htmx.js | 1564 +++++++++++++---- .../static/js/htmx.min.js | 5 +- .../static/js/htmx.js | 1564 +++++++++++++---- .../static/js/htmx.min.js | 5 +- .../static/js/htmx.js | 1564 +++++++++++++---- .../static/js/htmx.min.js | 5 +- .../starter_video_collector/static/js/htmx.js | 1564 +++++++++++++---- .../static/js/htmx.min.js | 5 +- 18 files changed, 10611 insertions(+), 3510 deletions(-) diff --git a/code/ch4_app/ch4_final_video_collector/static/js/htmx.js b/code/ch4_app/ch4_final_video_collector/static/js/htmx.js index 27e57bc..86e7668 100644 --- a/code/ch4_app/ch4_final_video_collector/static/js/htmx.js +++ b/code/ch4_app/ch4_final_video_collector/static/js/htmx.js @@ -1,13 +1,23 @@ -//AMD insanity +// /////////////////////////////////////////////////////////////////// +// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.js +// + +// UMD insanity +// This code sets up support for (in order) AMD, ES6 modules, and globals. (function (root, factory) { //@ts-ignore if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. //@ts-ignore define([], factory); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); } else { // Browser globals - root.htmx = factory(); + root.htmx = root.htmx || factory(); } }(typeof self !== 'undefined' ? self : this, function () { return (function () { @@ -38,6 +48,7 @@ return (function () { defineExtension : defineExtension, removeExtension : removeExtension, logAll : logAll, + logNone : logNone, logger : null, config : { historyEnabled:true, @@ -53,15 +64,24 @@ return (function () { settlingClass:'htmx-settling', swappingClass:'htmx-swapping', allowEval:true, + allowScriptTags:true, inlineScriptNonce:'', attributesToSettle:["class", "style", "width", "height"], withCredentials:false, timeout:0, wsReconnectDelay: 'full-jitter', + wsBinaryType: 'blob', disableSelector: "[hx-disable], [data-hx-disable]", useTemplateFragments: false, scrollBehavior: 'smooth', defaultFocusScroll: false, + getCacheBusterParam: false, + globalViewTransitions: false, + methodsThatUseUrlParams: ["get"], + selfRequestsOnly: false, + ignoreTitle: false, + scrollIntoViewOnBoost: true, + triggerSpecsCache: null, }, parseInterval:parseInterval, _:internalEval, @@ -69,17 +89,23 @@ return (function () { return new EventSource(url, {withCredentials:true}) }, createWebSocket: function(url){ - return new WebSocket(url, []); + var sock = new WebSocket(url, []); + sock.binaryType = htmx.config.wsBinaryType; + return sock; }, - version: "1.7.0" + version: "1.9.10" }; /** @type {import("./htmx").HtmxInternalApi} */ var internalAPI = { + addTriggerHandler: addTriggerHandler, bodyContains: bodyContains, + canAccessLocalStorage: canAccessLocalStorage, + findThisElement: findThisElement, filterValues: filterValues, hasAttribute: hasAttribute, getAttributeValue: getAttributeValue, + getClosestAttributeValue: getClosestAttributeValue, getClosestMatch: getClosestMatch, getExpressionVars: getExpressionVars, getHeaders: getHeaders, @@ -92,6 +118,7 @@ return (function () { mergeObjects: mergeObjects, makeSettleInfo: makeSettleInfo, oobSwap: oobSwap, + querySelectorExt: querySelectorExt, selectAndSwap: selectAndSwap, settleImmediately: settleImmediately, shouldCancel: shouldCancel, @@ -105,21 +132,40 @@ return (function () { return "[hx-" + verb + "], [data-hx-" + verb + "]" }).join(", "); + var HEAD_TAG_REGEX = makeTagRegEx('head'), + TITLE_TAG_REGEX = makeTagRegEx('title'), + SVG_TAGS_REGEX = makeTagRegEx('svg', true); + //==================================================================== // Utilities //==================================================================== + /** + * @param {string} tag + * @param {boolean} global + * @returns {RegExp} + */ + function makeTagRegEx(tag, global = false) { + return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, + global ? 'gim' : 'im'); + } + function parseInterval(str) { if (str == undefined) { - return undefined + return undefined; } + + let interval = NaN; if (str.slice(-2) == "ms") { - return parseFloat(str.slice(0,-2)) || undefined - } - if (str.slice(-1) == "s") { - return (parseFloat(str.slice(0,-1)) * 1000) || undefined + interval = parseFloat(str.slice(0, -2)); + } else if (str.slice(-1) == "s") { + interval = parseFloat(str.slice(0, -1)) * 1000; + } else if (str.slice(-1) == "m") { + interval = parseFloat(str.slice(0, -1)) * 1000 * 60; + } else { + interval = parseFloat(str); } - return parseFloat(str) || undefined + return isNaN(interval) ? undefined : interval; } /** @@ -168,13 +214,11 @@ return (function () { * @returns {HTMLElement | null} */ function getClosestMatch(elt, condition) { - if (condition(elt)) { - return elt; - } else if (parentElt(elt)) { - return getClosestMatch(parentElt(elt), condition); - } else { - return null; + while (elt && !condition(elt)) { + elt = parentElt(elt); } + + return elt ? elt : null; } function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ @@ -208,7 +252,7 @@ return (function () { * @returns {boolean} */ function matches(elt, selector) { - // @ts-ignore: non-standard properties for browser compatability + // @ts-ignore: non-standard properties for browser compatibility // noinspection JSUnresolvedVariable var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; return matchesFunction && matchesFunction.call(elt, selector); @@ -252,38 +296,47 @@ return (function () { return responseNode; } + function aFullPageResponse(resp) { + return /<body/.test(resp) + } + /** * - * @param {string} resp + * @param {string} response * @returns {Element} */ - function makeFragment(resp) { - if (htmx.config.useTemplateFragments) { - var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0); + function makeFragment(response) { + var partialResponse = !aFullPageResponse(response); + var startTag = getStartTag(response); + var content = response; + if (startTag === 'head') { + content = content.replace(HEAD_TAG_REGEX, ''); + } + if (htmx.config.useTemplateFragments && partialResponse) { + var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0); // @ts-ignore type mismatch between DocumentFragment and Element. - // TODO: Are these close enough for htmx to use interchangably? + // TODO: Are these close enough for htmx to use interchangeably? return documentFragment.querySelector('template').content; - } else { - 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); - case "script": - return parseHTML("<div>" + resp + "</div>", 1); - default: - return parseHTML(resp, 0); - } + } + switch (startTag) { + case "thead": + case "tbody": + case "tfoot": + case "colgroup": + case "caption": + return parseHTML("<table>" + content + "</table>", 1); + case "col": + return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2); + case "tr": + return parseHTML("<table><tbody>" + content + "</tbody></table>", 2); + case "td": + case "th": + return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3); + case "script": + case "style": + return parseHTML("<div>" + content + "</div>", 1); + default: + return parseHTML(content, 0); } } @@ -365,13 +418,14 @@ return (function () { return elemTop < window.innerHeight && elemBottom >= 0; } - function bodyContains(elt) { - if (elt.getRootNode() instanceof ShadowRoot) { - return getDocument().body.contains(elt.getRootNode().host); - } else { - return getDocument().body.contains(elt); - } - } + function bodyContains(elt) { + // IE Fix + if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) { + return getDocument().body.contains(elt.getRootNode().host); + } else { + return getDocument().body.contains(elt); + } + } function splitOnWhitespace(trigger) { return trigger.trim().split(/\s+/); @@ -402,6 +456,34 @@ return (function () { } } + function canAccessLocalStorage() { + var test = 'htmx:localStorageTest'; + try { + localStorage.setItem(test, test); + localStorage.removeItem(test); + return true; + } catch(e) { + return false; + } + } + + function normalizePath(path) { + try { + var url = new URL(path); + if (url) { + path = url.pathname + url.search; + } + // remove trailing slash, unless index page + if (!(/^\/$/.test(path))) { + path = path.replace(/\/+$/, ''); + } + return path; + } catch (e) { + // be kind to IE11, which doesn't support URL() + return path; + } + } + //========================================================================================== // public API //========================================================================================== @@ -427,6 +509,10 @@ return (function () { } } + function logNone() { + htmx.logger = null + } + function find(eltOrSelector, selector) { if (selector) { return eltOrSelector.querySelector(selector); @@ -446,7 +532,10 @@ return (function () { function removeElement(elt, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeElement(elt);}, delay) + setTimeout(function(){ + removeElement(elt); + elt = null; + }, delay); } else { elt.parentElement.removeChild(elt); } @@ -455,7 +544,10 @@ return (function () { function addClassToElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){addClassToElement(elt, clazz);}, delay) + setTimeout(function(){ + addClassToElement(elt, clazz); + elt = null; + }, delay); } else { elt.classList && elt.classList.add(clazz); } @@ -464,7 +556,10 @@ return (function () { function removeClassFromElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) + setTimeout(function(){ + removeClassFromElement(elt, clazz); + elt = null; + }, delay); } else { if (elt.classList) { elt.classList.remove(clazz); @@ -494,26 +589,75 @@ return (function () { if (elt.closest) { return elt.closest(selector); } else { + // TODO remove when IE goes away do{ if (elt == null || matches(elt, selector)){ return elt; } } while (elt = elt && parentElt(elt)); + return null; + } + } + + function startsWith(str, prefix) { + return str.substring(0, prefix.length) === prefix + } + + function endsWith(str, suffix) { + return str.substring(str.length - suffix.length) === suffix + } + + function normalizeSelector(selector) { + var trimmedSelector = selector.trim(); + if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) { + return trimmedSelector.substring(1, trimmedSelector.length - 2); + } else { + return trimmedSelector; } } function querySelectorAllExt(elt, selector) { if (selector.indexOf("closest ") === 0) { - return [closest(elt, selector.substr(8))]; + return [closest(elt, normalizeSelector(selector.substr(8)))]; } else if (selector.indexOf("find ") === 0) { - return [find(elt, selector.substr(5))]; + return [find(elt, normalizeSelector(selector.substr(5)))]; + } else if (selector === "next") { + return [elt.nextElementSibling] + } else if (selector.indexOf("next ") === 0) { + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; + } else if (selector === "previous") { + return [elt.previousElementSibling] + } else if (selector.indexOf("previous ") === 0) { + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; } else if (selector === 'document') { return [document]; } else if (selector === 'window') { return [window]; + } else if (selector === 'body') { + return [document.body]; } else { - return getDocument().querySelectorAll(selector); + return getDocument().querySelectorAll(normalizeSelector(selector)); + } + } + + var scanForwardQuery = function(start, match) { + var results = getDocument().querySelectorAll(match); + for (var i = 0; i < results.length; i++) { + var elt = results[i]; + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { + return elt; + } + } + } + + var scanBackwardsQuery = function(start, match) { + var results = getDocument().querySelectorAll(match); + for (var i = results.length - 1; i >= 0; i--) { + var elt = results[i]; + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { + return elt; + } } } @@ -570,7 +714,7 @@ return (function () { //==================================================================== // Node processing //==================================================================== - + var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors function findAttributeTargets(elt, attrName) { var attrTarget = getClosestAttributeValue(elt, attrName); @@ -659,7 +803,7 @@ return (function () { * @returns */ function oobSwap(oobValue, oobElement, settleInfo) { - var selector = "#" + oobElement.id; + var selector = "#" + getRawAttribute(oobElement, "id"); var swapStyle = "outerHTML"; if (oobValue === "true") { // do nothing @@ -703,7 +847,23 @@ return (function () { return oobValue; } - function handleOutOfBandSwaps(fragment, settleInfo) { + function handleOutOfBandSwaps(elt, fragment, settleInfo) { + var oobSelects = getClosestAttributeValue(elt, "hx-select-oob"); + if (oobSelects) { + var oobSelectValues = oobSelects.split(","); + for (var i = 0; i < oobSelectValues.length; i++) { + var oobSelectValue = oobSelectValues[i].split(":", 2); + var id = oobSelectValue[0].trim(); + if (id.indexOf("#") === 0) { + id = id.substring(1); + } + var oobValue = oobSelectValue[1] || "true"; + var oobElement = fragment.querySelector("#" + id); + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo); + } + } + } forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) { var oobValue = getAttributeValue(oobElement, "hx-swap-oob"); if (oobValue != null) { @@ -724,8 +884,11 @@ return (function () { function handleAttributes(parentNode, fragment, settleInfo) { forEach(fragment.querySelectorAll("[id]"), function (newNode) { - if (newNode.id && newNode.id.length > 0) { - var oldNode = parentNode.querySelector(newNode.tagName + "[id='" + newNode.id + "']"); + var id = getRawAttribute(newNode, "id") + if (id && id.length > 0) { + var normalizedId = id.replace("'", "\\'"); + var normalizedTag = newNode.tagName.replace(':', '\\:'); + var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']"); if (oldNode && oldNode !== parentNode) { var newAttributes = newNode.cloneNode(); cloneAttributes(newNode, oldNode); @@ -767,24 +930,67 @@ return (function () { } } - function cleanUpElement(element) { + // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, + // derived from Java's string hashcode implementation + function stringHash(string, hash) { + var char = 0; + while (char < string.length){ + hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int + } + return hash; + } + + function attributeHash(elt) { + var hash = 0; + // IE fix + if (elt.attributes) { + for (var i = 0; i < elt.attributes.length; i++) { + var attribute = elt.attributes[i]; + if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent) + hash = stringHash(attribute.name, hash); + hash = stringHash(attribute.value, hash); + } + } + } + return hash; + } + + function deInitOnHandlers(elt) { + var internalData = getInternalData(elt); + if (internalData.onHandlers) { + for (var i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i]; + elt.removeEventListener(handlerInfo.event, handlerInfo.listener); + } + delete internalData.onHandlers + } + } + + function deInitNode(element) { var internalData = getInternalData(element); + if (internalData.timeout) { + clearTimeout(internalData.timeout); + } if (internalData.webSocket) { internalData.webSocket.close(); } if (internalData.sseEventSource) { internalData.sseEventSource.close(); } - - triggerEvent(element, "htmx:beforeCleanupElement") - if (internalData.listenerInfos) { - forEach(internalData.listenerInfos, function(info) { - if (element !== info.on) { + forEach(internalData.listenerInfos, function (info) { + if (info.on) { info.on.removeEventListener(info.trigger, info.listener); } }); } + deInitOnHandlers(element); + forEach(Object.keys(internalData), function(key) { delete internalData[key] }); + } + + function cleanUpElement(element) { + triggerEvent(element, "htmx:beforeCleanupElement") + deInitNode(element); if (element.children) { // IE forEach(element.children, function(child) { cleanUpElement(child) }); } @@ -803,8 +1009,7 @@ return (function () { } else { newElt = eltBeforeNewContent.nextSibling; } - getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later - settleInfo.elts = [] // clear existing elements + settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target }); while(newElt && newElt !== target) { if (newElt.nodeType === Node.ELEMENT_NODE) { settleInfo.elts.push(newElt); @@ -849,8 +1054,8 @@ return (function () { } } - function maybeSelectFromResponse(elt, fragment) { - var selector = getClosestAttributeValue(elt, "hx-select"); + function maybeSelectFromResponse(elt, fragment, selectOverride) { + var selector = selectOverride || getClosestAttributeValue(elt, "hx-select"); if (selector) { var newFragment = getDocument().createDocumentFragment(); forEach(fragment.querySelectorAll(selector), function (node) { @@ -915,21 +1120,20 @@ return (function () { function findTitle(content) { if (content.indexOf('<title') > -1) { - var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, ''); - var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im); - + var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, ''); + var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX); if (result) { return result[2]; } } } - function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) { + function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) { settleInfo.title = findTitle(responseText); var fragment = makeFragment(responseText); if (fragment) { - handleOutOfBandSwaps(fragment, settleInfo); - fragment = maybeSelectFromResponse(elt, fragment); + handleOutOfBandSwaps(elt, fragment, settleInfo); + fragment = maybeSelectFromResponse(elt, fragment, selectOverride); handlePreservedElements(fragment); return swap(swapStyle, elt, target, fragment, settleInfo); } @@ -949,7 +1153,10 @@ return (function () { } } } else { - triggerEvent(elt, triggerBody, []); + var eventNames = triggerBody.split(",") + for (var i = 0; i < eventNames.length; i++) { + triggerEvent(elt, eventNames[i].trim(), []); + } } } @@ -959,6 +1166,8 @@ return (function () { var SYMBOL_CONT = /[_$a-zA-Z0-9]/; var STRINGISH_START = ['"', "'", "/"]; var NOT_WHITESPACE = /[^\s]/; + var COMBINED_SELECTOR_START = /[{(]/; + var COMBINED_SELECTOR_END = /[})]/; function tokenizeString(str) { var tokens = []; var position = 0; @@ -1041,101 +1250,137 @@ return (function () { function consumeUntil(tokens, match) { var result = ""; - while (tokens.length > 0 && !tokens[0].match(match)) { + while (tokens.length > 0 && !match.test(tokens[0])) { result += tokens.shift(); } return result; } + function consumeCSSSelector(tokens) { + var result; + if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { + tokens.shift(); + result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim(); + tokens.shift(); + } else { + result = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } + return result; + } + var INPUT_SELECTOR = 'input, textarea, select'; /** * @param {HTMLElement} elt + * @param {string} explicitTrigger + * @param {cache} cache for trigger specs * @returns {import("./htmx").HtmxTriggerSpecification[]} */ - function getTriggerSpecs(elt) { - var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); + function parseAndCacheTrigger(elt, explicitTrigger, cache) { var triggerSpecs = []; - if (explicitTrigger) { - var tokens = tokenizeString(explicitTrigger); - do { - consumeUntil(tokens, NOT_WHITESPACE); - var initialLength = tokens.length; - var trigger = consumeUntil(tokens, /[,\[\s]/); - if (trigger !== "") { - if (trigger === "every") { - var every = {trigger: 'every'}; - consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); - consumeUntil(tokens, NOT_WHITESPACE); - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - every.eventFilter = eventFilter; - } - triggerSpecs.push(every); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); - } else { - var triggerSpec = {trigger: trigger}; - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - triggerSpec.eventFilter = eventFilter; - } - while (tokens.length > 0 && tokens[0] !== ",") { - consumeUntil(tokens, NOT_WHITESPACE) - var token = tokens.shift(); - if (token === "changed") { - triggerSpec.changed = true; - } else if (token === "once") { - triggerSpec.once = true; - } else if (token === "consume") { - triggerSpec.consume = true; - } else if (token === "delay" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "from" && tokens[0] === ":") { - tokens.shift(); + var tokens = tokenizeString(explicitTrigger); + do { + consumeUntil(tokens, NOT_WHITESPACE); + var initialLength = tokens.length; + var trigger = consumeUntil(tokens, /[,\[\s]/); + if (trigger !== "") { + if (trigger === "every") { + var every = {trigger: 'every'}; + consumeUntil(tokens, NOT_WHITESPACE); + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); + consumeUntil(tokens, NOT_WHITESPACE); + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + every.eventFilter = eventFilter; + } + triggerSpecs.push(every); + } else if (trigger.indexOf("sse:") === 0) { + triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); + } else { + var triggerSpec = {trigger: trigger}; + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + triggerSpec.eventFilter = eventFilter; + } + while (tokens.length > 0 && tokens[0] !== ",") { + consumeUntil(tokens, NOT_WHITESPACE) + var token = tokens.shift(); + if (token === "changed") { + triggerSpec.changed = true; + } else if (token === "once") { + triggerSpec.once = true; + } else if (token === "consume") { + triggerSpec.consume = true; + } else if (token === "delay" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); + } else if (token === "from" && tokens[0] === ":") { + tokens.shift(); + if (COMBINED_SELECTOR_START.test(tokens[0])) { + var from_arg = consumeCSSSelector(tokens); + } else { var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); - if (from_arg === "closest" || from_arg === "find") { + if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") { tokens.shift(); - from_arg += - " " + - consumeUntil( - tokens, - WHITESPACE_OR_COMMA - ); + var selector = consumeCSSSelector(tokens); + // `next` and `previous` allow a selector-less syntax + if (selector.length > 0) { + from_arg += " " + selector; + } } - triggerSpec.from = from_arg; - } else if (token === "target" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if (token === "throttle" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "queue" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if ((token === "root" || token === "threshold") && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); } + triggerSpec.from = from_arg; + } else if (token === "target" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.target = consumeCSSSelector(tokens); + } else if (token === "throttle" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); + } else if (token === "queue" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } else if (token === "root" && tokens[0] === ":") { + tokens.shift(); + triggerSpec[token] = consumeCSSSelector(tokens); + } else if (token === "threshold" && tokens[0] === ":") { + tokens.shift(); + triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } else { + triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); } - triggerSpecs.push(triggerSpec); } + triggerSpecs.push(triggerSpec); } - if (tokens.length === initialLength) { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - consumeUntil(tokens, NOT_WHITESPACE); - } while (tokens[0] === "," && tokens.shift()) + } + if (tokens.length === initialLength) { + triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); + } + consumeUntil(tokens, NOT_WHITESPACE); + } while (tokens[0] === "," && tokens.shift()) + if (cache) { + cache[explicitTrigger] = triggerSpecs + } + return triggerSpecs + } + + /** + * @param {HTMLElement} elt + * @returns {import("./htmx").HtmxTriggerSpecification[]} + */ + function getTriggerSpecs(elt) { + var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); + var triggerSpecs = []; + if (explicitTrigger) { + var cache = htmx.config.triggerSpecsCache + triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) } if (triggerSpecs.length > 0) { return triggerSpecs; } else if (matches(elt, 'form')) { return [{trigger: 'submit'}]; + } else if (matches(elt, 'input[type="button"], input[type="submit"]')){ + return [{trigger: 'click'}]; } else if (matches(elt, INPUT_SELECTOR)) { return [{trigger: 'change'}]; } else { @@ -1147,14 +1392,17 @@ return (function () { getInternalData(elt).cancelled = true; } - function processPolling(elt, verb, path, spec) { + function processPolling(elt, handler, spec) { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { - issueAjaxRequest(verb, path, elt); + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { + handler(elt); } - processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), spec); + processPolling(elt, handler, spec); } }, spec.pollInterval); } @@ -1166,23 +1414,27 @@ return (function () { } function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt) && elt.target === "") || elt.tagName === "FORM") { + if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || elt.tagName === "FORM") { nodeData.boosted = true; var verb, path; if (elt.tagName === "A") { verb = "get"; - path = getRawAttribute(elt, 'href'); - nodeData.pushURL = true; + path = getRawAttribute(elt, 'href') } else { var rawAttribute = getRawAttribute(elt, "method"); verb = rawAttribute ? rawAttribute.toLowerCase() : "get"; if (verb === "get") { - nodeData.pushURL = true; } path = getRawAttribute(elt, 'action'); } triggerSpecs.forEach(function(triggerSpec) { - addEventListener(elt, verb, path, nodeData, triggerSpec, true); + addEventListener(elt, function(elt, evt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + issueAjaxRequest(verb, path, elt, evt) + }, nodeData, triggerSpec, true); }); } } @@ -1213,11 +1465,11 @@ return (function () { return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); } - function maybeFilterEvent(triggerSpec, evt) { + function maybeFilterEvent(triggerSpec, elt, evt) { var eventFilter = triggerSpec.eventFilter; if(eventFilter){ try { - return eventFilter(evt) !== true; + return eventFilter.call(elt, evt) !== true; } catch(e) { triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); return true; @@ -1226,13 +1478,21 @@ return (function () { return false; } - function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { + function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { + var elementData = getInternalData(elt); var eltsToListenOn; if (triggerSpec.from) { eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); } else { eltsToListenOn = [elt]; } + // store the initial values of the elements, so we can tell if they change + if (triggerSpec.changed) { + eltsToListenOn.forEach(function (eltToListenOn) { + var eltToListenOnData = getInternalData(eltToListenOn); + eltToListenOnData.lastValue = eltToListenOn.value; + }) + } forEach(eltsToListenOn, function (eltToListenOn) { var eventListener = function (evt) { if (!bodyContains(elt)) { @@ -1245,7 +1505,7 @@ return (function () { if (explicitCancel || shouldCancel(evt, elt)) { evt.preventDefault(); } - if (maybeFilterEvent(triggerSpec, evt)) { + if (maybeFilterEvent(triggerSpec, elt, evt)) { return; } var eventData = getInternalData(evt); @@ -1253,7 +1513,6 @@ return (function () { if (eventData.handledFor == null) { eventData.handledFor = []; } - var elementData = getInternalData(elt); if (eventData.handledFor.indexOf(elt) < 0) { eventData.handledFor.push(elt); if (triggerSpec.consume) { @@ -1272,11 +1531,11 @@ return (function () { } } if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { + var eltToListenOnData = getInternalData(eltToListenOn) + if (eltToListenOnData.lastValue === eltToListenOn.value) { return; - } else { - elementData.lastValue = elt.value; } + eltToListenOnData.lastValue = eltToListenOn.value } if (elementData.delayed) { clearTimeout(elementData.delayed); @@ -1285,19 +1544,18 @@ return (function () { return; } - if (triggerSpec.throttle) { + if (triggerSpec.throttle > 0) { if (!elementData.throttle) { - issueAjaxRequest(verb, path, elt, evt); + handler(elt, evt); elementData.throttle = setTimeout(function () { elementData.throttle = null; }, triggerSpec.throttle); } - } else if (triggerSpec.delay) { - elementData.delayed = setTimeout(function () { - issueAjaxRequest(verb, path, elt, evt); - }, triggerSpec.delay); + } else if (triggerSpec.delay > 0) { + elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); } else { - issueAjaxRequest(verb, path, elt, evt); + triggerEvent(elt, 'htmx:trigger') + handler(elt, evt); } } }; @@ -1310,7 +1568,7 @@ return (function () { on: eltToListenOn }) eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); - }) + }); } var windowIsScrolling = false // used by initScrollHandler @@ -1336,14 +1594,11 @@ return (function () { if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { elt.setAttribute('data-hx-revealed', 'true'); var nodeData = getInternalData(elt); - if (nodeData.initialized) { - issueAjaxRequest(nodeData.verb, nodeData.path, elt); + if (nodeData.initHash) { + triggerEvent(elt, 'revealed'); } else { // if the node isn't initialized, wait for it before triggering the request - elt.addEventListener("htmx:afterProcessNode", - function () { - issueAjaxRequest(nodeData.verb, nodeData.path, elt); - }, {once: true}); + elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true}); } } } @@ -1502,6 +1757,9 @@ return (function () { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function (event) { if (maybeCloseSSESource(sseSourceElt)) { + return; + } + if (!bodyContains(elt)) { sseEventSource.removeEventListener(sseEventName, sseListener); return; } @@ -1518,7 +1776,7 @@ return (function () { var target = getTarget(elt) var settleInfo = makeSettleInfo(elt); - selectAndSwap(swapSpec.swapStyle, elt, target, response, settleInfo) + selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) settleImmediately(settleInfo.tasks) triggerEvent(elt, "htmx:sseMessage", event) }; @@ -1530,14 +1788,14 @@ return (function () { } } - function processSSETrigger(elt, verb, path, sseEventName) { + function processSSETrigger(elt, handler, sseEventName) { var sseSourceElt = getClosestMatch(elt, hasEventSource); if (sseSourceElt) { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function () { if (!maybeCloseSSESource(sseSourceElt)) { if (bodyContains(elt)) { - issueAjaxRequest(verb, path, elt); + handler(elt); } else { sseEventSource.removeEventListener(sseEventName, sseListener); } @@ -1563,14 +1821,14 @@ return (function () { //==================================================================== - function loadImmediately(elt, verb, path, nodeData, delay) { + function loadImmediately(elt, handler, nodeData, delay) { var load = function(){ if (!nodeData.loaded) { nodeData.loaded = true; - issueAjaxRequest(verb, path, elt); + handler(elt); } } - if (delay) { + if (delay > 0) { setTimeout(load, delay); } else { load(); @@ -1586,46 +1844,59 @@ return (function () { nodeData.path = path; nodeData.verb = verb; triggerSpecs.forEach(function(triggerSpec) { - if (triggerSpec.sseEvent) { - processSSETrigger(elt, verb, path, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - maybeReveal(elt); - } else if (triggerSpec.trigger === "intersect") { - var observerOptions = {}; - if (triggerSpec.root) { - observerOptions.root = querySelectorExt(elt, triggerSpec.root) - } - if (triggerSpec.threshold) { - observerOptions.threshold = parseFloat(triggerSpec.threshold); + addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return } - var observer = new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - if (entry.isIntersecting) { - triggerEvent(elt, "intersect"); - break; - } - } - }, observerOptions); - observer.observe(elt); - addEventListener(elt, verb, path, nodeData, triggerSpec); - } else if (triggerSpec.trigger === "load") { - loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); - } else if (triggerSpec.pollInterval) { - nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec); - } else { - addEventListener(elt, verb, path, nodeData, triggerSpec); - } + issueAjaxRequest(verb, path, elt, evt) + }) }); } }); return explicitAction; } + function addTriggerHandler(elt, triggerSpec, nodeData, handler) { + if (triggerSpec.sseEvent) { + processSSETrigger(elt, handler, triggerSpec.sseEvent); + } else if (triggerSpec.trigger === "revealed") { + initScrollHandler(); + addEventListener(elt, handler, nodeData, triggerSpec); + maybeReveal(elt); + } else if (triggerSpec.trigger === "intersect") { + var observerOptions = {}; + if (triggerSpec.root) { + observerOptions.root = querySelectorExt(elt, triggerSpec.root) + } + if (triggerSpec.threshold) { + observerOptions.threshold = parseFloat(triggerSpec.threshold); + } + var observer = new IntersectionObserver(function (entries) { + for (var i = 0; i < entries.length; i++) { + var entry = entries[i]; + if (entry.isIntersecting) { + triggerEvent(elt, "intersect"); + break; + } + } + }, observerOptions); + observer.observe(elt); + addEventListener(elt, handler, nodeData, triggerSpec); + } else if (triggerSpec.trigger === "load") { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { + loadImmediately(elt, handler, nodeData, triggerSpec.delay); + } + } else if (triggerSpec.pollInterval > 0) { + nodeData.polling = true; + processPolling(elt, handler, triggerSpec); + } else { + addEventListener(elt, handler, nodeData, triggerSpec); + } + } + function evalScript(script) { - if (script.type === "text/javascript" || script.type === "module" || script.type === "") { + if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) { var newScript = getDocument().createElement("script"); forEach(script.attributes, function (attr) { newScript.setAttribute(attr.name, attr.value); @@ -1642,7 +1913,10 @@ return (function () { } catch (e) { logError(e); } finally { - parent.removeChild(script); + // remove old script element, but only if it is still in DOM + if (script.parentElement) { + script.parentElement.removeChild(script); + } } } } @@ -1656,48 +1930,187 @@ return (function () { }); } - function hasChanceOfBeingBoosted() { - return document.querySelector("[hx-boost], [data-hx-boost]"); + function shouldProcessHxOn(elt) { + var attributes = elt.attributes + for (var j = 0; j < attributes.length; j++) { + var attrName = attributes[j].name + if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") || + startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) { + return true + } + } + return false + } + + function findHxOnWildcardElements(elt) { + var node = null + var elements = [] + + if (shouldProcessHxOn(elt)) { + elements.push(elt) + } + + if (document.evaluate) { + var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + + ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt) + while (node = iter.iterateNext()) elements.push(node) + } else { + var allElements = elt.getElementsByTagName("*") + for (var i = 0; i < allElements.length; i++) { + if (shouldProcessHxOn(allElements[i])) { + elements.push(allElements[i]) + } + } + } + + return elements } function findElementsToProcess(elt) { if (elt.querySelectorAll) { - var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; - var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [hx-data-ext]"); + var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; + var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," + + " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]"); return results; } else { return []; } } - function initButtonTracking(form){ - var maybeSetLastButtonClicked = function(evt){ - if (matches(evt.target, "button, input[type='submit']")) { - var internalData = getInternalData(form); - internalData.lastButtonClicked = evt.target; - } - }; - + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + function maybeSetLastButtonClicked(evt) { + var elt = closest(evt.target, "button, input[type='submit']"); + var internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = elt; + } + }; + function maybeUnsetLastButtonClicked(evt){ + var internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = null; + } + } + function getRelatedFormData(evt) { + var elt = closest(evt.target, "button, input[type='submit']"); + if (!elt) { + return; + } + var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form'); + if (!form) { + return; + } + return getInternalData(form); + } + function initButtonTracking(elt) { // need to handle both click and focus in: // focusin - in case someone tabs in to a button and hits the space bar // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + elt.addEventListener('click', maybeSetLastButtonClicked) + elt.addEventListener('focusin', maybeSetLastButtonClicked) + elt.addEventListener('focusout', maybeUnsetLastButtonClicked) + } - form.addEventListener('click', maybeSetLastButtonClicked) - form.addEventListener('focusin', maybeSetLastButtonClicked) - form.addEventListener('focusout', function(evt){ - var internalData = getInternalData(form); - internalData.lastButtonClicked = null; - }) + function countCurlies(line) { + var tokens = tokenizeString(line); + var netCurlies = 0; + for (var i = 0; i < tokens.length; i++) { + const token = tokens[i]; + if (token === "{") { + netCurlies++; + } else if (token === "}") { + netCurlies--; + } + } + return netCurlies; + } + + function addHxOnEventHandler(elt, eventName, code) { + var nodeData = getInternalData(elt); + if (!Array.isArray(nodeData.onHandlers)) { + nodeData.onHandlers = []; + } + var func; + var listener = function (e) { + return maybeEval(elt, function() { + if (!func) { + func = new Function("event", code); + } + func.call(elt, e); + }); + }; + elt.addEventListener(eventName, listener); + nodeData.onHandlers.push({event:eventName, listener:listener}); + } + + function processHxOn(elt) { + var hxOnValue = getAttributeValue(elt, 'hx-on'); + if (hxOnValue) { + var handlers = {} + var lines = hxOnValue.split("\n"); + var currentEvent = null; + var curlyCount = 0; + while (lines.length > 0) { + var line = lines.shift(); + var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/); + if (curlyCount === 0 && match) { + line.split(":") + currentEvent = match[1].slice(0, -1); // strip last colon + handlers[currentEvent] = match[2]; + } else { + handlers[currentEvent] += line; + } + curlyCount += countCurlies(line); + } + + for (var eventName in handlers) { + addHxOnEventHandler(elt, eventName, handlers[eventName]); + } + } + } + + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (var i = 0; i < elt.attributes.length; i++) { + var name = elt.attributes[i].name + var value = elt.attributes[i].value + if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) { + var afterOnPosition = name.indexOf("-on") + 3; + var nextChar = name.slice(afterOnPosition, afterOnPosition + 1); + if (nextChar === "-" || nextChar === ":") { + var eventName = name.slice(afterOnPosition + 1); + // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support + if (startsWith(eventName, ":")) { + eventName = "htmx" + eventName + } else if (startsWith(eventName, "-")) { + eventName = "htmx:" + eventName.slice(1); + } else if (startsWith(eventName, "htmx-")) { + eventName = "htmx:" + eventName.slice(5); + } + + addHxOnEventHandler(elt, eventName, value) + } + } + } } function initNode(elt) { - if (elt.closest && elt.closest(htmx.config.disableSelector)) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) return; } var nodeData = getInternalData(elt); - if (!nodeData.initialized) { - nodeData.initialized = true; + if (nodeData.initHash !== attributeHash(elt)) { + // clean up any previously processed info + deInitNode(elt); + + nodeData.initHash = attributeHash(elt); + + processHxOn(elt); + triggerEvent(elt, "htmx:beforeProcessNode") if (elt.value) { @@ -1705,14 +2118,24 @@ return (function () { } var triggerSpecs = getTriggerSpecs(elt); - var explicitAction = processVerbs(elt, nodeData, triggerSpecs); - - if (!explicitAction && getClosestAttributeValue(elt, "hx-boost") === "true") { - boostElement(elt, nodeData, triggerSpecs); + var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs); + + if (!hasExplicitHttpAction) { + if (getClosestAttributeValue(elt, "hx-boost") === "true") { + boostElement(elt, nodeData, triggerSpecs); + } else if (hasAttribute(elt, 'hx-trigger')) { + triggerSpecs.forEach(function (triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function () { + }) + }) + } } - if (elt.tagName === "FORM") { - initButtonTracking(elt); + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) { + initButtonTracking(elt) } var sseInfo = getAttributeValue(elt, 'hx-sse'); @@ -1730,8 +2153,15 @@ return (function () { function processNode(elt) { elt = resolveTarget(elt); + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return; + } initNode(elt); forEach(findElementsToProcess(elt), function(child) { initNode(child) }); + // Because it happens second, the new way of adding onHandlers superseeds the old one + // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored + forEach(findHxOnWildcardElements(elt), processHxOnWildcard); } //==================================================================== @@ -1809,7 +2239,7 @@ return (function () { eventResult = eventResult && elt.dispatchEvent(kebabedEvent) } withExtensions(elt, function (extension) { - eventResult = eventResult && (extension.onEvent(eventName, event) !== false) + eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) }); return eventResult; } @@ -1825,6 +2255,18 @@ return (function () { } function saveToHistoryCache(url, content, title, scroll) { + if (!canAccessLocalStorage()) { + return; + } + + if (htmx.config.historyCacheSize <= 0) { + // make sure that an eventually already existing cache is purged + localStorage.removeItem("htmx-history-cache"); + return; + } + + url = normalizePath(url); + var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { @@ -1832,7 +2274,9 @@ return (function () { break; } } - historyCache.push({url:url, content: content, title:title, scroll:scroll}) + var newHistoryItem = {url:url, content: content, title:title, scroll:scroll}; + triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache}) + historyCache.push(newHistoryItem) while (historyCache.length > htmx.config.historyCacheSize) { historyCache.shift(); } @@ -1848,6 +2292,12 @@ return (function () { } function getCachedHistory(url) { + if (!canAccessLocalStorage()) { + return null; + } + + url = normalizePath(url); + var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { @@ -1869,13 +2319,43 @@ return (function () { function saveCurrentPageToHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; - triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); - if(htmx.config.historyEnabled) history.replaceState({htmx:true}, getDocument().title, window.location.href); - saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); + + // Allow history snapshot feature to be disabled where hx-history="false" + // is present *anywhere* in the current document we're about to save, + // so we can prevent privileged data entering the cache. + // The page will still be reachable as a history entry, but htmx will fetch it + // live from the server onpopstate rather than look in the localStorage cache + var disableHistoryCache + try { + disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') + } catch (e) { + // IE11: insensitive modifier not supported so fallback to case sensitive selector + disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') + } + if (!disableHistoryCache) { + triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt}); + saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); + } + + if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href); } function pushUrlIntoHistory(path) { - if(htmx.config.historyEnabled) history.pushState({htmx:true}, "", path); + // remove the cache buster parameter, if any + if (htmx.config.getCacheBusterParam) { + path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') + if (endsWith(path, '&') || endsWith(path, "?")) { + path = path.slice(0, -1); + } + } + if(htmx.config.historyEnabled) { + history.pushState({htmx:true}, "", path); + } + currentPathForHistory = path; + } + + function replaceUrlInHistory(path) { + if(htmx.config.historyEnabled) history.replaceState({htmx:true}, "", path); currentPathForHistory = path; } @@ -1890,7 +2370,9 @@ return (function () { var details = {path: path, xhr:request}; triggerEvent(getDocument().body, "htmx:historyCacheMiss", details); request.open('GET', path, true); + request.setRequestHeader("HX-Request", "true"); request.setRequestHeader("HX-History-Restore-Request", "true"); + request.setRequestHeader("HX-Current-URL", getDocument().location.href); request.onload = function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); @@ -1899,11 +2381,20 @@ return (function () { fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; var historyElement = getHistoryElement(); var settleInfo = makeSettleInfo(historyElement); + var title = findTitle(this.response); + if (title) { + var titleElt = find("title"); + if (titleElt) { + titleElt.innerHTML = title; + } else { + window.document.title = title; + } + } // @ts-ignore swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); + triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response}); } else { triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details); } @@ -1922,9 +2413,11 @@ return (function () { swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); document.title = cached.title; - window.scrollTo(0, cached.scroll); + setTimeout(function () { + window.scrollTo(0, cached.scroll); + }, 0); // next 'tick', so browser has time to render layout currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); + triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); } else { if (htmx.config.refreshOnHistoryMiss) { @@ -1936,31 +2429,46 @@ return (function () { } } - function shouldPush(elt) { - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - return (pushUrl && pushUrl !== "false") || - (getInternalData(elt).boosted && getInternalData(elt).pushURL); - } - - function getPushUrl(elt) { - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - return (pushUrl === "true" || pushUrl === "false") ? null : pushUrl; - } - function addRequestIndicatorClasses(elt) { var indicators = findAttributeTargets(elt, 'hx-indicator'); if (indicators == null) { indicators = [elt]; } forEach(indicators, function (ic) { + var internalData = getInternalData(ic); + internalData.requestCount = (internalData.requestCount || 0) + 1; ic.classList["add"].call(ic.classList, htmx.config.requestClass); }); return indicators; } - function removeRequestIndicatorClasses(indicators) { + function disableElements(elt) { + var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt'); + if (disabledElts == null) { + disabledElts = []; + } + forEach(disabledElts, function (disabledElement) { + var internalData = getInternalData(disabledElement); + internalData.requestCount = (internalData.requestCount || 0) + 1; + disabledElement.setAttribute("disabled", ""); + }); + return disabledElts; + } + + function removeRequestIndicators(indicators, disabled) { forEach(indicators, function (ic) { - ic.classList["remove"].call(ic.classList, htmx.config.requestClass); + var internalData = getInternalData(ic); + internalData.requestCount = (internalData.requestCount || 0) - 1; + if (internalData.requestCount === 0) { + ic.classList["remove"].call(ic.classList, htmx.config.requestClass); + } + }); + forEach(disabled, function (disabledElement) { + var internalData = getInternalData(disabledElement); + internalData.requestCount = (internalData.requestCount || 0) - 1; + if (internalData.requestCount === 0) { + disabledElement.removeAttribute('disabled'); + } }); } @@ -1979,7 +2487,7 @@ return (function () { } function shouldInclude(elt) { - if(elt.name === "" || elt.name == null || elt.disabled) { + if(elt.name === "" || elt.name == null || elt.disabled || closest(elt, "fieldset[disabled]")) { return false; } // ignore "submitter" types (see jQuery src/serialize.js) @@ -1992,6 +2500,29 @@ return (function () { return true; } + function addValueToValues(name, value, values) { + // This is a little ugly because both the current value of the named value in the form + // and the new value could be arrays, so we have to handle all four cases :/ + if (name != null && value != null) { + var current = values[name]; + if (current === undefined) { + values[name] = value; + } else if (Array.isArray(current)) { + if (Array.isArray(value)) { + values[name] = current.concat(value); + } else { + current.push(value); + } + } else { + if (Array.isArray(value)) { + values[name] = [current].concat(value); + } else { + values[name] = [current, value]; + } + } + } + } + function processInputValue(processed, values, errors, elt, validate) { if (elt == null || haveSeenNode(processed, elt)) { return; @@ -2001,35 +2532,14 @@ return (function () { if (shouldInclude(elt)) { var name = getRawAttribute(elt,"name"); var value = elt.value; - if (elt.multiple) { + if (elt.multiple && elt.tagName === "SELECT") { value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value }); } // include file inputs if (elt.files) { value = toArray(elt.files); } - // This is a little ugly because both the current value of the named value in the form - // and the new value could be arrays, so we have to handle all four cases :/ - if (name != null && value != null) { - var current = values[name]; - if(current) { - if (Array.isArray(current)) { - if (Array.isArray(value)) { - values[name] = current.concat(value); - } else { - current.push(value); - } - } else { - if (Array.isArray(value)) { - values[name] = [current].concat(value); - } else { - values[name] = [current, value]; - } - } - } else { - values[name] = value; - } - } + addValueToValues(name, value, values); if (validate) { validateElement(elt, errors); } @@ -2062,9 +2572,13 @@ return (function () { var formValues = {}; var errors = []; var internalData = getInternalData(elt); + if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { + internalData.lastButtonClicked = null + } // only validate when form is directly submitted and novalidate or formnovalidate are not set - var validate = matches(elt, 'form') && elt.noValidate !== true; + // or if the element has an explicit hx-validate="true" on it + var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true"; if (internalData.lastButtonClicked) { validate = validate && internalData.lastButtonClicked.formNoValidate !== true; } @@ -2078,11 +2592,11 @@ return (function () { processInputValue(processed, values, errors, elt, validate); // if a button or submit was clicked last, include its value - if (internalData.lastButtonClicked) { - var name = getRawAttribute(internalData.lastButtonClicked,"name"); - if (name) { - values[name] = internalData.lastButtonClicked.value; - } + if (internalData.lastButtonClicked || elt.tagName === "BUTTON" || + (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) { + var button = internalData.lastButtonClicked || elt + var name = getRawAttribute(button, "name") + addValueToValues(name, button.value, formValues) } // include any explicit includes @@ -2228,40 +2742,43 @@ return (function () { "swapDelay" : htmx.config.defaultSwapDelay, "settleDelay" : htmx.config.defaultSettleDelay } - if (getInternalData(elt).boosted && !isAnchorLink(elt)) { + if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { swapSpec["show"] = "top" } 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)); - } - if (modifier.indexOf("scroll:") === 0) { - var scrollSpec = modifier.substr(7); + for (var i = 0; i < split.length; i++) { + var value = split[i]; + if (value.indexOf("swap:") === 0) { + swapSpec["swapDelay"] = parseInterval(value.substr(5)); + } else if (value.indexOf("settle:") === 0) { + swapSpec["settleDelay"] = parseInterval(value.substr(7)); + } else if (value.indexOf("transition:") === 0) { + swapSpec["transition"] = value.substr(11) === "true"; + } else if (value.indexOf("ignoreTitle:") === 0) { + swapSpec["ignoreTitle"] = value.substr(12) === "true"; + } else if (value.indexOf("scroll:") === 0) { + var scrollSpec = value.substr(7); var splitSpec = scrollSpec.split(":"); var scrollVal = splitSpec.pop(); var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; swapSpec["scroll"] = scrollVal; swapSpec["scrollTarget"] = selectorVal; - } - if (modifier.indexOf("show:") === 0) { - var showSpec = modifier.substr(5); + } else if (value.indexOf("show:") === 0) { + var showSpec = value.substr(5); var splitSpec = showSpec.split(":"); var showVal = splitSpec.pop(); var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; swapSpec["show"] = showVal; swapSpec["showTarget"] = selectorVal; - } - if (modifier.indexOf("focus-scroll:") === 0) { - var focusScrollVal = modifier.substr("focus-scroll:".length); + } else if (value.indexOf("focus-scroll:") === 0) { + var focusScrollVal = value.substr("focus-scroll:".length); swapSpec["focusScroll"] = focusScrollVal == "true"; + } else if (i == 0) { + swapSpec["swapStyle"] = value; + } else { + logError('Unknown modifier in hx-swap: ' + value); } } } @@ -2269,6 +2786,11 @@ return (function () { return swapSpec; } + function usesFormData(elt) { + return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || + (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data"); + } + function encodeParamsForBody(xhr, elt, filteredParameters) { var encodedParameters = null; withExtensions(elt, function (extension) { @@ -2279,8 +2801,7 @@ return (function () { if (encodedParameters != null) { return encodedParameters; } else { - if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || - (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) { + if (usesFormData(elt)) { return makeFormData(filteredParameters); } else { return urlEncode(filteredParameters); @@ -2352,6 +2873,9 @@ return (function () { if (attributeValue) { var str = attributeValue.trim(); var evaluateValue = evalAsDefault; + if (str === "unset") { + return null; + } if (str.indexOf("javascript:") === 0) { str = str.substr(11); evaluateValue = true; @@ -2426,7 +2950,7 @@ return (function () { } } - function getResponseURL(xhr) { + function getPathFromResponse(xhr) { // NB: IE11 does not support this stuff if (xhr.responseURL && typeof(URL) !== "undefined") { try { @@ -2439,7 +2963,7 @@ return (function () { } function hasHeader(xhr, regexp) { - return xhr.getAllResponseHeaders().match(regexp); + return regexp.test(xhr.getAllResponseHeaders()) } function ajaxHelper(verb, path, context) { @@ -2458,6 +2982,7 @@ return (function () { values : context.values, targetOverride: resolveTarget(context.target), swapOverride: context.swap, + select: context.select, returnPromise: true }); } @@ -2477,7 +3002,28 @@ return (function () { return arr; } - function issueAjaxRequest(verb, path, elt, event, etc) { + function verifyPath(elt, path, requestConfig) { + var sameHost + var url + if (typeof URL === "function") { + url = new URL(path, document.location.href); + var origin = document.location.origin; + sameHost = origin === url.origin; + } else { + // IE11 doesn't support URL + url = path + sameHost = startsWith(path, document.location.origin) + } + + if (htmx.config.selfRequestsOnly) { + if (!sameHost) { + return false; + } + } + return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig)); + } + + function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { var resolve = null; var reject = null; etc = etc != null ? etc : {}; @@ -2491,18 +3037,52 @@ return (function () { elt = getDocument().body; } var responseHandler = etc.handler || handleAjaxResponse; + var select = etc.select || null; if (!bodyContains(elt)) { - return; // do not issue requests for elements removed from the DOM + // do not issue requests for elements removed from the DOM + maybeCall(resolve); + return promise; } var target = etc.targetOverride || getTarget(elt); if (target == null || target == DUMMY_ELT) { triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); - return; + maybeCall(reject); + return promise; } - var syncElt = elt; var eltData = getInternalData(elt); + var submitter = eltData.lastButtonClicked; + + if (submitter) { + var buttonPath = getRawAttribute(submitter, "formaction"); + if (buttonPath != null) { + path = buttonPath; + } + + var buttonVerb = getRawAttribute(submitter, "formmethod") + if (buttonVerb != null) { + // ignore buttons with formmethod="dialog" + if (buttonVerb.toLowerCase() !== "dialog") { + verb = buttonVerb; + } + } + } + + var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); + // allow event-based confirmation w/ a callback + if (confirmed === undefined) { + var issueRequest = function(skipConfirmation) { + return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation); + } + var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion}; + if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { + maybeCall(resolve); + return promise; + } + } + + var syncElt = elt; var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); var queueStrategy = null; var abortable = false; @@ -2518,10 +3098,12 @@ return (function () { syncStrategy = (syncStrings[1] || 'drop').trim(); eltData = getInternalData(syncElt); if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { - return; + maybeCall(resolve); + return promise; } else if (syncStrategy === "abort") { if (eltData.xhr) { - return; + maybeCall(resolve); + return promise; } else { abortable = true; } @@ -2565,7 +3147,8 @@ return (function () { issueAjaxRequest(verb, path, elt, event, etc) }); } - return; + maybeCall(resolve); + return promise; } } @@ -2593,8 +3176,7 @@ return (function () { } } - var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); - if (confirmQuestion) { + if (confirmQuestion && !confirmed) { if(!confirm(confirmQuestion)) { maybeCall(resolve); endRequestLock() @@ -2604,6 +3186,11 @@ return (function () { var headers = getHeaders(elt, target, promptResponse); + + if (verb !== 'get' && !usesFormData(elt)) { + headers['Content-Type'] = 'application/x-www-form-urlencoded'; + } + if (etc.headers) { headers = mergeObjects(headers, etc.headers); } @@ -2617,8 +3204,8 @@ return (function () { var allParameters = mergeObjects(rawParameters, expressionVars); var filteredParameters = filterValues(allParameters, elt); - if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null) { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; + if (htmx.config.getCacheBusterParam && verb === 'get') { + filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true"; } // behavior of anchors w/ empty href is to use the current URL @@ -2626,9 +3213,16 @@ return (function () { path = getDocument().location.href; } + var requestAttrValues = getValuesForElement(elt, 'hx-request'); + var eltIsBoosted = getInternalData(elt).boosted; + + var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + var requestConfig = { + boosted: eltIsBoosted, + useUrlParams: useUrlParams, parameters: filteredParameters, unfilteredParameters: allParameters, headers:headers, @@ -2653,6 +3247,7 @@ return (function () { headers = requestConfig.headers; filteredParameters = requestConfig.parameters; errors = requestConfig.errors; + useUrlParams = requestConfig.useUrlParams; if(errors && errors.length > 0){ triggerEvent(elt, 'htmx:validation:halted', requestConfig) @@ -2664,25 +3259,31 @@ return (function () { var splitPath = path.split("#"); var pathNoAnchor = splitPath[0]; var anchor = splitPath[1]; - if (verb === 'get') { - var finalPathForGet = pathNoAnchor; + + var finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor; var values = Object.keys(filteredParameters).length !== 0; if (values) { - if (finalPathForGet.indexOf("?") < 0) { - finalPathForGet += "?"; + if (finalPath.indexOf("?") < 0) { + finalPath += "?"; } else { - finalPathForGet += "&"; + finalPath += "&"; } - finalPathForGet += urlEncode(filteredParameters); + finalPath += urlEncode(filteredParameters); if (anchor) { - finalPathForGet += "#" + anchor; + finalPath += "#" + anchor; } } - xhr.open('GET', finalPathForGet, true); - } else { - xhr.open(verb.toUpperCase(), path, true); } + if (!verifyPath(elt, finalPath, requestConfig)) { + triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) + maybeCall(reject); + return promise; + }; + + xhr.open(verb.toUpperCase(), finalPath, true); xhr.overrideMimeType("text/html"); xhr.withCredentials = requestConfig.withCredentials; xhr.timeout = requestConfig.timeout; @@ -2699,19 +3300,24 @@ return (function () { } } - var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, etc:etc, pathInfo:{ - path:path, finalPath:finalPathForGet, anchor:anchor + var responseInfo = { + xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select, + pathInfo: { + requestPath: path, + finalRequestPath: finalPath, + anchor: anchor } }; xhr.onload = function () { try { var hierarchy = hierarchyForElt(elt); + responseInfo.pathInfo.responsePath = getPathFromResponse(xhr); responseHandler(elt, responseInfo); - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerEvent(elt, 'htmx:afterRequest', responseInfo); triggerEvent(elt, 'htmx:afterOnLoad', responseInfo); - // if the body no longer contains the element, trigger the even on the closest parent + // if the body no longer contains the element, trigger the event on the closest parent // remaining in the DOM if (!bodyContains(elt)) { var secondaryTriggerElt = null; @@ -2734,21 +3340,21 @@ return (function () { } } xhr.onerror = function () { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:sendError', responseInfo); maybeCall(reject); endRequestLock(); } xhr.onabort = function() { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo); maybeCall(reject); endRequestLock(); } xhr.ontimeout = function() { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:timeout', responseInfo); maybeCall(reject); @@ -2760,6 +3366,7 @@ return (function () { return promise } var indicators = addRequestIndicatorClasses(elt); + var disableElts = disableElements(elt); forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { forEach([xhr, xhr.upload], function (target) { @@ -2773,14 +3380,99 @@ return (function () { }); }); triggerEvent(elt, 'htmx:beforeSend', responseInfo); - xhr.send(verb === 'get' ? null : encodeParamsForBody(xhr, elt, filteredParameters)); + var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) + xhr.send(params); return promise; } + function determineHistoryUpdates(elt, responseInfo) { + + var xhr = responseInfo.xhr; + + //=========================================== + // First consult response headers + //=========================================== + var pathFromHeaders = null; + var typeFromHeaders = null; + if (hasHeader(xhr,/HX-Push:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Push"); + typeFromHeaders = "push"; + } else if (hasHeader(xhr,/HX-Push-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Push-Url"); + typeFromHeaders = "push"; + } else if (hasHeader(xhr,/HX-Replace-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url"); + typeFromHeaders = "replace"; + } + + // if there was a response header, that has priority + if (pathFromHeaders) { + if (pathFromHeaders === "false") { + return {} + } else { + return { + type: typeFromHeaders, + path : pathFromHeaders + } + } + } + + //=========================================== + // Next resolve via DOM values + //=========================================== + var requestPath = responseInfo.pathInfo.finalRequestPath; + var responsePath = responseInfo.pathInfo.responsePath; + + var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); + var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url"); + var elementIsBoosted = getInternalData(elt).boosted; + + var saveType = null; + var path = null; + + if (pushUrl) { + saveType = "push"; + path = pushUrl; + } else if (replaceUrl) { + saveType = "replace"; + path = replaceUrl; + } else if (elementIsBoosted) { + saveType = "push"; + path = responsePath || requestPath; // if there is no response path, go with the original request path + } + + if (path) { + // false indicates no push, return empty object + if (path === "false") { + return {}; + } + + // true indicates we want to follow wherever the server ended up sending us + if (path === "true") { + path = responsePath || requestPath; // if there is no response path, go with the original request path + } + + // restore any anchor associated with the request + if (responseInfo.pathInfo.anchor && + path.indexOf("#") === -1) { + path = path + "#" + responseInfo.pathInfo.anchor; + } + + return { + type:saveType, + path: path + } + } else { + return {}; + } + } + function handleAjaxResponse(elt, responseInfo) { var xhr = responseInfo.xhr; var target = responseInfo.target; var etc = responseInfo.etc; + var requestConfig = responseInfo.requestConfig; + var select = responseInfo.select; if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; @@ -2788,33 +3480,44 @@ return (function () { handleTrigger(xhr, "HX-Trigger", elt); } - if (hasHeader(xhr,/HX-Push:/i)) { - var pushedUrl = xhr.getResponseHeader("HX-Push"); + if (hasHeader(xhr, /HX-Location:/i)) { + saveCurrentPageToHistory(); + var redirectPath = xhr.getResponseHeader("HX-Location"); + var swapSpec; + if (redirectPath.indexOf("{") === 0) { + swapSpec = parseJSON(redirectPath); + // what's the best way to throw an error if the user didn't include this + redirectPath = swapSpec['path']; + delete swapSpec['path']; + } + ajaxHelper('GET', redirectPath, swapSpec).then(function(){ + pushUrlIntoHistory(redirectPath); + }); + return; } + var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh"); + if (hasHeader(xhr, /HX-Redirect:/i)) { - window.location.href = xhr.getResponseHeader("HX-Redirect"); + location.href = xhr.getResponseHeader("HX-Redirect"); + shouldRefresh && location.reload(); return; } - if (hasHeader(xhr,/HX-Refresh:/i)) { - if ("true" === xhr.getResponseHeader("HX-Refresh")) { - location.reload(); - return; - } + if (shouldRefresh) { + location.reload(); + return; } if (hasHeader(xhr,/HX-Retarget:/i)) { - responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget")); + if (xhr.getResponseHeader("HX-Retarget") === "this") { + responseInfo.target = elt; + } else { + responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget")); + } } - /** @type {boolean} */ - var shouldSaveHistory - if (pushedUrl == "false") { - shouldSaveHistory = false - } else { - shouldSaveHistory = shouldPush(elt) || pushedUrl; - } + var historyUpdate = determineHistoryUpdates(elt, responseInfo); // by default htmx only swaps on 200 return codes and does not swap // on 204 'No Content' @@ -2823,15 +3526,18 @@ return (function () { var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; var serverResponse = xhr.response; var isError = xhr.status >= 400; - var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo); + var ignoreTitle = htmx.config.ignoreTitle + var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo); if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; target = beforeSwapDetails.target; // allow re-targeting serverResponse = beforeSwapDetails.serverResponse; // allow updating content isError = beforeSwapDetails.isError; // allow updating error - + ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title + + responseInfo.target = target; // Make updated target available to response events responseInfo.failed = isError; // Make failed property available to response events - responseInfo.successful = !isError; // Make successful property available to response events + responseInfo.successful = !isError; // Make successful property available to response events if (beforeSwapDetails.shouldSwap) { if (xhr.status === 286) { @@ -2842,18 +3548,29 @@ return (function () { serverResponse = extension.transformResponse(serverResponse, xhr, elt); }); - // Save current page - if (shouldSaveHistory) { + // Save current page if there will be a history update + if (historyUpdate.type) { saveCurrentPageToHistory(); } var swapOverride = etc.swapOverride; + if (hasHeader(xhr,/HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader("HX-Reswap"); + } var swapSpec = getSwapSpecification(elt, swapOverride); + if (swapSpec.hasOwnProperty('ignoreTitle')) { + ignoreTitle = swapSpec.ignoreTitle; + } + target.classList.add(htmx.config.swappingClass); + + // optional transition API promise callbacks + var settleResolve = null; + var settleReject = null; + var doSwap = function () { try { - var activeElt = document.activeElement; var selectionInfo = {}; try { @@ -2868,19 +3585,44 @@ return (function () { // safari issue - see https://github.com/microsoft/playwright/issues/5894 } + var selectOverride; + if (select) { + selectOverride = select; + } + + if (hasHeader(xhr, /HX-Reselect:/i)) { + selectOverride = xhr.getResponseHeader("HX-Reselect"); + } + + // if we need to save history, do so, before swapping so that relative resources have the correct base URL + if (historyUpdate.type) { + triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)); + if (historyUpdate.type === "push") { + pushUrlIntoHistory(historyUpdate.path); + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path}); + } else { + replaceUrlInHistory(historyUpdate.path); + triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path}); + } + } + var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride); if (selectionInfo.elt && !bodyContains(selectionInfo.elt) && - selectionInfo.elt.id) { - var newActiveElt = document.getElementById(selectionInfo.elt.id); + getRawAttribute(selectionInfo.elt, "id")) { + var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id")); var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; if (newActiveElt) { // @ts-ignore if (selectionInfo.start && newActiveElt.setSelectionRange) { // @ts-ignore - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + try { + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + } catch (e) { + // the setSelectionRange method is present on fields that don't support it, so just let this fail + } } newActiveElt.focus(focusOptions); } @@ -2893,9 +3635,6 @@ return (function () { } triggerEvent(elt, 'htmx:afterSwap', responseInfo); }); - if (responseInfo.pathInfo.anchor) { - location.hash = responseInfo.pathInfo.anchor; - } if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { var finalElt = elt; @@ -2915,14 +3654,15 @@ return (function () { } triggerEvent(elt, 'htmx:afterSettle', responseInfo); }); - // push URL and save new page - if (shouldSaveHistory) { - var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; - pushUrlIntoHistory(pathToPush); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: pathToPush}); + + if (responseInfo.pathInfo.anchor) { + var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor); + if(anchorTarget) { + anchorTarget.scrollIntoView({block:'start', behavior: "auto"}); + } } - if(settleInfo.title) { + if(settleInfo.title && !ignoreTitle) { var titleElt = find("title"); if(titleElt) { titleElt.innerHTML = settleInfo.title; @@ -2940,6 +3680,7 @@ return (function () { } handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); } + maybeCall(settleResolve); } if (swapSpec.settleDelay > 0) { @@ -2949,10 +3690,34 @@ return (function () { } } catch (e) { triggerErrorEvent(elt, 'htmx:swapError', responseInfo); + maybeCall(settleReject); throw e; } }; + var shouldTransition = htmx.config.globalViewTransitions + if(swapSpec.hasOwnProperty('transition')){ + shouldTransition = swapSpec.transition; + } + + if(shouldTransition && + triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && + typeof Promise !== "undefined" && document.startViewTransition){ + var settlePromise = new Promise(function (_resolve, _reject) { + settleResolve = _resolve; + settleReject = _reject; + }); + // wrap the original doSwap() in a call to startViewTransition() + var innerDoSwap = doSwap; + doSwap = function() { + document.startViewTransition(function () { + innerDoSwap(); + return settlePromise; + }); + } + } + + if (swapSpec.swapDelay > 0) { setTimeout(doSwap, swapSpec.swapDelay) } else { @@ -2960,7 +3725,7 @@ return (function () { } } if (isError) { - triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.path}, responseInfo)); + triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo)); } } @@ -3048,9 +3813,22 @@ return (function () { //==================================================================== // Initialization //==================================================================== + var isReady = false + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true + }) + /** + * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. + * + * This function uses isReady because there is no realiable way to ask the browswer whether + * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded + * firing and readystate=complete. + */ function ready(fn) { - if (getDocument().readyState !== 'loading') { + // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by + // some means other than the initial page load. + if (isReady || getDocument().readyState === 'complete') { fn(); } else { getDocument().addEventListener('DOMContentLoaded', fn); @@ -3061,9 +3839,9 @@ return (function () { if (htmx.config.includeIndicatorStyles !== false) { getDocument().head.insertAdjacentHTML("beforeend", "<style>\ - ." + htmx.config.indicatorClass + "{opacity:0;transition: opacity 200ms ease-in;}\ - ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1}\ - ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1}\ + ." + htmx.config.indicatorClass + "{opacity:0}\ + ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ + ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ </style>"); } } @@ -3101,6 +3879,9 @@ return (function () { internalData.xhr.abort(); } }); + /** @type {(ev: PopStateEvent) => any} */ + const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null; + /** @type {(ev: PopStateEvent) => any} */ window.onpopstate = function (event) { if (event.state && event.state.htmx) { restoreHistory(); @@ -3110,10 +3891,15 @@ return (function () { 'triggerEvent': triggerEvent }); }); + } else { + if (originalPopstate) { + originalPopstate(event); + } } }; setTimeout(function () { triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event + body = null; // kill reference for gc }, 0); }) diff --git a/code/ch4_app/ch4_final_video_collector/static/js/htmx.min.js b/code/ch4_app/ch4_final_video_collector/static/js/htmx.min.js index 998414c..53bbdf6 100644 --- a/code/ch4_app/ch4_final_video_collector/static/js/htmx.min.js +++ b/code/ch4_app/ch4_final_video_collector/static/js/htmx.min.js @@ -1 +1,4 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(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 l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=k(e);e.classList.toggle(t)}function T(e,t){e=k(e);W(e.parentElement.children,function(e){q(e,t)});L(e,t)}function H(e,t){e=k(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function N(e,t){if(t.indexOf("closest ")===0){return[H(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[C(e,t.substr(5))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return z().querySelectorAll(t)}}function ee(e,t){if(t){return N(e,t)[0]}else{return N(z().body,e)[0]}}function k(e){if(p(e,"String")){return C(e)}else{return e}}function I(e,t,r){if(m(t)){return{target:z().body,event:e,listener:t}}else{return{target:k(e),event:t,listener:r}}}function M(t,r,n){lr(function(){var e=I(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function D(t,r,n){lr(function(){var e=I(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var te=z().createElement("output");function F(e,t){var r=G(e,t);if(r){if(r==="this"){return[re(e,t)]}else{var n=N(e,r);if(n.length===0){pt('The selector "'+r+'" on '+t+" returned no matches!");return[te]}else{return n}}}}function re(e,t){return h(e,function(e){return V(e,t)!=null})}function ne(e){var t=G(e,"hx-target");if(t){if(t==="this"){return re(e,"hx-target")}else{return ee(e,t)}}else{var r=_(e);if(r.boosted){return z().body}else{return e}}}function P(e){var t=U.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function X(t,r){W(t.attributes,function(e){if(!r.hasAttribute(e.name)&&P(e.name)){t.removeAttribute(e.name)}});W(r.attributes,function(e){if(P(e.name)){t.setAttribute(e.name,e.value)}})}function j(e,t){var r=sr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){pt(e)}}return e==="outerHTML"}function B(e,i,o){var t="#"+i.id;var a="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){a=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{a=e}var r=z().querySelectorAll(t);if(r){W(r,function(e){var t;var r=i.cloneNode(true);t=z().createDocumentFragment();t.appendChild(r);if(!j(a,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ye(a,e,e,t,o)}W(o.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(z().body,"htmx:oobErrorNoTarget",{content:i})}return e}function ie(e,r){W(R(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=V(e,"hx-swap-oob");if(t!=null){B(t,e,r)}})}function oe(e){W(R(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=V(e,"id");var r=z().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function ae(n,e,i){W(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();X(e,t);i.tasks.push(function(){X(e,r)})}}})}function se(e){return function(){q(e,U.config.addedClass);ct(e);at(e);le(e);$(e,"htmx:load")}}function le(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ue(e,t,r,n){ae(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(se(i))}}}function fe(t){var e=_(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){W(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){W(t.children,function(e){fe(e)})}}function ce(e,t,r){if(e.tagName==="BODY"){return me(e,t,r)}else{var n;var i=e.previousSibling;ue(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}_(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}fe(e);u(e).removeChild(e)}}function he(e,t,r){return ue(e,e.firstChild,t,r)}function de(e,t,r){return ue(u(e),e,t,r)}function ve(e,t,r){return ue(e,null,t,r)}function ge(e,t,r){return ue(u(e),e.nextSibling,t,r)}function pe(e,t,r){fe(e);return u(e).removeChild(e)}function me(e,t,r){var n=e.firstChild;ue(e,n,t,r);if(n){while(n.nextSibling){fe(n.nextSibling);e.removeChild(n.nextSibling)}fe(n);e.removeChild(n)}}function xe(e,t){var r=G(e,"hx-select");if(r){var n=z().createDocumentFragment();W(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function ye(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":ce(r,n,i);return;case"afterbegin":he(r,n,i);return;case"beforebegin":de(r,n,i);return;case"beforeend":ve(r,n,i);return;case"afterend":ge(r,n,i);return;case"delete":pe(r,n,i);return;default:var o=sr(t);for(var a=0;a<o.length;a++){var f=o[a];try{var s=f.handleSwap(e,r,n,i);if(s){if(typeof s.length!=="undefined"){for(var l=0;l<s.length;l++){var u=s[l];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){i.tasks.push(se(u))}}}return}}catch(e){pt(e)}}if(e==="innerHTML"){me(r,n,i)}else{ye(U.config.defaultSwapStyle,t,r,n,i)}}}function be(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function we(e,t,r,n,i){i.title=be(n);var o=g(n);if(o){ie(o,i);o=xe(r,o);oe(o);return ye(e,r,t,o,i)}}function Se(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!x(a)){a={value:a}}$(r,o,a)}}}else{$(r,n,[])}}var Ee=/\s/;var Ce=/[\s,]/;var Re=/[_$a-zA-Z]/;var Oe=/[_$a-zA-Z0-9]/;var Le=['"',"'","/"];var qe=/[^\s]/;function Ae(e){var t=[];var r=0;while(r<e.length){if(Re.exec(e.charAt(r))){var n=r;while(Oe.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Le.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function Te(e,t,r){return Re.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function He(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Jt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(z().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(Te(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var Ne="input, textarea, select";function ke(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=Ae(t);do{c(n,qe);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var o={trigger:"every"};c(n,qe);o.pollInterval=v(c(n,/[,\[\s]/));c(n,qe);var a=He(e,n,"event");if(a){o.eventFilter=a}r.push(o)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var a=He(e,n,"event");if(a){s.eventFilter=a}while(n.length>0&&n[0]!==","){c(n,qe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Ce))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Ce);if(u==="closest"||u==="find"){n.shift();u+=" "+c(n,Ce)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Ce)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Ce))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Ce)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Ce)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,qe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,Ne)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ie(e){_(e).cancelled=true}function Me(e,t,r,n){var i=_(e);i.timeout=setTimeout(function(){if(Y(e)&&i.cancelled!==true){if(!je(n,dt("hx:poll:trigger",{triggerSpec:n,target:e}))){Z(t,r,e)}Me(e,t,V(e,"hx-"+t),n)}},n.pollInterval)}function De(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&De(t)&&t.target===""||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href");r.pushURL=true}else{var o=f(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=f(t,"action")}e.forEach(function(e){Be(t,n,i,r,e,true)})}}function Pe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&H(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Xe(e,t){return _(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function je(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(z().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Be(o,a,s,e,l,u){var t;if(l.from){t=N(o,l.from)}else{t=[o]}W(t,function(n){var i=function(e){if(!Y(o)){n.removeEventListener(l.trigger,i);return}if(Xe(o,e)){return}if(u||Pe(e,o)){e.preventDefault()}if(je(l,e)){return}var t=_(e);t.triggerSpec=l;if(t.handledFor==null){t.handledFor=[]}var r=_(o);if(t.handledFor.indexOf(o)<0){t.handledFor.push(o);if(l.consume){e.stopPropagation()}if(l.target&&e.target){if(!d(e.target,l.target)){return}}if(l.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(l.changed){if(r.lastValue===o.value){return}else{r.lastValue=o.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(l.throttle){if(!r.throttle){Z(a,s,o,e);r.throttle=setTimeout(function(){r.throttle=null},l.throttle)}}else if(l.delay){r.delayed=setTimeout(function(){Z(a,s,o,e)},l.delay)}else{Z(a,s,o,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:l.trigger,listener:i,on:n});n.addEventListener(l.trigger,i)})}var Ue=false;var Ve=null;function ze(){if(!Ve){Ve=function(){Ue=true};window.addEventListener("scroll",Ve);setInterval(function(){if(Ue){Ue=false;W(z().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){_e(e)})}},200)}}function _e(e){if(!s(e,"data-hx-revealed")&&b(e)){e.setAttribute("data-hx-revealed","true");var t=_(e);if(t.initialized){Z(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Z(t.verb,t.path,e)},{once:true})}}}function We(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Je(e,o[1],0)}if(o[0]==="send"){Ze(e)}}}function Je(s,r,n){if(!Y(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=U.createWebSocket(r);t.onerror=function(e){J(s,"htmx:wsError",{error:e,socket:t});$e(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=Ge(n);setTimeout(function(){Je(s,r,n+1)},t)}};t.onopen=function(e){n=0};_(s).webSocket=t;t.addEventListener("message",function(e){if($e(s)){return}var t=e.data;gt(s,function(e){t=e.transformResponse(t,null,s)});var r=zt(s);var n=g(t);var i=y(n.children);for(var o=0;o<i.length;o++){var a=i[o];B(V(a,"hx-swap-oob")||"true",a,r)}Ct(r.tasks)})}function $e(e){if(!Y(e)){_(e).webSocket.close();return true}}function Ze(u){var f=h(u,function(e){return _(e).webSocket!=null});if(f){u.addEventListener(ke(u)[0].trigger,function(e){var t=_(f).webSocket;var r=Xt(u,f);var n=Mt(u,"post");var i=n.errors;var o=n.values;var a=Gt(u);var s=Q(o,a);var l=jt(s,u);l["HEADERS"]=r;if(i&&i.length>0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Pe(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ge(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}pt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ke(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Ye(e,o[1])}if(o[0]==="swap"){Qe(e,o[1])}}}function Ye(t,e){var r=U.createEventSource(e);r.onerror=function(e){J(t,"htmx:sseError",{error:e,source:r});tt(t)};_(t).sseEventSource=r}function Qe(o,a){var s=h(o,rt);if(s){var l=_(s).sseEventSource;var u=function(e){if(tt(s)){l.removeEventListener(a,u);return}var t=e.data;gt(o,function(e){t=e.transformResponse(t,null,o)});var r=Ut(o);var n=ne(o);var i=zt(o);we(r.swapStyle,o,n,t,i);Ct(i.tasks);$(o,"htmx:sseMessage",e)};_(o).sseListener=u;l.addEventListener(a,u)}else{J(o,"htmx:noSSESourceError")}}function et(e,t,r,n){var i=h(e,rt);if(i){var o=_(i).sseEventSource;var a=function(){if(!tt(i)){if(Y(e)){Z(t,r,e)}else{o.removeEventListener(n,a)}}};_(e).sseListener=a;o.addEventListener(n,a)}else{J(e,"htmx:noSSESourceError")}}function tt(e){if(!Y(e)){_(e).sseEventSource.close();return true}}function rt(e){return _(e).sseEventSource!=null}function nt(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Z(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function it(o,a,e){var t=false;W(n,function(n){if(s(o,"hx-"+n)){var i=V(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){et(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){ze();_e(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=ee(o,e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){$(o,"intersect");break}}},t);r.observe(o);Be(o,n,i,a,e)}else if(e.trigger==="load"){nt(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Me(o,n,i,e)}else{Be(o,n,i,a,e)}})}});return t}function ot(e){if(e.type==="text/javascript"||e.type==="module"||e.type===""){var t=z().createElement("script");W(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(U.config.inlineScriptNonce){t.nonce=U.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){pt(e)}finally{r.removeChild(e)}}}function at(e){if(d(e,"script")){ot(e)}W(R(e,"script"),function(e){ot(e)})}function st(){return document.querySelector("[hx-boost], [data-hx-boost]")}function lt(e){if(e.querySelectorAll){var t=st()?", a, form":"";var r=e.querySelectorAll(i+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [hx-data-ext]");return r}else{return[]}}function ut(r){var e=function(e){if(d(e.target,"button, input[type='submit']")){var t=_(r);t.lastButtonClicked=e.target}};r.addEventListener("click",e);r.addEventListener("focusin",e);r.addEventListener("focusout",function(e){var t=_(r);t.lastButtonClicked=null})}function ft(e){if(e.closest&&e.closest(U.config.disableSelector)){return}var t=_(e);if(!t.initialized){t.initialized=true;$(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=ke(e);var n=it(e,t,r);if(!n&&G(e,"hx-boost")==="true"){Fe(e,t,r)}if(e.tagName==="FORM"){ut(e)}var i=V(e,"hx-sse");if(i){Ke(e,t,i)}var o=V(e,"hx-ws");if(o){We(e,t,o)}$(e,"htmx:afterProcessNode")}}function ct(e){e=k(e);ft(e);W(lt(e),function(e){ft(e)})}function ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function dt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=z().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function J(e,t,r){$(e,t,Q({error:t},r))}function vt(e){return e==="htmx:afterProcessNode"}function gt(e,t){W(sr(e),function(e){try{t(e)}catch(e){pt(e)}})}function pt(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function $(e,t,r){e=k(e);if(r==null){r={}}r["elt"]=e;var n=dt(t,r);if(U.logger&&!vt(t)){U.logger(e,t,r)}if(r.error){pt(r.error);$(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=ht(t);if(i&&o!==t){var a=dt(o,n.detail);i=i&&e.dispatchEvent(a)}gt(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var mt=location.pathname+location.search;function xt(){var e=z().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||z().body}function yt(e,t,r,n){var i=S(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>U.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(z().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function bt(e){var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function wt(e){var t=U.config.requestClass;var r=e.cloneNode(true);W(R(r,"."+t),function(e){q(e,t)});return r.innerHTML}function St(){var e=xt();var t=mt||location.pathname+location.search;$(z().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(U.config.historyEnabled)history.replaceState({htmx:true},z().title,window.location.href);yt(t,wt(e),z().title,window.scrollY)}function Et(e){if(U.config.historyEnabled)history.pushState({htmx:true},"",e);mt=e}function Ct(e){W(e,function(e){e.call()})}function Rt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};$(z().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){$(z().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=xt();var r=zt(t);me(t,e,r);Ct(r.tasks);mt=n;$(z().body,"htmx:historyRestore",{path:n})}else{J(z().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Ot(e){St();e=e||location.pathname+location.search;var t=bt(e);if(t){var r=g(t.content);var n=xt();var i=zt(n);me(n,r,i);Ct(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);mt=e;$(z().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Rt(e)}}}function Lt(e){var t=G(e,"hx-push-url");return t&&t!=="false"||_(e).boosted&&_(e).pushURL}function qt(e){var t=G(e,"hx-push-url");return t==="true"||t==="false"?null:t}function At(e){var t=F(e,"hx-indicator");if(t==null){t=[e]}W(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Tt(e){W(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function Ht(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Nt(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 kt(t,r,n,e,i){if(e==null||Ht(t,e)){return}else{t.push(e)}if(Nt(e)){var o=f(e,"name");var a=e.value;if(e.multiple){a=y(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=y(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){It(e,n)}}if(d(e,"form")){var l=e.elements;W(l,function(e){kt(t,r,n,e,i)})}}function It(e,t){if(e.willValidate){$(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});$(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Mt(e,t){var r=[];var n={};var i={};var o=[];var a=_(e);var s=d(e,"form")&&e.noValidate!==true;if(a.lastButtonClicked){s=s&&a.lastButtonClicked.formNoValidate!==true}if(t!=="get"){kt(r,i,o,H(e,"form"),s)}kt(r,n,o,e,s);if(a.lastButtonClicked){var l=f(a.lastButtonClicked,"name");if(l){n[l]=a.lastButtonClicked.value}}var u=F(e,"hx-include");W(u,function(e){kt(r,n,o,e,s);if(!d(e,"form")){W(e.querySelectorAll(Ne),function(e){kt(r,n,o,e,s)})}});n=Q(n,i);return{errors:o,values:n}}function Dt(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function Ft(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=Dt(t,r,e)})}else{t=Dt(t,r,n)}}}return t}function Pt(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){W(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Xt(e,t,r){var n={"HX-Request":"true","HX-Trigger":f(e,"id"),"HX-Trigger-Name":f(e,"name"),"HX-Target":V(t,"id"),"HX-Current-URL":z().location.href};Wt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(_(e).boosted){n["HX-Boosted"]="true"}return n}function jt(t,e){var r=G(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){W(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};W(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Bt(e){return f(e,"href")&&f(e,"href").indexOf("#")>=0}function Ut(e,t){var r=t?t:G(e,"hx-swap");var n={swapStyle:_(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(_(e).boosted&&!Bt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var o=1;o<i.length;o++){var a=i[o];if(a.indexOf("swap:")===0){n["swapDelay"]=v(a.substr(5))}if(a.indexOf("settle:")===0){n["settleDelay"]=v(a.substr(7))}if(a.indexOf("scroll:")===0){var s=a.substr(7);var l=s.split(":");var f=l.pop();var u=l.length>0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(a.indexOf("show:")===0){var c=a.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(a.indexOf("focus-scroll:")===0){var d=a.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function Vt(t,r,n){var i=null;gt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(G(r,"hx-encoding")==="multipart/form-data"||d(r,"form")&&f(r,"enctype")==="multipart/form-data"){return Pt(n)}else{return Ft(n)}}}function zt(e){return{tasks:[],elts:[e]}}function _t(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ee(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var o=t.showTarget;if(t.showTarget==="window"){o="body"}i=ee(r,o)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function Wt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}else if(o.indexOf("js:")===0){o=o.substr(3);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Jt(e,function(){return Function("return ("+o+")")()},{})}else{s=S(o)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Wt(u(e),t,r,n)}function Jt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function $t(e,t){return Wt(e,"hx-vars",true,t)}function Zt(e,t){return Wt(e,"hx-vals",false,t)}function Gt(e){return Q($t(e),Zt(e))}function Kt(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Yt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(z().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Qt(e,t){return e.getAllResponseHeaders().match(t)}function er(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return Z(e,t,null,null,{targetOverride:k(r),returnPromise:true})}else{return Z(e,t,k(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:k(r.target),swapOverride:r.swap,returnPromise:true})}}else{return Z(e,t,null,null,{returnPromise:true})}}function tr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Z(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=z().body}var v=r.handler||rr;if(!Y(n)){return}var g=r.targetOverride||ne(n);if(g==null||g==te){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=_(n);var o=G(n,"hx-sync");var m=null;var x=false;if(o){var y=o.split(":");var b=y[0].trim();if(b==="this"){p=re(n,"hx-sync")}else{p=ee(n,b)}o=(y[1]||"drop").trim();i=_(p);if(o==="drop"&&i.xhr&&i.abortable!==true){return}else if(o==="abort"){if(i.xhr){return}else{x=true}}else if(o==="replace"){$(p,"htmx:abort")}else if(o.indexOf("queue")===0){var w=o.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=_(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){Z(e,t,n,f,r)})}return}}var a=new XMLHttpRequest;i.xhr=a;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=G(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){K(c);s();return d}}var R=G(n,"hx-confirm");if(R){if(!confirm(R)){K(c);s();return d}}var O=Xt(n,g,C);if(r.headers){O=Q(O,r.headers)}var L=Mt(n,e);var q=L.errors;var A=L.values;if(r.values){A=Q(A,r.values)}var T=Gt(n);var H=Q(A,T);var N=jt(H,n);if(e!=="get"&&G(n,"hx-encoding")==null){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=z().location.href}var k=Wt(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:q,withCredentials:r.credentials||k.credentials||U.config.withCredentials,timeout:r.timeout||k.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){K(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;q=l.errors;if(q&&q.length>0){$(n,"htmx:validation:halted",l);K(c);s();return d}var I=t.split("#");var M=I[0];var D=I[1];if(e==="get"){var F=M;var P=Object.keys(N).length!==0;if(P){if(F.indexOf("?")<0){F+="?"}else{F+="&"}F+=Ft(N);if(D){F+="#"+D}}a.open("GET",F,true)}else{a.open(e.toUpperCase(),t,true)}a.overrideMimeType("text/html");a.withCredentials=l.withCredentials;a.timeout=l.timeout;if(k.noHeaders){}else{for(var X in O){if(O.hasOwnProperty(X)){var j=O[X];Kt(a,X,j)}}}var u={xhr:a,target:g,requestConfig:l,etc:r,pathInfo:{path:t,finalPath:F,anchor:D}};a.onload=function(){try{var e=tr(n);v(n,u);Tt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!Y(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(Y(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}K(c);s()}catch(e){J(n,"htmx:onLoadError",Q({error:e},u));throw e}};a.onerror=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);K(h);s()};a.onabort=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);K(h);s()};a.ontimeout=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);K(h);s()};if(!$(n,"htmx:beforeRequest",u)){K(c);s();return d}var B=At(n);W(["loadstart","loadend","progress","abort"],function(t){W([a,a.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);a.send(e==="get"?null:Vt(a,n,N));return d}function rr(s,l){var u=l.xhr;var f=l.target;var r=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(Qt(u,/HX-Trigger:/i)){Se(u,"HX-Trigger",s)}if(Qt(u,/HX-Push:/i)){var c=u.getResponseHeader("HX-Push")}if(Qt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Qt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(Qt(u,/HX-Retarget:/i)){l.target=z().querySelector(u.getResponseHeader("HX-Retarget"))}var h;if(c=="false"){h=false}else{h=Lt(s)||c}var n=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var e=u.status>=400;var t=Q({shouldSwap:n,serverResponse:d,isError:e},l);if(!$(f,"htmx:beforeSwap",t))return;f=t.target;d=t.serverResponse;e=t.isError;l.failed=e;l.successful=!e;if(t.shouldSwap){if(u.status===286){Ie(s)}gt(s,function(e){d=e.transformResponse(d,u,s)});if(h){St()}var i=r.swapOverride;var v=Ut(s,i);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=zt(f);we(v.swapStyle,f,s,d,n);if(t.elt&&!Y(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);W(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(l.pathInfo.anchor){location.hash=l.pathInfo.anchor}if(Qt(u,/HX-Trigger-After-Swap:/i)){var o=s;if(!Y(s)){o=z().body}Se(u,"HX-Trigger-After-Swap",o)}var a=function(){W(n.tasks,function(e){e.call()});W(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h){var e=c||qt(s)||Yt(u)||l.pathInfo.finalPath||l.pathInfo.path;Et(e);$(z().body,"htmx:pushedIntoHistory",{path:e})}if(n.title){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}_t(n.elts,v);if(Qt(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!Y(s)){r=z().body}Se(u,"HX-Trigger-After-Settle",r)}};if(v.settleDelay>0){setTimeout(a,v.settleDelay)}else{a()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(v.swapDelay>0){setTimeout(o,v.swapDelay)}else{o()}}if(e){J(s,"htmx:responseError",Q({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var nr={};function ir(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function or(e,t){if(t.init){t.init(r)}nr[e]=Q(ir(),t)}function ar(e){delete nr[e]}function sr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){W(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=nr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return sr(u(e),r,n)}function lr(e){if(z().readyState!=="loading"){e()}else{z().addEventListener("DOMContentLoaded",e)}}function ur(){if(U.config.includeIndicatorStyles!==false){z().head.insertAdjacentHTML("beforeend","<style> ."+U.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+U.config.requestClass+" ."+U.config.indicatorClass+"{opacity:1} ."+U.config.requestClass+"."+U.config.indicatorClass+"{opacity:1} </style>")}}function fr(){var e=z().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function cr(){var e=fr();if(e){U.config=Q(U.config,e)}}lr(function(){cr();ur();var e=z().body;ct(e);var t=z().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=_(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){Ot();W(t,function(e){$(e,"htmx:restored",{document:z(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file +// /////////////////////////////////////////////////////////////////// +// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js +// +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(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 a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/<body/.test(e)}function l(e){var t=!N(e);var r=A(e);var n=e;if(r==="head"){n=n.replace(S,"")}if(Q.config.useTemplateFragments&&t){var i=a("<body><template>"+n+"</template></body>",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a("<table>"+n+"</table>",1);case"col":return a("<table><colgroup>"+n+"</colgroup></table>",2);case"tr":return a("<table><tbody>"+n+"</tbody></table>",2);case"td":case"th":return a("<table><tbody><tr>"+n+"</tr></tbody></table>",3);case"script":case"style":return a("<div>"+n+"</div>",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function oe(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function X(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var Y=function(e,t){var r=re().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function we(t,r){oe(t.attributes,function(e){if(!r.hasAttribute(e.name)&&be(e.name)){t.removeAttribute(e.name)}});oe(r.attributes,function(e){if(be(e.name)){t.setAttribute(e.name,e.value)}})}function Se(e,t){var r=Fr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){b(e)}}return e==="outerHTML"}function Ee(e,i,a){var t="#"+ee(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a<i.length;a++){var o=i[a].split(":",2);var s=o[0].trim();if(s.indexOf("#")===0){s=s.substring(1)}var l=o[1]||"true";var u=t.querySelector("#"+s);if(u){Ee(l,u,r)}}}oe(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=te(e,"hx-swap-oob");if(t!=null){Ee(t,e,r)}})}function Re(e){oe(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=te(e,"id");var r=re().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function Te(o,e,s){oe(e.querySelectorAll("[id]"),function(e){var t=ee(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Le(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=He(n.name,t);t=He(n.value,t)}}}return t}function Ae(e){var t=ae(e);if(t.onHandlers){for(var r=0;r<t.onHandlers.length;r++){const n=t.onHandlers[r];e.removeEventListener(n.event,n.listener)}delete t.onHandlers}}function Ne(e){var t=ae(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){oe(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}Ae(e);oe(Object.keys(t),function(e){delete t[e]})}function p(e){ce(e,"htmx:beforeCleanupElement");Ne(e);if(e.children){oe(e.children,function(e){p(e)})}}function Ie(t,e,r){if(t.tagName==="BODY"){return Ue(t,e,r)}else{var n;var i=t.previousSibling;m(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}p(t);u(t).removeChild(t)}}function ke(e,t,r){return m(e,e.firstChild,t,r)}function Pe(e,t,r){return m(u(e),e,t,r)}function Me(e,t,r){return m(e,null,t,r)}function Xe(e,t,r){return m(u(e),e.nextSibling,t,r)}function De(e,t,r){p(e);return u(e).removeChild(e)}function Ue(e,t,r){var n=e.firstChild;m(e,n,t,r);if(n){while(n.nextSibling){p(n.nextSibling);e.removeChild(n.nextSibling)}p(n);e.removeChild(n)}}function Be(e,t,r){var n=r||ne(e,"hx-select");if(n){var i=re().createDocumentFragment();oe(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function Fe(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Ie(r,n,i);return;case"afterbegin":ke(r,n,i);return;case"beforebegin":Pe(r,n,i);return;case"beforeend":Me(r,n,i);return;case"afterend":Xe(r,n,i);return;case"delete":De(r,n,i);return;default:var a=Fr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Oe(f))}}}return}}catch(e){b(e)}}if(e==="innerHTML"){Ue(r,n,i)}else{Fe(Q.config.defaultSwapStyle,t,r,n,i)}}}function Ve(e){if(e.indexOf("<title")>-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){ce(r,s[l].trim(),[])}}}var ze=/\s/;var x=/[\s,]/;var $e=/[_$a-zA-Z]/;var We=/[_$a-zA-Z0-9]/;var Ge=['"',"'","/"];var Je=/[^\s]/;var Ze=/[{(]/;var Ke=/[})]/;function Ye(e){var t=[];var r=0;while(r<e.length){if($e.exec(e.charAt(r))){var n=r;while(We.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ge.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function Qe(e,t,r){return $e.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function et(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){xt(e,a[1],0)}if(a[0]==="send"){bt(e)}}}function xt(s,r,n){if(!se(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=Q.createWebSocket(r);t.onerror=function(e){fe(s,"htmx:wsError",{error:e,socket:t});yt(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a<i.length;a++){var o=i[a];Ee(te(o,"hx-swap-oob")||"true",o,r)}nr(r.tasks)})}function yt(e){if(!se(e)){ae(e).webSocket.close();return true}}function bt(u){var f=c(u,function(e){return ae(e).webSocket!=null});if(f){u.addEventListener(it(u)[0].trigger,function(e){var t=ae(f).webSocket;var r=xr(u,f);var n=dr(u,"post");var i=n.errors;var a=n.values;var o=Hr(u);var s=le(a,o);var l=yr(s,u);l["HEADERS"]=r;if(i&&i.length>0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){Et(e,a[1])}if(a[0]==="swap"){Ct(e,a[1])}}}function Et(t,e){var r=Q.createEventSource(e);r.onerror=function(e){fe(t,"htmx:sseError",{error:e,source:r});Tt(t)};ae(t).sseEventSource=r}function Ct(a,o){var s=c(a,Ot);if(s){var l=ae(s).sseEventSource;var u=function(e){if(Tt(s)){return}if(!se(a)){l.removeEventListener(o,u);return}var t=e.data;R(a,function(e){t=e.transformResponse(t,null,a)});var r=wr(a);var n=ye(a);var i=T(a);je(r.swapStyle,n,a,t,i);nr(i.tasks);ce(a,"htmx:sseMessage",e)};ae(a).sseListener=u;l.addEventListener(o,u)}else{fe(a,"htmx:noSSESourceError")}}function Rt(e,t,r){var n=c(e,Ot);if(n){var i=ae(n).sseEventSource;var a=function(){if(!Tt(n)){if(se(e)){t(e)}else{i.removeEventListener(r,a)}}};ae(e).sseListener=a;i.addEventListener(r,a)}else{fe(e,"htmx:noSSESourceError")}}function Tt(e){if(!se(e)){ae(e).sseEventSource.close();return true}}function Ot(e){return ae(e).sseEventSource!=null}function qt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n>0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){ce(n,"intersect");break}}},i);a.observe(n);ht(n,r,t,e)}else if(e.trigger==="load"){if(!ct(e,n,Wt("load",{elt:n}))){qt(n,r,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r<t.length;r++){var n=t[r].name;if(s(n,"hx-on:")||s(n,"data-hx-on:")||s(n,"hx-on-")||s(n,"data-hx-on-")){return true}}return false}function kt(e){var t=null;var r=[];if(It(e)){r.push(e)}if(document.evaluate){var n=document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]',e);while(t=n.iterateNext())r.push(t)}else{var i=e.getElementsByTagName("*");for(var a=0;a<i.length;a++){if(It(i[a])){r.push(i[a])}}}return r}function Pt(e){if(e.querySelectorAll){var t=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";var r=e.querySelectorAll(i+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Mt(e){var t=v(e.target,"button, input[type='submit']");var r=Dt(e);if(r){r.lastButtonClicked=t}}function Xt(e){var t=Dt(e);if(t){t.lastButtonClicked=null}}function Dt(e){var t=v(e.target,"button, input[type='submit']");if(!t){return}var r=g("#"+ee(t,"form"))||v(t,"form");if(!r){return}return ae(r)}function Ut(e){e.addEventListener("click",Mt);e.addEventListener("focusin",Mt);e.addEventListener("focusout",Xt)}function Bt(e){var t=Ye(e);var r=0;for(var n=0;n<t.length;n++){const i=t[n];if(i==="{"){r++}else if(i==="}"){r--}}return r}function Ft(t,e,r){var n=ae(t);if(!Array.isArray(n.onHandlers)){n.onHandlers=[]}var i;var a=function(e){return Tr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Vt(e){var t=te(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;t<e.attributes.length;t++){var r=e.attributes[t].name;var n=e.attributes[t].value;if(s(r,"hx-on")||s(r,"data-hx-on")){var i=r.indexOf("-on")+3;var a=r.slice(i,i+1);if(a==="-"||a===":"){var o=r.slice(i+1);if(s(o,":")){o="htmx"+o}else if(s(o,"-")){o="htmx:"+o.slice(1)}else if(s(o,"htmx-")){o="htmx:"+o.slice(5)}Ft(e,o,n)}}}}function _t(t){if(v(t,Q.config.disableSelector)){p(t);return}var r=ae(t);if(r.initHash!==Le(t)){Ne(t);r.initHash=Le(t);Vt(t);ce(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=it(t);var n=Ht(t,r,e);if(!n){if(ne(t,"hx-boost")==="true"){lt(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){Lt(t,e,r,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&o(t,"form")){Ut(t)}var i=te(t,"hx-sse");if(i){St(t,r,i)}var a=te(t,"hx-ws");if(a){pt(t,r,a)}ce(t,"htmx:afterProcessNode")}}function zt(e){e=g(e);if(v(e,Q.config.disableSelector)){p(e);return}_t(e);oe(Pt(e),function(e){_t(e)});oe(kt(e),jt)}function $t(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=re().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function fe(e,t,r){ce(e,t,le({error:t},r))}function Gt(e){return e==="htmx:afterProcessNode"}function R(e,t){oe(Fr(e),function(e){try{t(e)}catch(e){b(e)}})}function b(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ce(e,t,r){e=g(e);if(r==null){r={}}r["elt"]=e;var n=Wt(t,r);if(Q.logger&&!Gt(t)){Q.logger(e,t,r)}if(r.error){b(r.error);ce(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=$t(t);if(i&&a!==t){var o=Wt(a,n.detail);i=i&&e.dispatchEvent(o)}R(e,function(e){i=i&&(e.onEvent(t,n)!==false&&!n.defaultPrevented)});return i}var Jt=location.pathname+location.search;function Zt(){var e=re().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||re().body}function Kt(e,t,r,n){if(!U()){return}if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}e=B(e);var i=E(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};ce(re().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Qt(e){var t=Q.config.requestClass;var r=e.cloneNode(true);oe(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function er(){var e=Zt();var t=Jt||location.pathname+location.search;var r;try{r=re().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){r=re().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!r){ce(re().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Kt(t,Qt(e),re().title,window.scrollY)}if(Q.config.historyEnabled)history.replaceState({htmx:true},re().title,window.location.href)}function tr(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(G(e,"&")||G(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Jt=e}function rr(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Jt=e}function nr(e){oe(e,function(e){e.call()})}function ir(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};ce(re().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",re().location.href);e.onload=function(){if(this.status>=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function fr(e){if(e.name===""||e.name==null||e.disabled||v(e,"fieldset[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 cr(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function hr(t,r,n,e,i){if(e==null||ur(t,e)){return}else{t.push(e)}if(fr(e)){var a=ee(e,"name");var o=e.value;if(e.multiple&&e.tagName==="SELECT"){o=M(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=M(e.files)}cr(a,o,r);if(i){vr(e,n)}}if(h(e,"form")){var s=e.elements;oe(s,function(e){hr(t,r,n,e,i)})}}function vr(e,t){if(e.willValidate){ce(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});ce(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function dr(e,t){var r=[];var n={};var i={};var a=[];var o=ae(e);if(o.lastButtonClicked&&!se(o.lastButtonClicked)){o.lastButtonClicked=null}var s=h(e,"form")&&e.noValidate!==true||te(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){hr(r,i,a,v(e,"form"),s)}hr(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=ee(l,"name");cr(u,l.value,i)}var f=pe(e,"hx-include");oe(f,function(e){hr(r,n,a,e,s);if(!h(e,"form")){oe(e.querySelectorAll(rt),function(e){hr(r,n,a,e,s)})}});n=le(n,i);return{errors:a,values:n}}function gr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function mr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t=gr(t,r,e)})}else{t=gr(t,r,n)}}}return t}function pr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function xr(e,t,r){var n={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":re().location.href};Rr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ae(e).boosted){n["HX-Boosted"]="true"}return n}function yr(t,e){var r=ne(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){oe(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};oe(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function br(e){return ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=d(o.substr(5))}else if(o.indexOf("settle:")===0){n["settleDelay"]=d(o.substr(7))}else if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}else if(o.indexOf("ignoreTitle:")===0){n["ignoreTitle"]=o.substr(12)==="true"}else if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","<style> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file diff --git a/code/ch4_app/ch4_starter_video_collector/static/js/htmx.js b/code/ch4_app/ch4_starter_video_collector/static/js/htmx.js index 27e57bc..86e7668 100644 --- a/code/ch4_app/ch4_starter_video_collector/static/js/htmx.js +++ b/code/ch4_app/ch4_starter_video_collector/static/js/htmx.js @@ -1,13 +1,23 @@ -//AMD insanity +// /////////////////////////////////////////////////////////////////// +// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.js +// + +// UMD insanity +// This code sets up support for (in order) AMD, ES6 modules, and globals. (function (root, factory) { //@ts-ignore if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. //@ts-ignore define([], factory); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); } else { // Browser globals - root.htmx = factory(); + root.htmx = root.htmx || factory(); } }(typeof self !== 'undefined' ? self : this, function () { return (function () { @@ -38,6 +48,7 @@ return (function () { defineExtension : defineExtension, removeExtension : removeExtension, logAll : logAll, + logNone : logNone, logger : null, config : { historyEnabled:true, @@ -53,15 +64,24 @@ return (function () { settlingClass:'htmx-settling', swappingClass:'htmx-swapping', allowEval:true, + allowScriptTags:true, inlineScriptNonce:'', attributesToSettle:["class", "style", "width", "height"], withCredentials:false, timeout:0, wsReconnectDelay: 'full-jitter', + wsBinaryType: 'blob', disableSelector: "[hx-disable], [data-hx-disable]", useTemplateFragments: false, scrollBehavior: 'smooth', defaultFocusScroll: false, + getCacheBusterParam: false, + globalViewTransitions: false, + methodsThatUseUrlParams: ["get"], + selfRequestsOnly: false, + ignoreTitle: false, + scrollIntoViewOnBoost: true, + triggerSpecsCache: null, }, parseInterval:parseInterval, _:internalEval, @@ -69,17 +89,23 @@ return (function () { return new EventSource(url, {withCredentials:true}) }, createWebSocket: function(url){ - return new WebSocket(url, []); + var sock = new WebSocket(url, []); + sock.binaryType = htmx.config.wsBinaryType; + return sock; }, - version: "1.7.0" + version: "1.9.10" }; /** @type {import("./htmx").HtmxInternalApi} */ var internalAPI = { + addTriggerHandler: addTriggerHandler, bodyContains: bodyContains, + canAccessLocalStorage: canAccessLocalStorage, + findThisElement: findThisElement, filterValues: filterValues, hasAttribute: hasAttribute, getAttributeValue: getAttributeValue, + getClosestAttributeValue: getClosestAttributeValue, getClosestMatch: getClosestMatch, getExpressionVars: getExpressionVars, getHeaders: getHeaders, @@ -92,6 +118,7 @@ return (function () { mergeObjects: mergeObjects, makeSettleInfo: makeSettleInfo, oobSwap: oobSwap, + querySelectorExt: querySelectorExt, selectAndSwap: selectAndSwap, settleImmediately: settleImmediately, shouldCancel: shouldCancel, @@ -105,21 +132,40 @@ return (function () { return "[hx-" + verb + "], [data-hx-" + verb + "]" }).join(", "); + var HEAD_TAG_REGEX = makeTagRegEx('head'), + TITLE_TAG_REGEX = makeTagRegEx('title'), + SVG_TAGS_REGEX = makeTagRegEx('svg', true); + //==================================================================== // Utilities //==================================================================== + /** + * @param {string} tag + * @param {boolean} global + * @returns {RegExp} + */ + function makeTagRegEx(tag, global = false) { + return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, + global ? 'gim' : 'im'); + } + function parseInterval(str) { if (str == undefined) { - return undefined + return undefined; } + + let interval = NaN; if (str.slice(-2) == "ms") { - return parseFloat(str.slice(0,-2)) || undefined - } - if (str.slice(-1) == "s") { - return (parseFloat(str.slice(0,-1)) * 1000) || undefined + interval = parseFloat(str.slice(0, -2)); + } else if (str.slice(-1) == "s") { + interval = parseFloat(str.slice(0, -1)) * 1000; + } else if (str.slice(-1) == "m") { + interval = parseFloat(str.slice(0, -1)) * 1000 * 60; + } else { + interval = parseFloat(str); } - return parseFloat(str) || undefined + return isNaN(interval) ? undefined : interval; } /** @@ -168,13 +214,11 @@ return (function () { * @returns {HTMLElement | null} */ function getClosestMatch(elt, condition) { - if (condition(elt)) { - return elt; - } else if (parentElt(elt)) { - return getClosestMatch(parentElt(elt), condition); - } else { - return null; + while (elt && !condition(elt)) { + elt = parentElt(elt); } + + return elt ? elt : null; } function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ @@ -208,7 +252,7 @@ return (function () { * @returns {boolean} */ function matches(elt, selector) { - // @ts-ignore: non-standard properties for browser compatability + // @ts-ignore: non-standard properties for browser compatibility // noinspection JSUnresolvedVariable var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; return matchesFunction && matchesFunction.call(elt, selector); @@ -252,38 +296,47 @@ return (function () { return responseNode; } + function aFullPageResponse(resp) { + return /<body/.test(resp) + } + /** * - * @param {string} resp + * @param {string} response * @returns {Element} */ - function makeFragment(resp) { - if (htmx.config.useTemplateFragments) { - var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0); + function makeFragment(response) { + var partialResponse = !aFullPageResponse(response); + var startTag = getStartTag(response); + var content = response; + if (startTag === 'head') { + content = content.replace(HEAD_TAG_REGEX, ''); + } + if (htmx.config.useTemplateFragments && partialResponse) { + var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0); // @ts-ignore type mismatch between DocumentFragment and Element. - // TODO: Are these close enough for htmx to use interchangably? + // TODO: Are these close enough for htmx to use interchangeably? return documentFragment.querySelector('template').content; - } else { - 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); - case "script": - return parseHTML("<div>" + resp + "</div>", 1); - default: - return parseHTML(resp, 0); - } + } + switch (startTag) { + case "thead": + case "tbody": + case "tfoot": + case "colgroup": + case "caption": + return parseHTML("<table>" + content + "</table>", 1); + case "col": + return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2); + case "tr": + return parseHTML("<table><tbody>" + content + "</tbody></table>", 2); + case "td": + case "th": + return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3); + case "script": + case "style": + return parseHTML("<div>" + content + "</div>", 1); + default: + return parseHTML(content, 0); } } @@ -365,13 +418,14 @@ return (function () { return elemTop < window.innerHeight && elemBottom >= 0; } - function bodyContains(elt) { - if (elt.getRootNode() instanceof ShadowRoot) { - return getDocument().body.contains(elt.getRootNode().host); - } else { - return getDocument().body.contains(elt); - } - } + function bodyContains(elt) { + // IE Fix + if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) { + return getDocument().body.contains(elt.getRootNode().host); + } else { + return getDocument().body.contains(elt); + } + } function splitOnWhitespace(trigger) { return trigger.trim().split(/\s+/); @@ -402,6 +456,34 @@ return (function () { } } + function canAccessLocalStorage() { + var test = 'htmx:localStorageTest'; + try { + localStorage.setItem(test, test); + localStorage.removeItem(test); + return true; + } catch(e) { + return false; + } + } + + function normalizePath(path) { + try { + var url = new URL(path); + if (url) { + path = url.pathname + url.search; + } + // remove trailing slash, unless index page + if (!(/^\/$/.test(path))) { + path = path.replace(/\/+$/, ''); + } + return path; + } catch (e) { + // be kind to IE11, which doesn't support URL() + return path; + } + } + //========================================================================================== // public API //========================================================================================== @@ -427,6 +509,10 @@ return (function () { } } + function logNone() { + htmx.logger = null + } + function find(eltOrSelector, selector) { if (selector) { return eltOrSelector.querySelector(selector); @@ -446,7 +532,10 @@ return (function () { function removeElement(elt, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeElement(elt);}, delay) + setTimeout(function(){ + removeElement(elt); + elt = null; + }, delay); } else { elt.parentElement.removeChild(elt); } @@ -455,7 +544,10 @@ return (function () { function addClassToElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){addClassToElement(elt, clazz);}, delay) + setTimeout(function(){ + addClassToElement(elt, clazz); + elt = null; + }, delay); } else { elt.classList && elt.classList.add(clazz); } @@ -464,7 +556,10 @@ return (function () { function removeClassFromElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) + setTimeout(function(){ + removeClassFromElement(elt, clazz); + elt = null; + }, delay); } else { if (elt.classList) { elt.classList.remove(clazz); @@ -494,26 +589,75 @@ return (function () { if (elt.closest) { return elt.closest(selector); } else { + // TODO remove when IE goes away do{ if (elt == null || matches(elt, selector)){ return elt; } } while (elt = elt && parentElt(elt)); + return null; + } + } + + function startsWith(str, prefix) { + return str.substring(0, prefix.length) === prefix + } + + function endsWith(str, suffix) { + return str.substring(str.length - suffix.length) === suffix + } + + function normalizeSelector(selector) { + var trimmedSelector = selector.trim(); + if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) { + return trimmedSelector.substring(1, trimmedSelector.length - 2); + } else { + return trimmedSelector; } } function querySelectorAllExt(elt, selector) { if (selector.indexOf("closest ") === 0) { - return [closest(elt, selector.substr(8))]; + return [closest(elt, normalizeSelector(selector.substr(8)))]; } else if (selector.indexOf("find ") === 0) { - return [find(elt, selector.substr(5))]; + return [find(elt, normalizeSelector(selector.substr(5)))]; + } else if (selector === "next") { + return [elt.nextElementSibling] + } else if (selector.indexOf("next ") === 0) { + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; + } else if (selector === "previous") { + return [elt.previousElementSibling] + } else if (selector.indexOf("previous ") === 0) { + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; } else if (selector === 'document') { return [document]; } else if (selector === 'window') { return [window]; + } else if (selector === 'body') { + return [document.body]; } else { - return getDocument().querySelectorAll(selector); + return getDocument().querySelectorAll(normalizeSelector(selector)); + } + } + + var scanForwardQuery = function(start, match) { + var results = getDocument().querySelectorAll(match); + for (var i = 0; i < results.length; i++) { + var elt = results[i]; + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { + return elt; + } + } + } + + var scanBackwardsQuery = function(start, match) { + var results = getDocument().querySelectorAll(match); + for (var i = results.length - 1; i >= 0; i--) { + var elt = results[i]; + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { + return elt; + } } } @@ -570,7 +714,7 @@ return (function () { //==================================================================== // Node processing //==================================================================== - + var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors function findAttributeTargets(elt, attrName) { var attrTarget = getClosestAttributeValue(elt, attrName); @@ -659,7 +803,7 @@ return (function () { * @returns */ function oobSwap(oobValue, oobElement, settleInfo) { - var selector = "#" + oobElement.id; + var selector = "#" + getRawAttribute(oobElement, "id"); var swapStyle = "outerHTML"; if (oobValue === "true") { // do nothing @@ -703,7 +847,23 @@ return (function () { return oobValue; } - function handleOutOfBandSwaps(fragment, settleInfo) { + function handleOutOfBandSwaps(elt, fragment, settleInfo) { + var oobSelects = getClosestAttributeValue(elt, "hx-select-oob"); + if (oobSelects) { + var oobSelectValues = oobSelects.split(","); + for (var i = 0; i < oobSelectValues.length; i++) { + var oobSelectValue = oobSelectValues[i].split(":", 2); + var id = oobSelectValue[0].trim(); + if (id.indexOf("#") === 0) { + id = id.substring(1); + } + var oobValue = oobSelectValue[1] || "true"; + var oobElement = fragment.querySelector("#" + id); + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo); + } + } + } forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) { var oobValue = getAttributeValue(oobElement, "hx-swap-oob"); if (oobValue != null) { @@ -724,8 +884,11 @@ return (function () { function handleAttributes(parentNode, fragment, settleInfo) { forEach(fragment.querySelectorAll("[id]"), function (newNode) { - if (newNode.id && newNode.id.length > 0) { - var oldNode = parentNode.querySelector(newNode.tagName + "[id='" + newNode.id + "']"); + var id = getRawAttribute(newNode, "id") + if (id && id.length > 0) { + var normalizedId = id.replace("'", "\\'"); + var normalizedTag = newNode.tagName.replace(':', '\\:'); + var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']"); if (oldNode && oldNode !== parentNode) { var newAttributes = newNode.cloneNode(); cloneAttributes(newNode, oldNode); @@ -767,24 +930,67 @@ return (function () { } } - function cleanUpElement(element) { + // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, + // derived from Java's string hashcode implementation + function stringHash(string, hash) { + var char = 0; + while (char < string.length){ + hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int + } + return hash; + } + + function attributeHash(elt) { + var hash = 0; + // IE fix + if (elt.attributes) { + for (var i = 0; i < elt.attributes.length; i++) { + var attribute = elt.attributes[i]; + if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent) + hash = stringHash(attribute.name, hash); + hash = stringHash(attribute.value, hash); + } + } + } + return hash; + } + + function deInitOnHandlers(elt) { + var internalData = getInternalData(elt); + if (internalData.onHandlers) { + for (var i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i]; + elt.removeEventListener(handlerInfo.event, handlerInfo.listener); + } + delete internalData.onHandlers + } + } + + function deInitNode(element) { var internalData = getInternalData(element); + if (internalData.timeout) { + clearTimeout(internalData.timeout); + } if (internalData.webSocket) { internalData.webSocket.close(); } if (internalData.sseEventSource) { internalData.sseEventSource.close(); } - - triggerEvent(element, "htmx:beforeCleanupElement") - if (internalData.listenerInfos) { - forEach(internalData.listenerInfos, function(info) { - if (element !== info.on) { + forEach(internalData.listenerInfos, function (info) { + if (info.on) { info.on.removeEventListener(info.trigger, info.listener); } }); } + deInitOnHandlers(element); + forEach(Object.keys(internalData), function(key) { delete internalData[key] }); + } + + function cleanUpElement(element) { + triggerEvent(element, "htmx:beforeCleanupElement") + deInitNode(element); if (element.children) { // IE forEach(element.children, function(child) { cleanUpElement(child) }); } @@ -803,8 +1009,7 @@ return (function () { } else { newElt = eltBeforeNewContent.nextSibling; } - getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later - settleInfo.elts = [] // clear existing elements + settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target }); while(newElt && newElt !== target) { if (newElt.nodeType === Node.ELEMENT_NODE) { settleInfo.elts.push(newElt); @@ -849,8 +1054,8 @@ return (function () { } } - function maybeSelectFromResponse(elt, fragment) { - var selector = getClosestAttributeValue(elt, "hx-select"); + function maybeSelectFromResponse(elt, fragment, selectOverride) { + var selector = selectOverride || getClosestAttributeValue(elt, "hx-select"); if (selector) { var newFragment = getDocument().createDocumentFragment(); forEach(fragment.querySelectorAll(selector), function (node) { @@ -915,21 +1120,20 @@ return (function () { function findTitle(content) { if (content.indexOf('<title') > -1) { - var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, ''); - var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im); - + var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, ''); + var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX); if (result) { return result[2]; } } } - function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) { + function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) { settleInfo.title = findTitle(responseText); var fragment = makeFragment(responseText); if (fragment) { - handleOutOfBandSwaps(fragment, settleInfo); - fragment = maybeSelectFromResponse(elt, fragment); + handleOutOfBandSwaps(elt, fragment, settleInfo); + fragment = maybeSelectFromResponse(elt, fragment, selectOverride); handlePreservedElements(fragment); return swap(swapStyle, elt, target, fragment, settleInfo); } @@ -949,7 +1153,10 @@ return (function () { } } } else { - triggerEvent(elt, triggerBody, []); + var eventNames = triggerBody.split(",") + for (var i = 0; i < eventNames.length; i++) { + triggerEvent(elt, eventNames[i].trim(), []); + } } } @@ -959,6 +1166,8 @@ return (function () { var SYMBOL_CONT = /[_$a-zA-Z0-9]/; var STRINGISH_START = ['"', "'", "/"]; var NOT_WHITESPACE = /[^\s]/; + var COMBINED_SELECTOR_START = /[{(]/; + var COMBINED_SELECTOR_END = /[})]/; function tokenizeString(str) { var tokens = []; var position = 0; @@ -1041,101 +1250,137 @@ return (function () { function consumeUntil(tokens, match) { var result = ""; - while (tokens.length > 0 && !tokens[0].match(match)) { + while (tokens.length > 0 && !match.test(tokens[0])) { result += tokens.shift(); } return result; } + function consumeCSSSelector(tokens) { + var result; + if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { + tokens.shift(); + result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim(); + tokens.shift(); + } else { + result = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } + return result; + } + var INPUT_SELECTOR = 'input, textarea, select'; /** * @param {HTMLElement} elt + * @param {string} explicitTrigger + * @param {cache} cache for trigger specs * @returns {import("./htmx").HtmxTriggerSpecification[]} */ - function getTriggerSpecs(elt) { - var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); + function parseAndCacheTrigger(elt, explicitTrigger, cache) { var triggerSpecs = []; - if (explicitTrigger) { - var tokens = tokenizeString(explicitTrigger); - do { - consumeUntil(tokens, NOT_WHITESPACE); - var initialLength = tokens.length; - var trigger = consumeUntil(tokens, /[,\[\s]/); - if (trigger !== "") { - if (trigger === "every") { - var every = {trigger: 'every'}; - consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); - consumeUntil(tokens, NOT_WHITESPACE); - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - every.eventFilter = eventFilter; - } - triggerSpecs.push(every); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); - } else { - var triggerSpec = {trigger: trigger}; - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - triggerSpec.eventFilter = eventFilter; - } - while (tokens.length > 0 && tokens[0] !== ",") { - consumeUntil(tokens, NOT_WHITESPACE) - var token = tokens.shift(); - if (token === "changed") { - triggerSpec.changed = true; - } else if (token === "once") { - triggerSpec.once = true; - } else if (token === "consume") { - triggerSpec.consume = true; - } else if (token === "delay" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "from" && tokens[0] === ":") { - tokens.shift(); + var tokens = tokenizeString(explicitTrigger); + do { + consumeUntil(tokens, NOT_WHITESPACE); + var initialLength = tokens.length; + var trigger = consumeUntil(tokens, /[,\[\s]/); + if (trigger !== "") { + if (trigger === "every") { + var every = {trigger: 'every'}; + consumeUntil(tokens, NOT_WHITESPACE); + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); + consumeUntil(tokens, NOT_WHITESPACE); + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + every.eventFilter = eventFilter; + } + triggerSpecs.push(every); + } else if (trigger.indexOf("sse:") === 0) { + triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); + } else { + var triggerSpec = {trigger: trigger}; + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + triggerSpec.eventFilter = eventFilter; + } + while (tokens.length > 0 && tokens[0] !== ",") { + consumeUntil(tokens, NOT_WHITESPACE) + var token = tokens.shift(); + if (token === "changed") { + triggerSpec.changed = true; + } else if (token === "once") { + triggerSpec.once = true; + } else if (token === "consume") { + triggerSpec.consume = true; + } else if (token === "delay" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); + } else if (token === "from" && tokens[0] === ":") { + tokens.shift(); + if (COMBINED_SELECTOR_START.test(tokens[0])) { + var from_arg = consumeCSSSelector(tokens); + } else { var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); - if (from_arg === "closest" || from_arg === "find") { + if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") { tokens.shift(); - from_arg += - " " + - consumeUntil( - tokens, - WHITESPACE_OR_COMMA - ); + var selector = consumeCSSSelector(tokens); + // `next` and `previous` allow a selector-less syntax + if (selector.length > 0) { + from_arg += " " + selector; + } } - triggerSpec.from = from_arg; - } else if (token === "target" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if (token === "throttle" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "queue" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if ((token === "root" || token === "threshold") && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); } + triggerSpec.from = from_arg; + } else if (token === "target" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.target = consumeCSSSelector(tokens); + } else if (token === "throttle" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); + } else if (token === "queue" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } else if (token === "root" && tokens[0] === ":") { + tokens.shift(); + triggerSpec[token] = consumeCSSSelector(tokens); + } else if (token === "threshold" && tokens[0] === ":") { + tokens.shift(); + triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } else { + triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); } - triggerSpecs.push(triggerSpec); } + triggerSpecs.push(triggerSpec); } - if (tokens.length === initialLength) { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - consumeUntil(tokens, NOT_WHITESPACE); - } while (tokens[0] === "," && tokens.shift()) + } + if (tokens.length === initialLength) { + triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); + } + consumeUntil(tokens, NOT_WHITESPACE); + } while (tokens[0] === "," && tokens.shift()) + if (cache) { + cache[explicitTrigger] = triggerSpecs + } + return triggerSpecs + } + + /** + * @param {HTMLElement} elt + * @returns {import("./htmx").HtmxTriggerSpecification[]} + */ + function getTriggerSpecs(elt) { + var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); + var triggerSpecs = []; + if (explicitTrigger) { + var cache = htmx.config.triggerSpecsCache + triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) } if (triggerSpecs.length > 0) { return triggerSpecs; } else if (matches(elt, 'form')) { return [{trigger: 'submit'}]; + } else if (matches(elt, 'input[type="button"], input[type="submit"]')){ + return [{trigger: 'click'}]; } else if (matches(elt, INPUT_SELECTOR)) { return [{trigger: 'change'}]; } else { @@ -1147,14 +1392,17 @@ return (function () { getInternalData(elt).cancelled = true; } - function processPolling(elt, verb, path, spec) { + function processPolling(elt, handler, spec) { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { - issueAjaxRequest(verb, path, elt); + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { + handler(elt); } - processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), spec); + processPolling(elt, handler, spec); } }, spec.pollInterval); } @@ -1166,23 +1414,27 @@ return (function () { } function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt) && elt.target === "") || elt.tagName === "FORM") { + if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || elt.tagName === "FORM") { nodeData.boosted = true; var verb, path; if (elt.tagName === "A") { verb = "get"; - path = getRawAttribute(elt, 'href'); - nodeData.pushURL = true; + path = getRawAttribute(elt, 'href') } else { var rawAttribute = getRawAttribute(elt, "method"); verb = rawAttribute ? rawAttribute.toLowerCase() : "get"; if (verb === "get") { - nodeData.pushURL = true; } path = getRawAttribute(elt, 'action'); } triggerSpecs.forEach(function(triggerSpec) { - addEventListener(elt, verb, path, nodeData, triggerSpec, true); + addEventListener(elt, function(elt, evt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + issueAjaxRequest(verb, path, elt, evt) + }, nodeData, triggerSpec, true); }); } } @@ -1213,11 +1465,11 @@ return (function () { return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); } - function maybeFilterEvent(triggerSpec, evt) { + function maybeFilterEvent(triggerSpec, elt, evt) { var eventFilter = triggerSpec.eventFilter; if(eventFilter){ try { - return eventFilter(evt) !== true; + return eventFilter.call(elt, evt) !== true; } catch(e) { triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); return true; @@ -1226,13 +1478,21 @@ return (function () { return false; } - function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { + function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { + var elementData = getInternalData(elt); var eltsToListenOn; if (triggerSpec.from) { eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); } else { eltsToListenOn = [elt]; } + // store the initial values of the elements, so we can tell if they change + if (triggerSpec.changed) { + eltsToListenOn.forEach(function (eltToListenOn) { + var eltToListenOnData = getInternalData(eltToListenOn); + eltToListenOnData.lastValue = eltToListenOn.value; + }) + } forEach(eltsToListenOn, function (eltToListenOn) { var eventListener = function (evt) { if (!bodyContains(elt)) { @@ -1245,7 +1505,7 @@ return (function () { if (explicitCancel || shouldCancel(evt, elt)) { evt.preventDefault(); } - if (maybeFilterEvent(triggerSpec, evt)) { + if (maybeFilterEvent(triggerSpec, elt, evt)) { return; } var eventData = getInternalData(evt); @@ -1253,7 +1513,6 @@ return (function () { if (eventData.handledFor == null) { eventData.handledFor = []; } - var elementData = getInternalData(elt); if (eventData.handledFor.indexOf(elt) < 0) { eventData.handledFor.push(elt); if (triggerSpec.consume) { @@ -1272,11 +1531,11 @@ return (function () { } } if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { + var eltToListenOnData = getInternalData(eltToListenOn) + if (eltToListenOnData.lastValue === eltToListenOn.value) { return; - } else { - elementData.lastValue = elt.value; } + eltToListenOnData.lastValue = eltToListenOn.value } if (elementData.delayed) { clearTimeout(elementData.delayed); @@ -1285,19 +1544,18 @@ return (function () { return; } - if (triggerSpec.throttle) { + if (triggerSpec.throttle > 0) { if (!elementData.throttle) { - issueAjaxRequest(verb, path, elt, evt); + handler(elt, evt); elementData.throttle = setTimeout(function () { elementData.throttle = null; }, triggerSpec.throttle); } - } else if (triggerSpec.delay) { - elementData.delayed = setTimeout(function () { - issueAjaxRequest(verb, path, elt, evt); - }, triggerSpec.delay); + } else if (triggerSpec.delay > 0) { + elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); } else { - issueAjaxRequest(verb, path, elt, evt); + triggerEvent(elt, 'htmx:trigger') + handler(elt, evt); } } }; @@ -1310,7 +1568,7 @@ return (function () { on: eltToListenOn }) eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); - }) + }); } var windowIsScrolling = false // used by initScrollHandler @@ -1336,14 +1594,11 @@ return (function () { if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { elt.setAttribute('data-hx-revealed', 'true'); var nodeData = getInternalData(elt); - if (nodeData.initialized) { - issueAjaxRequest(nodeData.verb, nodeData.path, elt); + if (nodeData.initHash) { + triggerEvent(elt, 'revealed'); } else { // if the node isn't initialized, wait for it before triggering the request - elt.addEventListener("htmx:afterProcessNode", - function () { - issueAjaxRequest(nodeData.verb, nodeData.path, elt); - }, {once: true}); + elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true}); } } } @@ -1502,6 +1757,9 @@ return (function () { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function (event) { if (maybeCloseSSESource(sseSourceElt)) { + return; + } + if (!bodyContains(elt)) { sseEventSource.removeEventListener(sseEventName, sseListener); return; } @@ -1518,7 +1776,7 @@ return (function () { var target = getTarget(elt) var settleInfo = makeSettleInfo(elt); - selectAndSwap(swapSpec.swapStyle, elt, target, response, settleInfo) + selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) settleImmediately(settleInfo.tasks) triggerEvent(elt, "htmx:sseMessage", event) }; @@ -1530,14 +1788,14 @@ return (function () { } } - function processSSETrigger(elt, verb, path, sseEventName) { + function processSSETrigger(elt, handler, sseEventName) { var sseSourceElt = getClosestMatch(elt, hasEventSource); if (sseSourceElt) { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function () { if (!maybeCloseSSESource(sseSourceElt)) { if (bodyContains(elt)) { - issueAjaxRequest(verb, path, elt); + handler(elt); } else { sseEventSource.removeEventListener(sseEventName, sseListener); } @@ -1563,14 +1821,14 @@ return (function () { //==================================================================== - function loadImmediately(elt, verb, path, nodeData, delay) { + function loadImmediately(elt, handler, nodeData, delay) { var load = function(){ if (!nodeData.loaded) { nodeData.loaded = true; - issueAjaxRequest(verb, path, elt); + handler(elt); } } - if (delay) { + if (delay > 0) { setTimeout(load, delay); } else { load(); @@ -1586,46 +1844,59 @@ return (function () { nodeData.path = path; nodeData.verb = verb; triggerSpecs.forEach(function(triggerSpec) { - if (triggerSpec.sseEvent) { - processSSETrigger(elt, verb, path, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - maybeReveal(elt); - } else if (triggerSpec.trigger === "intersect") { - var observerOptions = {}; - if (triggerSpec.root) { - observerOptions.root = querySelectorExt(elt, triggerSpec.root) - } - if (triggerSpec.threshold) { - observerOptions.threshold = parseFloat(triggerSpec.threshold); + addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return } - var observer = new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - if (entry.isIntersecting) { - triggerEvent(elt, "intersect"); - break; - } - } - }, observerOptions); - observer.observe(elt); - addEventListener(elt, verb, path, nodeData, triggerSpec); - } else if (triggerSpec.trigger === "load") { - loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); - } else if (triggerSpec.pollInterval) { - nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec); - } else { - addEventListener(elt, verb, path, nodeData, triggerSpec); - } + issueAjaxRequest(verb, path, elt, evt) + }) }); } }); return explicitAction; } + function addTriggerHandler(elt, triggerSpec, nodeData, handler) { + if (triggerSpec.sseEvent) { + processSSETrigger(elt, handler, triggerSpec.sseEvent); + } else if (triggerSpec.trigger === "revealed") { + initScrollHandler(); + addEventListener(elt, handler, nodeData, triggerSpec); + maybeReveal(elt); + } else if (triggerSpec.trigger === "intersect") { + var observerOptions = {}; + if (triggerSpec.root) { + observerOptions.root = querySelectorExt(elt, triggerSpec.root) + } + if (triggerSpec.threshold) { + observerOptions.threshold = parseFloat(triggerSpec.threshold); + } + var observer = new IntersectionObserver(function (entries) { + for (var i = 0; i < entries.length; i++) { + var entry = entries[i]; + if (entry.isIntersecting) { + triggerEvent(elt, "intersect"); + break; + } + } + }, observerOptions); + observer.observe(elt); + addEventListener(elt, handler, nodeData, triggerSpec); + } else if (triggerSpec.trigger === "load") { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { + loadImmediately(elt, handler, nodeData, triggerSpec.delay); + } + } else if (triggerSpec.pollInterval > 0) { + nodeData.polling = true; + processPolling(elt, handler, triggerSpec); + } else { + addEventListener(elt, handler, nodeData, triggerSpec); + } + } + function evalScript(script) { - if (script.type === "text/javascript" || script.type === "module" || script.type === "") { + if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) { var newScript = getDocument().createElement("script"); forEach(script.attributes, function (attr) { newScript.setAttribute(attr.name, attr.value); @@ -1642,7 +1913,10 @@ return (function () { } catch (e) { logError(e); } finally { - parent.removeChild(script); + // remove old script element, but only if it is still in DOM + if (script.parentElement) { + script.parentElement.removeChild(script); + } } } } @@ -1656,48 +1930,187 @@ return (function () { }); } - function hasChanceOfBeingBoosted() { - return document.querySelector("[hx-boost], [data-hx-boost]"); + function shouldProcessHxOn(elt) { + var attributes = elt.attributes + for (var j = 0; j < attributes.length; j++) { + var attrName = attributes[j].name + if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") || + startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) { + return true + } + } + return false + } + + function findHxOnWildcardElements(elt) { + var node = null + var elements = [] + + if (shouldProcessHxOn(elt)) { + elements.push(elt) + } + + if (document.evaluate) { + var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + + ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt) + while (node = iter.iterateNext()) elements.push(node) + } else { + var allElements = elt.getElementsByTagName("*") + for (var i = 0; i < allElements.length; i++) { + if (shouldProcessHxOn(allElements[i])) { + elements.push(allElements[i]) + } + } + } + + return elements } function findElementsToProcess(elt) { if (elt.querySelectorAll) { - var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; - var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [hx-data-ext]"); + var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; + var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," + + " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]"); return results; } else { return []; } } - function initButtonTracking(form){ - var maybeSetLastButtonClicked = function(evt){ - if (matches(evt.target, "button, input[type='submit']")) { - var internalData = getInternalData(form); - internalData.lastButtonClicked = evt.target; - } - }; - + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + function maybeSetLastButtonClicked(evt) { + var elt = closest(evt.target, "button, input[type='submit']"); + var internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = elt; + } + }; + function maybeUnsetLastButtonClicked(evt){ + var internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = null; + } + } + function getRelatedFormData(evt) { + var elt = closest(evt.target, "button, input[type='submit']"); + if (!elt) { + return; + } + var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form'); + if (!form) { + return; + } + return getInternalData(form); + } + function initButtonTracking(elt) { // need to handle both click and focus in: // focusin - in case someone tabs in to a button and hits the space bar // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + elt.addEventListener('click', maybeSetLastButtonClicked) + elt.addEventListener('focusin', maybeSetLastButtonClicked) + elt.addEventListener('focusout', maybeUnsetLastButtonClicked) + } - form.addEventListener('click', maybeSetLastButtonClicked) - form.addEventListener('focusin', maybeSetLastButtonClicked) - form.addEventListener('focusout', function(evt){ - var internalData = getInternalData(form); - internalData.lastButtonClicked = null; - }) + function countCurlies(line) { + var tokens = tokenizeString(line); + var netCurlies = 0; + for (var i = 0; i < tokens.length; i++) { + const token = tokens[i]; + if (token === "{") { + netCurlies++; + } else if (token === "}") { + netCurlies--; + } + } + return netCurlies; + } + + function addHxOnEventHandler(elt, eventName, code) { + var nodeData = getInternalData(elt); + if (!Array.isArray(nodeData.onHandlers)) { + nodeData.onHandlers = []; + } + var func; + var listener = function (e) { + return maybeEval(elt, function() { + if (!func) { + func = new Function("event", code); + } + func.call(elt, e); + }); + }; + elt.addEventListener(eventName, listener); + nodeData.onHandlers.push({event:eventName, listener:listener}); + } + + function processHxOn(elt) { + var hxOnValue = getAttributeValue(elt, 'hx-on'); + if (hxOnValue) { + var handlers = {} + var lines = hxOnValue.split("\n"); + var currentEvent = null; + var curlyCount = 0; + while (lines.length > 0) { + var line = lines.shift(); + var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/); + if (curlyCount === 0 && match) { + line.split(":") + currentEvent = match[1].slice(0, -1); // strip last colon + handlers[currentEvent] = match[2]; + } else { + handlers[currentEvent] += line; + } + curlyCount += countCurlies(line); + } + + for (var eventName in handlers) { + addHxOnEventHandler(elt, eventName, handlers[eventName]); + } + } + } + + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (var i = 0; i < elt.attributes.length; i++) { + var name = elt.attributes[i].name + var value = elt.attributes[i].value + if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) { + var afterOnPosition = name.indexOf("-on") + 3; + var nextChar = name.slice(afterOnPosition, afterOnPosition + 1); + if (nextChar === "-" || nextChar === ":") { + var eventName = name.slice(afterOnPosition + 1); + // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support + if (startsWith(eventName, ":")) { + eventName = "htmx" + eventName + } else if (startsWith(eventName, "-")) { + eventName = "htmx:" + eventName.slice(1); + } else if (startsWith(eventName, "htmx-")) { + eventName = "htmx:" + eventName.slice(5); + } + + addHxOnEventHandler(elt, eventName, value) + } + } + } } function initNode(elt) { - if (elt.closest && elt.closest(htmx.config.disableSelector)) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) return; } var nodeData = getInternalData(elt); - if (!nodeData.initialized) { - nodeData.initialized = true; + if (nodeData.initHash !== attributeHash(elt)) { + // clean up any previously processed info + deInitNode(elt); + + nodeData.initHash = attributeHash(elt); + + processHxOn(elt); + triggerEvent(elt, "htmx:beforeProcessNode") if (elt.value) { @@ -1705,14 +2118,24 @@ return (function () { } var triggerSpecs = getTriggerSpecs(elt); - var explicitAction = processVerbs(elt, nodeData, triggerSpecs); - - if (!explicitAction && getClosestAttributeValue(elt, "hx-boost") === "true") { - boostElement(elt, nodeData, triggerSpecs); + var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs); + + if (!hasExplicitHttpAction) { + if (getClosestAttributeValue(elt, "hx-boost") === "true") { + boostElement(elt, nodeData, triggerSpecs); + } else if (hasAttribute(elt, 'hx-trigger')) { + triggerSpecs.forEach(function (triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function () { + }) + }) + } } - if (elt.tagName === "FORM") { - initButtonTracking(elt); + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) { + initButtonTracking(elt) } var sseInfo = getAttributeValue(elt, 'hx-sse'); @@ -1730,8 +2153,15 @@ return (function () { function processNode(elt) { elt = resolveTarget(elt); + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return; + } initNode(elt); forEach(findElementsToProcess(elt), function(child) { initNode(child) }); + // Because it happens second, the new way of adding onHandlers superseeds the old one + // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored + forEach(findHxOnWildcardElements(elt), processHxOnWildcard); } //==================================================================== @@ -1809,7 +2239,7 @@ return (function () { eventResult = eventResult && elt.dispatchEvent(kebabedEvent) } withExtensions(elt, function (extension) { - eventResult = eventResult && (extension.onEvent(eventName, event) !== false) + eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) }); return eventResult; } @@ -1825,6 +2255,18 @@ return (function () { } function saveToHistoryCache(url, content, title, scroll) { + if (!canAccessLocalStorage()) { + return; + } + + if (htmx.config.historyCacheSize <= 0) { + // make sure that an eventually already existing cache is purged + localStorage.removeItem("htmx-history-cache"); + return; + } + + url = normalizePath(url); + var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { @@ -1832,7 +2274,9 @@ return (function () { break; } } - historyCache.push({url:url, content: content, title:title, scroll:scroll}) + var newHistoryItem = {url:url, content: content, title:title, scroll:scroll}; + triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache}) + historyCache.push(newHistoryItem) while (historyCache.length > htmx.config.historyCacheSize) { historyCache.shift(); } @@ -1848,6 +2292,12 @@ return (function () { } function getCachedHistory(url) { + if (!canAccessLocalStorage()) { + return null; + } + + url = normalizePath(url); + var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { @@ -1869,13 +2319,43 @@ return (function () { function saveCurrentPageToHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; - triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); - if(htmx.config.historyEnabled) history.replaceState({htmx:true}, getDocument().title, window.location.href); - saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); + + // Allow history snapshot feature to be disabled where hx-history="false" + // is present *anywhere* in the current document we're about to save, + // so we can prevent privileged data entering the cache. + // The page will still be reachable as a history entry, but htmx will fetch it + // live from the server onpopstate rather than look in the localStorage cache + var disableHistoryCache + try { + disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') + } catch (e) { + // IE11: insensitive modifier not supported so fallback to case sensitive selector + disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') + } + if (!disableHistoryCache) { + triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt}); + saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); + } + + if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href); } function pushUrlIntoHistory(path) { - if(htmx.config.historyEnabled) history.pushState({htmx:true}, "", path); + // remove the cache buster parameter, if any + if (htmx.config.getCacheBusterParam) { + path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') + if (endsWith(path, '&') || endsWith(path, "?")) { + path = path.slice(0, -1); + } + } + if(htmx.config.historyEnabled) { + history.pushState({htmx:true}, "", path); + } + currentPathForHistory = path; + } + + function replaceUrlInHistory(path) { + if(htmx.config.historyEnabled) history.replaceState({htmx:true}, "", path); currentPathForHistory = path; } @@ -1890,7 +2370,9 @@ return (function () { var details = {path: path, xhr:request}; triggerEvent(getDocument().body, "htmx:historyCacheMiss", details); request.open('GET', path, true); + request.setRequestHeader("HX-Request", "true"); request.setRequestHeader("HX-History-Restore-Request", "true"); + request.setRequestHeader("HX-Current-URL", getDocument().location.href); request.onload = function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); @@ -1899,11 +2381,20 @@ return (function () { fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; var historyElement = getHistoryElement(); var settleInfo = makeSettleInfo(historyElement); + var title = findTitle(this.response); + if (title) { + var titleElt = find("title"); + if (titleElt) { + titleElt.innerHTML = title; + } else { + window.document.title = title; + } + } // @ts-ignore swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); + triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response}); } else { triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details); } @@ -1922,9 +2413,11 @@ return (function () { swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); document.title = cached.title; - window.scrollTo(0, cached.scroll); + setTimeout(function () { + window.scrollTo(0, cached.scroll); + }, 0); // next 'tick', so browser has time to render layout currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); + triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); } else { if (htmx.config.refreshOnHistoryMiss) { @@ -1936,31 +2429,46 @@ return (function () { } } - function shouldPush(elt) { - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - return (pushUrl && pushUrl !== "false") || - (getInternalData(elt).boosted && getInternalData(elt).pushURL); - } - - function getPushUrl(elt) { - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - return (pushUrl === "true" || pushUrl === "false") ? null : pushUrl; - } - function addRequestIndicatorClasses(elt) { var indicators = findAttributeTargets(elt, 'hx-indicator'); if (indicators == null) { indicators = [elt]; } forEach(indicators, function (ic) { + var internalData = getInternalData(ic); + internalData.requestCount = (internalData.requestCount || 0) + 1; ic.classList["add"].call(ic.classList, htmx.config.requestClass); }); return indicators; } - function removeRequestIndicatorClasses(indicators) { + function disableElements(elt) { + var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt'); + if (disabledElts == null) { + disabledElts = []; + } + forEach(disabledElts, function (disabledElement) { + var internalData = getInternalData(disabledElement); + internalData.requestCount = (internalData.requestCount || 0) + 1; + disabledElement.setAttribute("disabled", ""); + }); + return disabledElts; + } + + function removeRequestIndicators(indicators, disabled) { forEach(indicators, function (ic) { - ic.classList["remove"].call(ic.classList, htmx.config.requestClass); + var internalData = getInternalData(ic); + internalData.requestCount = (internalData.requestCount || 0) - 1; + if (internalData.requestCount === 0) { + ic.classList["remove"].call(ic.classList, htmx.config.requestClass); + } + }); + forEach(disabled, function (disabledElement) { + var internalData = getInternalData(disabledElement); + internalData.requestCount = (internalData.requestCount || 0) - 1; + if (internalData.requestCount === 0) { + disabledElement.removeAttribute('disabled'); + } }); } @@ -1979,7 +2487,7 @@ return (function () { } function shouldInclude(elt) { - if(elt.name === "" || elt.name == null || elt.disabled) { + if(elt.name === "" || elt.name == null || elt.disabled || closest(elt, "fieldset[disabled]")) { return false; } // ignore "submitter" types (see jQuery src/serialize.js) @@ -1992,6 +2500,29 @@ return (function () { return true; } + function addValueToValues(name, value, values) { + // This is a little ugly because both the current value of the named value in the form + // and the new value could be arrays, so we have to handle all four cases :/ + if (name != null && value != null) { + var current = values[name]; + if (current === undefined) { + values[name] = value; + } else if (Array.isArray(current)) { + if (Array.isArray(value)) { + values[name] = current.concat(value); + } else { + current.push(value); + } + } else { + if (Array.isArray(value)) { + values[name] = [current].concat(value); + } else { + values[name] = [current, value]; + } + } + } + } + function processInputValue(processed, values, errors, elt, validate) { if (elt == null || haveSeenNode(processed, elt)) { return; @@ -2001,35 +2532,14 @@ return (function () { if (shouldInclude(elt)) { var name = getRawAttribute(elt,"name"); var value = elt.value; - if (elt.multiple) { + if (elt.multiple && elt.tagName === "SELECT") { value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value }); } // include file inputs if (elt.files) { value = toArray(elt.files); } - // This is a little ugly because both the current value of the named value in the form - // and the new value could be arrays, so we have to handle all four cases :/ - if (name != null && value != null) { - var current = values[name]; - if(current) { - if (Array.isArray(current)) { - if (Array.isArray(value)) { - values[name] = current.concat(value); - } else { - current.push(value); - } - } else { - if (Array.isArray(value)) { - values[name] = [current].concat(value); - } else { - values[name] = [current, value]; - } - } - } else { - values[name] = value; - } - } + addValueToValues(name, value, values); if (validate) { validateElement(elt, errors); } @@ -2062,9 +2572,13 @@ return (function () { var formValues = {}; var errors = []; var internalData = getInternalData(elt); + if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { + internalData.lastButtonClicked = null + } // only validate when form is directly submitted and novalidate or formnovalidate are not set - var validate = matches(elt, 'form') && elt.noValidate !== true; + // or if the element has an explicit hx-validate="true" on it + var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true"; if (internalData.lastButtonClicked) { validate = validate && internalData.lastButtonClicked.formNoValidate !== true; } @@ -2078,11 +2592,11 @@ return (function () { processInputValue(processed, values, errors, elt, validate); // if a button or submit was clicked last, include its value - if (internalData.lastButtonClicked) { - var name = getRawAttribute(internalData.lastButtonClicked,"name"); - if (name) { - values[name] = internalData.lastButtonClicked.value; - } + if (internalData.lastButtonClicked || elt.tagName === "BUTTON" || + (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) { + var button = internalData.lastButtonClicked || elt + var name = getRawAttribute(button, "name") + addValueToValues(name, button.value, formValues) } // include any explicit includes @@ -2228,40 +2742,43 @@ return (function () { "swapDelay" : htmx.config.defaultSwapDelay, "settleDelay" : htmx.config.defaultSettleDelay } - if (getInternalData(elt).boosted && !isAnchorLink(elt)) { + if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { swapSpec["show"] = "top" } 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)); - } - if (modifier.indexOf("scroll:") === 0) { - var scrollSpec = modifier.substr(7); + for (var i = 0; i < split.length; i++) { + var value = split[i]; + if (value.indexOf("swap:") === 0) { + swapSpec["swapDelay"] = parseInterval(value.substr(5)); + } else if (value.indexOf("settle:") === 0) { + swapSpec["settleDelay"] = parseInterval(value.substr(7)); + } else if (value.indexOf("transition:") === 0) { + swapSpec["transition"] = value.substr(11) === "true"; + } else if (value.indexOf("ignoreTitle:") === 0) { + swapSpec["ignoreTitle"] = value.substr(12) === "true"; + } else if (value.indexOf("scroll:") === 0) { + var scrollSpec = value.substr(7); var splitSpec = scrollSpec.split(":"); var scrollVal = splitSpec.pop(); var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; swapSpec["scroll"] = scrollVal; swapSpec["scrollTarget"] = selectorVal; - } - if (modifier.indexOf("show:") === 0) { - var showSpec = modifier.substr(5); + } else if (value.indexOf("show:") === 0) { + var showSpec = value.substr(5); var splitSpec = showSpec.split(":"); var showVal = splitSpec.pop(); var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; swapSpec["show"] = showVal; swapSpec["showTarget"] = selectorVal; - } - if (modifier.indexOf("focus-scroll:") === 0) { - var focusScrollVal = modifier.substr("focus-scroll:".length); + } else if (value.indexOf("focus-scroll:") === 0) { + var focusScrollVal = value.substr("focus-scroll:".length); swapSpec["focusScroll"] = focusScrollVal == "true"; + } else if (i == 0) { + swapSpec["swapStyle"] = value; + } else { + logError('Unknown modifier in hx-swap: ' + value); } } } @@ -2269,6 +2786,11 @@ return (function () { return swapSpec; } + function usesFormData(elt) { + return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || + (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data"); + } + function encodeParamsForBody(xhr, elt, filteredParameters) { var encodedParameters = null; withExtensions(elt, function (extension) { @@ -2279,8 +2801,7 @@ return (function () { if (encodedParameters != null) { return encodedParameters; } else { - if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || - (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) { + if (usesFormData(elt)) { return makeFormData(filteredParameters); } else { return urlEncode(filteredParameters); @@ -2352,6 +2873,9 @@ return (function () { if (attributeValue) { var str = attributeValue.trim(); var evaluateValue = evalAsDefault; + if (str === "unset") { + return null; + } if (str.indexOf("javascript:") === 0) { str = str.substr(11); evaluateValue = true; @@ -2426,7 +2950,7 @@ return (function () { } } - function getResponseURL(xhr) { + function getPathFromResponse(xhr) { // NB: IE11 does not support this stuff if (xhr.responseURL && typeof(URL) !== "undefined") { try { @@ -2439,7 +2963,7 @@ return (function () { } function hasHeader(xhr, regexp) { - return xhr.getAllResponseHeaders().match(regexp); + return regexp.test(xhr.getAllResponseHeaders()) } function ajaxHelper(verb, path, context) { @@ -2458,6 +2982,7 @@ return (function () { values : context.values, targetOverride: resolveTarget(context.target), swapOverride: context.swap, + select: context.select, returnPromise: true }); } @@ -2477,7 +3002,28 @@ return (function () { return arr; } - function issueAjaxRequest(verb, path, elt, event, etc) { + function verifyPath(elt, path, requestConfig) { + var sameHost + var url + if (typeof URL === "function") { + url = new URL(path, document.location.href); + var origin = document.location.origin; + sameHost = origin === url.origin; + } else { + // IE11 doesn't support URL + url = path + sameHost = startsWith(path, document.location.origin) + } + + if (htmx.config.selfRequestsOnly) { + if (!sameHost) { + return false; + } + } + return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig)); + } + + function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { var resolve = null; var reject = null; etc = etc != null ? etc : {}; @@ -2491,18 +3037,52 @@ return (function () { elt = getDocument().body; } var responseHandler = etc.handler || handleAjaxResponse; + var select = etc.select || null; if (!bodyContains(elt)) { - return; // do not issue requests for elements removed from the DOM + // do not issue requests for elements removed from the DOM + maybeCall(resolve); + return promise; } var target = etc.targetOverride || getTarget(elt); if (target == null || target == DUMMY_ELT) { triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); - return; + maybeCall(reject); + return promise; } - var syncElt = elt; var eltData = getInternalData(elt); + var submitter = eltData.lastButtonClicked; + + if (submitter) { + var buttonPath = getRawAttribute(submitter, "formaction"); + if (buttonPath != null) { + path = buttonPath; + } + + var buttonVerb = getRawAttribute(submitter, "formmethod") + if (buttonVerb != null) { + // ignore buttons with formmethod="dialog" + if (buttonVerb.toLowerCase() !== "dialog") { + verb = buttonVerb; + } + } + } + + var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); + // allow event-based confirmation w/ a callback + if (confirmed === undefined) { + var issueRequest = function(skipConfirmation) { + return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation); + } + var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion}; + if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { + maybeCall(resolve); + return promise; + } + } + + var syncElt = elt; var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); var queueStrategy = null; var abortable = false; @@ -2518,10 +3098,12 @@ return (function () { syncStrategy = (syncStrings[1] || 'drop').trim(); eltData = getInternalData(syncElt); if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { - return; + maybeCall(resolve); + return promise; } else if (syncStrategy === "abort") { if (eltData.xhr) { - return; + maybeCall(resolve); + return promise; } else { abortable = true; } @@ -2565,7 +3147,8 @@ return (function () { issueAjaxRequest(verb, path, elt, event, etc) }); } - return; + maybeCall(resolve); + return promise; } } @@ -2593,8 +3176,7 @@ return (function () { } } - var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); - if (confirmQuestion) { + if (confirmQuestion && !confirmed) { if(!confirm(confirmQuestion)) { maybeCall(resolve); endRequestLock() @@ -2604,6 +3186,11 @@ return (function () { var headers = getHeaders(elt, target, promptResponse); + + if (verb !== 'get' && !usesFormData(elt)) { + headers['Content-Type'] = 'application/x-www-form-urlencoded'; + } + if (etc.headers) { headers = mergeObjects(headers, etc.headers); } @@ -2617,8 +3204,8 @@ return (function () { var allParameters = mergeObjects(rawParameters, expressionVars); var filteredParameters = filterValues(allParameters, elt); - if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null) { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; + if (htmx.config.getCacheBusterParam && verb === 'get') { + filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true"; } // behavior of anchors w/ empty href is to use the current URL @@ -2626,9 +3213,16 @@ return (function () { path = getDocument().location.href; } + var requestAttrValues = getValuesForElement(elt, 'hx-request'); + var eltIsBoosted = getInternalData(elt).boosted; + + var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + var requestConfig = { + boosted: eltIsBoosted, + useUrlParams: useUrlParams, parameters: filteredParameters, unfilteredParameters: allParameters, headers:headers, @@ -2653,6 +3247,7 @@ return (function () { headers = requestConfig.headers; filteredParameters = requestConfig.parameters; errors = requestConfig.errors; + useUrlParams = requestConfig.useUrlParams; if(errors && errors.length > 0){ triggerEvent(elt, 'htmx:validation:halted', requestConfig) @@ -2664,25 +3259,31 @@ return (function () { var splitPath = path.split("#"); var pathNoAnchor = splitPath[0]; var anchor = splitPath[1]; - if (verb === 'get') { - var finalPathForGet = pathNoAnchor; + + var finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor; var values = Object.keys(filteredParameters).length !== 0; if (values) { - if (finalPathForGet.indexOf("?") < 0) { - finalPathForGet += "?"; + if (finalPath.indexOf("?") < 0) { + finalPath += "?"; } else { - finalPathForGet += "&"; + finalPath += "&"; } - finalPathForGet += urlEncode(filteredParameters); + finalPath += urlEncode(filteredParameters); if (anchor) { - finalPathForGet += "#" + anchor; + finalPath += "#" + anchor; } } - xhr.open('GET', finalPathForGet, true); - } else { - xhr.open(verb.toUpperCase(), path, true); } + if (!verifyPath(elt, finalPath, requestConfig)) { + triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) + maybeCall(reject); + return promise; + }; + + xhr.open(verb.toUpperCase(), finalPath, true); xhr.overrideMimeType("text/html"); xhr.withCredentials = requestConfig.withCredentials; xhr.timeout = requestConfig.timeout; @@ -2699,19 +3300,24 @@ return (function () { } } - var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, etc:etc, pathInfo:{ - path:path, finalPath:finalPathForGet, anchor:anchor + var responseInfo = { + xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select, + pathInfo: { + requestPath: path, + finalRequestPath: finalPath, + anchor: anchor } }; xhr.onload = function () { try { var hierarchy = hierarchyForElt(elt); + responseInfo.pathInfo.responsePath = getPathFromResponse(xhr); responseHandler(elt, responseInfo); - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerEvent(elt, 'htmx:afterRequest', responseInfo); triggerEvent(elt, 'htmx:afterOnLoad', responseInfo); - // if the body no longer contains the element, trigger the even on the closest parent + // if the body no longer contains the element, trigger the event on the closest parent // remaining in the DOM if (!bodyContains(elt)) { var secondaryTriggerElt = null; @@ -2734,21 +3340,21 @@ return (function () { } } xhr.onerror = function () { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:sendError', responseInfo); maybeCall(reject); endRequestLock(); } xhr.onabort = function() { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo); maybeCall(reject); endRequestLock(); } xhr.ontimeout = function() { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:timeout', responseInfo); maybeCall(reject); @@ -2760,6 +3366,7 @@ return (function () { return promise } var indicators = addRequestIndicatorClasses(elt); + var disableElts = disableElements(elt); forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { forEach([xhr, xhr.upload], function (target) { @@ -2773,14 +3380,99 @@ return (function () { }); }); triggerEvent(elt, 'htmx:beforeSend', responseInfo); - xhr.send(verb === 'get' ? null : encodeParamsForBody(xhr, elt, filteredParameters)); + var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) + xhr.send(params); return promise; } + function determineHistoryUpdates(elt, responseInfo) { + + var xhr = responseInfo.xhr; + + //=========================================== + // First consult response headers + //=========================================== + var pathFromHeaders = null; + var typeFromHeaders = null; + if (hasHeader(xhr,/HX-Push:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Push"); + typeFromHeaders = "push"; + } else if (hasHeader(xhr,/HX-Push-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Push-Url"); + typeFromHeaders = "push"; + } else if (hasHeader(xhr,/HX-Replace-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url"); + typeFromHeaders = "replace"; + } + + // if there was a response header, that has priority + if (pathFromHeaders) { + if (pathFromHeaders === "false") { + return {} + } else { + return { + type: typeFromHeaders, + path : pathFromHeaders + } + } + } + + //=========================================== + // Next resolve via DOM values + //=========================================== + var requestPath = responseInfo.pathInfo.finalRequestPath; + var responsePath = responseInfo.pathInfo.responsePath; + + var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); + var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url"); + var elementIsBoosted = getInternalData(elt).boosted; + + var saveType = null; + var path = null; + + if (pushUrl) { + saveType = "push"; + path = pushUrl; + } else if (replaceUrl) { + saveType = "replace"; + path = replaceUrl; + } else if (elementIsBoosted) { + saveType = "push"; + path = responsePath || requestPath; // if there is no response path, go with the original request path + } + + if (path) { + // false indicates no push, return empty object + if (path === "false") { + return {}; + } + + // true indicates we want to follow wherever the server ended up sending us + if (path === "true") { + path = responsePath || requestPath; // if there is no response path, go with the original request path + } + + // restore any anchor associated with the request + if (responseInfo.pathInfo.anchor && + path.indexOf("#") === -1) { + path = path + "#" + responseInfo.pathInfo.anchor; + } + + return { + type:saveType, + path: path + } + } else { + return {}; + } + } + function handleAjaxResponse(elt, responseInfo) { var xhr = responseInfo.xhr; var target = responseInfo.target; var etc = responseInfo.etc; + var requestConfig = responseInfo.requestConfig; + var select = responseInfo.select; if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; @@ -2788,33 +3480,44 @@ return (function () { handleTrigger(xhr, "HX-Trigger", elt); } - if (hasHeader(xhr,/HX-Push:/i)) { - var pushedUrl = xhr.getResponseHeader("HX-Push"); + if (hasHeader(xhr, /HX-Location:/i)) { + saveCurrentPageToHistory(); + var redirectPath = xhr.getResponseHeader("HX-Location"); + var swapSpec; + if (redirectPath.indexOf("{") === 0) { + swapSpec = parseJSON(redirectPath); + // what's the best way to throw an error if the user didn't include this + redirectPath = swapSpec['path']; + delete swapSpec['path']; + } + ajaxHelper('GET', redirectPath, swapSpec).then(function(){ + pushUrlIntoHistory(redirectPath); + }); + return; } + var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh"); + if (hasHeader(xhr, /HX-Redirect:/i)) { - window.location.href = xhr.getResponseHeader("HX-Redirect"); + location.href = xhr.getResponseHeader("HX-Redirect"); + shouldRefresh && location.reload(); return; } - if (hasHeader(xhr,/HX-Refresh:/i)) { - if ("true" === xhr.getResponseHeader("HX-Refresh")) { - location.reload(); - return; - } + if (shouldRefresh) { + location.reload(); + return; } if (hasHeader(xhr,/HX-Retarget:/i)) { - responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget")); + if (xhr.getResponseHeader("HX-Retarget") === "this") { + responseInfo.target = elt; + } else { + responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget")); + } } - /** @type {boolean} */ - var shouldSaveHistory - if (pushedUrl == "false") { - shouldSaveHistory = false - } else { - shouldSaveHistory = shouldPush(elt) || pushedUrl; - } + var historyUpdate = determineHistoryUpdates(elt, responseInfo); // by default htmx only swaps on 200 return codes and does not swap // on 204 'No Content' @@ -2823,15 +3526,18 @@ return (function () { var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; var serverResponse = xhr.response; var isError = xhr.status >= 400; - var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo); + var ignoreTitle = htmx.config.ignoreTitle + var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo); if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; target = beforeSwapDetails.target; // allow re-targeting serverResponse = beforeSwapDetails.serverResponse; // allow updating content isError = beforeSwapDetails.isError; // allow updating error - + ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title + + responseInfo.target = target; // Make updated target available to response events responseInfo.failed = isError; // Make failed property available to response events - responseInfo.successful = !isError; // Make successful property available to response events + responseInfo.successful = !isError; // Make successful property available to response events if (beforeSwapDetails.shouldSwap) { if (xhr.status === 286) { @@ -2842,18 +3548,29 @@ return (function () { serverResponse = extension.transformResponse(serverResponse, xhr, elt); }); - // Save current page - if (shouldSaveHistory) { + // Save current page if there will be a history update + if (historyUpdate.type) { saveCurrentPageToHistory(); } var swapOverride = etc.swapOverride; + if (hasHeader(xhr,/HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader("HX-Reswap"); + } var swapSpec = getSwapSpecification(elt, swapOverride); + if (swapSpec.hasOwnProperty('ignoreTitle')) { + ignoreTitle = swapSpec.ignoreTitle; + } + target.classList.add(htmx.config.swappingClass); + + // optional transition API promise callbacks + var settleResolve = null; + var settleReject = null; + var doSwap = function () { try { - var activeElt = document.activeElement; var selectionInfo = {}; try { @@ -2868,19 +3585,44 @@ return (function () { // safari issue - see https://github.com/microsoft/playwright/issues/5894 } + var selectOverride; + if (select) { + selectOverride = select; + } + + if (hasHeader(xhr, /HX-Reselect:/i)) { + selectOverride = xhr.getResponseHeader("HX-Reselect"); + } + + // if we need to save history, do so, before swapping so that relative resources have the correct base URL + if (historyUpdate.type) { + triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)); + if (historyUpdate.type === "push") { + pushUrlIntoHistory(historyUpdate.path); + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path}); + } else { + replaceUrlInHistory(historyUpdate.path); + triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path}); + } + } + var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride); if (selectionInfo.elt && !bodyContains(selectionInfo.elt) && - selectionInfo.elt.id) { - var newActiveElt = document.getElementById(selectionInfo.elt.id); + getRawAttribute(selectionInfo.elt, "id")) { + var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id")); var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; if (newActiveElt) { // @ts-ignore if (selectionInfo.start && newActiveElt.setSelectionRange) { // @ts-ignore - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + try { + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + } catch (e) { + // the setSelectionRange method is present on fields that don't support it, so just let this fail + } } newActiveElt.focus(focusOptions); } @@ -2893,9 +3635,6 @@ return (function () { } triggerEvent(elt, 'htmx:afterSwap', responseInfo); }); - if (responseInfo.pathInfo.anchor) { - location.hash = responseInfo.pathInfo.anchor; - } if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { var finalElt = elt; @@ -2915,14 +3654,15 @@ return (function () { } triggerEvent(elt, 'htmx:afterSettle', responseInfo); }); - // push URL and save new page - if (shouldSaveHistory) { - var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; - pushUrlIntoHistory(pathToPush); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: pathToPush}); + + if (responseInfo.pathInfo.anchor) { + var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor); + if(anchorTarget) { + anchorTarget.scrollIntoView({block:'start', behavior: "auto"}); + } } - if(settleInfo.title) { + if(settleInfo.title && !ignoreTitle) { var titleElt = find("title"); if(titleElt) { titleElt.innerHTML = settleInfo.title; @@ -2940,6 +3680,7 @@ return (function () { } handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); } + maybeCall(settleResolve); } if (swapSpec.settleDelay > 0) { @@ -2949,10 +3690,34 @@ return (function () { } } catch (e) { triggerErrorEvent(elt, 'htmx:swapError', responseInfo); + maybeCall(settleReject); throw e; } }; + var shouldTransition = htmx.config.globalViewTransitions + if(swapSpec.hasOwnProperty('transition')){ + shouldTransition = swapSpec.transition; + } + + if(shouldTransition && + triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && + typeof Promise !== "undefined" && document.startViewTransition){ + var settlePromise = new Promise(function (_resolve, _reject) { + settleResolve = _resolve; + settleReject = _reject; + }); + // wrap the original doSwap() in a call to startViewTransition() + var innerDoSwap = doSwap; + doSwap = function() { + document.startViewTransition(function () { + innerDoSwap(); + return settlePromise; + }); + } + } + + if (swapSpec.swapDelay > 0) { setTimeout(doSwap, swapSpec.swapDelay) } else { @@ -2960,7 +3725,7 @@ return (function () { } } if (isError) { - triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.path}, responseInfo)); + triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo)); } } @@ -3048,9 +3813,22 @@ return (function () { //==================================================================== // Initialization //==================================================================== + var isReady = false + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true + }) + /** + * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. + * + * This function uses isReady because there is no realiable way to ask the browswer whether + * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded + * firing and readystate=complete. + */ function ready(fn) { - if (getDocument().readyState !== 'loading') { + // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by + // some means other than the initial page load. + if (isReady || getDocument().readyState === 'complete') { fn(); } else { getDocument().addEventListener('DOMContentLoaded', fn); @@ -3061,9 +3839,9 @@ return (function () { if (htmx.config.includeIndicatorStyles !== false) { getDocument().head.insertAdjacentHTML("beforeend", "<style>\ - ." + htmx.config.indicatorClass + "{opacity:0;transition: opacity 200ms ease-in;}\ - ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1}\ - ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1}\ + ." + htmx.config.indicatorClass + "{opacity:0}\ + ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ + ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ </style>"); } } @@ -3101,6 +3879,9 @@ return (function () { internalData.xhr.abort(); } }); + /** @type {(ev: PopStateEvent) => any} */ + const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null; + /** @type {(ev: PopStateEvent) => any} */ window.onpopstate = function (event) { if (event.state && event.state.htmx) { restoreHistory(); @@ -3110,10 +3891,15 @@ return (function () { 'triggerEvent': triggerEvent }); }); + } else { + if (originalPopstate) { + originalPopstate(event); + } } }; setTimeout(function () { triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event + body = null; // kill reference for gc }, 0); }) diff --git a/code/ch4_app/ch4_starter_video_collector/static/js/htmx.min.js b/code/ch4_app/ch4_starter_video_collector/static/js/htmx.min.js index 998414c..53bbdf6 100644 --- a/code/ch4_app/ch4_starter_video_collector/static/js/htmx.min.js +++ b/code/ch4_app/ch4_starter_video_collector/static/js/htmx.min.js @@ -1 +1,4 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(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 l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=k(e);e.classList.toggle(t)}function T(e,t){e=k(e);W(e.parentElement.children,function(e){q(e,t)});L(e,t)}function H(e,t){e=k(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function N(e,t){if(t.indexOf("closest ")===0){return[H(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[C(e,t.substr(5))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return z().querySelectorAll(t)}}function ee(e,t){if(t){return N(e,t)[0]}else{return N(z().body,e)[0]}}function k(e){if(p(e,"String")){return C(e)}else{return e}}function I(e,t,r){if(m(t)){return{target:z().body,event:e,listener:t}}else{return{target:k(e),event:t,listener:r}}}function M(t,r,n){lr(function(){var e=I(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function D(t,r,n){lr(function(){var e=I(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var te=z().createElement("output");function F(e,t){var r=G(e,t);if(r){if(r==="this"){return[re(e,t)]}else{var n=N(e,r);if(n.length===0){pt('The selector "'+r+'" on '+t+" returned no matches!");return[te]}else{return n}}}}function re(e,t){return h(e,function(e){return V(e,t)!=null})}function ne(e){var t=G(e,"hx-target");if(t){if(t==="this"){return re(e,"hx-target")}else{return ee(e,t)}}else{var r=_(e);if(r.boosted){return z().body}else{return e}}}function P(e){var t=U.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function X(t,r){W(t.attributes,function(e){if(!r.hasAttribute(e.name)&&P(e.name)){t.removeAttribute(e.name)}});W(r.attributes,function(e){if(P(e.name)){t.setAttribute(e.name,e.value)}})}function j(e,t){var r=sr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){pt(e)}}return e==="outerHTML"}function B(e,i,o){var t="#"+i.id;var a="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){a=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{a=e}var r=z().querySelectorAll(t);if(r){W(r,function(e){var t;var r=i.cloneNode(true);t=z().createDocumentFragment();t.appendChild(r);if(!j(a,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ye(a,e,e,t,o)}W(o.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(z().body,"htmx:oobErrorNoTarget",{content:i})}return e}function ie(e,r){W(R(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=V(e,"hx-swap-oob");if(t!=null){B(t,e,r)}})}function oe(e){W(R(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=V(e,"id");var r=z().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function ae(n,e,i){W(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();X(e,t);i.tasks.push(function(){X(e,r)})}}})}function se(e){return function(){q(e,U.config.addedClass);ct(e);at(e);le(e);$(e,"htmx:load")}}function le(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ue(e,t,r,n){ae(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(se(i))}}}function fe(t){var e=_(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){W(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){W(t.children,function(e){fe(e)})}}function ce(e,t,r){if(e.tagName==="BODY"){return me(e,t,r)}else{var n;var i=e.previousSibling;ue(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}_(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}fe(e);u(e).removeChild(e)}}function he(e,t,r){return ue(e,e.firstChild,t,r)}function de(e,t,r){return ue(u(e),e,t,r)}function ve(e,t,r){return ue(e,null,t,r)}function ge(e,t,r){return ue(u(e),e.nextSibling,t,r)}function pe(e,t,r){fe(e);return u(e).removeChild(e)}function me(e,t,r){var n=e.firstChild;ue(e,n,t,r);if(n){while(n.nextSibling){fe(n.nextSibling);e.removeChild(n.nextSibling)}fe(n);e.removeChild(n)}}function xe(e,t){var r=G(e,"hx-select");if(r){var n=z().createDocumentFragment();W(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function ye(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":ce(r,n,i);return;case"afterbegin":he(r,n,i);return;case"beforebegin":de(r,n,i);return;case"beforeend":ve(r,n,i);return;case"afterend":ge(r,n,i);return;case"delete":pe(r,n,i);return;default:var o=sr(t);for(var a=0;a<o.length;a++){var f=o[a];try{var s=f.handleSwap(e,r,n,i);if(s){if(typeof s.length!=="undefined"){for(var l=0;l<s.length;l++){var u=s[l];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){i.tasks.push(se(u))}}}return}}catch(e){pt(e)}}if(e==="innerHTML"){me(r,n,i)}else{ye(U.config.defaultSwapStyle,t,r,n,i)}}}function be(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function we(e,t,r,n,i){i.title=be(n);var o=g(n);if(o){ie(o,i);o=xe(r,o);oe(o);return ye(e,r,t,o,i)}}function Se(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!x(a)){a={value:a}}$(r,o,a)}}}else{$(r,n,[])}}var Ee=/\s/;var Ce=/[\s,]/;var Re=/[_$a-zA-Z]/;var Oe=/[_$a-zA-Z0-9]/;var Le=['"',"'","/"];var qe=/[^\s]/;function Ae(e){var t=[];var r=0;while(r<e.length){if(Re.exec(e.charAt(r))){var n=r;while(Oe.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Le.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function Te(e,t,r){return Re.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function He(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Jt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(z().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(Te(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var Ne="input, textarea, select";function ke(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=Ae(t);do{c(n,qe);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var o={trigger:"every"};c(n,qe);o.pollInterval=v(c(n,/[,\[\s]/));c(n,qe);var a=He(e,n,"event");if(a){o.eventFilter=a}r.push(o)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var a=He(e,n,"event");if(a){s.eventFilter=a}while(n.length>0&&n[0]!==","){c(n,qe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Ce))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Ce);if(u==="closest"||u==="find"){n.shift();u+=" "+c(n,Ce)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Ce)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Ce))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Ce)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Ce)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,qe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,Ne)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ie(e){_(e).cancelled=true}function Me(e,t,r,n){var i=_(e);i.timeout=setTimeout(function(){if(Y(e)&&i.cancelled!==true){if(!je(n,dt("hx:poll:trigger",{triggerSpec:n,target:e}))){Z(t,r,e)}Me(e,t,V(e,"hx-"+t),n)}},n.pollInterval)}function De(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&De(t)&&t.target===""||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href");r.pushURL=true}else{var o=f(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=f(t,"action")}e.forEach(function(e){Be(t,n,i,r,e,true)})}}function Pe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&H(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Xe(e,t){return _(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function je(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(z().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Be(o,a,s,e,l,u){var t;if(l.from){t=N(o,l.from)}else{t=[o]}W(t,function(n){var i=function(e){if(!Y(o)){n.removeEventListener(l.trigger,i);return}if(Xe(o,e)){return}if(u||Pe(e,o)){e.preventDefault()}if(je(l,e)){return}var t=_(e);t.triggerSpec=l;if(t.handledFor==null){t.handledFor=[]}var r=_(o);if(t.handledFor.indexOf(o)<0){t.handledFor.push(o);if(l.consume){e.stopPropagation()}if(l.target&&e.target){if(!d(e.target,l.target)){return}}if(l.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(l.changed){if(r.lastValue===o.value){return}else{r.lastValue=o.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(l.throttle){if(!r.throttle){Z(a,s,o,e);r.throttle=setTimeout(function(){r.throttle=null},l.throttle)}}else if(l.delay){r.delayed=setTimeout(function(){Z(a,s,o,e)},l.delay)}else{Z(a,s,o,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:l.trigger,listener:i,on:n});n.addEventListener(l.trigger,i)})}var Ue=false;var Ve=null;function ze(){if(!Ve){Ve=function(){Ue=true};window.addEventListener("scroll",Ve);setInterval(function(){if(Ue){Ue=false;W(z().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){_e(e)})}},200)}}function _e(e){if(!s(e,"data-hx-revealed")&&b(e)){e.setAttribute("data-hx-revealed","true");var t=_(e);if(t.initialized){Z(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Z(t.verb,t.path,e)},{once:true})}}}function We(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Je(e,o[1],0)}if(o[0]==="send"){Ze(e)}}}function Je(s,r,n){if(!Y(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=U.createWebSocket(r);t.onerror=function(e){J(s,"htmx:wsError",{error:e,socket:t});$e(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=Ge(n);setTimeout(function(){Je(s,r,n+1)},t)}};t.onopen=function(e){n=0};_(s).webSocket=t;t.addEventListener("message",function(e){if($e(s)){return}var t=e.data;gt(s,function(e){t=e.transformResponse(t,null,s)});var r=zt(s);var n=g(t);var i=y(n.children);for(var o=0;o<i.length;o++){var a=i[o];B(V(a,"hx-swap-oob")||"true",a,r)}Ct(r.tasks)})}function $e(e){if(!Y(e)){_(e).webSocket.close();return true}}function Ze(u){var f=h(u,function(e){return _(e).webSocket!=null});if(f){u.addEventListener(ke(u)[0].trigger,function(e){var t=_(f).webSocket;var r=Xt(u,f);var n=Mt(u,"post");var i=n.errors;var o=n.values;var a=Gt(u);var s=Q(o,a);var l=jt(s,u);l["HEADERS"]=r;if(i&&i.length>0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Pe(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ge(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}pt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ke(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Ye(e,o[1])}if(o[0]==="swap"){Qe(e,o[1])}}}function Ye(t,e){var r=U.createEventSource(e);r.onerror=function(e){J(t,"htmx:sseError",{error:e,source:r});tt(t)};_(t).sseEventSource=r}function Qe(o,a){var s=h(o,rt);if(s){var l=_(s).sseEventSource;var u=function(e){if(tt(s)){l.removeEventListener(a,u);return}var t=e.data;gt(o,function(e){t=e.transformResponse(t,null,o)});var r=Ut(o);var n=ne(o);var i=zt(o);we(r.swapStyle,o,n,t,i);Ct(i.tasks);$(o,"htmx:sseMessage",e)};_(o).sseListener=u;l.addEventListener(a,u)}else{J(o,"htmx:noSSESourceError")}}function et(e,t,r,n){var i=h(e,rt);if(i){var o=_(i).sseEventSource;var a=function(){if(!tt(i)){if(Y(e)){Z(t,r,e)}else{o.removeEventListener(n,a)}}};_(e).sseListener=a;o.addEventListener(n,a)}else{J(e,"htmx:noSSESourceError")}}function tt(e){if(!Y(e)){_(e).sseEventSource.close();return true}}function rt(e){return _(e).sseEventSource!=null}function nt(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Z(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function it(o,a,e){var t=false;W(n,function(n){if(s(o,"hx-"+n)){var i=V(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){et(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){ze();_e(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=ee(o,e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){$(o,"intersect");break}}},t);r.observe(o);Be(o,n,i,a,e)}else if(e.trigger==="load"){nt(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Me(o,n,i,e)}else{Be(o,n,i,a,e)}})}});return t}function ot(e){if(e.type==="text/javascript"||e.type==="module"||e.type===""){var t=z().createElement("script");W(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(U.config.inlineScriptNonce){t.nonce=U.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){pt(e)}finally{r.removeChild(e)}}}function at(e){if(d(e,"script")){ot(e)}W(R(e,"script"),function(e){ot(e)})}function st(){return document.querySelector("[hx-boost], [data-hx-boost]")}function lt(e){if(e.querySelectorAll){var t=st()?", a, form":"";var r=e.querySelectorAll(i+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [hx-data-ext]");return r}else{return[]}}function ut(r){var e=function(e){if(d(e.target,"button, input[type='submit']")){var t=_(r);t.lastButtonClicked=e.target}};r.addEventListener("click",e);r.addEventListener("focusin",e);r.addEventListener("focusout",function(e){var t=_(r);t.lastButtonClicked=null})}function ft(e){if(e.closest&&e.closest(U.config.disableSelector)){return}var t=_(e);if(!t.initialized){t.initialized=true;$(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=ke(e);var n=it(e,t,r);if(!n&&G(e,"hx-boost")==="true"){Fe(e,t,r)}if(e.tagName==="FORM"){ut(e)}var i=V(e,"hx-sse");if(i){Ke(e,t,i)}var o=V(e,"hx-ws");if(o){We(e,t,o)}$(e,"htmx:afterProcessNode")}}function ct(e){e=k(e);ft(e);W(lt(e),function(e){ft(e)})}function ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function dt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=z().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function J(e,t,r){$(e,t,Q({error:t},r))}function vt(e){return e==="htmx:afterProcessNode"}function gt(e,t){W(sr(e),function(e){try{t(e)}catch(e){pt(e)}})}function pt(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function $(e,t,r){e=k(e);if(r==null){r={}}r["elt"]=e;var n=dt(t,r);if(U.logger&&!vt(t)){U.logger(e,t,r)}if(r.error){pt(r.error);$(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=ht(t);if(i&&o!==t){var a=dt(o,n.detail);i=i&&e.dispatchEvent(a)}gt(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var mt=location.pathname+location.search;function xt(){var e=z().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||z().body}function yt(e,t,r,n){var i=S(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>U.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(z().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function bt(e){var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function wt(e){var t=U.config.requestClass;var r=e.cloneNode(true);W(R(r,"."+t),function(e){q(e,t)});return r.innerHTML}function St(){var e=xt();var t=mt||location.pathname+location.search;$(z().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(U.config.historyEnabled)history.replaceState({htmx:true},z().title,window.location.href);yt(t,wt(e),z().title,window.scrollY)}function Et(e){if(U.config.historyEnabled)history.pushState({htmx:true},"",e);mt=e}function Ct(e){W(e,function(e){e.call()})}function Rt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};$(z().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){$(z().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=xt();var r=zt(t);me(t,e,r);Ct(r.tasks);mt=n;$(z().body,"htmx:historyRestore",{path:n})}else{J(z().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Ot(e){St();e=e||location.pathname+location.search;var t=bt(e);if(t){var r=g(t.content);var n=xt();var i=zt(n);me(n,r,i);Ct(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);mt=e;$(z().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Rt(e)}}}function Lt(e){var t=G(e,"hx-push-url");return t&&t!=="false"||_(e).boosted&&_(e).pushURL}function qt(e){var t=G(e,"hx-push-url");return t==="true"||t==="false"?null:t}function At(e){var t=F(e,"hx-indicator");if(t==null){t=[e]}W(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Tt(e){W(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function Ht(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Nt(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 kt(t,r,n,e,i){if(e==null||Ht(t,e)){return}else{t.push(e)}if(Nt(e)){var o=f(e,"name");var a=e.value;if(e.multiple){a=y(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=y(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){It(e,n)}}if(d(e,"form")){var l=e.elements;W(l,function(e){kt(t,r,n,e,i)})}}function It(e,t){if(e.willValidate){$(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});$(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Mt(e,t){var r=[];var n={};var i={};var o=[];var a=_(e);var s=d(e,"form")&&e.noValidate!==true;if(a.lastButtonClicked){s=s&&a.lastButtonClicked.formNoValidate!==true}if(t!=="get"){kt(r,i,o,H(e,"form"),s)}kt(r,n,o,e,s);if(a.lastButtonClicked){var l=f(a.lastButtonClicked,"name");if(l){n[l]=a.lastButtonClicked.value}}var u=F(e,"hx-include");W(u,function(e){kt(r,n,o,e,s);if(!d(e,"form")){W(e.querySelectorAll(Ne),function(e){kt(r,n,o,e,s)})}});n=Q(n,i);return{errors:o,values:n}}function Dt(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function Ft(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=Dt(t,r,e)})}else{t=Dt(t,r,n)}}}return t}function Pt(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){W(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Xt(e,t,r){var n={"HX-Request":"true","HX-Trigger":f(e,"id"),"HX-Trigger-Name":f(e,"name"),"HX-Target":V(t,"id"),"HX-Current-URL":z().location.href};Wt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(_(e).boosted){n["HX-Boosted"]="true"}return n}function jt(t,e){var r=G(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){W(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};W(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Bt(e){return f(e,"href")&&f(e,"href").indexOf("#")>=0}function Ut(e,t){var r=t?t:G(e,"hx-swap");var n={swapStyle:_(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(_(e).boosted&&!Bt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var o=1;o<i.length;o++){var a=i[o];if(a.indexOf("swap:")===0){n["swapDelay"]=v(a.substr(5))}if(a.indexOf("settle:")===0){n["settleDelay"]=v(a.substr(7))}if(a.indexOf("scroll:")===0){var s=a.substr(7);var l=s.split(":");var f=l.pop();var u=l.length>0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(a.indexOf("show:")===0){var c=a.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(a.indexOf("focus-scroll:")===0){var d=a.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function Vt(t,r,n){var i=null;gt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(G(r,"hx-encoding")==="multipart/form-data"||d(r,"form")&&f(r,"enctype")==="multipart/form-data"){return Pt(n)}else{return Ft(n)}}}function zt(e){return{tasks:[],elts:[e]}}function _t(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ee(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var o=t.showTarget;if(t.showTarget==="window"){o="body"}i=ee(r,o)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function Wt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}else if(o.indexOf("js:")===0){o=o.substr(3);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Jt(e,function(){return Function("return ("+o+")")()},{})}else{s=S(o)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Wt(u(e),t,r,n)}function Jt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function $t(e,t){return Wt(e,"hx-vars",true,t)}function Zt(e,t){return Wt(e,"hx-vals",false,t)}function Gt(e){return Q($t(e),Zt(e))}function Kt(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Yt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(z().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Qt(e,t){return e.getAllResponseHeaders().match(t)}function er(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return Z(e,t,null,null,{targetOverride:k(r),returnPromise:true})}else{return Z(e,t,k(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:k(r.target),swapOverride:r.swap,returnPromise:true})}}else{return Z(e,t,null,null,{returnPromise:true})}}function tr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Z(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=z().body}var v=r.handler||rr;if(!Y(n)){return}var g=r.targetOverride||ne(n);if(g==null||g==te){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=_(n);var o=G(n,"hx-sync");var m=null;var x=false;if(o){var y=o.split(":");var b=y[0].trim();if(b==="this"){p=re(n,"hx-sync")}else{p=ee(n,b)}o=(y[1]||"drop").trim();i=_(p);if(o==="drop"&&i.xhr&&i.abortable!==true){return}else if(o==="abort"){if(i.xhr){return}else{x=true}}else if(o==="replace"){$(p,"htmx:abort")}else if(o.indexOf("queue")===0){var w=o.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=_(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){Z(e,t,n,f,r)})}return}}var a=new XMLHttpRequest;i.xhr=a;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=G(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){K(c);s();return d}}var R=G(n,"hx-confirm");if(R){if(!confirm(R)){K(c);s();return d}}var O=Xt(n,g,C);if(r.headers){O=Q(O,r.headers)}var L=Mt(n,e);var q=L.errors;var A=L.values;if(r.values){A=Q(A,r.values)}var T=Gt(n);var H=Q(A,T);var N=jt(H,n);if(e!=="get"&&G(n,"hx-encoding")==null){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=z().location.href}var k=Wt(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:q,withCredentials:r.credentials||k.credentials||U.config.withCredentials,timeout:r.timeout||k.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){K(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;q=l.errors;if(q&&q.length>0){$(n,"htmx:validation:halted",l);K(c);s();return d}var I=t.split("#");var M=I[0];var D=I[1];if(e==="get"){var F=M;var P=Object.keys(N).length!==0;if(P){if(F.indexOf("?")<0){F+="?"}else{F+="&"}F+=Ft(N);if(D){F+="#"+D}}a.open("GET",F,true)}else{a.open(e.toUpperCase(),t,true)}a.overrideMimeType("text/html");a.withCredentials=l.withCredentials;a.timeout=l.timeout;if(k.noHeaders){}else{for(var X in O){if(O.hasOwnProperty(X)){var j=O[X];Kt(a,X,j)}}}var u={xhr:a,target:g,requestConfig:l,etc:r,pathInfo:{path:t,finalPath:F,anchor:D}};a.onload=function(){try{var e=tr(n);v(n,u);Tt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!Y(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(Y(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}K(c);s()}catch(e){J(n,"htmx:onLoadError",Q({error:e},u));throw e}};a.onerror=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);K(h);s()};a.onabort=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);K(h);s()};a.ontimeout=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);K(h);s()};if(!$(n,"htmx:beforeRequest",u)){K(c);s();return d}var B=At(n);W(["loadstart","loadend","progress","abort"],function(t){W([a,a.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);a.send(e==="get"?null:Vt(a,n,N));return d}function rr(s,l){var u=l.xhr;var f=l.target;var r=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(Qt(u,/HX-Trigger:/i)){Se(u,"HX-Trigger",s)}if(Qt(u,/HX-Push:/i)){var c=u.getResponseHeader("HX-Push")}if(Qt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Qt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(Qt(u,/HX-Retarget:/i)){l.target=z().querySelector(u.getResponseHeader("HX-Retarget"))}var h;if(c=="false"){h=false}else{h=Lt(s)||c}var n=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var e=u.status>=400;var t=Q({shouldSwap:n,serverResponse:d,isError:e},l);if(!$(f,"htmx:beforeSwap",t))return;f=t.target;d=t.serverResponse;e=t.isError;l.failed=e;l.successful=!e;if(t.shouldSwap){if(u.status===286){Ie(s)}gt(s,function(e){d=e.transformResponse(d,u,s)});if(h){St()}var i=r.swapOverride;var v=Ut(s,i);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=zt(f);we(v.swapStyle,f,s,d,n);if(t.elt&&!Y(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);W(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(l.pathInfo.anchor){location.hash=l.pathInfo.anchor}if(Qt(u,/HX-Trigger-After-Swap:/i)){var o=s;if(!Y(s)){o=z().body}Se(u,"HX-Trigger-After-Swap",o)}var a=function(){W(n.tasks,function(e){e.call()});W(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h){var e=c||qt(s)||Yt(u)||l.pathInfo.finalPath||l.pathInfo.path;Et(e);$(z().body,"htmx:pushedIntoHistory",{path:e})}if(n.title){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}_t(n.elts,v);if(Qt(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!Y(s)){r=z().body}Se(u,"HX-Trigger-After-Settle",r)}};if(v.settleDelay>0){setTimeout(a,v.settleDelay)}else{a()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(v.swapDelay>0){setTimeout(o,v.swapDelay)}else{o()}}if(e){J(s,"htmx:responseError",Q({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var nr={};function ir(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function or(e,t){if(t.init){t.init(r)}nr[e]=Q(ir(),t)}function ar(e){delete nr[e]}function sr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){W(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=nr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return sr(u(e),r,n)}function lr(e){if(z().readyState!=="loading"){e()}else{z().addEventListener("DOMContentLoaded",e)}}function ur(){if(U.config.includeIndicatorStyles!==false){z().head.insertAdjacentHTML("beforeend","<style> ."+U.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+U.config.requestClass+" ."+U.config.indicatorClass+"{opacity:1} ."+U.config.requestClass+"."+U.config.indicatorClass+"{opacity:1} </style>")}}function fr(){var e=z().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function cr(){var e=fr();if(e){U.config=Q(U.config,e)}}lr(function(){cr();ur();var e=z().body;ct(e);var t=z().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=_(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){Ot();W(t,function(e){$(e,"htmx:restored",{document:z(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file +// /////////////////////////////////////////////////////////////////// +// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js +// +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(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 a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/<body/.test(e)}function l(e){var t=!N(e);var r=A(e);var n=e;if(r==="head"){n=n.replace(S,"")}if(Q.config.useTemplateFragments&&t){var i=a("<body><template>"+n+"</template></body>",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a("<table>"+n+"</table>",1);case"col":return a("<table><colgroup>"+n+"</colgroup></table>",2);case"tr":return a("<table><tbody>"+n+"</tbody></table>",2);case"td":case"th":return a("<table><tbody><tr>"+n+"</tr></tbody></table>",3);case"script":case"style":return a("<div>"+n+"</div>",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function oe(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function X(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var Y=function(e,t){var r=re().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function we(t,r){oe(t.attributes,function(e){if(!r.hasAttribute(e.name)&&be(e.name)){t.removeAttribute(e.name)}});oe(r.attributes,function(e){if(be(e.name)){t.setAttribute(e.name,e.value)}})}function Se(e,t){var r=Fr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){b(e)}}return e==="outerHTML"}function Ee(e,i,a){var t="#"+ee(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a<i.length;a++){var o=i[a].split(":",2);var s=o[0].trim();if(s.indexOf("#")===0){s=s.substring(1)}var l=o[1]||"true";var u=t.querySelector("#"+s);if(u){Ee(l,u,r)}}}oe(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=te(e,"hx-swap-oob");if(t!=null){Ee(t,e,r)}})}function Re(e){oe(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=te(e,"id");var r=re().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function Te(o,e,s){oe(e.querySelectorAll("[id]"),function(e){var t=ee(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Le(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=He(n.name,t);t=He(n.value,t)}}}return t}function Ae(e){var t=ae(e);if(t.onHandlers){for(var r=0;r<t.onHandlers.length;r++){const n=t.onHandlers[r];e.removeEventListener(n.event,n.listener)}delete t.onHandlers}}function Ne(e){var t=ae(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){oe(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}Ae(e);oe(Object.keys(t),function(e){delete t[e]})}function p(e){ce(e,"htmx:beforeCleanupElement");Ne(e);if(e.children){oe(e.children,function(e){p(e)})}}function Ie(t,e,r){if(t.tagName==="BODY"){return Ue(t,e,r)}else{var n;var i=t.previousSibling;m(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}p(t);u(t).removeChild(t)}}function ke(e,t,r){return m(e,e.firstChild,t,r)}function Pe(e,t,r){return m(u(e),e,t,r)}function Me(e,t,r){return m(e,null,t,r)}function Xe(e,t,r){return m(u(e),e.nextSibling,t,r)}function De(e,t,r){p(e);return u(e).removeChild(e)}function Ue(e,t,r){var n=e.firstChild;m(e,n,t,r);if(n){while(n.nextSibling){p(n.nextSibling);e.removeChild(n.nextSibling)}p(n);e.removeChild(n)}}function Be(e,t,r){var n=r||ne(e,"hx-select");if(n){var i=re().createDocumentFragment();oe(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function Fe(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Ie(r,n,i);return;case"afterbegin":ke(r,n,i);return;case"beforebegin":Pe(r,n,i);return;case"beforeend":Me(r,n,i);return;case"afterend":Xe(r,n,i);return;case"delete":De(r,n,i);return;default:var a=Fr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Oe(f))}}}return}}catch(e){b(e)}}if(e==="innerHTML"){Ue(r,n,i)}else{Fe(Q.config.defaultSwapStyle,t,r,n,i)}}}function Ve(e){if(e.indexOf("<title")>-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){ce(r,s[l].trim(),[])}}}var ze=/\s/;var x=/[\s,]/;var $e=/[_$a-zA-Z]/;var We=/[_$a-zA-Z0-9]/;var Ge=['"',"'","/"];var Je=/[^\s]/;var Ze=/[{(]/;var Ke=/[})]/;function Ye(e){var t=[];var r=0;while(r<e.length){if($e.exec(e.charAt(r))){var n=r;while(We.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ge.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function Qe(e,t,r){return $e.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function et(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){xt(e,a[1],0)}if(a[0]==="send"){bt(e)}}}function xt(s,r,n){if(!se(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=Q.createWebSocket(r);t.onerror=function(e){fe(s,"htmx:wsError",{error:e,socket:t});yt(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a<i.length;a++){var o=i[a];Ee(te(o,"hx-swap-oob")||"true",o,r)}nr(r.tasks)})}function yt(e){if(!se(e)){ae(e).webSocket.close();return true}}function bt(u){var f=c(u,function(e){return ae(e).webSocket!=null});if(f){u.addEventListener(it(u)[0].trigger,function(e){var t=ae(f).webSocket;var r=xr(u,f);var n=dr(u,"post");var i=n.errors;var a=n.values;var o=Hr(u);var s=le(a,o);var l=yr(s,u);l["HEADERS"]=r;if(i&&i.length>0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){Et(e,a[1])}if(a[0]==="swap"){Ct(e,a[1])}}}function Et(t,e){var r=Q.createEventSource(e);r.onerror=function(e){fe(t,"htmx:sseError",{error:e,source:r});Tt(t)};ae(t).sseEventSource=r}function Ct(a,o){var s=c(a,Ot);if(s){var l=ae(s).sseEventSource;var u=function(e){if(Tt(s)){return}if(!se(a)){l.removeEventListener(o,u);return}var t=e.data;R(a,function(e){t=e.transformResponse(t,null,a)});var r=wr(a);var n=ye(a);var i=T(a);je(r.swapStyle,n,a,t,i);nr(i.tasks);ce(a,"htmx:sseMessage",e)};ae(a).sseListener=u;l.addEventListener(o,u)}else{fe(a,"htmx:noSSESourceError")}}function Rt(e,t,r){var n=c(e,Ot);if(n){var i=ae(n).sseEventSource;var a=function(){if(!Tt(n)){if(se(e)){t(e)}else{i.removeEventListener(r,a)}}};ae(e).sseListener=a;i.addEventListener(r,a)}else{fe(e,"htmx:noSSESourceError")}}function Tt(e){if(!se(e)){ae(e).sseEventSource.close();return true}}function Ot(e){return ae(e).sseEventSource!=null}function qt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n>0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){ce(n,"intersect");break}}},i);a.observe(n);ht(n,r,t,e)}else if(e.trigger==="load"){if(!ct(e,n,Wt("load",{elt:n}))){qt(n,r,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r<t.length;r++){var n=t[r].name;if(s(n,"hx-on:")||s(n,"data-hx-on:")||s(n,"hx-on-")||s(n,"data-hx-on-")){return true}}return false}function kt(e){var t=null;var r=[];if(It(e)){r.push(e)}if(document.evaluate){var n=document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]',e);while(t=n.iterateNext())r.push(t)}else{var i=e.getElementsByTagName("*");for(var a=0;a<i.length;a++){if(It(i[a])){r.push(i[a])}}}return r}function Pt(e){if(e.querySelectorAll){var t=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";var r=e.querySelectorAll(i+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Mt(e){var t=v(e.target,"button, input[type='submit']");var r=Dt(e);if(r){r.lastButtonClicked=t}}function Xt(e){var t=Dt(e);if(t){t.lastButtonClicked=null}}function Dt(e){var t=v(e.target,"button, input[type='submit']");if(!t){return}var r=g("#"+ee(t,"form"))||v(t,"form");if(!r){return}return ae(r)}function Ut(e){e.addEventListener("click",Mt);e.addEventListener("focusin",Mt);e.addEventListener("focusout",Xt)}function Bt(e){var t=Ye(e);var r=0;for(var n=0;n<t.length;n++){const i=t[n];if(i==="{"){r++}else if(i==="}"){r--}}return r}function Ft(t,e,r){var n=ae(t);if(!Array.isArray(n.onHandlers)){n.onHandlers=[]}var i;var a=function(e){return Tr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Vt(e){var t=te(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;t<e.attributes.length;t++){var r=e.attributes[t].name;var n=e.attributes[t].value;if(s(r,"hx-on")||s(r,"data-hx-on")){var i=r.indexOf("-on")+3;var a=r.slice(i,i+1);if(a==="-"||a===":"){var o=r.slice(i+1);if(s(o,":")){o="htmx"+o}else if(s(o,"-")){o="htmx:"+o.slice(1)}else if(s(o,"htmx-")){o="htmx:"+o.slice(5)}Ft(e,o,n)}}}}function _t(t){if(v(t,Q.config.disableSelector)){p(t);return}var r=ae(t);if(r.initHash!==Le(t)){Ne(t);r.initHash=Le(t);Vt(t);ce(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=it(t);var n=Ht(t,r,e);if(!n){if(ne(t,"hx-boost")==="true"){lt(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){Lt(t,e,r,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&o(t,"form")){Ut(t)}var i=te(t,"hx-sse");if(i){St(t,r,i)}var a=te(t,"hx-ws");if(a){pt(t,r,a)}ce(t,"htmx:afterProcessNode")}}function zt(e){e=g(e);if(v(e,Q.config.disableSelector)){p(e);return}_t(e);oe(Pt(e),function(e){_t(e)});oe(kt(e),jt)}function $t(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=re().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function fe(e,t,r){ce(e,t,le({error:t},r))}function Gt(e){return e==="htmx:afterProcessNode"}function R(e,t){oe(Fr(e),function(e){try{t(e)}catch(e){b(e)}})}function b(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ce(e,t,r){e=g(e);if(r==null){r={}}r["elt"]=e;var n=Wt(t,r);if(Q.logger&&!Gt(t)){Q.logger(e,t,r)}if(r.error){b(r.error);ce(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=$t(t);if(i&&a!==t){var o=Wt(a,n.detail);i=i&&e.dispatchEvent(o)}R(e,function(e){i=i&&(e.onEvent(t,n)!==false&&!n.defaultPrevented)});return i}var Jt=location.pathname+location.search;function Zt(){var e=re().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||re().body}function Kt(e,t,r,n){if(!U()){return}if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}e=B(e);var i=E(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};ce(re().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Qt(e){var t=Q.config.requestClass;var r=e.cloneNode(true);oe(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function er(){var e=Zt();var t=Jt||location.pathname+location.search;var r;try{r=re().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){r=re().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!r){ce(re().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Kt(t,Qt(e),re().title,window.scrollY)}if(Q.config.historyEnabled)history.replaceState({htmx:true},re().title,window.location.href)}function tr(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(G(e,"&")||G(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Jt=e}function rr(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Jt=e}function nr(e){oe(e,function(e){e.call()})}function ir(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};ce(re().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",re().location.href);e.onload=function(){if(this.status>=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function fr(e){if(e.name===""||e.name==null||e.disabled||v(e,"fieldset[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 cr(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function hr(t,r,n,e,i){if(e==null||ur(t,e)){return}else{t.push(e)}if(fr(e)){var a=ee(e,"name");var o=e.value;if(e.multiple&&e.tagName==="SELECT"){o=M(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=M(e.files)}cr(a,o,r);if(i){vr(e,n)}}if(h(e,"form")){var s=e.elements;oe(s,function(e){hr(t,r,n,e,i)})}}function vr(e,t){if(e.willValidate){ce(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});ce(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function dr(e,t){var r=[];var n={};var i={};var a=[];var o=ae(e);if(o.lastButtonClicked&&!se(o.lastButtonClicked)){o.lastButtonClicked=null}var s=h(e,"form")&&e.noValidate!==true||te(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){hr(r,i,a,v(e,"form"),s)}hr(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=ee(l,"name");cr(u,l.value,i)}var f=pe(e,"hx-include");oe(f,function(e){hr(r,n,a,e,s);if(!h(e,"form")){oe(e.querySelectorAll(rt),function(e){hr(r,n,a,e,s)})}});n=le(n,i);return{errors:a,values:n}}function gr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function mr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t=gr(t,r,e)})}else{t=gr(t,r,n)}}}return t}function pr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function xr(e,t,r){var n={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":re().location.href};Rr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ae(e).boosted){n["HX-Boosted"]="true"}return n}function yr(t,e){var r=ne(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){oe(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};oe(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function br(e){return ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=d(o.substr(5))}else if(o.indexOf("settle:")===0){n["settleDelay"]=d(o.substr(7))}else if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}else if(o.indexOf("ignoreTitle:")===0){n["ignoreTitle"]=o.substr(12)==="true"}else if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","<style> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file diff --git a/code/ch5_partials/ch5_final_video_collector/static/js/htmx.js b/code/ch5_partials/ch5_final_video_collector/static/js/htmx.js index 27e57bc..86e7668 100644 --- a/code/ch5_partials/ch5_final_video_collector/static/js/htmx.js +++ b/code/ch5_partials/ch5_final_video_collector/static/js/htmx.js @@ -1,13 +1,23 @@ -//AMD insanity +// /////////////////////////////////////////////////////////////////// +// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.js +// + +// UMD insanity +// This code sets up support for (in order) AMD, ES6 modules, and globals. (function (root, factory) { //@ts-ignore if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. //@ts-ignore define([], factory); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); } else { // Browser globals - root.htmx = factory(); + root.htmx = root.htmx || factory(); } }(typeof self !== 'undefined' ? self : this, function () { return (function () { @@ -38,6 +48,7 @@ return (function () { defineExtension : defineExtension, removeExtension : removeExtension, logAll : logAll, + logNone : logNone, logger : null, config : { historyEnabled:true, @@ -53,15 +64,24 @@ return (function () { settlingClass:'htmx-settling', swappingClass:'htmx-swapping', allowEval:true, + allowScriptTags:true, inlineScriptNonce:'', attributesToSettle:["class", "style", "width", "height"], withCredentials:false, timeout:0, wsReconnectDelay: 'full-jitter', + wsBinaryType: 'blob', disableSelector: "[hx-disable], [data-hx-disable]", useTemplateFragments: false, scrollBehavior: 'smooth', defaultFocusScroll: false, + getCacheBusterParam: false, + globalViewTransitions: false, + methodsThatUseUrlParams: ["get"], + selfRequestsOnly: false, + ignoreTitle: false, + scrollIntoViewOnBoost: true, + triggerSpecsCache: null, }, parseInterval:parseInterval, _:internalEval, @@ -69,17 +89,23 @@ return (function () { return new EventSource(url, {withCredentials:true}) }, createWebSocket: function(url){ - return new WebSocket(url, []); + var sock = new WebSocket(url, []); + sock.binaryType = htmx.config.wsBinaryType; + return sock; }, - version: "1.7.0" + version: "1.9.10" }; /** @type {import("./htmx").HtmxInternalApi} */ var internalAPI = { + addTriggerHandler: addTriggerHandler, bodyContains: bodyContains, + canAccessLocalStorage: canAccessLocalStorage, + findThisElement: findThisElement, filterValues: filterValues, hasAttribute: hasAttribute, getAttributeValue: getAttributeValue, + getClosestAttributeValue: getClosestAttributeValue, getClosestMatch: getClosestMatch, getExpressionVars: getExpressionVars, getHeaders: getHeaders, @@ -92,6 +118,7 @@ return (function () { mergeObjects: mergeObjects, makeSettleInfo: makeSettleInfo, oobSwap: oobSwap, + querySelectorExt: querySelectorExt, selectAndSwap: selectAndSwap, settleImmediately: settleImmediately, shouldCancel: shouldCancel, @@ -105,21 +132,40 @@ return (function () { return "[hx-" + verb + "], [data-hx-" + verb + "]" }).join(", "); + var HEAD_TAG_REGEX = makeTagRegEx('head'), + TITLE_TAG_REGEX = makeTagRegEx('title'), + SVG_TAGS_REGEX = makeTagRegEx('svg', true); + //==================================================================== // Utilities //==================================================================== + /** + * @param {string} tag + * @param {boolean} global + * @returns {RegExp} + */ + function makeTagRegEx(tag, global = false) { + return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, + global ? 'gim' : 'im'); + } + function parseInterval(str) { if (str == undefined) { - return undefined + return undefined; } + + let interval = NaN; if (str.slice(-2) == "ms") { - return parseFloat(str.slice(0,-2)) || undefined - } - if (str.slice(-1) == "s") { - return (parseFloat(str.slice(0,-1)) * 1000) || undefined + interval = parseFloat(str.slice(0, -2)); + } else if (str.slice(-1) == "s") { + interval = parseFloat(str.slice(0, -1)) * 1000; + } else if (str.slice(-1) == "m") { + interval = parseFloat(str.slice(0, -1)) * 1000 * 60; + } else { + interval = parseFloat(str); } - return parseFloat(str) || undefined + return isNaN(interval) ? undefined : interval; } /** @@ -168,13 +214,11 @@ return (function () { * @returns {HTMLElement | null} */ function getClosestMatch(elt, condition) { - if (condition(elt)) { - return elt; - } else if (parentElt(elt)) { - return getClosestMatch(parentElt(elt), condition); - } else { - return null; + while (elt && !condition(elt)) { + elt = parentElt(elt); } + + return elt ? elt : null; } function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ @@ -208,7 +252,7 @@ return (function () { * @returns {boolean} */ function matches(elt, selector) { - // @ts-ignore: non-standard properties for browser compatability + // @ts-ignore: non-standard properties for browser compatibility // noinspection JSUnresolvedVariable var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; return matchesFunction && matchesFunction.call(elt, selector); @@ -252,38 +296,47 @@ return (function () { return responseNode; } + function aFullPageResponse(resp) { + return /<body/.test(resp) + } + /** * - * @param {string} resp + * @param {string} response * @returns {Element} */ - function makeFragment(resp) { - if (htmx.config.useTemplateFragments) { - var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0); + function makeFragment(response) { + var partialResponse = !aFullPageResponse(response); + var startTag = getStartTag(response); + var content = response; + if (startTag === 'head') { + content = content.replace(HEAD_TAG_REGEX, ''); + } + if (htmx.config.useTemplateFragments && partialResponse) { + var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0); // @ts-ignore type mismatch between DocumentFragment and Element. - // TODO: Are these close enough for htmx to use interchangably? + // TODO: Are these close enough for htmx to use interchangeably? return documentFragment.querySelector('template').content; - } else { - 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); - case "script": - return parseHTML("<div>" + resp + "</div>", 1); - default: - return parseHTML(resp, 0); - } + } + switch (startTag) { + case "thead": + case "tbody": + case "tfoot": + case "colgroup": + case "caption": + return parseHTML("<table>" + content + "</table>", 1); + case "col": + return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2); + case "tr": + return parseHTML("<table><tbody>" + content + "</tbody></table>", 2); + case "td": + case "th": + return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3); + case "script": + case "style": + return parseHTML("<div>" + content + "</div>", 1); + default: + return parseHTML(content, 0); } } @@ -365,13 +418,14 @@ return (function () { return elemTop < window.innerHeight && elemBottom >= 0; } - function bodyContains(elt) { - if (elt.getRootNode() instanceof ShadowRoot) { - return getDocument().body.contains(elt.getRootNode().host); - } else { - return getDocument().body.contains(elt); - } - } + function bodyContains(elt) { + // IE Fix + if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) { + return getDocument().body.contains(elt.getRootNode().host); + } else { + return getDocument().body.contains(elt); + } + } function splitOnWhitespace(trigger) { return trigger.trim().split(/\s+/); @@ -402,6 +456,34 @@ return (function () { } } + function canAccessLocalStorage() { + var test = 'htmx:localStorageTest'; + try { + localStorage.setItem(test, test); + localStorage.removeItem(test); + return true; + } catch(e) { + return false; + } + } + + function normalizePath(path) { + try { + var url = new URL(path); + if (url) { + path = url.pathname + url.search; + } + // remove trailing slash, unless index page + if (!(/^\/$/.test(path))) { + path = path.replace(/\/+$/, ''); + } + return path; + } catch (e) { + // be kind to IE11, which doesn't support URL() + return path; + } + } + //========================================================================================== // public API //========================================================================================== @@ -427,6 +509,10 @@ return (function () { } } + function logNone() { + htmx.logger = null + } + function find(eltOrSelector, selector) { if (selector) { return eltOrSelector.querySelector(selector); @@ -446,7 +532,10 @@ return (function () { function removeElement(elt, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeElement(elt);}, delay) + setTimeout(function(){ + removeElement(elt); + elt = null; + }, delay); } else { elt.parentElement.removeChild(elt); } @@ -455,7 +544,10 @@ return (function () { function addClassToElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){addClassToElement(elt, clazz);}, delay) + setTimeout(function(){ + addClassToElement(elt, clazz); + elt = null; + }, delay); } else { elt.classList && elt.classList.add(clazz); } @@ -464,7 +556,10 @@ return (function () { function removeClassFromElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) + setTimeout(function(){ + removeClassFromElement(elt, clazz); + elt = null; + }, delay); } else { if (elt.classList) { elt.classList.remove(clazz); @@ -494,26 +589,75 @@ return (function () { if (elt.closest) { return elt.closest(selector); } else { + // TODO remove when IE goes away do{ if (elt == null || matches(elt, selector)){ return elt; } } while (elt = elt && parentElt(elt)); + return null; + } + } + + function startsWith(str, prefix) { + return str.substring(0, prefix.length) === prefix + } + + function endsWith(str, suffix) { + return str.substring(str.length - suffix.length) === suffix + } + + function normalizeSelector(selector) { + var trimmedSelector = selector.trim(); + if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) { + return trimmedSelector.substring(1, trimmedSelector.length - 2); + } else { + return trimmedSelector; } } function querySelectorAllExt(elt, selector) { if (selector.indexOf("closest ") === 0) { - return [closest(elt, selector.substr(8))]; + return [closest(elt, normalizeSelector(selector.substr(8)))]; } else if (selector.indexOf("find ") === 0) { - return [find(elt, selector.substr(5))]; + return [find(elt, normalizeSelector(selector.substr(5)))]; + } else if (selector === "next") { + return [elt.nextElementSibling] + } else if (selector.indexOf("next ") === 0) { + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; + } else if (selector === "previous") { + return [elt.previousElementSibling] + } else if (selector.indexOf("previous ") === 0) { + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; } else if (selector === 'document') { return [document]; } else if (selector === 'window') { return [window]; + } else if (selector === 'body') { + return [document.body]; } else { - return getDocument().querySelectorAll(selector); + return getDocument().querySelectorAll(normalizeSelector(selector)); + } + } + + var scanForwardQuery = function(start, match) { + var results = getDocument().querySelectorAll(match); + for (var i = 0; i < results.length; i++) { + var elt = results[i]; + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { + return elt; + } + } + } + + var scanBackwardsQuery = function(start, match) { + var results = getDocument().querySelectorAll(match); + for (var i = results.length - 1; i >= 0; i--) { + var elt = results[i]; + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { + return elt; + } } } @@ -570,7 +714,7 @@ return (function () { //==================================================================== // Node processing //==================================================================== - + var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors function findAttributeTargets(elt, attrName) { var attrTarget = getClosestAttributeValue(elt, attrName); @@ -659,7 +803,7 @@ return (function () { * @returns */ function oobSwap(oobValue, oobElement, settleInfo) { - var selector = "#" + oobElement.id; + var selector = "#" + getRawAttribute(oobElement, "id"); var swapStyle = "outerHTML"; if (oobValue === "true") { // do nothing @@ -703,7 +847,23 @@ return (function () { return oobValue; } - function handleOutOfBandSwaps(fragment, settleInfo) { + function handleOutOfBandSwaps(elt, fragment, settleInfo) { + var oobSelects = getClosestAttributeValue(elt, "hx-select-oob"); + if (oobSelects) { + var oobSelectValues = oobSelects.split(","); + for (var i = 0; i < oobSelectValues.length; i++) { + var oobSelectValue = oobSelectValues[i].split(":", 2); + var id = oobSelectValue[0].trim(); + if (id.indexOf("#") === 0) { + id = id.substring(1); + } + var oobValue = oobSelectValue[1] || "true"; + var oobElement = fragment.querySelector("#" + id); + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo); + } + } + } forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) { var oobValue = getAttributeValue(oobElement, "hx-swap-oob"); if (oobValue != null) { @@ -724,8 +884,11 @@ return (function () { function handleAttributes(parentNode, fragment, settleInfo) { forEach(fragment.querySelectorAll("[id]"), function (newNode) { - if (newNode.id && newNode.id.length > 0) { - var oldNode = parentNode.querySelector(newNode.tagName + "[id='" + newNode.id + "']"); + var id = getRawAttribute(newNode, "id") + if (id && id.length > 0) { + var normalizedId = id.replace("'", "\\'"); + var normalizedTag = newNode.tagName.replace(':', '\\:'); + var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']"); if (oldNode && oldNode !== parentNode) { var newAttributes = newNode.cloneNode(); cloneAttributes(newNode, oldNode); @@ -767,24 +930,67 @@ return (function () { } } - function cleanUpElement(element) { + // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, + // derived from Java's string hashcode implementation + function stringHash(string, hash) { + var char = 0; + while (char < string.length){ + hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int + } + return hash; + } + + function attributeHash(elt) { + var hash = 0; + // IE fix + if (elt.attributes) { + for (var i = 0; i < elt.attributes.length; i++) { + var attribute = elt.attributes[i]; + if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent) + hash = stringHash(attribute.name, hash); + hash = stringHash(attribute.value, hash); + } + } + } + return hash; + } + + function deInitOnHandlers(elt) { + var internalData = getInternalData(elt); + if (internalData.onHandlers) { + for (var i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i]; + elt.removeEventListener(handlerInfo.event, handlerInfo.listener); + } + delete internalData.onHandlers + } + } + + function deInitNode(element) { var internalData = getInternalData(element); + if (internalData.timeout) { + clearTimeout(internalData.timeout); + } if (internalData.webSocket) { internalData.webSocket.close(); } if (internalData.sseEventSource) { internalData.sseEventSource.close(); } - - triggerEvent(element, "htmx:beforeCleanupElement") - if (internalData.listenerInfos) { - forEach(internalData.listenerInfos, function(info) { - if (element !== info.on) { + forEach(internalData.listenerInfos, function (info) { + if (info.on) { info.on.removeEventListener(info.trigger, info.listener); } }); } + deInitOnHandlers(element); + forEach(Object.keys(internalData), function(key) { delete internalData[key] }); + } + + function cleanUpElement(element) { + triggerEvent(element, "htmx:beforeCleanupElement") + deInitNode(element); if (element.children) { // IE forEach(element.children, function(child) { cleanUpElement(child) }); } @@ -803,8 +1009,7 @@ return (function () { } else { newElt = eltBeforeNewContent.nextSibling; } - getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later - settleInfo.elts = [] // clear existing elements + settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target }); while(newElt && newElt !== target) { if (newElt.nodeType === Node.ELEMENT_NODE) { settleInfo.elts.push(newElt); @@ -849,8 +1054,8 @@ return (function () { } } - function maybeSelectFromResponse(elt, fragment) { - var selector = getClosestAttributeValue(elt, "hx-select"); + function maybeSelectFromResponse(elt, fragment, selectOverride) { + var selector = selectOverride || getClosestAttributeValue(elt, "hx-select"); if (selector) { var newFragment = getDocument().createDocumentFragment(); forEach(fragment.querySelectorAll(selector), function (node) { @@ -915,21 +1120,20 @@ return (function () { function findTitle(content) { if (content.indexOf('<title') > -1) { - var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, ''); - var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im); - + var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, ''); + var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX); if (result) { return result[2]; } } } - function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) { + function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) { settleInfo.title = findTitle(responseText); var fragment = makeFragment(responseText); if (fragment) { - handleOutOfBandSwaps(fragment, settleInfo); - fragment = maybeSelectFromResponse(elt, fragment); + handleOutOfBandSwaps(elt, fragment, settleInfo); + fragment = maybeSelectFromResponse(elt, fragment, selectOverride); handlePreservedElements(fragment); return swap(swapStyle, elt, target, fragment, settleInfo); } @@ -949,7 +1153,10 @@ return (function () { } } } else { - triggerEvent(elt, triggerBody, []); + var eventNames = triggerBody.split(",") + for (var i = 0; i < eventNames.length; i++) { + triggerEvent(elt, eventNames[i].trim(), []); + } } } @@ -959,6 +1166,8 @@ return (function () { var SYMBOL_CONT = /[_$a-zA-Z0-9]/; var STRINGISH_START = ['"', "'", "/"]; var NOT_WHITESPACE = /[^\s]/; + var COMBINED_SELECTOR_START = /[{(]/; + var COMBINED_SELECTOR_END = /[})]/; function tokenizeString(str) { var tokens = []; var position = 0; @@ -1041,101 +1250,137 @@ return (function () { function consumeUntil(tokens, match) { var result = ""; - while (tokens.length > 0 && !tokens[0].match(match)) { + while (tokens.length > 0 && !match.test(tokens[0])) { result += tokens.shift(); } return result; } + function consumeCSSSelector(tokens) { + var result; + if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { + tokens.shift(); + result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim(); + tokens.shift(); + } else { + result = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } + return result; + } + var INPUT_SELECTOR = 'input, textarea, select'; /** * @param {HTMLElement} elt + * @param {string} explicitTrigger + * @param {cache} cache for trigger specs * @returns {import("./htmx").HtmxTriggerSpecification[]} */ - function getTriggerSpecs(elt) { - var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); + function parseAndCacheTrigger(elt, explicitTrigger, cache) { var triggerSpecs = []; - if (explicitTrigger) { - var tokens = tokenizeString(explicitTrigger); - do { - consumeUntil(tokens, NOT_WHITESPACE); - var initialLength = tokens.length; - var trigger = consumeUntil(tokens, /[,\[\s]/); - if (trigger !== "") { - if (trigger === "every") { - var every = {trigger: 'every'}; - consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); - consumeUntil(tokens, NOT_WHITESPACE); - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - every.eventFilter = eventFilter; - } - triggerSpecs.push(every); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); - } else { - var triggerSpec = {trigger: trigger}; - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - triggerSpec.eventFilter = eventFilter; - } - while (tokens.length > 0 && tokens[0] !== ",") { - consumeUntil(tokens, NOT_WHITESPACE) - var token = tokens.shift(); - if (token === "changed") { - triggerSpec.changed = true; - } else if (token === "once") { - triggerSpec.once = true; - } else if (token === "consume") { - triggerSpec.consume = true; - } else if (token === "delay" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "from" && tokens[0] === ":") { - tokens.shift(); + var tokens = tokenizeString(explicitTrigger); + do { + consumeUntil(tokens, NOT_WHITESPACE); + var initialLength = tokens.length; + var trigger = consumeUntil(tokens, /[,\[\s]/); + if (trigger !== "") { + if (trigger === "every") { + var every = {trigger: 'every'}; + consumeUntil(tokens, NOT_WHITESPACE); + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); + consumeUntil(tokens, NOT_WHITESPACE); + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + every.eventFilter = eventFilter; + } + triggerSpecs.push(every); + } else if (trigger.indexOf("sse:") === 0) { + triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); + } else { + var triggerSpec = {trigger: trigger}; + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + triggerSpec.eventFilter = eventFilter; + } + while (tokens.length > 0 && tokens[0] !== ",") { + consumeUntil(tokens, NOT_WHITESPACE) + var token = tokens.shift(); + if (token === "changed") { + triggerSpec.changed = true; + } else if (token === "once") { + triggerSpec.once = true; + } else if (token === "consume") { + triggerSpec.consume = true; + } else if (token === "delay" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); + } else if (token === "from" && tokens[0] === ":") { + tokens.shift(); + if (COMBINED_SELECTOR_START.test(tokens[0])) { + var from_arg = consumeCSSSelector(tokens); + } else { var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); - if (from_arg === "closest" || from_arg === "find") { + if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") { tokens.shift(); - from_arg += - " " + - consumeUntil( - tokens, - WHITESPACE_OR_COMMA - ); + var selector = consumeCSSSelector(tokens); + // `next` and `previous` allow a selector-less syntax + if (selector.length > 0) { + from_arg += " " + selector; + } } - triggerSpec.from = from_arg; - } else if (token === "target" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if (token === "throttle" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "queue" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if ((token === "root" || token === "threshold") && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); } + triggerSpec.from = from_arg; + } else if (token === "target" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.target = consumeCSSSelector(tokens); + } else if (token === "throttle" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); + } else if (token === "queue" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } else if (token === "root" && tokens[0] === ":") { + tokens.shift(); + triggerSpec[token] = consumeCSSSelector(tokens); + } else if (token === "threshold" && tokens[0] === ":") { + tokens.shift(); + triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } else { + triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); } - triggerSpecs.push(triggerSpec); } + triggerSpecs.push(triggerSpec); } - if (tokens.length === initialLength) { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - consumeUntil(tokens, NOT_WHITESPACE); - } while (tokens[0] === "," && tokens.shift()) + } + if (tokens.length === initialLength) { + triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); + } + consumeUntil(tokens, NOT_WHITESPACE); + } while (tokens[0] === "," && tokens.shift()) + if (cache) { + cache[explicitTrigger] = triggerSpecs + } + return triggerSpecs + } + + /** + * @param {HTMLElement} elt + * @returns {import("./htmx").HtmxTriggerSpecification[]} + */ + function getTriggerSpecs(elt) { + var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); + var triggerSpecs = []; + if (explicitTrigger) { + var cache = htmx.config.triggerSpecsCache + triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) } if (triggerSpecs.length > 0) { return triggerSpecs; } else if (matches(elt, 'form')) { return [{trigger: 'submit'}]; + } else if (matches(elt, 'input[type="button"], input[type="submit"]')){ + return [{trigger: 'click'}]; } else if (matches(elt, INPUT_SELECTOR)) { return [{trigger: 'change'}]; } else { @@ -1147,14 +1392,17 @@ return (function () { getInternalData(elt).cancelled = true; } - function processPolling(elt, verb, path, spec) { + function processPolling(elt, handler, spec) { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { - issueAjaxRequest(verb, path, elt); + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { + handler(elt); } - processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), spec); + processPolling(elt, handler, spec); } }, spec.pollInterval); } @@ -1166,23 +1414,27 @@ return (function () { } function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt) && elt.target === "") || elt.tagName === "FORM") { + if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || elt.tagName === "FORM") { nodeData.boosted = true; var verb, path; if (elt.tagName === "A") { verb = "get"; - path = getRawAttribute(elt, 'href'); - nodeData.pushURL = true; + path = getRawAttribute(elt, 'href') } else { var rawAttribute = getRawAttribute(elt, "method"); verb = rawAttribute ? rawAttribute.toLowerCase() : "get"; if (verb === "get") { - nodeData.pushURL = true; } path = getRawAttribute(elt, 'action'); } triggerSpecs.forEach(function(triggerSpec) { - addEventListener(elt, verb, path, nodeData, triggerSpec, true); + addEventListener(elt, function(elt, evt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + issueAjaxRequest(verb, path, elt, evt) + }, nodeData, triggerSpec, true); }); } } @@ -1213,11 +1465,11 @@ return (function () { return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); } - function maybeFilterEvent(triggerSpec, evt) { + function maybeFilterEvent(triggerSpec, elt, evt) { var eventFilter = triggerSpec.eventFilter; if(eventFilter){ try { - return eventFilter(evt) !== true; + return eventFilter.call(elt, evt) !== true; } catch(e) { triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); return true; @@ -1226,13 +1478,21 @@ return (function () { return false; } - function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { + function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { + var elementData = getInternalData(elt); var eltsToListenOn; if (triggerSpec.from) { eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); } else { eltsToListenOn = [elt]; } + // store the initial values of the elements, so we can tell if they change + if (triggerSpec.changed) { + eltsToListenOn.forEach(function (eltToListenOn) { + var eltToListenOnData = getInternalData(eltToListenOn); + eltToListenOnData.lastValue = eltToListenOn.value; + }) + } forEach(eltsToListenOn, function (eltToListenOn) { var eventListener = function (evt) { if (!bodyContains(elt)) { @@ -1245,7 +1505,7 @@ return (function () { if (explicitCancel || shouldCancel(evt, elt)) { evt.preventDefault(); } - if (maybeFilterEvent(triggerSpec, evt)) { + if (maybeFilterEvent(triggerSpec, elt, evt)) { return; } var eventData = getInternalData(evt); @@ -1253,7 +1513,6 @@ return (function () { if (eventData.handledFor == null) { eventData.handledFor = []; } - var elementData = getInternalData(elt); if (eventData.handledFor.indexOf(elt) < 0) { eventData.handledFor.push(elt); if (triggerSpec.consume) { @@ -1272,11 +1531,11 @@ return (function () { } } if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { + var eltToListenOnData = getInternalData(eltToListenOn) + if (eltToListenOnData.lastValue === eltToListenOn.value) { return; - } else { - elementData.lastValue = elt.value; } + eltToListenOnData.lastValue = eltToListenOn.value } if (elementData.delayed) { clearTimeout(elementData.delayed); @@ -1285,19 +1544,18 @@ return (function () { return; } - if (triggerSpec.throttle) { + if (triggerSpec.throttle > 0) { if (!elementData.throttle) { - issueAjaxRequest(verb, path, elt, evt); + handler(elt, evt); elementData.throttle = setTimeout(function () { elementData.throttle = null; }, triggerSpec.throttle); } - } else if (triggerSpec.delay) { - elementData.delayed = setTimeout(function () { - issueAjaxRequest(verb, path, elt, evt); - }, triggerSpec.delay); + } else if (triggerSpec.delay > 0) { + elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); } else { - issueAjaxRequest(verb, path, elt, evt); + triggerEvent(elt, 'htmx:trigger') + handler(elt, evt); } } }; @@ -1310,7 +1568,7 @@ return (function () { on: eltToListenOn }) eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); - }) + }); } var windowIsScrolling = false // used by initScrollHandler @@ -1336,14 +1594,11 @@ return (function () { if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { elt.setAttribute('data-hx-revealed', 'true'); var nodeData = getInternalData(elt); - if (nodeData.initialized) { - issueAjaxRequest(nodeData.verb, nodeData.path, elt); + if (nodeData.initHash) { + triggerEvent(elt, 'revealed'); } else { // if the node isn't initialized, wait for it before triggering the request - elt.addEventListener("htmx:afterProcessNode", - function () { - issueAjaxRequest(nodeData.verb, nodeData.path, elt); - }, {once: true}); + elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true}); } } } @@ -1502,6 +1757,9 @@ return (function () { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function (event) { if (maybeCloseSSESource(sseSourceElt)) { + return; + } + if (!bodyContains(elt)) { sseEventSource.removeEventListener(sseEventName, sseListener); return; } @@ -1518,7 +1776,7 @@ return (function () { var target = getTarget(elt) var settleInfo = makeSettleInfo(elt); - selectAndSwap(swapSpec.swapStyle, elt, target, response, settleInfo) + selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) settleImmediately(settleInfo.tasks) triggerEvent(elt, "htmx:sseMessage", event) }; @@ -1530,14 +1788,14 @@ return (function () { } } - function processSSETrigger(elt, verb, path, sseEventName) { + function processSSETrigger(elt, handler, sseEventName) { var sseSourceElt = getClosestMatch(elt, hasEventSource); if (sseSourceElt) { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function () { if (!maybeCloseSSESource(sseSourceElt)) { if (bodyContains(elt)) { - issueAjaxRequest(verb, path, elt); + handler(elt); } else { sseEventSource.removeEventListener(sseEventName, sseListener); } @@ -1563,14 +1821,14 @@ return (function () { //==================================================================== - function loadImmediately(elt, verb, path, nodeData, delay) { + function loadImmediately(elt, handler, nodeData, delay) { var load = function(){ if (!nodeData.loaded) { nodeData.loaded = true; - issueAjaxRequest(verb, path, elt); + handler(elt); } } - if (delay) { + if (delay > 0) { setTimeout(load, delay); } else { load(); @@ -1586,46 +1844,59 @@ return (function () { nodeData.path = path; nodeData.verb = verb; triggerSpecs.forEach(function(triggerSpec) { - if (triggerSpec.sseEvent) { - processSSETrigger(elt, verb, path, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - maybeReveal(elt); - } else if (triggerSpec.trigger === "intersect") { - var observerOptions = {}; - if (triggerSpec.root) { - observerOptions.root = querySelectorExt(elt, triggerSpec.root) - } - if (triggerSpec.threshold) { - observerOptions.threshold = parseFloat(triggerSpec.threshold); + addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return } - var observer = new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - if (entry.isIntersecting) { - triggerEvent(elt, "intersect"); - break; - } - } - }, observerOptions); - observer.observe(elt); - addEventListener(elt, verb, path, nodeData, triggerSpec); - } else if (triggerSpec.trigger === "load") { - loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); - } else if (triggerSpec.pollInterval) { - nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec); - } else { - addEventListener(elt, verb, path, nodeData, triggerSpec); - } + issueAjaxRequest(verb, path, elt, evt) + }) }); } }); return explicitAction; } + function addTriggerHandler(elt, triggerSpec, nodeData, handler) { + if (triggerSpec.sseEvent) { + processSSETrigger(elt, handler, triggerSpec.sseEvent); + } else if (triggerSpec.trigger === "revealed") { + initScrollHandler(); + addEventListener(elt, handler, nodeData, triggerSpec); + maybeReveal(elt); + } else if (triggerSpec.trigger === "intersect") { + var observerOptions = {}; + if (triggerSpec.root) { + observerOptions.root = querySelectorExt(elt, triggerSpec.root) + } + if (triggerSpec.threshold) { + observerOptions.threshold = parseFloat(triggerSpec.threshold); + } + var observer = new IntersectionObserver(function (entries) { + for (var i = 0; i < entries.length; i++) { + var entry = entries[i]; + if (entry.isIntersecting) { + triggerEvent(elt, "intersect"); + break; + } + } + }, observerOptions); + observer.observe(elt); + addEventListener(elt, handler, nodeData, triggerSpec); + } else if (triggerSpec.trigger === "load") { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { + loadImmediately(elt, handler, nodeData, triggerSpec.delay); + } + } else if (triggerSpec.pollInterval > 0) { + nodeData.polling = true; + processPolling(elt, handler, triggerSpec); + } else { + addEventListener(elt, handler, nodeData, triggerSpec); + } + } + function evalScript(script) { - if (script.type === "text/javascript" || script.type === "module" || script.type === "") { + if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) { var newScript = getDocument().createElement("script"); forEach(script.attributes, function (attr) { newScript.setAttribute(attr.name, attr.value); @@ -1642,7 +1913,10 @@ return (function () { } catch (e) { logError(e); } finally { - parent.removeChild(script); + // remove old script element, but only if it is still in DOM + if (script.parentElement) { + script.parentElement.removeChild(script); + } } } } @@ -1656,48 +1930,187 @@ return (function () { }); } - function hasChanceOfBeingBoosted() { - return document.querySelector("[hx-boost], [data-hx-boost]"); + function shouldProcessHxOn(elt) { + var attributes = elt.attributes + for (var j = 0; j < attributes.length; j++) { + var attrName = attributes[j].name + if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") || + startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) { + return true + } + } + return false + } + + function findHxOnWildcardElements(elt) { + var node = null + var elements = [] + + if (shouldProcessHxOn(elt)) { + elements.push(elt) + } + + if (document.evaluate) { + var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + + ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt) + while (node = iter.iterateNext()) elements.push(node) + } else { + var allElements = elt.getElementsByTagName("*") + for (var i = 0; i < allElements.length; i++) { + if (shouldProcessHxOn(allElements[i])) { + elements.push(allElements[i]) + } + } + } + + return elements } function findElementsToProcess(elt) { if (elt.querySelectorAll) { - var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; - var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [hx-data-ext]"); + var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; + var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," + + " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]"); return results; } else { return []; } } - function initButtonTracking(form){ - var maybeSetLastButtonClicked = function(evt){ - if (matches(evt.target, "button, input[type='submit']")) { - var internalData = getInternalData(form); - internalData.lastButtonClicked = evt.target; - } - }; - + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + function maybeSetLastButtonClicked(evt) { + var elt = closest(evt.target, "button, input[type='submit']"); + var internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = elt; + } + }; + function maybeUnsetLastButtonClicked(evt){ + var internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = null; + } + } + function getRelatedFormData(evt) { + var elt = closest(evt.target, "button, input[type='submit']"); + if (!elt) { + return; + } + var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form'); + if (!form) { + return; + } + return getInternalData(form); + } + function initButtonTracking(elt) { // need to handle both click and focus in: // focusin - in case someone tabs in to a button and hits the space bar // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + elt.addEventListener('click', maybeSetLastButtonClicked) + elt.addEventListener('focusin', maybeSetLastButtonClicked) + elt.addEventListener('focusout', maybeUnsetLastButtonClicked) + } - form.addEventListener('click', maybeSetLastButtonClicked) - form.addEventListener('focusin', maybeSetLastButtonClicked) - form.addEventListener('focusout', function(evt){ - var internalData = getInternalData(form); - internalData.lastButtonClicked = null; - }) + function countCurlies(line) { + var tokens = tokenizeString(line); + var netCurlies = 0; + for (var i = 0; i < tokens.length; i++) { + const token = tokens[i]; + if (token === "{") { + netCurlies++; + } else if (token === "}") { + netCurlies--; + } + } + return netCurlies; + } + + function addHxOnEventHandler(elt, eventName, code) { + var nodeData = getInternalData(elt); + if (!Array.isArray(nodeData.onHandlers)) { + nodeData.onHandlers = []; + } + var func; + var listener = function (e) { + return maybeEval(elt, function() { + if (!func) { + func = new Function("event", code); + } + func.call(elt, e); + }); + }; + elt.addEventListener(eventName, listener); + nodeData.onHandlers.push({event:eventName, listener:listener}); + } + + function processHxOn(elt) { + var hxOnValue = getAttributeValue(elt, 'hx-on'); + if (hxOnValue) { + var handlers = {} + var lines = hxOnValue.split("\n"); + var currentEvent = null; + var curlyCount = 0; + while (lines.length > 0) { + var line = lines.shift(); + var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/); + if (curlyCount === 0 && match) { + line.split(":") + currentEvent = match[1].slice(0, -1); // strip last colon + handlers[currentEvent] = match[2]; + } else { + handlers[currentEvent] += line; + } + curlyCount += countCurlies(line); + } + + for (var eventName in handlers) { + addHxOnEventHandler(elt, eventName, handlers[eventName]); + } + } + } + + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (var i = 0; i < elt.attributes.length; i++) { + var name = elt.attributes[i].name + var value = elt.attributes[i].value + if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) { + var afterOnPosition = name.indexOf("-on") + 3; + var nextChar = name.slice(afterOnPosition, afterOnPosition + 1); + if (nextChar === "-" || nextChar === ":") { + var eventName = name.slice(afterOnPosition + 1); + // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support + if (startsWith(eventName, ":")) { + eventName = "htmx" + eventName + } else if (startsWith(eventName, "-")) { + eventName = "htmx:" + eventName.slice(1); + } else if (startsWith(eventName, "htmx-")) { + eventName = "htmx:" + eventName.slice(5); + } + + addHxOnEventHandler(elt, eventName, value) + } + } + } } function initNode(elt) { - if (elt.closest && elt.closest(htmx.config.disableSelector)) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) return; } var nodeData = getInternalData(elt); - if (!nodeData.initialized) { - nodeData.initialized = true; + if (nodeData.initHash !== attributeHash(elt)) { + // clean up any previously processed info + deInitNode(elt); + + nodeData.initHash = attributeHash(elt); + + processHxOn(elt); + triggerEvent(elt, "htmx:beforeProcessNode") if (elt.value) { @@ -1705,14 +2118,24 @@ return (function () { } var triggerSpecs = getTriggerSpecs(elt); - var explicitAction = processVerbs(elt, nodeData, triggerSpecs); - - if (!explicitAction && getClosestAttributeValue(elt, "hx-boost") === "true") { - boostElement(elt, nodeData, triggerSpecs); + var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs); + + if (!hasExplicitHttpAction) { + if (getClosestAttributeValue(elt, "hx-boost") === "true") { + boostElement(elt, nodeData, triggerSpecs); + } else if (hasAttribute(elt, 'hx-trigger')) { + triggerSpecs.forEach(function (triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function () { + }) + }) + } } - if (elt.tagName === "FORM") { - initButtonTracking(elt); + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) { + initButtonTracking(elt) } var sseInfo = getAttributeValue(elt, 'hx-sse'); @@ -1730,8 +2153,15 @@ return (function () { function processNode(elt) { elt = resolveTarget(elt); + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return; + } initNode(elt); forEach(findElementsToProcess(elt), function(child) { initNode(child) }); + // Because it happens second, the new way of adding onHandlers superseeds the old one + // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored + forEach(findHxOnWildcardElements(elt), processHxOnWildcard); } //==================================================================== @@ -1809,7 +2239,7 @@ return (function () { eventResult = eventResult && elt.dispatchEvent(kebabedEvent) } withExtensions(elt, function (extension) { - eventResult = eventResult && (extension.onEvent(eventName, event) !== false) + eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) }); return eventResult; } @@ -1825,6 +2255,18 @@ return (function () { } function saveToHistoryCache(url, content, title, scroll) { + if (!canAccessLocalStorage()) { + return; + } + + if (htmx.config.historyCacheSize <= 0) { + // make sure that an eventually already existing cache is purged + localStorage.removeItem("htmx-history-cache"); + return; + } + + url = normalizePath(url); + var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { @@ -1832,7 +2274,9 @@ return (function () { break; } } - historyCache.push({url:url, content: content, title:title, scroll:scroll}) + var newHistoryItem = {url:url, content: content, title:title, scroll:scroll}; + triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache}) + historyCache.push(newHistoryItem) while (historyCache.length > htmx.config.historyCacheSize) { historyCache.shift(); } @@ -1848,6 +2292,12 @@ return (function () { } function getCachedHistory(url) { + if (!canAccessLocalStorage()) { + return null; + } + + url = normalizePath(url); + var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { @@ -1869,13 +2319,43 @@ return (function () { function saveCurrentPageToHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; - triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); - if(htmx.config.historyEnabled) history.replaceState({htmx:true}, getDocument().title, window.location.href); - saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); + + // Allow history snapshot feature to be disabled where hx-history="false" + // is present *anywhere* in the current document we're about to save, + // so we can prevent privileged data entering the cache. + // The page will still be reachable as a history entry, but htmx will fetch it + // live from the server onpopstate rather than look in the localStorage cache + var disableHistoryCache + try { + disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') + } catch (e) { + // IE11: insensitive modifier not supported so fallback to case sensitive selector + disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') + } + if (!disableHistoryCache) { + triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt}); + saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); + } + + if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href); } function pushUrlIntoHistory(path) { - if(htmx.config.historyEnabled) history.pushState({htmx:true}, "", path); + // remove the cache buster parameter, if any + if (htmx.config.getCacheBusterParam) { + path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') + if (endsWith(path, '&') || endsWith(path, "?")) { + path = path.slice(0, -1); + } + } + if(htmx.config.historyEnabled) { + history.pushState({htmx:true}, "", path); + } + currentPathForHistory = path; + } + + function replaceUrlInHistory(path) { + if(htmx.config.historyEnabled) history.replaceState({htmx:true}, "", path); currentPathForHistory = path; } @@ -1890,7 +2370,9 @@ return (function () { var details = {path: path, xhr:request}; triggerEvent(getDocument().body, "htmx:historyCacheMiss", details); request.open('GET', path, true); + request.setRequestHeader("HX-Request", "true"); request.setRequestHeader("HX-History-Restore-Request", "true"); + request.setRequestHeader("HX-Current-URL", getDocument().location.href); request.onload = function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); @@ -1899,11 +2381,20 @@ return (function () { fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; var historyElement = getHistoryElement(); var settleInfo = makeSettleInfo(historyElement); + var title = findTitle(this.response); + if (title) { + var titleElt = find("title"); + if (titleElt) { + titleElt.innerHTML = title; + } else { + window.document.title = title; + } + } // @ts-ignore swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); + triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response}); } else { triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details); } @@ -1922,9 +2413,11 @@ return (function () { swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); document.title = cached.title; - window.scrollTo(0, cached.scroll); + setTimeout(function () { + window.scrollTo(0, cached.scroll); + }, 0); // next 'tick', so browser has time to render layout currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); + triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); } else { if (htmx.config.refreshOnHistoryMiss) { @@ -1936,31 +2429,46 @@ return (function () { } } - function shouldPush(elt) { - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - return (pushUrl && pushUrl !== "false") || - (getInternalData(elt).boosted && getInternalData(elt).pushURL); - } - - function getPushUrl(elt) { - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - return (pushUrl === "true" || pushUrl === "false") ? null : pushUrl; - } - function addRequestIndicatorClasses(elt) { var indicators = findAttributeTargets(elt, 'hx-indicator'); if (indicators == null) { indicators = [elt]; } forEach(indicators, function (ic) { + var internalData = getInternalData(ic); + internalData.requestCount = (internalData.requestCount || 0) + 1; ic.classList["add"].call(ic.classList, htmx.config.requestClass); }); return indicators; } - function removeRequestIndicatorClasses(indicators) { + function disableElements(elt) { + var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt'); + if (disabledElts == null) { + disabledElts = []; + } + forEach(disabledElts, function (disabledElement) { + var internalData = getInternalData(disabledElement); + internalData.requestCount = (internalData.requestCount || 0) + 1; + disabledElement.setAttribute("disabled", ""); + }); + return disabledElts; + } + + function removeRequestIndicators(indicators, disabled) { forEach(indicators, function (ic) { - ic.classList["remove"].call(ic.classList, htmx.config.requestClass); + var internalData = getInternalData(ic); + internalData.requestCount = (internalData.requestCount || 0) - 1; + if (internalData.requestCount === 0) { + ic.classList["remove"].call(ic.classList, htmx.config.requestClass); + } + }); + forEach(disabled, function (disabledElement) { + var internalData = getInternalData(disabledElement); + internalData.requestCount = (internalData.requestCount || 0) - 1; + if (internalData.requestCount === 0) { + disabledElement.removeAttribute('disabled'); + } }); } @@ -1979,7 +2487,7 @@ return (function () { } function shouldInclude(elt) { - if(elt.name === "" || elt.name == null || elt.disabled) { + if(elt.name === "" || elt.name == null || elt.disabled || closest(elt, "fieldset[disabled]")) { return false; } // ignore "submitter" types (see jQuery src/serialize.js) @@ -1992,6 +2500,29 @@ return (function () { return true; } + function addValueToValues(name, value, values) { + // This is a little ugly because both the current value of the named value in the form + // and the new value could be arrays, so we have to handle all four cases :/ + if (name != null && value != null) { + var current = values[name]; + if (current === undefined) { + values[name] = value; + } else if (Array.isArray(current)) { + if (Array.isArray(value)) { + values[name] = current.concat(value); + } else { + current.push(value); + } + } else { + if (Array.isArray(value)) { + values[name] = [current].concat(value); + } else { + values[name] = [current, value]; + } + } + } + } + function processInputValue(processed, values, errors, elt, validate) { if (elt == null || haveSeenNode(processed, elt)) { return; @@ -2001,35 +2532,14 @@ return (function () { if (shouldInclude(elt)) { var name = getRawAttribute(elt,"name"); var value = elt.value; - if (elt.multiple) { + if (elt.multiple && elt.tagName === "SELECT") { value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value }); } // include file inputs if (elt.files) { value = toArray(elt.files); } - // This is a little ugly because both the current value of the named value in the form - // and the new value could be arrays, so we have to handle all four cases :/ - if (name != null && value != null) { - var current = values[name]; - if(current) { - if (Array.isArray(current)) { - if (Array.isArray(value)) { - values[name] = current.concat(value); - } else { - current.push(value); - } - } else { - if (Array.isArray(value)) { - values[name] = [current].concat(value); - } else { - values[name] = [current, value]; - } - } - } else { - values[name] = value; - } - } + addValueToValues(name, value, values); if (validate) { validateElement(elt, errors); } @@ -2062,9 +2572,13 @@ return (function () { var formValues = {}; var errors = []; var internalData = getInternalData(elt); + if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { + internalData.lastButtonClicked = null + } // only validate when form is directly submitted and novalidate or formnovalidate are not set - var validate = matches(elt, 'form') && elt.noValidate !== true; + // or if the element has an explicit hx-validate="true" on it + var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true"; if (internalData.lastButtonClicked) { validate = validate && internalData.lastButtonClicked.formNoValidate !== true; } @@ -2078,11 +2592,11 @@ return (function () { processInputValue(processed, values, errors, elt, validate); // if a button or submit was clicked last, include its value - if (internalData.lastButtonClicked) { - var name = getRawAttribute(internalData.lastButtonClicked,"name"); - if (name) { - values[name] = internalData.lastButtonClicked.value; - } + if (internalData.lastButtonClicked || elt.tagName === "BUTTON" || + (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) { + var button = internalData.lastButtonClicked || elt + var name = getRawAttribute(button, "name") + addValueToValues(name, button.value, formValues) } // include any explicit includes @@ -2228,40 +2742,43 @@ return (function () { "swapDelay" : htmx.config.defaultSwapDelay, "settleDelay" : htmx.config.defaultSettleDelay } - if (getInternalData(elt).boosted && !isAnchorLink(elt)) { + if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { swapSpec["show"] = "top" } 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)); - } - if (modifier.indexOf("scroll:") === 0) { - var scrollSpec = modifier.substr(7); + for (var i = 0; i < split.length; i++) { + var value = split[i]; + if (value.indexOf("swap:") === 0) { + swapSpec["swapDelay"] = parseInterval(value.substr(5)); + } else if (value.indexOf("settle:") === 0) { + swapSpec["settleDelay"] = parseInterval(value.substr(7)); + } else if (value.indexOf("transition:") === 0) { + swapSpec["transition"] = value.substr(11) === "true"; + } else if (value.indexOf("ignoreTitle:") === 0) { + swapSpec["ignoreTitle"] = value.substr(12) === "true"; + } else if (value.indexOf("scroll:") === 0) { + var scrollSpec = value.substr(7); var splitSpec = scrollSpec.split(":"); var scrollVal = splitSpec.pop(); var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; swapSpec["scroll"] = scrollVal; swapSpec["scrollTarget"] = selectorVal; - } - if (modifier.indexOf("show:") === 0) { - var showSpec = modifier.substr(5); + } else if (value.indexOf("show:") === 0) { + var showSpec = value.substr(5); var splitSpec = showSpec.split(":"); var showVal = splitSpec.pop(); var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; swapSpec["show"] = showVal; swapSpec["showTarget"] = selectorVal; - } - if (modifier.indexOf("focus-scroll:") === 0) { - var focusScrollVal = modifier.substr("focus-scroll:".length); + } else if (value.indexOf("focus-scroll:") === 0) { + var focusScrollVal = value.substr("focus-scroll:".length); swapSpec["focusScroll"] = focusScrollVal == "true"; + } else if (i == 0) { + swapSpec["swapStyle"] = value; + } else { + logError('Unknown modifier in hx-swap: ' + value); } } } @@ -2269,6 +2786,11 @@ return (function () { return swapSpec; } + function usesFormData(elt) { + return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || + (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data"); + } + function encodeParamsForBody(xhr, elt, filteredParameters) { var encodedParameters = null; withExtensions(elt, function (extension) { @@ -2279,8 +2801,7 @@ return (function () { if (encodedParameters != null) { return encodedParameters; } else { - if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || - (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) { + if (usesFormData(elt)) { return makeFormData(filteredParameters); } else { return urlEncode(filteredParameters); @@ -2352,6 +2873,9 @@ return (function () { if (attributeValue) { var str = attributeValue.trim(); var evaluateValue = evalAsDefault; + if (str === "unset") { + return null; + } if (str.indexOf("javascript:") === 0) { str = str.substr(11); evaluateValue = true; @@ -2426,7 +2950,7 @@ return (function () { } } - function getResponseURL(xhr) { + function getPathFromResponse(xhr) { // NB: IE11 does not support this stuff if (xhr.responseURL && typeof(URL) !== "undefined") { try { @@ -2439,7 +2963,7 @@ return (function () { } function hasHeader(xhr, regexp) { - return xhr.getAllResponseHeaders().match(regexp); + return regexp.test(xhr.getAllResponseHeaders()) } function ajaxHelper(verb, path, context) { @@ -2458,6 +2982,7 @@ return (function () { values : context.values, targetOverride: resolveTarget(context.target), swapOverride: context.swap, + select: context.select, returnPromise: true }); } @@ -2477,7 +3002,28 @@ return (function () { return arr; } - function issueAjaxRequest(verb, path, elt, event, etc) { + function verifyPath(elt, path, requestConfig) { + var sameHost + var url + if (typeof URL === "function") { + url = new URL(path, document.location.href); + var origin = document.location.origin; + sameHost = origin === url.origin; + } else { + // IE11 doesn't support URL + url = path + sameHost = startsWith(path, document.location.origin) + } + + if (htmx.config.selfRequestsOnly) { + if (!sameHost) { + return false; + } + } + return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig)); + } + + function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { var resolve = null; var reject = null; etc = etc != null ? etc : {}; @@ -2491,18 +3037,52 @@ return (function () { elt = getDocument().body; } var responseHandler = etc.handler || handleAjaxResponse; + var select = etc.select || null; if (!bodyContains(elt)) { - return; // do not issue requests for elements removed from the DOM + // do not issue requests for elements removed from the DOM + maybeCall(resolve); + return promise; } var target = etc.targetOverride || getTarget(elt); if (target == null || target == DUMMY_ELT) { triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); - return; + maybeCall(reject); + return promise; } - var syncElt = elt; var eltData = getInternalData(elt); + var submitter = eltData.lastButtonClicked; + + if (submitter) { + var buttonPath = getRawAttribute(submitter, "formaction"); + if (buttonPath != null) { + path = buttonPath; + } + + var buttonVerb = getRawAttribute(submitter, "formmethod") + if (buttonVerb != null) { + // ignore buttons with formmethod="dialog" + if (buttonVerb.toLowerCase() !== "dialog") { + verb = buttonVerb; + } + } + } + + var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); + // allow event-based confirmation w/ a callback + if (confirmed === undefined) { + var issueRequest = function(skipConfirmation) { + return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation); + } + var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion}; + if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { + maybeCall(resolve); + return promise; + } + } + + var syncElt = elt; var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); var queueStrategy = null; var abortable = false; @@ -2518,10 +3098,12 @@ return (function () { syncStrategy = (syncStrings[1] || 'drop').trim(); eltData = getInternalData(syncElt); if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { - return; + maybeCall(resolve); + return promise; } else if (syncStrategy === "abort") { if (eltData.xhr) { - return; + maybeCall(resolve); + return promise; } else { abortable = true; } @@ -2565,7 +3147,8 @@ return (function () { issueAjaxRequest(verb, path, elt, event, etc) }); } - return; + maybeCall(resolve); + return promise; } } @@ -2593,8 +3176,7 @@ return (function () { } } - var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); - if (confirmQuestion) { + if (confirmQuestion && !confirmed) { if(!confirm(confirmQuestion)) { maybeCall(resolve); endRequestLock() @@ -2604,6 +3186,11 @@ return (function () { var headers = getHeaders(elt, target, promptResponse); + + if (verb !== 'get' && !usesFormData(elt)) { + headers['Content-Type'] = 'application/x-www-form-urlencoded'; + } + if (etc.headers) { headers = mergeObjects(headers, etc.headers); } @@ -2617,8 +3204,8 @@ return (function () { var allParameters = mergeObjects(rawParameters, expressionVars); var filteredParameters = filterValues(allParameters, elt); - if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null) { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; + if (htmx.config.getCacheBusterParam && verb === 'get') { + filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true"; } // behavior of anchors w/ empty href is to use the current URL @@ -2626,9 +3213,16 @@ return (function () { path = getDocument().location.href; } + var requestAttrValues = getValuesForElement(elt, 'hx-request'); + var eltIsBoosted = getInternalData(elt).boosted; + + var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + var requestConfig = { + boosted: eltIsBoosted, + useUrlParams: useUrlParams, parameters: filteredParameters, unfilteredParameters: allParameters, headers:headers, @@ -2653,6 +3247,7 @@ return (function () { headers = requestConfig.headers; filteredParameters = requestConfig.parameters; errors = requestConfig.errors; + useUrlParams = requestConfig.useUrlParams; if(errors && errors.length > 0){ triggerEvent(elt, 'htmx:validation:halted', requestConfig) @@ -2664,25 +3259,31 @@ return (function () { var splitPath = path.split("#"); var pathNoAnchor = splitPath[0]; var anchor = splitPath[1]; - if (verb === 'get') { - var finalPathForGet = pathNoAnchor; + + var finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor; var values = Object.keys(filteredParameters).length !== 0; if (values) { - if (finalPathForGet.indexOf("?") < 0) { - finalPathForGet += "?"; + if (finalPath.indexOf("?") < 0) { + finalPath += "?"; } else { - finalPathForGet += "&"; + finalPath += "&"; } - finalPathForGet += urlEncode(filteredParameters); + finalPath += urlEncode(filteredParameters); if (anchor) { - finalPathForGet += "#" + anchor; + finalPath += "#" + anchor; } } - xhr.open('GET', finalPathForGet, true); - } else { - xhr.open(verb.toUpperCase(), path, true); } + if (!verifyPath(elt, finalPath, requestConfig)) { + triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) + maybeCall(reject); + return promise; + }; + + xhr.open(verb.toUpperCase(), finalPath, true); xhr.overrideMimeType("text/html"); xhr.withCredentials = requestConfig.withCredentials; xhr.timeout = requestConfig.timeout; @@ -2699,19 +3300,24 @@ return (function () { } } - var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, etc:etc, pathInfo:{ - path:path, finalPath:finalPathForGet, anchor:anchor + var responseInfo = { + xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select, + pathInfo: { + requestPath: path, + finalRequestPath: finalPath, + anchor: anchor } }; xhr.onload = function () { try { var hierarchy = hierarchyForElt(elt); + responseInfo.pathInfo.responsePath = getPathFromResponse(xhr); responseHandler(elt, responseInfo); - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerEvent(elt, 'htmx:afterRequest', responseInfo); triggerEvent(elt, 'htmx:afterOnLoad', responseInfo); - // if the body no longer contains the element, trigger the even on the closest parent + // if the body no longer contains the element, trigger the event on the closest parent // remaining in the DOM if (!bodyContains(elt)) { var secondaryTriggerElt = null; @@ -2734,21 +3340,21 @@ return (function () { } } xhr.onerror = function () { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:sendError', responseInfo); maybeCall(reject); endRequestLock(); } xhr.onabort = function() { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo); maybeCall(reject); endRequestLock(); } xhr.ontimeout = function() { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:timeout', responseInfo); maybeCall(reject); @@ -2760,6 +3366,7 @@ return (function () { return promise } var indicators = addRequestIndicatorClasses(elt); + var disableElts = disableElements(elt); forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { forEach([xhr, xhr.upload], function (target) { @@ -2773,14 +3380,99 @@ return (function () { }); }); triggerEvent(elt, 'htmx:beforeSend', responseInfo); - xhr.send(verb === 'get' ? null : encodeParamsForBody(xhr, elt, filteredParameters)); + var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) + xhr.send(params); return promise; } + function determineHistoryUpdates(elt, responseInfo) { + + var xhr = responseInfo.xhr; + + //=========================================== + // First consult response headers + //=========================================== + var pathFromHeaders = null; + var typeFromHeaders = null; + if (hasHeader(xhr,/HX-Push:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Push"); + typeFromHeaders = "push"; + } else if (hasHeader(xhr,/HX-Push-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Push-Url"); + typeFromHeaders = "push"; + } else if (hasHeader(xhr,/HX-Replace-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url"); + typeFromHeaders = "replace"; + } + + // if there was a response header, that has priority + if (pathFromHeaders) { + if (pathFromHeaders === "false") { + return {} + } else { + return { + type: typeFromHeaders, + path : pathFromHeaders + } + } + } + + //=========================================== + // Next resolve via DOM values + //=========================================== + var requestPath = responseInfo.pathInfo.finalRequestPath; + var responsePath = responseInfo.pathInfo.responsePath; + + var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); + var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url"); + var elementIsBoosted = getInternalData(elt).boosted; + + var saveType = null; + var path = null; + + if (pushUrl) { + saveType = "push"; + path = pushUrl; + } else if (replaceUrl) { + saveType = "replace"; + path = replaceUrl; + } else if (elementIsBoosted) { + saveType = "push"; + path = responsePath || requestPath; // if there is no response path, go with the original request path + } + + if (path) { + // false indicates no push, return empty object + if (path === "false") { + return {}; + } + + // true indicates we want to follow wherever the server ended up sending us + if (path === "true") { + path = responsePath || requestPath; // if there is no response path, go with the original request path + } + + // restore any anchor associated with the request + if (responseInfo.pathInfo.anchor && + path.indexOf("#") === -1) { + path = path + "#" + responseInfo.pathInfo.anchor; + } + + return { + type:saveType, + path: path + } + } else { + return {}; + } + } + function handleAjaxResponse(elt, responseInfo) { var xhr = responseInfo.xhr; var target = responseInfo.target; var etc = responseInfo.etc; + var requestConfig = responseInfo.requestConfig; + var select = responseInfo.select; if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; @@ -2788,33 +3480,44 @@ return (function () { handleTrigger(xhr, "HX-Trigger", elt); } - if (hasHeader(xhr,/HX-Push:/i)) { - var pushedUrl = xhr.getResponseHeader("HX-Push"); + if (hasHeader(xhr, /HX-Location:/i)) { + saveCurrentPageToHistory(); + var redirectPath = xhr.getResponseHeader("HX-Location"); + var swapSpec; + if (redirectPath.indexOf("{") === 0) { + swapSpec = parseJSON(redirectPath); + // what's the best way to throw an error if the user didn't include this + redirectPath = swapSpec['path']; + delete swapSpec['path']; + } + ajaxHelper('GET', redirectPath, swapSpec).then(function(){ + pushUrlIntoHistory(redirectPath); + }); + return; } + var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh"); + if (hasHeader(xhr, /HX-Redirect:/i)) { - window.location.href = xhr.getResponseHeader("HX-Redirect"); + location.href = xhr.getResponseHeader("HX-Redirect"); + shouldRefresh && location.reload(); return; } - if (hasHeader(xhr,/HX-Refresh:/i)) { - if ("true" === xhr.getResponseHeader("HX-Refresh")) { - location.reload(); - return; - } + if (shouldRefresh) { + location.reload(); + return; } if (hasHeader(xhr,/HX-Retarget:/i)) { - responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget")); + if (xhr.getResponseHeader("HX-Retarget") === "this") { + responseInfo.target = elt; + } else { + responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget")); + } } - /** @type {boolean} */ - var shouldSaveHistory - if (pushedUrl == "false") { - shouldSaveHistory = false - } else { - shouldSaveHistory = shouldPush(elt) || pushedUrl; - } + var historyUpdate = determineHistoryUpdates(elt, responseInfo); // by default htmx only swaps on 200 return codes and does not swap // on 204 'No Content' @@ -2823,15 +3526,18 @@ return (function () { var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; var serverResponse = xhr.response; var isError = xhr.status >= 400; - var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo); + var ignoreTitle = htmx.config.ignoreTitle + var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo); if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; target = beforeSwapDetails.target; // allow re-targeting serverResponse = beforeSwapDetails.serverResponse; // allow updating content isError = beforeSwapDetails.isError; // allow updating error - + ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title + + responseInfo.target = target; // Make updated target available to response events responseInfo.failed = isError; // Make failed property available to response events - responseInfo.successful = !isError; // Make successful property available to response events + responseInfo.successful = !isError; // Make successful property available to response events if (beforeSwapDetails.shouldSwap) { if (xhr.status === 286) { @@ -2842,18 +3548,29 @@ return (function () { serverResponse = extension.transformResponse(serverResponse, xhr, elt); }); - // Save current page - if (shouldSaveHistory) { + // Save current page if there will be a history update + if (historyUpdate.type) { saveCurrentPageToHistory(); } var swapOverride = etc.swapOverride; + if (hasHeader(xhr,/HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader("HX-Reswap"); + } var swapSpec = getSwapSpecification(elt, swapOverride); + if (swapSpec.hasOwnProperty('ignoreTitle')) { + ignoreTitle = swapSpec.ignoreTitle; + } + target.classList.add(htmx.config.swappingClass); + + // optional transition API promise callbacks + var settleResolve = null; + var settleReject = null; + var doSwap = function () { try { - var activeElt = document.activeElement; var selectionInfo = {}; try { @@ -2868,19 +3585,44 @@ return (function () { // safari issue - see https://github.com/microsoft/playwright/issues/5894 } + var selectOverride; + if (select) { + selectOverride = select; + } + + if (hasHeader(xhr, /HX-Reselect:/i)) { + selectOverride = xhr.getResponseHeader("HX-Reselect"); + } + + // if we need to save history, do so, before swapping so that relative resources have the correct base URL + if (historyUpdate.type) { + triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)); + if (historyUpdate.type === "push") { + pushUrlIntoHistory(historyUpdate.path); + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path}); + } else { + replaceUrlInHistory(historyUpdate.path); + triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path}); + } + } + var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride); if (selectionInfo.elt && !bodyContains(selectionInfo.elt) && - selectionInfo.elt.id) { - var newActiveElt = document.getElementById(selectionInfo.elt.id); + getRawAttribute(selectionInfo.elt, "id")) { + var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id")); var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; if (newActiveElt) { // @ts-ignore if (selectionInfo.start && newActiveElt.setSelectionRange) { // @ts-ignore - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + try { + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + } catch (e) { + // the setSelectionRange method is present on fields that don't support it, so just let this fail + } } newActiveElt.focus(focusOptions); } @@ -2893,9 +3635,6 @@ return (function () { } triggerEvent(elt, 'htmx:afterSwap', responseInfo); }); - if (responseInfo.pathInfo.anchor) { - location.hash = responseInfo.pathInfo.anchor; - } if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { var finalElt = elt; @@ -2915,14 +3654,15 @@ return (function () { } triggerEvent(elt, 'htmx:afterSettle', responseInfo); }); - // push URL and save new page - if (shouldSaveHistory) { - var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; - pushUrlIntoHistory(pathToPush); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: pathToPush}); + + if (responseInfo.pathInfo.anchor) { + var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor); + if(anchorTarget) { + anchorTarget.scrollIntoView({block:'start', behavior: "auto"}); + } } - if(settleInfo.title) { + if(settleInfo.title && !ignoreTitle) { var titleElt = find("title"); if(titleElt) { titleElt.innerHTML = settleInfo.title; @@ -2940,6 +3680,7 @@ return (function () { } handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); } + maybeCall(settleResolve); } if (swapSpec.settleDelay > 0) { @@ -2949,10 +3690,34 @@ return (function () { } } catch (e) { triggerErrorEvent(elt, 'htmx:swapError', responseInfo); + maybeCall(settleReject); throw e; } }; + var shouldTransition = htmx.config.globalViewTransitions + if(swapSpec.hasOwnProperty('transition')){ + shouldTransition = swapSpec.transition; + } + + if(shouldTransition && + triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && + typeof Promise !== "undefined" && document.startViewTransition){ + var settlePromise = new Promise(function (_resolve, _reject) { + settleResolve = _resolve; + settleReject = _reject; + }); + // wrap the original doSwap() in a call to startViewTransition() + var innerDoSwap = doSwap; + doSwap = function() { + document.startViewTransition(function () { + innerDoSwap(); + return settlePromise; + }); + } + } + + if (swapSpec.swapDelay > 0) { setTimeout(doSwap, swapSpec.swapDelay) } else { @@ -2960,7 +3725,7 @@ return (function () { } } if (isError) { - triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.path}, responseInfo)); + triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo)); } } @@ -3048,9 +3813,22 @@ return (function () { //==================================================================== // Initialization //==================================================================== + var isReady = false + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true + }) + /** + * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. + * + * This function uses isReady because there is no realiable way to ask the browswer whether + * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded + * firing and readystate=complete. + */ function ready(fn) { - if (getDocument().readyState !== 'loading') { + // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by + // some means other than the initial page load. + if (isReady || getDocument().readyState === 'complete') { fn(); } else { getDocument().addEventListener('DOMContentLoaded', fn); @@ -3061,9 +3839,9 @@ return (function () { if (htmx.config.includeIndicatorStyles !== false) { getDocument().head.insertAdjacentHTML("beforeend", "<style>\ - ." + htmx.config.indicatorClass + "{opacity:0;transition: opacity 200ms ease-in;}\ - ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1}\ - ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1}\ + ." + htmx.config.indicatorClass + "{opacity:0}\ + ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ + ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ </style>"); } } @@ -3101,6 +3879,9 @@ return (function () { internalData.xhr.abort(); } }); + /** @type {(ev: PopStateEvent) => any} */ + const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null; + /** @type {(ev: PopStateEvent) => any} */ window.onpopstate = function (event) { if (event.state && event.state.htmx) { restoreHistory(); @@ -3110,10 +3891,15 @@ return (function () { 'triggerEvent': triggerEvent }); }); + } else { + if (originalPopstate) { + originalPopstate(event); + } } }; setTimeout(function () { triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event + body = null; // kill reference for gc }, 0); }) diff --git a/code/ch5_partials/ch5_final_video_collector/static/js/htmx.min.js b/code/ch5_partials/ch5_final_video_collector/static/js/htmx.min.js index 998414c..53bbdf6 100644 --- a/code/ch5_partials/ch5_final_video_collector/static/js/htmx.min.js +++ b/code/ch5_partials/ch5_final_video_collector/static/js/htmx.min.js @@ -1 +1,4 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(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 l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=k(e);e.classList.toggle(t)}function T(e,t){e=k(e);W(e.parentElement.children,function(e){q(e,t)});L(e,t)}function H(e,t){e=k(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function N(e,t){if(t.indexOf("closest ")===0){return[H(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[C(e,t.substr(5))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return z().querySelectorAll(t)}}function ee(e,t){if(t){return N(e,t)[0]}else{return N(z().body,e)[0]}}function k(e){if(p(e,"String")){return C(e)}else{return e}}function I(e,t,r){if(m(t)){return{target:z().body,event:e,listener:t}}else{return{target:k(e),event:t,listener:r}}}function M(t,r,n){lr(function(){var e=I(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function D(t,r,n){lr(function(){var e=I(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var te=z().createElement("output");function F(e,t){var r=G(e,t);if(r){if(r==="this"){return[re(e,t)]}else{var n=N(e,r);if(n.length===0){pt('The selector "'+r+'" on '+t+" returned no matches!");return[te]}else{return n}}}}function re(e,t){return h(e,function(e){return V(e,t)!=null})}function ne(e){var t=G(e,"hx-target");if(t){if(t==="this"){return re(e,"hx-target")}else{return ee(e,t)}}else{var r=_(e);if(r.boosted){return z().body}else{return e}}}function P(e){var t=U.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function X(t,r){W(t.attributes,function(e){if(!r.hasAttribute(e.name)&&P(e.name)){t.removeAttribute(e.name)}});W(r.attributes,function(e){if(P(e.name)){t.setAttribute(e.name,e.value)}})}function j(e,t){var r=sr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){pt(e)}}return e==="outerHTML"}function B(e,i,o){var t="#"+i.id;var a="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){a=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{a=e}var r=z().querySelectorAll(t);if(r){W(r,function(e){var t;var r=i.cloneNode(true);t=z().createDocumentFragment();t.appendChild(r);if(!j(a,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ye(a,e,e,t,o)}W(o.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(z().body,"htmx:oobErrorNoTarget",{content:i})}return e}function ie(e,r){W(R(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=V(e,"hx-swap-oob");if(t!=null){B(t,e,r)}})}function oe(e){W(R(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=V(e,"id");var r=z().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function ae(n,e,i){W(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();X(e,t);i.tasks.push(function(){X(e,r)})}}})}function se(e){return function(){q(e,U.config.addedClass);ct(e);at(e);le(e);$(e,"htmx:load")}}function le(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ue(e,t,r,n){ae(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(se(i))}}}function fe(t){var e=_(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){W(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){W(t.children,function(e){fe(e)})}}function ce(e,t,r){if(e.tagName==="BODY"){return me(e,t,r)}else{var n;var i=e.previousSibling;ue(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}_(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}fe(e);u(e).removeChild(e)}}function he(e,t,r){return ue(e,e.firstChild,t,r)}function de(e,t,r){return ue(u(e),e,t,r)}function ve(e,t,r){return ue(e,null,t,r)}function ge(e,t,r){return ue(u(e),e.nextSibling,t,r)}function pe(e,t,r){fe(e);return u(e).removeChild(e)}function me(e,t,r){var n=e.firstChild;ue(e,n,t,r);if(n){while(n.nextSibling){fe(n.nextSibling);e.removeChild(n.nextSibling)}fe(n);e.removeChild(n)}}function xe(e,t){var r=G(e,"hx-select");if(r){var n=z().createDocumentFragment();W(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function ye(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":ce(r,n,i);return;case"afterbegin":he(r,n,i);return;case"beforebegin":de(r,n,i);return;case"beforeend":ve(r,n,i);return;case"afterend":ge(r,n,i);return;case"delete":pe(r,n,i);return;default:var o=sr(t);for(var a=0;a<o.length;a++){var f=o[a];try{var s=f.handleSwap(e,r,n,i);if(s){if(typeof s.length!=="undefined"){for(var l=0;l<s.length;l++){var u=s[l];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){i.tasks.push(se(u))}}}return}}catch(e){pt(e)}}if(e==="innerHTML"){me(r,n,i)}else{ye(U.config.defaultSwapStyle,t,r,n,i)}}}function be(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function we(e,t,r,n,i){i.title=be(n);var o=g(n);if(o){ie(o,i);o=xe(r,o);oe(o);return ye(e,r,t,o,i)}}function Se(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!x(a)){a={value:a}}$(r,o,a)}}}else{$(r,n,[])}}var Ee=/\s/;var Ce=/[\s,]/;var Re=/[_$a-zA-Z]/;var Oe=/[_$a-zA-Z0-9]/;var Le=['"',"'","/"];var qe=/[^\s]/;function Ae(e){var t=[];var r=0;while(r<e.length){if(Re.exec(e.charAt(r))){var n=r;while(Oe.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Le.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function Te(e,t,r){return Re.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function He(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Jt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(z().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(Te(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var Ne="input, textarea, select";function ke(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=Ae(t);do{c(n,qe);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var o={trigger:"every"};c(n,qe);o.pollInterval=v(c(n,/[,\[\s]/));c(n,qe);var a=He(e,n,"event");if(a){o.eventFilter=a}r.push(o)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var a=He(e,n,"event");if(a){s.eventFilter=a}while(n.length>0&&n[0]!==","){c(n,qe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Ce))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Ce);if(u==="closest"||u==="find"){n.shift();u+=" "+c(n,Ce)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Ce)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Ce))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Ce)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Ce)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,qe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,Ne)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ie(e){_(e).cancelled=true}function Me(e,t,r,n){var i=_(e);i.timeout=setTimeout(function(){if(Y(e)&&i.cancelled!==true){if(!je(n,dt("hx:poll:trigger",{triggerSpec:n,target:e}))){Z(t,r,e)}Me(e,t,V(e,"hx-"+t),n)}},n.pollInterval)}function De(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&De(t)&&t.target===""||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href");r.pushURL=true}else{var o=f(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=f(t,"action")}e.forEach(function(e){Be(t,n,i,r,e,true)})}}function Pe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&H(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Xe(e,t){return _(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function je(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(z().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Be(o,a,s,e,l,u){var t;if(l.from){t=N(o,l.from)}else{t=[o]}W(t,function(n){var i=function(e){if(!Y(o)){n.removeEventListener(l.trigger,i);return}if(Xe(o,e)){return}if(u||Pe(e,o)){e.preventDefault()}if(je(l,e)){return}var t=_(e);t.triggerSpec=l;if(t.handledFor==null){t.handledFor=[]}var r=_(o);if(t.handledFor.indexOf(o)<0){t.handledFor.push(o);if(l.consume){e.stopPropagation()}if(l.target&&e.target){if(!d(e.target,l.target)){return}}if(l.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(l.changed){if(r.lastValue===o.value){return}else{r.lastValue=o.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(l.throttle){if(!r.throttle){Z(a,s,o,e);r.throttle=setTimeout(function(){r.throttle=null},l.throttle)}}else if(l.delay){r.delayed=setTimeout(function(){Z(a,s,o,e)},l.delay)}else{Z(a,s,o,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:l.trigger,listener:i,on:n});n.addEventListener(l.trigger,i)})}var Ue=false;var Ve=null;function ze(){if(!Ve){Ve=function(){Ue=true};window.addEventListener("scroll",Ve);setInterval(function(){if(Ue){Ue=false;W(z().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){_e(e)})}},200)}}function _e(e){if(!s(e,"data-hx-revealed")&&b(e)){e.setAttribute("data-hx-revealed","true");var t=_(e);if(t.initialized){Z(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Z(t.verb,t.path,e)},{once:true})}}}function We(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Je(e,o[1],0)}if(o[0]==="send"){Ze(e)}}}function Je(s,r,n){if(!Y(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=U.createWebSocket(r);t.onerror=function(e){J(s,"htmx:wsError",{error:e,socket:t});$e(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=Ge(n);setTimeout(function(){Je(s,r,n+1)},t)}};t.onopen=function(e){n=0};_(s).webSocket=t;t.addEventListener("message",function(e){if($e(s)){return}var t=e.data;gt(s,function(e){t=e.transformResponse(t,null,s)});var r=zt(s);var n=g(t);var i=y(n.children);for(var o=0;o<i.length;o++){var a=i[o];B(V(a,"hx-swap-oob")||"true",a,r)}Ct(r.tasks)})}function $e(e){if(!Y(e)){_(e).webSocket.close();return true}}function Ze(u){var f=h(u,function(e){return _(e).webSocket!=null});if(f){u.addEventListener(ke(u)[0].trigger,function(e){var t=_(f).webSocket;var r=Xt(u,f);var n=Mt(u,"post");var i=n.errors;var o=n.values;var a=Gt(u);var s=Q(o,a);var l=jt(s,u);l["HEADERS"]=r;if(i&&i.length>0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Pe(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ge(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}pt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ke(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Ye(e,o[1])}if(o[0]==="swap"){Qe(e,o[1])}}}function Ye(t,e){var r=U.createEventSource(e);r.onerror=function(e){J(t,"htmx:sseError",{error:e,source:r});tt(t)};_(t).sseEventSource=r}function Qe(o,a){var s=h(o,rt);if(s){var l=_(s).sseEventSource;var u=function(e){if(tt(s)){l.removeEventListener(a,u);return}var t=e.data;gt(o,function(e){t=e.transformResponse(t,null,o)});var r=Ut(o);var n=ne(o);var i=zt(o);we(r.swapStyle,o,n,t,i);Ct(i.tasks);$(o,"htmx:sseMessage",e)};_(o).sseListener=u;l.addEventListener(a,u)}else{J(o,"htmx:noSSESourceError")}}function et(e,t,r,n){var i=h(e,rt);if(i){var o=_(i).sseEventSource;var a=function(){if(!tt(i)){if(Y(e)){Z(t,r,e)}else{o.removeEventListener(n,a)}}};_(e).sseListener=a;o.addEventListener(n,a)}else{J(e,"htmx:noSSESourceError")}}function tt(e){if(!Y(e)){_(e).sseEventSource.close();return true}}function rt(e){return _(e).sseEventSource!=null}function nt(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Z(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function it(o,a,e){var t=false;W(n,function(n){if(s(o,"hx-"+n)){var i=V(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){et(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){ze();_e(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=ee(o,e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){$(o,"intersect");break}}},t);r.observe(o);Be(o,n,i,a,e)}else if(e.trigger==="load"){nt(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Me(o,n,i,e)}else{Be(o,n,i,a,e)}})}});return t}function ot(e){if(e.type==="text/javascript"||e.type==="module"||e.type===""){var t=z().createElement("script");W(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(U.config.inlineScriptNonce){t.nonce=U.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){pt(e)}finally{r.removeChild(e)}}}function at(e){if(d(e,"script")){ot(e)}W(R(e,"script"),function(e){ot(e)})}function st(){return document.querySelector("[hx-boost], [data-hx-boost]")}function lt(e){if(e.querySelectorAll){var t=st()?", a, form":"";var r=e.querySelectorAll(i+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [hx-data-ext]");return r}else{return[]}}function ut(r){var e=function(e){if(d(e.target,"button, input[type='submit']")){var t=_(r);t.lastButtonClicked=e.target}};r.addEventListener("click",e);r.addEventListener("focusin",e);r.addEventListener("focusout",function(e){var t=_(r);t.lastButtonClicked=null})}function ft(e){if(e.closest&&e.closest(U.config.disableSelector)){return}var t=_(e);if(!t.initialized){t.initialized=true;$(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=ke(e);var n=it(e,t,r);if(!n&&G(e,"hx-boost")==="true"){Fe(e,t,r)}if(e.tagName==="FORM"){ut(e)}var i=V(e,"hx-sse");if(i){Ke(e,t,i)}var o=V(e,"hx-ws");if(o){We(e,t,o)}$(e,"htmx:afterProcessNode")}}function ct(e){e=k(e);ft(e);W(lt(e),function(e){ft(e)})}function ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function dt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=z().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function J(e,t,r){$(e,t,Q({error:t},r))}function vt(e){return e==="htmx:afterProcessNode"}function gt(e,t){W(sr(e),function(e){try{t(e)}catch(e){pt(e)}})}function pt(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function $(e,t,r){e=k(e);if(r==null){r={}}r["elt"]=e;var n=dt(t,r);if(U.logger&&!vt(t)){U.logger(e,t,r)}if(r.error){pt(r.error);$(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=ht(t);if(i&&o!==t){var a=dt(o,n.detail);i=i&&e.dispatchEvent(a)}gt(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var mt=location.pathname+location.search;function xt(){var e=z().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||z().body}function yt(e,t,r,n){var i=S(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>U.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(z().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function bt(e){var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function wt(e){var t=U.config.requestClass;var r=e.cloneNode(true);W(R(r,"."+t),function(e){q(e,t)});return r.innerHTML}function St(){var e=xt();var t=mt||location.pathname+location.search;$(z().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(U.config.historyEnabled)history.replaceState({htmx:true},z().title,window.location.href);yt(t,wt(e),z().title,window.scrollY)}function Et(e){if(U.config.historyEnabled)history.pushState({htmx:true},"",e);mt=e}function Ct(e){W(e,function(e){e.call()})}function Rt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};$(z().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){$(z().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=xt();var r=zt(t);me(t,e,r);Ct(r.tasks);mt=n;$(z().body,"htmx:historyRestore",{path:n})}else{J(z().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Ot(e){St();e=e||location.pathname+location.search;var t=bt(e);if(t){var r=g(t.content);var n=xt();var i=zt(n);me(n,r,i);Ct(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);mt=e;$(z().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Rt(e)}}}function Lt(e){var t=G(e,"hx-push-url");return t&&t!=="false"||_(e).boosted&&_(e).pushURL}function qt(e){var t=G(e,"hx-push-url");return t==="true"||t==="false"?null:t}function At(e){var t=F(e,"hx-indicator");if(t==null){t=[e]}W(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Tt(e){W(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function Ht(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Nt(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 kt(t,r,n,e,i){if(e==null||Ht(t,e)){return}else{t.push(e)}if(Nt(e)){var o=f(e,"name");var a=e.value;if(e.multiple){a=y(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=y(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){It(e,n)}}if(d(e,"form")){var l=e.elements;W(l,function(e){kt(t,r,n,e,i)})}}function It(e,t){if(e.willValidate){$(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});$(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Mt(e,t){var r=[];var n={};var i={};var o=[];var a=_(e);var s=d(e,"form")&&e.noValidate!==true;if(a.lastButtonClicked){s=s&&a.lastButtonClicked.formNoValidate!==true}if(t!=="get"){kt(r,i,o,H(e,"form"),s)}kt(r,n,o,e,s);if(a.lastButtonClicked){var l=f(a.lastButtonClicked,"name");if(l){n[l]=a.lastButtonClicked.value}}var u=F(e,"hx-include");W(u,function(e){kt(r,n,o,e,s);if(!d(e,"form")){W(e.querySelectorAll(Ne),function(e){kt(r,n,o,e,s)})}});n=Q(n,i);return{errors:o,values:n}}function Dt(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function Ft(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=Dt(t,r,e)})}else{t=Dt(t,r,n)}}}return t}function Pt(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){W(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Xt(e,t,r){var n={"HX-Request":"true","HX-Trigger":f(e,"id"),"HX-Trigger-Name":f(e,"name"),"HX-Target":V(t,"id"),"HX-Current-URL":z().location.href};Wt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(_(e).boosted){n["HX-Boosted"]="true"}return n}function jt(t,e){var r=G(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){W(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};W(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Bt(e){return f(e,"href")&&f(e,"href").indexOf("#")>=0}function Ut(e,t){var r=t?t:G(e,"hx-swap");var n={swapStyle:_(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(_(e).boosted&&!Bt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var o=1;o<i.length;o++){var a=i[o];if(a.indexOf("swap:")===0){n["swapDelay"]=v(a.substr(5))}if(a.indexOf("settle:")===0){n["settleDelay"]=v(a.substr(7))}if(a.indexOf("scroll:")===0){var s=a.substr(7);var l=s.split(":");var f=l.pop();var u=l.length>0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(a.indexOf("show:")===0){var c=a.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(a.indexOf("focus-scroll:")===0){var d=a.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function Vt(t,r,n){var i=null;gt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(G(r,"hx-encoding")==="multipart/form-data"||d(r,"form")&&f(r,"enctype")==="multipart/form-data"){return Pt(n)}else{return Ft(n)}}}function zt(e){return{tasks:[],elts:[e]}}function _t(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ee(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var o=t.showTarget;if(t.showTarget==="window"){o="body"}i=ee(r,o)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function Wt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}else if(o.indexOf("js:")===0){o=o.substr(3);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Jt(e,function(){return Function("return ("+o+")")()},{})}else{s=S(o)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Wt(u(e),t,r,n)}function Jt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function $t(e,t){return Wt(e,"hx-vars",true,t)}function Zt(e,t){return Wt(e,"hx-vals",false,t)}function Gt(e){return Q($t(e),Zt(e))}function Kt(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Yt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(z().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Qt(e,t){return e.getAllResponseHeaders().match(t)}function er(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return Z(e,t,null,null,{targetOverride:k(r),returnPromise:true})}else{return Z(e,t,k(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:k(r.target),swapOverride:r.swap,returnPromise:true})}}else{return Z(e,t,null,null,{returnPromise:true})}}function tr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Z(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=z().body}var v=r.handler||rr;if(!Y(n)){return}var g=r.targetOverride||ne(n);if(g==null||g==te){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=_(n);var o=G(n,"hx-sync");var m=null;var x=false;if(o){var y=o.split(":");var b=y[0].trim();if(b==="this"){p=re(n,"hx-sync")}else{p=ee(n,b)}o=(y[1]||"drop").trim();i=_(p);if(o==="drop"&&i.xhr&&i.abortable!==true){return}else if(o==="abort"){if(i.xhr){return}else{x=true}}else if(o==="replace"){$(p,"htmx:abort")}else if(o.indexOf("queue")===0){var w=o.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=_(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){Z(e,t,n,f,r)})}return}}var a=new XMLHttpRequest;i.xhr=a;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=G(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){K(c);s();return d}}var R=G(n,"hx-confirm");if(R){if(!confirm(R)){K(c);s();return d}}var O=Xt(n,g,C);if(r.headers){O=Q(O,r.headers)}var L=Mt(n,e);var q=L.errors;var A=L.values;if(r.values){A=Q(A,r.values)}var T=Gt(n);var H=Q(A,T);var N=jt(H,n);if(e!=="get"&&G(n,"hx-encoding")==null){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=z().location.href}var k=Wt(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:q,withCredentials:r.credentials||k.credentials||U.config.withCredentials,timeout:r.timeout||k.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){K(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;q=l.errors;if(q&&q.length>0){$(n,"htmx:validation:halted",l);K(c);s();return d}var I=t.split("#");var M=I[0];var D=I[1];if(e==="get"){var F=M;var P=Object.keys(N).length!==0;if(P){if(F.indexOf("?")<0){F+="?"}else{F+="&"}F+=Ft(N);if(D){F+="#"+D}}a.open("GET",F,true)}else{a.open(e.toUpperCase(),t,true)}a.overrideMimeType("text/html");a.withCredentials=l.withCredentials;a.timeout=l.timeout;if(k.noHeaders){}else{for(var X in O){if(O.hasOwnProperty(X)){var j=O[X];Kt(a,X,j)}}}var u={xhr:a,target:g,requestConfig:l,etc:r,pathInfo:{path:t,finalPath:F,anchor:D}};a.onload=function(){try{var e=tr(n);v(n,u);Tt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!Y(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(Y(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}K(c);s()}catch(e){J(n,"htmx:onLoadError",Q({error:e},u));throw e}};a.onerror=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);K(h);s()};a.onabort=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);K(h);s()};a.ontimeout=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);K(h);s()};if(!$(n,"htmx:beforeRequest",u)){K(c);s();return d}var B=At(n);W(["loadstart","loadend","progress","abort"],function(t){W([a,a.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);a.send(e==="get"?null:Vt(a,n,N));return d}function rr(s,l){var u=l.xhr;var f=l.target;var r=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(Qt(u,/HX-Trigger:/i)){Se(u,"HX-Trigger",s)}if(Qt(u,/HX-Push:/i)){var c=u.getResponseHeader("HX-Push")}if(Qt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Qt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(Qt(u,/HX-Retarget:/i)){l.target=z().querySelector(u.getResponseHeader("HX-Retarget"))}var h;if(c=="false"){h=false}else{h=Lt(s)||c}var n=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var e=u.status>=400;var t=Q({shouldSwap:n,serverResponse:d,isError:e},l);if(!$(f,"htmx:beforeSwap",t))return;f=t.target;d=t.serverResponse;e=t.isError;l.failed=e;l.successful=!e;if(t.shouldSwap){if(u.status===286){Ie(s)}gt(s,function(e){d=e.transformResponse(d,u,s)});if(h){St()}var i=r.swapOverride;var v=Ut(s,i);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=zt(f);we(v.swapStyle,f,s,d,n);if(t.elt&&!Y(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);W(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(l.pathInfo.anchor){location.hash=l.pathInfo.anchor}if(Qt(u,/HX-Trigger-After-Swap:/i)){var o=s;if(!Y(s)){o=z().body}Se(u,"HX-Trigger-After-Swap",o)}var a=function(){W(n.tasks,function(e){e.call()});W(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h){var e=c||qt(s)||Yt(u)||l.pathInfo.finalPath||l.pathInfo.path;Et(e);$(z().body,"htmx:pushedIntoHistory",{path:e})}if(n.title){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}_t(n.elts,v);if(Qt(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!Y(s)){r=z().body}Se(u,"HX-Trigger-After-Settle",r)}};if(v.settleDelay>0){setTimeout(a,v.settleDelay)}else{a()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(v.swapDelay>0){setTimeout(o,v.swapDelay)}else{o()}}if(e){J(s,"htmx:responseError",Q({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var nr={};function ir(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function or(e,t){if(t.init){t.init(r)}nr[e]=Q(ir(),t)}function ar(e){delete nr[e]}function sr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){W(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=nr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return sr(u(e),r,n)}function lr(e){if(z().readyState!=="loading"){e()}else{z().addEventListener("DOMContentLoaded",e)}}function ur(){if(U.config.includeIndicatorStyles!==false){z().head.insertAdjacentHTML("beforeend","<style> ."+U.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+U.config.requestClass+" ."+U.config.indicatorClass+"{opacity:1} ."+U.config.requestClass+"."+U.config.indicatorClass+"{opacity:1} </style>")}}function fr(){var e=z().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function cr(){var e=fr();if(e){U.config=Q(U.config,e)}}lr(function(){cr();ur();var e=z().body;ct(e);var t=z().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=_(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){Ot();W(t,function(e){$(e,"htmx:restored",{document:z(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file +// /////////////////////////////////////////////////////////////////// +// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js +// +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(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 a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/<body/.test(e)}function l(e){var t=!N(e);var r=A(e);var n=e;if(r==="head"){n=n.replace(S,"")}if(Q.config.useTemplateFragments&&t){var i=a("<body><template>"+n+"</template></body>",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a("<table>"+n+"</table>",1);case"col":return a("<table><colgroup>"+n+"</colgroup></table>",2);case"tr":return a("<table><tbody>"+n+"</tbody></table>",2);case"td":case"th":return a("<table><tbody><tr>"+n+"</tr></tbody></table>",3);case"script":case"style":return a("<div>"+n+"</div>",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function oe(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function X(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var Y=function(e,t){var r=re().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function we(t,r){oe(t.attributes,function(e){if(!r.hasAttribute(e.name)&&be(e.name)){t.removeAttribute(e.name)}});oe(r.attributes,function(e){if(be(e.name)){t.setAttribute(e.name,e.value)}})}function Se(e,t){var r=Fr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){b(e)}}return e==="outerHTML"}function Ee(e,i,a){var t="#"+ee(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a<i.length;a++){var o=i[a].split(":",2);var s=o[0].trim();if(s.indexOf("#")===0){s=s.substring(1)}var l=o[1]||"true";var u=t.querySelector("#"+s);if(u){Ee(l,u,r)}}}oe(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=te(e,"hx-swap-oob");if(t!=null){Ee(t,e,r)}})}function Re(e){oe(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=te(e,"id");var r=re().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function Te(o,e,s){oe(e.querySelectorAll("[id]"),function(e){var t=ee(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Le(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=He(n.name,t);t=He(n.value,t)}}}return t}function Ae(e){var t=ae(e);if(t.onHandlers){for(var r=0;r<t.onHandlers.length;r++){const n=t.onHandlers[r];e.removeEventListener(n.event,n.listener)}delete t.onHandlers}}function Ne(e){var t=ae(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){oe(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}Ae(e);oe(Object.keys(t),function(e){delete t[e]})}function p(e){ce(e,"htmx:beforeCleanupElement");Ne(e);if(e.children){oe(e.children,function(e){p(e)})}}function Ie(t,e,r){if(t.tagName==="BODY"){return Ue(t,e,r)}else{var n;var i=t.previousSibling;m(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}p(t);u(t).removeChild(t)}}function ke(e,t,r){return m(e,e.firstChild,t,r)}function Pe(e,t,r){return m(u(e),e,t,r)}function Me(e,t,r){return m(e,null,t,r)}function Xe(e,t,r){return m(u(e),e.nextSibling,t,r)}function De(e,t,r){p(e);return u(e).removeChild(e)}function Ue(e,t,r){var n=e.firstChild;m(e,n,t,r);if(n){while(n.nextSibling){p(n.nextSibling);e.removeChild(n.nextSibling)}p(n);e.removeChild(n)}}function Be(e,t,r){var n=r||ne(e,"hx-select");if(n){var i=re().createDocumentFragment();oe(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function Fe(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Ie(r,n,i);return;case"afterbegin":ke(r,n,i);return;case"beforebegin":Pe(r,n,i);return;case"beforeend":Me(r,n,i);return;case"afterend":Xe(r,n,i);return;case"delete":De(r,n,i);return;default:var a=Fr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Oe(f))}}}return}}catch(e){b(e)}}if(e==="innerHTML"){Ue(r,n,i)}else{Fe(Q.config.defaultSwapStyle,t,r,n,i)}}}function Ve(e){if(e.indexOf("<title")>-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){ce(r,s[l].trim(),[])}}}var ze=/\s/;var x=/[\s,]/;var $e=/[_$a-zA-Z]/;var We=/[_$a-zA-Z0-9]/;var Ge=['"',"'","/"];var Je=/[^\s]/;var Ze=/[{(]/;var Ke=/[})]/;function Ye(e){var t=[];var r=0;while(r<e.length){if($e.exec(e.charAt(r))){var n=r;while(We.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ge.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function Qe(e,t,r){return $e.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function et(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){xt(e,a[1],0)}if(a[0]==="send"){bt(e)}}}function xt(s,r,n){if(!se(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=Q.createWebSocket(r);t.onerror=function(e){fe(s,"htmx:wsError",{error:e,socket:t});yt(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a<i.length;a++){var o=i[a];Ee(te(o,"hx-swap-oob")||"true",o,r)}nr(r.tasks)})}function yt(e){if(!se(e)){ae(e).webSocket.close();return true}}function bt(u){var f=c(u,function(e){return ae(e).webSocket!=null});if(f){u.addEventListener(it(u)[0].trigger,function(e){var t=ae(f).webSocket;var r=xr(u,f);var n=dr(u,"post");var i=n.errors;var a=n.values;var o=Hr(u);var s=le(a,o);var l=yr(s,u);l["HEADERS"]=r;if(i&&i.length>0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){Et(e,a[1])}if(a[0]==="swap"){Ct(e,a[1])}}}function Et(t,e){var r=Q.createEventSource(e);r.onerror=function(e){fe(t,"htmx:sseError",{error:e,source:r});Tt(t)};ae(t).sseEventSource=r}function Ct(a,o){var s=c(a,Ot);if(s){var l=ae(s).sseEventSource;var u=function(e){if(Tt(s)){return}if(!se(a)){l.removeEventListener(o,u);return}var t=e.data;R(a,function(e){t=e.transformResponse(t,null,a)});var r=wr(a);var n=ye(a);var i=T(a);je(r.swapStyle,n,a,t,i);nr(i.tasks);ce(a,"htmx:sseMessage",e)};ae(a).sseListener=u;l.addEventListener(o,u)}else{fe(a,"htmx:noSSESourceError")}}function Rt(e,t,r){var n=c(e,Ot);if(n){var i=ae(n).sseEventSource;var a=function(){if(!Tt(n)){if(se(e)){t(e)}else{i.removeEventListener(r,a)}}};ae(e).sseListener=a;i.addEventListener(r,a)}else{fe(e,"htmx:noSSESourceError")}}function Tt(e){if(!se(e)){ae(e).sseEventSource.close();return true}}function Ot(e){return ae(e).sseEventSource!=null}function qt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n>0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){ce(n,"intersect");break}}},i);a.observe(n);ht(n,r,t,e)}else if(e.trigger==="load"){if(!ct(e,n,Wt("load",{elt:n}))){qt(n,r,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r<t.length;r++){var n=t[r].name;if(s(n,"hx-on:")||s(n,"data-hx-on:")||s(n,"hx-on-")||s(n,"data-hx-on-")){return true}}return false}function kt(e){var t=null;var r=[];if(It(e)){r.push(e)}if(document.evaluate){var n=document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]',e);while(t=n.iterateNext())r.push(t)}else{var i=e.getElementsByTagName("*");for(var a=0;a<i.length;a++){if(It(i[a])){r.push(i[a])}}}return r}function Pt(e){if(e.querySelectorAll){var t=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";var r=e.querySelectorAll(i+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Mt(e){var t=v(e.target,"button, input[type='submit']");var r=Dt(e);if(r){r.lastButtonClicked=t}}function Xt(e){var t=Dt(e);if(t){t.lastButtonClicked=null}}function Dt(e){var t=v(e.target,"button, input[type='submit']");if(!t){return}var r=g("#"+ee(t,"form"))||v(t,"form");if(!r){return}return ae(r)}function Ut(e){e.addEventListener("click",Mt);e.addEventListener("focusin",Mt);e.addEventListener("focusout",Xt)}function Bt(e){var t=Ye(e);var r=0;for(var n=0;n<t.length;n++){const i=t[n];if(i==="{"){r++}else if(i==="}"){r--}}return r}function Ft(t,e,r){var n=ae(t);if(!Array.isArray(n.onHandlers)){n.onHandlers=[]}var i;var a=function(e){return Tr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Vt(e){var t=te(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;t<e.attributes.length;t++){var r=e.attributes[t].name;var n=e.attributes[t].value;if(s(r,"hx-on")||s(r,"data-hx-on")){var i=r.indexOf("-on")+3;var a=r.slice(i,i+1);if(a==="-"||a===":"){var o=r.slice(i+1);if(s(o,":")){o="htmx"+o}else if(s(o,"-")){o="htmx:"+o.slice(1)}else if(s(o,"htmx-")){o="htmx:"+o.slice(5)}Ft(e,o,n)}}}}function _t(t){if(v(t,Q.config.disableSelector)){p(t);return}var r=ae(t);if(r.initHash!==Le(t)){Ne(t);r.initHash=Le(t);Vt(t);ce(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=it(t);var n=Ht(t,r,e);if(!n){if(ne(t,"hx-boost")==="true"){lt(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){Lt(t,e,r,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&o(t,"form")){Ut(t)}var i=te(t,"hx-sse");if(i){St(t,r,i)}var a=te(t,"hx-ws");if(a){pt(t,r,a)}ce(t,"htmx:afterProcessNode")}}function zt(e){e=g(e);if(v(e,Q.config.disableSelector)){p(e);return}_t(e);oe(Pt(e),function(e){_t(e)});oe(kt(e),jt)}function $t(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=re().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function fe(e,t,r){ce(e,t,le({error:t},r))}function Gt(e){return e==="htmx:afterProcessNode"}function R(e,t){oe(Fr(e),function(e){try{t(e)}catch(e){b(e)}})}function b(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ce(e,t,r){e=g(e);if(r==null){r={}}r["elt"]=e;var n=Wt(t,r);if(Q.logger&&!Gt(t)){Q.logger(e,t,r)}if(r.error){b(r.error);ce(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=$t(t);if(i&&a!==t){var o=Wt(a,n.detail);i=i&&e.dispatchEvent(o)}R(e,function(e){i=i&&(e.onEvent(t,n)!==false&&!n.defaultPrevented)});return i}var Jt=location.pathname+location.search;function Zt(){var e=re().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||re().body}function Kt(e,t,r,n){if(!U()){return}if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}e=B(e);var i=E(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};ce(re().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Qt(e){var t=Q.config.requestClass;var r=e.cloneNode(true);oe(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function er(){var e=Zt();var t=Jt||location.pathname+location.search;var r;try{r=re().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){r=re().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!r){ce(re().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Kt(t,Qt(e),re().title,window.scrollY)}if(Q.config.historyEnabled)history.replaceState({htmx:true},re().title,window.location.href)}function tr(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(G(e,"&")||G(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Jt=e}function rr(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Jt=e}function nr(e){oe(e,function(e){e.call()})}function ir(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};ce(re().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",re().location.href);e.onload=function(){if(this.status>=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function fr(e){if(e.name===""||e.name==null||e.disabled||v(e,"fieldset[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 cr(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function hr(t,r,n,e,i){if(e==null||ur(t,e)){return}else{t.push(e)}if(fr(e)){var a=ee(e,"name");var o=e.value;if(e.multiple&&e.tagName==="SELECT"){o=M(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=M(e.files)}cr(a,o,r);if(i){vr(e,n)}}if(h(e,"form")){var s=e.elements;oe(s,function(e){hr(t,r,n,e,i)})}}function vr(e,t){if(e.willValidate){ce(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});ce(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function dr(e,t){var r=[];var n={};var i={};var a=[];var o=ae(e);if(o.lastButtonClicked&&!se(o.lastButtonClicked)){o.lastButtonClicked=null}var s=h(e,"form")&&e.noValidate!==true||te(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){hr(r,i,a,v(e,"form"),s)}hr(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=ee(l,"name");cr(u,l.value,i)}var f=pe(e,"hx-include");oe(f,function(e){hr(r,n,a,e,s);if(!h(e,"form")){oe(e.querySelectorAll(rt),function(e){hr(r,n,a,e,s)})}});n=le(n,i);return{errors:a,values:n}}function gr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function mr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t=gr(t,r,e)})}else{t=gr(t,r,n)}}}return t}function pr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function xr(e,t,r){var n={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":re().location.href};Rr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ae(e).boosted){n["HX-Boosted"]="true"}return n}function yr(t,e){var r=ne(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){oe(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};oe(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function br(e){return ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=d(o.substr(5))}else if(o.indexOf("settle:")===0){n["settleDelay"]=d(o.substr(7))}else if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}else if(o.indexOf("ignoreTitle:")===0){n["ignoreTitle"]=o.substr(12)==="true"}else if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","<style> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file diff --git a/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.js b/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.js index 27e57bc..86e7668 100644 --- a/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.js +++ b/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.js @@ -1,13 +1,23 @@ -//AMD insanity +// /////////////////////////////////////////////////////////////////// +// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.js +// + +// UMD insanity +// This code sets up support for (in order) AMD, ES6 modules, and globals. (function (root, factory) { //@ts-ignore if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. //@ts-ignore define([], factory); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); } else { // Browser globals - root.htmx = factory(); + root.htmx = root.htmx || factory(); } }(typeof self !== 'undefined' ? self : this, function () { return (function () { @@ -38,6 +48,7 @@ return (function () { defineExtension : defineExtension, removeExtension : removeExtension, logAll : logAll, + logNone : logNone, logger : null, config : { historyEnabled:true, @@ -53,15 +64,24 @@ return (function () { settlingClass:'htmx-settling', swappingClass:'htmx-swapping', allowEval:true, + allowScriptTags:true, inlineScriptNonce:'', attributesToSettle:["class", "style", "width", "height"], withCredentials:false, timeout:0, wsReconnectDelay: 'full-jitter', + wsBinaryType: 'blob', disableSelector: "[hx-disable], [data-hx-disable]", useTemplateFragments: false, scrollBehavior: 'smooth', defaultFocusScroll: false, + getCacheBusterParam: false, + globalViewTransitions: false, + methodsThatUseUrlParams: ["get"], + selfRequestsOnly: false, + ignoreTitle: false, + scrollIntoViewOnBoost: true, + triggerSpecsCache: null, }, parseInterval:parseInterval, _:internalEval, @@ -69,17 +89,23 @@ return (function () { return new EventSource(url, {withCredentials:true}) }, createWebSocket: function(url){ - return new WebSocket(url, []); + var sock = new WebSocket(url, []); + sock.binaryType = htmx.config.wsBinaryType; + return sock; }, - version: "1.7.0" + version: "1.9.10" }; /** @type {import("./htmx").HtmxInternalApi} */ var internalAPI = { + addTriggerHandler: addTriggerHandler, bodyContains: bodyContains, + canAccessLocalStorage: canAccessLocalStorage, + findThisElement: findThisElement, filterValues: filterValues, hasAttribute: hasAttribute, getAttributeValue: getAttributeValue, + getClosestAttributeValue: getClosestAttributeValue, getClosestMatch: getClosestMatch, getExpressionVars: getExpressionVars, getHeaders: getHeaders, @@ -92,6 +118,7 @@ return (function () { mergeObjects: mergeObjects, makeSettleInfo: makeSettleInfo, oobSwap: oobSwap, + querySelectorExt: querySelectorExt, selectAndSwap: selectAndSwap, settleImmediately: settleImmediately, shouldCancel: shouldCancel, @@ -105,21 +132,40 @@ return (function () { return "[hx-" + verb + "], [data-hx-" + verb + "]" }).join(", "); + var HEAD_TAG_REGEX = makeTagRegEx('head'), + TITLE_TAG_REGEX = makeTagRegEx('title'), + SVG_TAGS_REGEX = makeTagRegEx('svg', true); + //==================================================================== // Utilities //==================================================================== + /** + * @param {string} tag + * @param {boolean} global + * @returns {RegExp} + */ + function makeTagRegEx(tag, global = false) { + return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, + global ? 'gim' : 'im'); + } + function parseInterval(str) { if (str == undefined) { - return undefined + return undefined; } + + let interval = NaN; if (str.slice(-2) == "ms") { - return parseFloat(str.slice(0,-2)) || undefined - } - if (str.slice(-1) == "s") { - return (parseFloat(str.slice(0,-1)) * 1000) || undefined + interval = parseFloat(str.slice(0, -2)); + } else if (str.slice(-1) == "s") { + interval = parseFloat(str.slice(0, -1)) * 1000; + } else if (str.slice(-1) == "m") { + interval = parseFloat(str.slice(0, -1)) * 1000 * 60; + } else { + interval = parseFloat(str); } - return parseFloat(str) || undefined + return isNaN(interval) ? undefined : interval; } /** @@ -168,13 +214,11 @@ return (function () { * @returns {HTMLElement | null} */ function getClosestMatch(elt, condition) { - if (condition(elt)) { - return elt; - } else if (parentElt(elt)) { - return getClosestMatch(parentElt(elt), condition); - } else { - return null; + while (elt && !condition(elt)) { + elt = parentElt(elt); } + + return elt ? elt : null; } function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ @@ -208,7 +252,7 @@ return (function () { * @returns {boolean} */ function matches(elt, selector) { - // @ts-ignore: non-standard properties for browser compatability + // @ts-ignore: non-standard properties for browser compatibility // noinspection JSUnresolvedVariable var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; return matchesFunction && matchesFunction.call(elt, selector); @@ -252,38 +296,47 @@ return (function () { return responseNode; } + function aFullPageResponse(resp) { + return /<body/.test(resp) + } + /** * - * @param {string} resp + * @param {string} response * @returns {Element} */ - function makeFragment(resp) { - if (htmx.config.useTemplateFragments) { - var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0); + function makeFragment(response) { + var partialResponse = !aFullPageResponse(response); + var startTag = getStartTag(response); + var content = response; + if (startTag === 'head') { + content = content.replace(HEAD_TAG_REGEX, ''); + } + if (htmx.config.useTemplateFragments && partialResponse) { + var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0); // @ts-ignore type mismatch between DocumentFragment and Element. - // TODO: Are these close enough for htmx to use interchangably? + // TODO: Are these close enough for htmx to use interchangeably? return documentFragment.querySelector('template').content; - } else { - 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); - case "script": - return parseHTML("<div>" + resp + "</div>", 1); - default: - return parseHTML(resp, 0); - } + } + switch (startTag) { + case "thead": + case "tbody": + case "tfoot": + case "colgroup": + case "caption": + return parseHTML("<table>" + content + "</table>", 1); + case "col": + return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2); + case "tr": + return parseHTML("<table><tbody>" + content + "</tbody></table>", 2); + case "td": + case "th": + return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3); + case "script": + case "style": + return parseHTML("<div>" + content + "</div>", 1); + default: + return parseHTML(content, 0); } } @@ -365,13 +418,14 @@ return (function () { return elemTop < window.innerHeight && elemBottom >= 0; } - function bodyContains(elt) { - if (elt.getRootNode() instanceof ShadowRoot) { - return getDocument().body.contains(elt.getRootNode().host); - } else { - return getDocument().body.contains(elt); - } - } + function bodyContains(elt) { + // IE Fix + if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) { + return getDocument().body.contains(elt.getRootNode().host); + } else { + return getDocument().body.contains(elt); + } + } function splitOnWhitespace(trigger) { return trigger.trim().split(/\s+/); @@ -402,6 +456,34 @@ return (function () { } } + function canAccessLocalStorage() { + var test = 'htmx:localStorageTest'; + try { + localStorage.setItem(test, test); + localStorage.removeItem(test); + return true; + } catch(e) { + return false; + } + } + + function normalizePath(path) { + try { + var url = new URL(path); + if (url) { + path = url.pathname + url.search; + } + // remove trailing slash, unless index page + if (!(/^\/$/.test(path))) { + path = path.replace(/\/+$/, ''); + } + return path; + } catch (e) { + // be kind to IE11, which doesn't support URL() + return path; + } + } + //========================================================================================== // public API //========================================================================================== @@ -427,6 +509,10 @@ return (function () { } } + function logNone() { + htmx.logger = null + } + function find(eltOrSelector, selector) { if (selector) { return eltOrSelector.querySelector(selector); @@ -446,7 +532,10 @@ return (function () { function removeElement(elt, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeElement(elt);}, delay) + setTimeout(function(){ + removeElement(elt); + elt = null; + }, delay); } else { elt.parentElement.removeChild(elt); } @@ -455,7 +544,10 @@ return (function () { function addClassToElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){addClassToElement(elt, clazz);}, delay) + setTimeout(function(){ + addClassToElement(elt, clazz); + elt = null; + }, delay); } else { elt.classList && elt.classList.add(clazz); } @@ -464,7 +556,10 @@ return (function () { function removeClassFromElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) + setTimeout(function(){ + removeClassFromElement(elt, clazz); + elt = null; + }, delay); } else { if (elt.classList) { elt.classList.remove(clazz); @@ -494,26 +589,75 @@ return (function () { if (elt.closest) { return elt.closest(selector); } else { + // TODO remove when IE goes away do{ if (elt == null || matches(elt, selector)){ return elt; } } while (elt = elt && parentElt(elt)); + return null; + } + } + + function startsWith(str, prefix) { + return str.substring(0, prefix.length) === prefix + } + + function endsWith(str, suffix) { + return str.substring(str.length - suffix.length) === suffix + } + + function normalizeSelector(selector) { + var trimmedSelector = selector.trim(); + if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) { + return trimmedSelector.substring(1, trimmedSelector.length - 2); + } else { + return trimmedSelector; } } function querySelectorAllExt(elt, selector) { if (selector.indexOf("closest ") === 0) { - return [closest(elt, selector.substr(8))]; + return [closest(elt, normalizeSelector(selector.substr(8)))]; } else if (selector.indexOf("find ") === 0) { - return [find(elt, selector.substr(5))]; + return [find(elt, normalizeSelector(selector.substr(5)))]; + } else if (selector === "next") { + return [elt.nextElementSibling] + } else if (selector.indexOf("next ") === 0) { + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; + } else if (selector === "previous") { + return [elt.previousElementSibling] + } else if (selector.indexOf("previous ") === 0) { + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; } else if (selector === 'document') { return [document]; } else if (selector === 'window') { return [window]; + } else if (selector === 'body') { + return [document.body]; } else { - return getDocument().querySelectorAll(selector); + return getDocument().querySelectorAll(normalizeSelector(selector)); + } + } + + var scanForwardQuery = function(start, match) { + var results = getDocument().querySelectorAll(match); + for (var i = 0; i < results.length; i++) { + var elt = results[i]; + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { + return elt; + } + } + } + + var scanBackwardsQuery = function(start, match) { + var results = getDocument().querySelectorAll(match); + for (var i = results.length - 1; i >= 0; i--) { + var elt = results[i]; + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { + return elt; + } } } @@ -570,7 +714,7 @@ return (function () { //==================================================================== // Node processing //==================================================================== - + var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors function findAttributeTargets(elt, attrName) { var attrTarget = getClosestAttributeValue(elt, attrName); @@ -659,7 +803,7 @@ return (function () { * @returns */ function oobSwap(oobValue, oobElement, settleInfo) { - var selector = "#" + oobElement.id; + var selector = "#" + getRawAttribute(oobElement, "id"); var swapStyle = "outerHTML"; if (oobValue === "true") { // do nothing @@ -703,7 +847,23 @@ return (function () { return oobValue; } - function handleOutOfBandSwaps(fragment, settleInfo) { + function handleOutOfBandSwaps(elt, fragment, settleInfo) { + var oobSelects = getClosestAttributeValue(elt, "hx-select-oob"); + if (oobSelects) { + var oobSelectValues = oobSelects.split(","); + for (var i = 0; i < oobSelectValues.length; i++) { + var oobSelectValue = oobSelectValues[i].split(":", 2); + var id = oobSelectValue[0].trim(); + if (id.indexOf("#") === 0) { + id = id.substring(1); + } + var oobValue = oobSelectValue[1] || "true"; + var oobElement = fragment.querySelector("#" + id); + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo); + } + } + } forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) { var oobValue = getAttributeValue(oobElement, "hx-swap-oob"); if (oobValue != null) { @@ -724,8 +884,11 @@ return (function () { function handleAttributes(parentNode, fragment, settleInfo) { forEach(fragment.querySelectorAll("[id]"), function (newNode) { - if (newNode.id && newNode.id.length > 0) { - var oldNode = parentNode.querySelector(newNode.tagName + "[id='" + newNode.id + "']"); + var id = getRawAttribute(newNode, "id") + if (id && id.length > 0) { + var normalizedId = id.replace("'", "\\'"); + var normalizedTag = newNode.tagName.replace(':', '\\:'); + var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']"); if (oldNode && oldNode !== parentNode) { var newAttributes = newNode.cloneNode(); cloneAttributes(newNode, oldNode); @@ -767,24 +930,67 @@ return (function () { } } - function cleanUpElement(element) { + // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, + // derived from Java's string hashcode implementation + function stringHash(string, hash) { + var char = 0; + while (char < string.length){ + hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int + } + return hash; + } + + function attributeHash(elt) { + var hash = 0; + // IE fix + if (elt.attributes) { + for (var i = 0; i < elt.attributes.length; i++) { + var attribute = elt.attributes[i]; + if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent) + hash = stringHash(attribute.name, hash); + hash = stringHash(attribute.value, hash); + } + } + } + return hash; + } + + function deInitOnHandlers(elt) { + var internalData = getInternalData(elt); + if (internalData.onHandlers) { + for (var i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i]; + elt.removeEventListener(handlerInfo.event, handlerInfo.listener); + } + delete internalData.onHandlers + } + } + + function deInitNode(element) { var internalData = getInternalData(element); + if (internalData.timeout) { + clearTimeout(internalData.timeout); + } if (internalData.webSocket) { internalData.webSocket.close(); } if (internalData.sseEventSource) { internalData.sseEventSource.close(); } - - triggerEvent(element, "htmx:beforeCleanupElement") - if (internalData.listenerInfos) { - forEach(internalData.listenerInfos, function(info) { - if (element !== info.on) { + forEach(internalData.listenerInfos, function (info) { + if (info.on) { info.on.removeEventListener(info.trigger, info.listener); } }); } + deInitOnHandlers(element); + forEach(Object.keys(internalData), function(key) { delete internalData[key] }); + } + + function cleanUpElement(element) { + triggerEvent(element, "htmx:beforeCleanupElement") + deInitNode(element); if (element.children) { // IE forEach(element.children, function(child) { cleanUpElement(child) }); } @@ -803,8 +1009,7 @@ return (function () { } else { newElt = eltBeforeNewContent.nextSibling; } - getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later - settleInfo.elts = [] // clear existing elements + settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target }); while(newElt && newElt !== target) { if (newElt.nodeType === Node.ELEMENT_NODE) { settleInfo.elts.push(newElt); @@ -849,8 +1054,8 @@ return (function () { } } - function maybeSelectFromResponse(elt, fragment) { - var selector = getClosestAttributeValue(elt, "hx-select"); + function maybeSelectFromResponse(elt, fragment, selectOverride) { + var selector = selectOverride || getClosestAttributeValue(elt, "hx-select"); if (selector) { var newFragment = getDocument().createDocumentFragment(); forEach(fragment.querySelectorAll(selector), function (node) { @@ -915,21 +1120,20 @@ return (function () { function findTitle(content) { if (content.indexOf('<title') > -1) { - var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, ''); - var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im); - + var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, ''); + var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX); if (result) { return result[2]; } } } - function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) { + function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) { settleInfo.title = findTitle(responseText); var fragment = makeFragment(responseText); if (fragment) { - handleOutOfBandSwaps(fragment, settleInfo); - fragment = maybeSelectFromResponse(elt, fragment); + handleOutOfBandSwaps(elt, fragment, settleInfo); + fragment = maybeSelectFromResponse(elt, fragment, selectOverride); handlePreservedElements(fragment); return swap(swapStyle, elt, target, fragment, settleInfo); } @@ -949,7 +1153,10 @@ return (function () { } } } else { - triggerEvent(elt, triggerBody, []); + var eventNames = triggerBody.split(",") + for (var i = 0; i < eventNames.length; i++) { + triggerEvent(elt, eventNames[i].trim(), []); + } } } @@ -959,6 +1166,8 @@ return (function () { var SYMBOL_CONT = /[_$a-zA-Z0-9]/; var STRINGISH_START = ['"', "'", "/"]; var NOT_WHITESPACE = /[^\s]/; + var COMBINED_SELECTOR_START = /[{(]/; + var COMBINED_SELECTOR_END = /[})]/; function tokenizeString(str) { var tokens = []; var position = 0; @@ -1041,101 +1250,137 @@ return (function () { function consumeUntil(tokens, match) { var result = ""; - while (tokens.length > 0 && !tokens[0].match(match)) { + while (tokens.length > 0 && !match.test(tokens[0])) { result += tokens.shift(); } return result; } + function consumeCSSSelector(tokens) { + var result; + if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { + tokens.shift(); + result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim(); + tokens.shift(); + } else { + result = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } + return result; + } + var INPUT_SELECTOR = 'input, textarea, select'; /** * @param {HTMLElement} elt + * @param {string} explicitTrigger + * @param {cache} cache for trigger specs * @returns {import("./htmx").HtmxTriggerSpecification[]} */ - function getTriggerSpecs(elt) { - var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); + function parseAndCacheTrigger(elt, explicitTrigger, cache) { var triggerSpecs = []; - if (explicitTrigger) { - var tokens = tokenizeString(explicitTrigger); - do { - consumeUntil(tokens, NOT_WHITESPACE); - var initialLength = tokens.length; - var trigger = consumeUntil(tokens, /[,\[\s]/); - if (trigger !== "") { - if (trigger === "every") { - var every = {trigger: 'every'}; - consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); - consumeUntil(tokens, NOT_WHITESPACE); - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - every.eventFilter = eventFilter; - } - triggerSpecs.push(every); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); - } else { - var triggerSpec = {trigger: trigger}; - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - triggerSpec.eventFilter = eventFilter; - } - while (tokens.length > 0 && tokens[0] !== ",") { - consumeUntil(tokens, NOT_WHITESPACE) - var token = tokens.shift(); - if (token === "changed") { - triggerSpec.changed = true; - } else if (token === "once") { - triggerSpec.once = true; - } else if (token === "consume") { - triggerSpec.consume = true; - } else if (token === "delay" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "from" && tokens[0] === ":") { - tokens.shift(); + var tokens = tokenizeString(explicitTrigger); + do { + consumeUntil(tokens, NOT_WHITESPACE); + var initialLength = tokens.length; + var trigger = consumeUntil(tokens, /[,\[\s]/); + if (trigger !== "") { + if (trigger === "every") { + var every = {trigger: 'every'}; + consumeUntil(tokens, NOT_WHITESPACE); + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); + consumeUntil(tokens, NOT_WHITESPACE); + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + every.eventFilter = eventFilter; + } + triggerSpecs.push(every); + } else if (trigger.indexOf("sse:") === 0) { + triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); + } else { + var triggerSpec = {trigger: trigger}; + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + triggerSpec.eventFilter = eventFilter; + } + while (tokens.length > 0 && tokens[0] !== ",") { + consumeUntil(tokens, NOT_WHITESPACE) + var token = tokens.shift(); + if (token === "changed") { + triggerSpec.changed = true; + } else if (token === "once") { + triggerSpec.once = true; + } else if (token === "consume") { + triggerSpec.consume = true; + } else if (token === "delay" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); + } else if (token === "from" && tokens[0] === ":") { + tokens.shift(); + if (COMBINED_SELECTOR_START.test(tokens[0])) { + var from_arg = consumeCSSSelector(tokens); + } else { var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); - if (from_arg === "closest" || from_arg === "find") { + if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") { tokens.shift(); - from_arg += - " " + - consumeUntil( - tokens, - WHITESPACE_OR_COMMA - ); + var selector = consumeCSSSelector(tokens); + // `next` and `previous` allow a selector-less syntax + if (selector.length > 0) { + from_arg += " " + selector; + } } - triggerSpec.from = from_arg; - } else if (token === "target" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if (token === "throttle" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "queue" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if ((token === "root" || token === "threshold") && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); } + triggerSpec.from = from_arg; + } else if (token === "target" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.target = consumeCSSSelector(tokens); + } else if (token === "throttle" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); + } else if (token === "queue" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } else if (token === "root" && tokens[0] === ":") { + tokens.shift(); + triggerSpec[token] = consumeCSSSelector(tokens); + } else if (token === "threshold" && tokens[0] === ":") { + tokens.shift(); + triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } else { + triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); } - triggerSpecs.push(triggerSpec); } + triggerSpecs.push(triggerSpec); } - if (tokens.length === initialLength) { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - consumeUntil(tokens, NOT_WHITESPACE); - } while (tokens[0] === "," && tokens.shift()) + } + if (tokens.length === initialLength) { + triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); + } + consumeUntil(tokens, NOT_WHITESPACE); + } while (tokens[0] === "," && tokens.shift()) + if (cache) { + cache[explicitTrigger] = triggerSpecs + } + return triggerSpecs + } + + /** + * @param {HTMLElement} elt + * @returns {import("./htmx").HtmxTriggerSpecification[]} + */ + function getTriggerSpecs(elt) { + var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); + var triggerSpecs = []; + if (explicitTrigger) { + var cache = htmx.config.triggerSpecsCache + triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) } if (triggerSpecs.length > 0) { return triggerSpecs; } else if (matches(elt, 'form')) { return [{trigger: 'submit'}]; + } else if (matches(elt, 'input[type="button"], input[type="submit"]')){ + return [{trigger: 'click'}]; } else if (matches(elt, INPUT_SELECTOR)) { return [{trigger: 'change'}]; } else { @@ -1147,14 +1392,17 @@ return (function () { getInternalData(elt).cancelled = true; } - function processPolling(elt, verb, path, spec) { + function processPolling(elt, handler, spec) { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { - issueAjaxRequest(verb, path, elt); + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { + handler(elt); } - processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), spec); + processPolling(elt, handler, spec); } }, spec.pollInterval); } @@ -1166,23 +1414,27 @@ return (function () { } function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt) && elt.target === "") || elt.tagName === "FORM") { + if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || elt.tagName === "FORM") { nodeData.boosted = true; var verb, path; if (elt.tagName === "A") { verb = "get"; - path = getRawAttribute(elt, 'href'); - nodeData.pushURL = true; + path = getRawAttribute(elt, 'href') } else { var rawAttribute = getRawAttribute(elt, "method"); verb = rawAttribute ? rawAttribute.toLowerCase() : "get"; if (verb === "get") { - nodeData.pushURL = true; } path = getRawAttribute(elt, 'action'); } triggerSpecs.forEach(function(triggerSpec) { - addEventListener(elt, verb, path, nodeData, triggerSpec, true); + addEventListener(elt, function(elt, evt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + issueAjaxRequest(verb, path, elt, evt) + }, nodeData, triggerSpec, true); }); } } @@ -1213,11 +1465,11 @@ return (function () { return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); } - function maybeFilterEvent(triggerSpec, evt) { + function maybeFilterEvent(triggerSpec, elt, evt) { var eventFilter = triggerSpec.eventFilter; if(eventFilter){ try { - return eventFilter(evt) !== true; + return eventFilter.call(elt, evt) !== true; } catch(e) { triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); return true; @@ -1226,13 +1478,21 @@ return (function () { return false; } - function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { + function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { + var elementData = getInternalData(elt); var eltsToListenOn; if (triggerSpec.from) { eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); } else { eltsToListenOn = [elt]; } + // store the initial values of the elements, so we can tell if they change + if (triggerSpec.changed) { + eltsToListenOn.forEach(function (eltToListenOn) { + var eltToListenOnData = getInternalData(eltToListenOn); + eltToListenOnData.lastValue = eltToListenOn.value; + }) + } forEach(eltsToListenOn, function (eltToListenOn) { var eventListener = function (evt) { if (!bodyContains(elt)) { @@ -1245,7 +1505,7 @@ return (function () { if (explicitCancel || shouldCancel(evt, elt)) { evt.preventDefault(); } - if (maybeFilterEvent(triggerSpec, evt)) { + if (maybeFilterEvent(triggerSpec, elt, evt)) { return; } var eventData = getInternalData(evt); @@ -1253,7 +1513,6 @@ return (function () { if (eventData.handledFor == null) { eventData.handledFor = []; } - var elementData = getInternalData(elt); if (eventData.handledFor.indexOf(elt) < 0) { eventData.handledFor.push(elt); if (triggerSpec.consume) { @@ -1272,11 +1531,11 @@ return (function () { } } if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { + var eltToListenOnData = getInternalData(eltToListenOn) + if (eltToListenOnData.lastValue === eltToListenOn.value) { return; - } else { - elementData.lastValue = elt.value; } + eltToListenOnData.lastValue = eltToListenOn.value } if (elementData.delayed) { clearTimeout(elementData.delayed); @@ -1285,19 +1544,18 @@ return (function () { return; } - if (triggerSpec.throttle) { + if (triggerSpec.throttle > 0) { if (!elementData.throttle) { - issueAjaxRequest(verb, path, elt, evt); + handler(elt, evt); elementData.throttle = setTimeout(function () { elementData.throttle = null; }, triggerSpec.throttle); } - } else if (triggerSpec.delay) { - elementData.delayed = setTimeout(function () { - issueAjaxRequest(verb, path, elt, evt); - }, triggerSpec.delay); + } else if (triggerSpec.delay > 0) { + elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); } else { - issueAjaxRequest(verb, path, elt, evt); + triggerEvent(elt, 'htmx:trigger') + handler(elt, evt); } } }; @@ -1310,7 +1568,7 @@ return (function () { on: eltToListenOn }) eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); - }) + }); } var windowIsScrolling = false // used by initScrollHandler @@ -1336,14 +1594,11 @@ return (function () { if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { elt.setAttribute('data-hx-revealed', 'true'); var nodeData = getInternalData(elt); - if (nodeData.initialized) { - issueAjaxRequest(nodeData.verb, nodeData.path, elt); + if (nodeData.initHash) { + triggerEvent(elt, 'revealed'); } else { // if the node isn't initialized, wait for it before triggering the request - elt.addEventListener("htmx:afterProcessNode", - function () { - issueAjaxRequest(nodeData.verb, nodeData.path, elt); - }, {once: true}); + elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true}); } } } @@ -1502,6 +1757,9 @@ return (function () { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function (event) { if (maybeCloseSSESource(sseSourceElt)) { + return; + } + if (!bodyContains(elt)) { sseEventSource.removeEventListener(sseEventName, sseListener); return; } @@ -1518,7 +1776,7 @@ return (function () { var target = getTarget(elt) var settleInfo = makeSettleInfo(elt); - selectAndSwap(swapSpec.swapStyle, elt, target, response, settleInfo) + selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) settleImmediately(settleInfo.tasks) triggerEvent(elt, "htmx:sseMessage", event) }; @@ -1530,14 +1788,14 @@ return (function () { } } - function processSSETrigger(elt, verb, path, sseEventName) { + function processSSETrigger(elt, handler, sseEventName) { var sseSourceElt = getClosestMatch(elt, hasEventSource); if (sseSourceElt) { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function () { if (!maybeCloseSSESource(sseSourceElt)) { if (bodyContains(elt)) { - issueAjaxRequest(verb, path, elt); + handler(elt); } else { sseEventSource.removeEventListener(sseEventName, sseListener); } @@ -1563,14 +1821,14 @@ return (function () { //==================================================================== - function loadImmediately(elt, verb, path, nodeData, delay) { + function loadImmediately(elt, handler, nodeData, delay) { var load = function(){ if (!nodeData.loaded) { nodeData.loaded = true; - issueAjaxRequest(verb, path, elt); + handler(elt); } } - if (delay) { + if (delay > 0) { setTimeout(load, delay); } else { load(); @@ -1586,46 +1844,59 @@ return (function () { nodeData.path = path; nodeData.verb = verb; triggerSpecs.forEach(function(triggerSpec) { - if (triggerSpec.sseEvent) { - processSSETrigger(elt, verb, path, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - maybeReveal(elt); - } else if (triggerSpec.trigger === "intersect") { - var observerOptions = {}; - if (triggerSpec.root) { - observerOptions.root = querySelectorExt(elt, triggerSpec.root) - } - if (triggerSpec.threshold) { - observerOptions.threshold = parseFloat(triggerSpec.threshold); + addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return } - var observer = new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - if (entry.isIntersecting) { - triggerEvent(elt, "intersect"); - break; - } - } - }, observerOptions); - observer.observe(elt); - addEventListener(elt, verb, path, nodeData, triggerSpec); - } else if (triggerSpec.trigger === "load") { - loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); - } else if (triggerSpec.pollInterval) { - nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec); - } else { - addEventListener(elt, verb, path, nodeData, triggerSpec); - } + issueAjaxRequest(verb, path, elt, evt) + }) }); } }); return explicitAction; } + function addTriggerHandler(elt, triggerSpec, nodeData, handler) { + if (triggerSpec.sseEvent) { + processSSETrigger(elt, handler, triggerSpec.sseEvent); + } else if (triggerSpec.trigger === "revealed") { + initScrollHandler(); + addEventListener(elt, handler, nodeData, triggerSpec); + maybeReveal(elt); + } else if (triggerSpec.trigger === "intersect") { + var observerOptions = {}; + if (triggerSpec.root) { + observerOptions.root = querySelectorExt(elt, triggerSpec.root) + } + if (triggerSpec.threshold) { + observerOptions.threshold = parseFloat(triggerSpec.threshold); + } + var observer = new IntersectionObserver(function (entries) { + for (var i = 0; i < entries.length; i++) { + var entry = entries[i]; + if (entry.isIntersecting) { + triggerEvent(elt, "intersect"); + break; + } + } + }, observerOptions); + observer.observe(elt); + addEventListener(elt, handler, nodeData, triggerSpec); + } else if (triggerSpec.trigger === "load") { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { + loadImmediately(elt, handler, nodeData, triggerSpec.delay); + } + } else if (triggerSpec.pollInterval > 0) { + nodeData.polling = true; + processPolling(elt, handler, triggerSpec); + } else { + addEventListener(elt, handler, nodeData, triggerSpec); + } + } + function evalScript(script) { - if (script.type === "text/javascript" || script.type === "module" || script.type === "") { + if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) { var newScript = getDocument().createElement("script"); forEach(script.attributes, function (attr) { newScript.setAttribute(attr.name, attr.value); @@ -1642,7 +1913,10 @@ return (function () { } catch (e) { logError(e); } finally { - parent.removeChild(script); + // remove old script element, but only if it is still in DOM + if (script.parentElement) { + script.parentElement.removeChild(script); + } } } } @@ -1656,48 +1930,187 @@ return (function () { }); } - function hasChanceOfBeingBoosted() { - return document.querySelector("[hx-boost], [data-hx-boost]"); + function shouldProcessHxOn(elt) { + var attributes = elt.attributes + for (var j = 0; j < attributes.length; j++) { + var attrName = attributes[j].name + if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") || + startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) { + return true + } + } + return false + } + + function findHxOnWildcardElements(elt) { + var node = null + var elements = [] + + if (shouldProcessHxOn(elt)) { + elements.push(elt) + } + + if (document.evaluate) { + var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + + ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt) + while (node = iter.iterateNext()) elements.push(node) + } else { + var allElements = elt.getElementsByTagName("*") + for (var i = 0; i < allElements.length; i++) { + if (shouldProcessHxOn(allElements[i])) { + elements.push(allElements[i]) + } + } + } + + return elements } function findElementsToProcess(elt) { if (elt.querySelectorAll) { - var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; - var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [hx-data-ext]"); + var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; + var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," + + " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]"); return results; } else { return []; } } - function initButtonTracking(form){ - var maybeSetLastButtonClicked = function(evt){ - if (matches(evt.target, "button, input[type='submit']")) { - var internalData = getInternalData(form); - internalData.lastButtonClicked = evt.target; - } - }; - + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + function maybeSetLastButtonClicked(evt) { + var elt = closest(evt.target, "button, input[type='submit']"); + var internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = elt; + } + }; + function maybeUnsetLastButtonClicked(evt){ + var internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = null; + } + } + function getRelatedFormData(evt) { + var elt = closest(evt.target, "button, input[type='submit']"); + if (!elt) { + return; + } + var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form'); + if (!form) { + return; + } + return getInternalData(form); + } + function initButtonTracking(elt) { // need to handle both click and focus in: // focusin - in case someone tabs in to a button and hits the space bar // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + elt.addEventListener('click', maybeSetLastButtonClicked) + elt.addEventListener('focusin', maybeSetLastButtonClicked) + elt.addEventListener('focusout', maybeUnsetLastButtonClicked) + } - form.addEventListener('click', maybeSetLastButtonClicked) - form.addEventListener('focusin', maybeSetLastButtonClicked) - form.addEventListener('focusout', function(evt){ - var internalData = getInternalData(form); - internalData.lastButtonClicked = null; - }) + function countCurlies(line) { + var tokens = tokenizeString(line); + var netCurlies = 0; + for (var i = 0; i < tokens.length; i++) { + const token = tokens[i]; + if (token === "{") { + netCurlies++; + } else if (token === "}") { + netCurlies--; + } + } + return netCurlies; + } + + function addHxOnEventHandler(elt, eventName, code) { + var nodeData = getInternalData(elt); + if (!Array.isArray(nodeData.onHandlers)) { + nodeData.onHandlers = []; + } + var func; + var listener = function (e) { + return maybeEval(elt, function() { + if (!func) { + func = new Function("event", code); + } + func.call(elt, e); + }); + }; + elt.addEventListener(eventName, listener); + nodeData.onHandlers.push({event:eventName, listener:listener}); + } + + function processHxOn(elt) { + var hxOnValue = getAttributeValue(elt, 'hx-on'); + if (hxOnValue) { + var handlers = {} + var lines = hxOnValue.split("\n"); + var currentEvent = null; + var curlyCount = 0; + while (lines.length > 0) { + var line = lines.shift(); + var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/); + if (curlyCount === 0 && match) { + line.split(":") + currentEvent = match[1].slice(0, -1); // strip last colon + handlers[currentEvent] = match[2]; + } else { + handlers[currentEvent] += line; + } + curlyCount += countCurlies(line); + } + + for (var eventName in handlers) { + addHxOnEventHandler(elt, eventName, handlers[eventName]); + } + } + } + + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (var i = 0; i < elt.attributes.length; i++) { + var name = elt.attributes[i].name + var value = elt.attributes[i].value + if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) { + var afterOnPosition = name.indexOf("-on") + 3; + var nextChar = name.slice(afterOnPosition, afterOnPosition + 1); + if (nextChar === "-" || nextChar === ":") { + var eventName = name.slice(afterOnPosition + 1); + // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support + if (startsWith(eventName, ":")) { + eventName = "htmx" + eventName + } else if (startsWith(eventName, "-")) { + eventName = "htmx:" + eventName.slice(1); + } else if (startsWith(eventName, "htmx-")) { + eventName = "htmx:" + eventName.slice(5); + } + + addHxOnEventHandler(elt, eventName, value) + } + } + } } function initNode(elt) { - if (elt.closest && elt.closest(htmx.config.disableSelector)) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) return; } var nodeData = getInternalData(elt); - if (!nodeData.initialized) { - nodeData.initialized = true; + if (nodeData.initHash !== attributeHash(elt)) { + // clean up any previously processed info + deInitNode(elt); + + nodeData.initHash = attributeHash(elt); + + processHxOn(elt); + triggerEvent(elt, "htmx:beforeProcessNode") if (elt.value) { @@ -1705,14 +2118,24 @@ return (function () { } var triggerSpecs = getTriggerSpecs(elt); - var explicitAction = processVerbs(elt, nodeData, triggerSpecs); - - if (!explicitAction && getClosestAttributeValue(elt, "hx-boost") === "true") { - boostElement(elt, nodeData, triggerSpecs); + var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs); + + if (!hasExplicitHttpAction) { + if (getClosestAttributeValue(elt, "hx-boost") === "true") { + boostElement(elt, nodeData, triggerSpecs); + } else if (hasAttribute(elt, 'hx-trigger')) { + triggerSpecs.forEach(function (triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function () { + }) + }) + } } - if (elt.tagName === "FORM") { - initButtonTracking(elt); + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) { + initButtonTracking(elt) } var sseInfo = getAttributeValue(elt, 'hx-sse'); @@ -1730,8 +2153,15 @@ return (function () { function processNode(elt) { elt = resolveTarget(elt); + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return; + } initNode(elt); forEach(findElementsToProcess(elt), function(child) { initNode(child) }); + // Because it happens second, the new way of adding onHandlers superseeds the old one + // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored + forEach(findHxOnWildcardElements(elt), processHxOnWildcard); } //==================================================================== @@ -1809,7 +2239,7 @@ return (function () { eventResult = eventResult && elt.dispatchEvent(kebabedEvent) } withExtensions(elt, function (extension) { - eventResult = eventResult && (extension.onEvent(eventName, event) !== false) + eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) }); return eventResult; } @@ -1825,6 +2255,18 @@ return (function () { } function saveToHistoryCache(url, content, title, scroll) { + if (!canAccessLocalStorage()) { + return; + } + + if (htmx.config.historyCacheSize <= 0) { + // make sure that an eventually already existing cache is purged + localStorage.removeItem("htmx-history-cache"); + return; + } + + url = normalizePath(url); + var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { @@ -1832,7 +2274,9 @@ return (function () { break; } } - historyCache.push({url:url, content: content, title:title, scroll:scroll}) + var newHistoryItem = {url:url, content: content, title:title, scroll:scroll}; + triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache}) + historyCache.push(newHistoryItem) while (historyCache.length > htmx.config.historyCacheSize) { historyCache.shift(); } @@ -1848,6 +2292,12 @@ return (function () { } function getCachedHistory(url) { + if (!canAccessLocalStorage()) { + return null; + } + + url = normalizePath(url); + var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { @@ -1869,13 +2319,43 @@ return (function () { function saveCurrentPageToHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; - triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); - if(htmx.config.historyEnabled) history.replaceState({htmx:true}, getDocument().title, window.location.href); - saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); + + // Allow history snapshot feature to be disabled where hx-history="false" + // is present *anywhere* in the current document we're about to save, + // so we can prevent privileged data entering the cache. + // The page will still be reachable as a history entry, but htmx will fetch it + // live from the server onpopstate rather than look in the localStorage cache + var disableHistoryCache + try { + disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') + } catch (e) { + // IE11: insensitive modifier not supported so fallback to case sensitive selector + disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') + } + if (!disableHistoryCache) { + triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt}); + saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); + } + + if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href); } function pushUrlIntoHistory(path) { - if(htmx.config.historyEnabled) history.pushState({htmx:true}, "", path); + // remove the cache buster parameter, if any + if (htmx.config.getCacheBusterParam) { + path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') + if (endsWith(path, '&') || endsWith(path, "?")) { + path = path.slice(0, -1); + } + } + if(htmx.config.historyEnabled) { + history.pushState({htmx:true}, "", path); + } + currentPathForHistory = path; + } + + function replaceUrlInHistory(path) { + if(htmx.config.historyEnabled) history.replaceState({htmx:true}, "", path); currentPathForHistory = path; } @@ -1890,7 +2370,9 @@ return (function () { var details = {path: path, xhr:request}; triggerEvent(getDocument().body, "htmx:historyCacheMiss", details); request.open('GET', path, true); + request.setRequestHeader("HX-Request", "true"); request.setRequestHeader("HX-History-Restore-Request", "true"); + request.setRequestHeader("HX-Current-URL", getDocument().location.href); request.onload = function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); @@ -1899,11 +2381,20 @@ return (function () { fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; var historyElement = getHistoryElement(); var settleInfo = makeSettleInfo(historyElement); + var title = findTitle(this.response); + if (title) { + var titleElt = find("title"); + if (titleElt) { + titleElt.innerHTML = title; + } else { + window.document.title = title; + } + } // @ts-ignore swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); + triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response}); } else { triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details); } @@ -1922,9 +2413,11 @@ return (function () { swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); document.title = cached.title; - window.scrollTo(0, cached.scroll); + setTimeout(function () { + window.scrollTo(0, cached.scroll); + }, 0); // next 'tick', so browser has time to render layout currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); + triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); } else { if (htmx.config.refreshOnHistoryMiss) { @@ -1936,31 +2429,46 @@ return (function () { } } - function shouldPush(elt) { - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - return (pushUrl && pushUrl !== "false") || - (getInternalData(elt).boosted && getInternalData(elt).pushURL); - } - - function getPushUrl(elt) { - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - return (pushUrl === "true" || pushUrl === "false") ? null : pushUrl; - } - function addRequestIndicatorClasses(elt) { var indicators = findAttributeTargets(elt, 'hx-indicator'); if (indicators == null) { indicators = [elt]; } forEach(indicators, function (ic) { + var internalData = getInternalData(ic); + internalData.requestCount = (internalData.requestCount || 0) + 1; ic.classList["add"].call(ic.classList, htmx.config.requestClass); }); return indicators; } - function removeRequestIndicatorClasses(indicators) { + function disableElements(elt) { + var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt'); + if (disabledElts == null) { + disabledElts = []; + } + forEach(disabledElts, function (disabledElement) { + var internalData = getInternalData(disabledElement); + internalData.requestCount = (internalData.requestCount || 0) + 1; + disabledElement.setAttribute("disabled", ""); + }); + return disabledElts; + } + + function removeRequestIndicators(indicators, disabled) { forEach(indicators, function (ic) { - ic.classList["remove"].call(ic.classList, htmx.config.requestClass); + var internalData = getInternalData(ic); + internalData.requestCount = (internalData.requestCount || 0) - 1; + if (internalData.requestCount === 0) { + ic.classList["remove"].call(ic.classList, htmx.config.requestClass); + } + }); + forEach(disabled, function (disabledElement) { + var internalData = getInternalData(disabledElement); + internalData.requestCount = (internalData.requestCount || 0) - 1; + if (internalData.requestCount === 0) { + disabledElement.removeAttribute('disabled'); + } }); } @@ -1979,7 +2487,7 @@ return (function () { } function shouldInclude(elt) { - if(elt.name === "" || elt.name == null || elt.disabled) { + if(elt.name === "" || elt.name == null || elt.disabled || closest(elt, "fieldset[disabled]")) { return false; } // ignore "submitter" types (see jQuery src/serialize.js) @@ -1992,6 +2500,29 @@ return (function () { return true; } + function addValueToValues(name, value, values) { + // This is a little ugly because both the current value of the named value in the form + // and the new value could be arrays, so we have to handle all four cases :/ + if (name != null && value != null) { + var current = values[name]; + if (current === undefined) { + values[name] = value; + } else if (Array.isArray(current)) { + if (Array.isArray(value)) { + values[name] = current.concat(value); + } else { + current.push(value); + } + } else { + if (Array.isArray(value)) { + values[name] = [current].concat(value); + } else { + values[name] = [current, value]; + } + } + } + } + function processInputValue(processed, values, errors, elt, validate) { if (elt == null || haveSeenNode(processed, elt)) { return; @@ -2001,35 +2532,14 @@ return (function () { if (shouldInclude(elt)) { var name = getRawAttribute(elt,"name"); var value = elt.value; - if (elt.multiple) { + if (elt.multiple && elt.tagName === "SELECT") { value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value }); } // include file inputs if (elt.files) { value = toArray(elt.files); } - // This is a little ugly because both the current value of the named value in the form - // and the new value could be arrays, so we have to handle all four cases :/ - if (name != null && value != null) { - var current = values[name]; - if(current) { - if (Array.isArray(current)) { - if (Array.isArray(value)) { - values[name] = current.concat(value); - } else { - current.push(value); - } - } else { - if (Array.isArray(value)) { - values[name] = [current].concat(value); - } else { - values[name] = [current, value]; - } - } - } else { - values[name] = value; - } - } + addValueToValues(name, value, values); if (validate) { validateElement(elt, errors); } @@ -2062,9 +2572,13 @@ return (function () { var formValues = {}; var errors = []; var internalData = getInternalData(elt); + if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { + internalData.lastButtonClicked = null + } // only validate when form is directly submitted and novalidate or formnovalidate are not set - var validate = matches(elt, 'form') && elt.noValidate !== true; + // or if the element has an explicit hx-validate="true" on it + var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true"; if (internalData.lastButtonClicked) { validate = validate && internalData.lastButtonClicked.formNoValidate !== true; } @@ -2078,11 +2592,11 @@ return (function () { processInputValue(processed, values, errors, elt, validate); // if a button or submit was clicked last, include its value - if (internalData.lastButtonClicked) { - var name = getRawAttribute(internalData.lastButtonClicked,"name"); - if (name) { - values[name] = internalData.lastButtonClicked.value; - } + if (internalData.lastButtonClicked || elt.tagName === "BUTTON" || + (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) { + var button = internalData.lastButtonClicked || elt + var name = getRawAttribute(button, "name") + addValueToValues(name, button.value, formValues) } // include any explicit includes @@ -2228,40 +2742,43 @@ return (function () { "swapDelay" : htmx.config.defaultSwapDelay, "settleDelay" : htmx.config.defaultSettleDelay } - if (getInternalData(elt).boosted && !isAnchorLink(elt)) { + if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { swapSpec["show"] = "top" } 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)); - } - if (modifier.indexOf("scroll:") === 0) { - var scrollSpec = modifier.substr(7); + for (var i = 0; i < split.length; i++) { + var value = split[i]; + if (value.indexOf("swap:") === 0) { + swapSpec["swapDelay"] = parseInterval(value.substr(5)); + } else if (value.indexOf("settle:") === 0) { + swapSpec["settleDelay"] = parseInterval(value.substr(7)); + } else if (value.indexOf("transition:") === 0) { + swapSpec["transition"] = value.substr(11) === "true"; + } else if (value.indexOf("ignoreTitle:") === 0) { + swapSpec["ignoreTitle"] = value.substr(12) === "true"; + } else if (value.indexOf("scroll:") === 0) { + var scrollSpec = value.substr(7); var splitSpec = scrollSpec.split(":"); var scrollVal = splitSpec.pop(); var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; swapSpec["scroll"] = scrollVal; swapSpec["scrollTarget"] = selectorVal; - } - if (modifier.indexOf("show:") === 0) { - var showSpec = modifier.substr(5); + } else if (value.indexOf("show:") === 0) { + var showSpec = value.substr(5); var splitSpec = showSpec.split(":"); var showVal = splitSpec.pop(); var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; swapSpec["show"] = showVal; swapSpec["showTarget"] = selectorVal; - } - if (modifier.indexOf("focus-scroll:") === 0) { - var focusScrollVal = modifier.substr("focus-scroll:".length); + } else if (value.indexOf("focus-scroll:") === 0) { + var focusScrollVal = value.substr("focus-scroll:".length); swapSpec["focusScroll"] = focusScrollVal == "true"; + } else if (i == 0) { + swapSpec["swapStyle"] = value; + } else { + logError('Unknown modifier in hx-swap: ' + value); } } } @@ -2269,6 +2786,11 @@ return (function () { return swapSpec; } + function usesFormData(elt) { + return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || + (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data"); + } + function encodeParamsForBody(xhr, elt, filteredParameters) { var encodedParameters = null; withExtensions(elt, function (extension) { @@ -2279,8 +2801,7 @@ return (function () { if (encodedParameters != null) { return encodedParameters; } else { - if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || - (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) { + if (usesFormData(elt)) { return makeFormData(filteredParameters); } else { return urlEncode(filteredParameters); @@ -2352,6 +2873,9 @@ return (function () { if (attributeValue) { var str = attributeValue.trim(); var evaluateValue = evalAsDefault; + if (str === "unset") { + return null; + } if (str.indexOf("javascript:") === 0) { str = str.substr(11); evaluateValue = true; @@ -2426,7 +2950,7 @@ return (function () { } } - function getResponseURL(xhr) { + function getPathFromResponse(xhr) { // NB: IE11 does not support this stuff if (xhr.responseURL && typeof(URL) !== "undefined") { try { @@ -2439,7 +2963,7 @@ return (function () { } function hasHeader(xhr, regexp) { - return xhr.getAllResponseHeaders().match(regexp); + return regexp.test(xhr.getAllResponseHeaders()) } function ajaxHelper(verb, path, context) { @@ -2458,6 +2982,7 @@ return (function () { values : context.values, targetOverride: resolveTarget(context.target), swapOverride: context.swap, + select: context.select, returnPromise: true }); } @@ -2477,7 +3002,28 @@ return (function () { return arr; } - function issueAjaxRequest(verb, path, elt, event, etc) { + function verifyPath(elt, path, requestConfig) { + var sameHost + var url + if (typeof URL === "function") { + url = new URL(path, document.location.href); + var origin = document.location.origin; + sameHost = origin === url.origin; + } else { + // IE11 doesn't support URL + url = path + sameHost = startsWith(path, document.location.origin) + } + + if (htmx.config.selfRequestsOnly) { + if (!sameHost) { + return false; + } + } + return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig)); + } + + function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { var resolve = null; var reject = null; etc = etc != null ? etc : {}; @@ -2491,18 +3037,52 @@ return (function () { elt = getDocument().body; } var responseHandler = etc.handler || handleAjaxResponse; + var select = etc.select || null; if (!bodyContains(elt)) { - return; // do not issue requests for elements removed from the DOM + // do not issue requests for elements removed from the DOM + maybeCall(resolve); + return promise; } var target = etc.targetOverride || getTarget(elt); if (target == null || target == DUMMY_ELT) { triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); - return; + maybeCall(reject); + return promise; } - var syncElt = elt; var eltData = getInternalData(elt); + var submitter = eltData.lastButtonClicked; + + if (submitter) { + var buttonPath = getRawAttribute(submitter, "formaction"); + if (buttonPath != null) { + path = buttonPath; + } + + var buttonVerb = getRawAttribute(submitter, "formmethod") + if (buttonVerb != null) { + // ignore buttons with formmethod="dialog" + if (buttonVerb.toLowerCase() !== "dialog") { + verb = buttonVerb; + } + } + } + + var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); + // allow event-based confirmation w/ a callback + if (confirmed === undefined) { + var issueRequest = function(skipConfirmation) { + return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation); + } + var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion}; + if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { + maybeCall(resolve); + return promise; + } + } + + var syncElt = elt; var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); var queueStrategy = null; var abortable = false; @@ -2518,10 +3098,12 @@ return (function () { syncStrategy = (syncStrings[1] || 'drop').trim(); eltData = getInternalData(syncElt); if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { - return; + maybeCall(resolve); + return promise; } else if (syncStrategy === "abort") { if (eltData.xhr) { - return; + maybeCall(resolve); + return promise; } else { abortable = true; } @@ -2565,7 +3147,8 @@ return (function () { issueAjaxRequest(verb, path, elt, event, etc) }); } - return; + maybeCall(resolve); + return promise; } } @@ -2593,8 +3176,7 @@ return (function () { } } - var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); - if (confirmQuestion) { + if (confirmQuestion && !confirmed) { if(!confirm(confirmQuestion)) { maybeCall(resolve); endRequestLock() @@ -2604,6 +3186,11 @@ return (function () { var headers = getHeaders(elt, target, promptResponse); + + if (verb !== 'get' && !usesFormData(elt)) { + headers['Content-Type'] = 'application/x-www-form-urlencoded'; + } + if (etc.headers) { headers = mergeObjects(headers, etc.headers); } @@ -2617,8 +3204,8 @@ return (function () { var allParameters = mergeObjects(rawParameters, expressionVars); var filteredParameters = filterValues(allParameters, elt); - if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null) { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; + if (htmx.config.getCacheBusterParam && verb === 'get') { + filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true"; } // behavior of anchors w/ empty href is to use the current URL @@ -2626,9 +3213,16 @@ return (function () { path = getDocument().location.href; } + var requestAttrValues = getValuesForElement(elt, 'hx-request'); + var eltIsBoosted = getInternalData(elt).boosted; + + var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + var requestConfig = { + boosted: eltIsBoosted, + useUrlParams: useUrlParams, parameters: filteredParameters, unfilteredParameters: allParameters, headers:headers, @@ -2653,6 +3247,7 @@ return (function () { headers = requestConfig.headers; filteredParameters = requestConfig.parameters; errors = requestConfig.errors; + useUrlParams = requestConfig.useUrlParams; if(errors && errors.length > 0){ triggerEvent(elt, 'htmx:validation:halted', requestConfig) @@ -2664,25 +3259,31 @@ return (function () { var splitPath = path.split("#"); var pathNoAnchor = splitPath[0]; var anchor = splitPath[1]; - if (verb === 'get') { - var finalPathForGet = pathNoAnchor; + + var finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor; var values = Object.keys(filteredParameters).length !== 0; if (values) { - if (finalPathForGet.indexOf("?") < 0) { - finalPathForGet += "?"; + if (finalPath.indexOf("?") < 0) { + finalPath += "?"; } else { - finalPathForGet += "&"; + finalPath += "&"; } - finalPathForGet += urlEncode(filteredParameters); + finalPath += urlEncode(filteredParameters); if (anchor) { - finalPathForGet += "#" + anchor; + finalPath += "#" + anchor; } } - xhr.open('GET', finalPathForGet, true); - } else { - xhr.open(verb.toUpperCase(), path, true); } + if (!verifyPath(elt, finalPath, requestConfig)) { + triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) + maybeCall(reject); + return promise; + }; + + xhr.open(verb.toUpperCase(), finalPath, true); xhr.overrideMimeType("text/html"); xhr.withCredentials = requestConfig.withCredentials; xhr.timeout = requestConfig.timeout; @@ -2699,19 +3300,24 @@ return (function () { } } - var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, etc:etc, pathInfo:{ - path:path, finalPath:finalPathForGet, anchor:anchor + var responseInfo = { + xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select, + pathInfo: { + requestPath: path, + finalRequestPath: finalPath, + anchor: anchor } }; xhr.onload = function () { try { var hierarchy = hierarchyForElt(elt); + responseInfo.pathInfo.responsePath = getPathFromResponse(xhr); responseHandler(elt, responseInfo); - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerEvent(elt, 'htmx:afterRequest', responseInfo); triggerEvent(elt, 'htmx:afterOnLoad', responseInfo); - // if the body no longer contains the element, trigger the even on the closest parent + // if the body no longer contains the element, trigger the event on the closest parent // remaining in the DOM if (!bodyContains(elt)) { var secondaryTriggerElt = null; @@ -2734,21 +3340,21 @@ return (function () { } } xhr.onerror = function () { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:sendError', responseInfo); maybeCall(reject); endRequestLock(); } xhr.onabort = function() { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo); maybeCall(reject); endRequestLock(); } xhr.ontimeout = function() { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:timeout', responseInfo); maybeCall(reject); @@ -2760,6 +3366,7 @@ return (function () { return promise } var indicators = addRequestIndicatorClasses(elt); + var disableElts = disableElements(elt); forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { forEach([xhr, xhr.upload], function (target) { @@ -2773,14 +3380,99 @@ return (function () { }); }); triggerEvent(elt, 'htmx:beforeSend', responseInfo); - xhr.send(verb === 'get' ? null : encodeParamsForBody(xhr, elt, filteredParameters)); + var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) + xhr.send(params); return promise; } + function determineHistoryUpdates(elt, responseInfo) { + + var xhr = responseInfo.xhr; + + //=========================================== + // First consult response headers + //=========================================== + var pathFromHeaders = null; + var typeFromHeaders = null; + if (hasHeader(xhr,/HX-Push:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Push"); + typeFromHeaders = "push"; + } else if (hasHeader(xhr,/HX-Push-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Push-Url"); + typeFromHeaders = "push"; + } else if (hasHeader(xhr,/HX-Replace-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url"); + typeFromHeaders = "replace"; + } + + // if there was a response header, that has priority + if (pathFromHeaders) { + if (pathFromHeaders === "false") { + return {} + } else { + return { + type: typeFromHeaders, + path : pathFromHeaders + } + } + } + + //=========================================== + // Next resolve via DOM values + //=========================================== + var requestPath = responseInfo.pathInfo.finalRequestPath; + var responsePath = responseInfo.pathInfo.responsePath; + + var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); + var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url"); + var elementIsBoosted = getInternalData(elt).boosted; + + var saveType = null; + var path = null; + + if (pushUrl) { + saveType = "push"; + path = pushUrl; + } else if (replaceUrl) { + saveType = "replace"; + path = replaceUrl; + } else if (elementIsBoosted) { + saveType = "push"; + path = responsePath || requestPath; // if there is no response path, go with the original request path + } + + if (path) { + // false indicates no push, return empty object + if (path === "false") { + return {}; + } + + // true indicates we want to follow wherever the server ended up sending us + if (path === "true") { + path = responsePath || requestPath; // if there is no response path, go with the original request path + } + + // restore any anchor associated with the request + if (responseInfo.pathInfo.anchor && + path.indexOf("#") === -1) { + path = path + "#" + responseInfo.pathInfo.anchor; + } + + return { + type:saveType, + path: path + } + } else { + return {}; + } + } + function handleAjaxResponse(elt, responseInfo) { var xhr = responseInfo.xhr; var target = responseInfo.target; var etc = responseInfo.etc; + var requestConfig = responseInfo.requestConfig; + var select = responseInfo.select; if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; @@ -2788,33 +3480,44 @@ return (function () { handleTrigger(xhr, "HX-Trigger", elt); } - if (hasHeader(xhr,/HX-Push:/i)) { - var pushedUrl = xhr.getResponseHeader("HX-Push"); + if (hasHeader(xhr, /HX-Location:/i)) { + saveCurrentPageToHistory(); + var redirectPath = xhr.getResponseHeader("HX-Location"); + var swapSpec; + if (redirectPath.indexOf("{") === 0) { + swapSpec = parseJSON(redirectPath); + // what's the best way to throw an error if the user didn't include this + redirectPath = swapSpec['path']; + delete swapSpec['path']; + } + ajaxHelper('GET', redirectPath, swapSpec).then(function(){ + pushUrlIntoHistory(redirectPath); + }); + return; } + var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh"); + if (hasHeader(xhr, /HX-Redirect:/i)) { - window.location.href = xhr.getResponseHeader("HX-Redirect"); + location.href = xhr.getResponseHeader("HX-Redirect"); + shouldRefresh && location.reload(); return; } - if (hasHeader(xhr,/HX-Refresh:/i)) { - if ("true" === xhr.getResponseHeader("HX-Refresh")) { - location.reload(); - return; - } + if (shouldRefresh) { + location.reload(); + return; } if (hasHeader(xhr,/HX-Retarget:/i)) { - responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget")); + if (xhr.getResponseHeader("HX-Retarget") === "this") { + responseInfo.target = elt; + } else { + responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget")); + } } - /** @type {boolean} */ - var shouldSaveHistory - if (pushedUrl == "false") { - shouldSaveHistory = false - } else { - shouldSaveHistory = shouldPush(elt) || pushedUrl; - } + var historyUpdate = determineHistoryUpdates(elt, responseInfo); // by default htmx only swaps on 200 return codes and does not swap // on 204 'No Content' @@ -2823,15 +3526,18 @@ return (function () { var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; var serverResponse = xhr.response; var isError = xhr.status >= 400; - var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo); + var ignoreTitle = htmx.config.ignoreTitle + var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo); if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; target = beforeSwapDetails.target; // allow re-targeting serverResponse = beforeSwapDetails.serverResponse; // allow updating content isError = beforeSwapDetails.isError; // allow updating error - + ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title + + responseInfo.target = target; // Make updated target available to response events responseInfo.failed = isError; // Make failed property available to response events - responseInfo.successful = !isError; // Make successful property available to response events + responseInfo.successful = !isError; // Make successful property available to response events if (beforeSwapDetails.shouldSwap) { if (xhr.status === 286) { @@ -2842,18 +3548,29 @@ return (function () { serverResponse = extension.transformResponse(serverResponse, xhr, elt); }); - // Save current page - if (shouldSaveHistory) { + // Save current page if there will be a history update + if (historyUpdate.type) { saveCurrentPageToHistory(); } var swapOverride = etc.swapOverride; + if (hasHeader(xhr,/HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader("HX-Reswap"); + } var swapSpec = getSwapSpecification(elt, swapOverride); + if (swapSpec.hasOwnProperty('ignoreTitle')) { + ignoreTitle = swapSpec.ignoreTitle; + } + target.classList.add(htmx.config.swappingClass); + + // optional transition API promise callbacks + var settleResolve = null; + var settleReject = null; + var doSwap = function () { try { - var activeElt = document.activeElement; var selectionInfo = {}; try { @@ -2868,19 +3585,44 @@ return (function () { // safari issue - see https://github.com/microsoft/playwright/issues/5894 } + var selectOverride; + if (select) { + selectOverride = select; + } + + if (hasHeader(xhr, /HX-Reselect:/i)) { + selectOverride = xhr.getResponseHeader("HX-Reselect"); + } + + // if we need to save history, do so, before swapping so that relative resources have the correct base URL + if (historyUpdate.type) { + triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)); + if (historyUpdate.type === "push") { + pushUrlIntoHistory(historyUpdate.path); + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path}); + } else { + replaceUrlInHistory(historyUpdate.path); + triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path}); + } + } + var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride); if (selectionInfo.elt && !bodyContains(selectionInfo.elt) && - selectionInfo.elt.id) { - var newActiveElt = document.getElementById(selectionInfo.elt.id); + getRawAttribute(selectionInfo.elt, "id")) { + var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id")); var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; if (newActiveElt) { // @ts-ignore if (selectionInfo.start && newActiveElt.setSelectionRange) { // @ts-ignore - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + try { + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + } catch (e) { + // the setSelectionRange method is present on fields that don't support it, so just let this fail + } } newActiveElt.focus(focusOptions); } @@ -2893,9 +3635,6 @@ return (function () { } triggerEvent(elt, 'htmx:afterSwap', responseInfo); }); - if (responseInfo.pathInfo.anchor) { - location.hash = responseInfo.pathInfo.anchor; - } if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { var finalElt = elt; @@ -2915,14 +3654,15 @@ return (function () { } triggerEvent(elt, 'htmx:afterSettle', responseInfo); }); - // push URL and save new page - if (shouldSaveHistory) { - var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; - pushUrlIntoHistory(pathToPush); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: pathToPush}); + + if (responseInfo.pathInfo.anchor) { + var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor); + if(anchorTarget) { + anchorTarget.scrollIntoView({block:'start', behavior: "auto"}); + } } - if(settleInfo.title) { + if(settleInfo.title && !ignoreTitle) { var titleElt = find("title"); if(titleElt) { titleElt.innerHTML = settleInfo.title; @@ -2940,6 +3680,7 @@ return (function () { } handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); } + maybeCall(settleResolve); } if (swapSpec.settleDelay > 0) { @@ -2949,10 +3690,34 @@ return (function () { } } catch (e) { triggerErrorEvent(elt, 'htmx:swapError', responseInfo); + maybeCall(settleReject); throw e; } }; + var shouldTransition = htmx.config.globalViewTransitions + if(swapSpec.hasOwnProperty('transition')){ + shouldTransition = swapSpec.transition; + } + + if(shouldTransition && + triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && + typeof Promise !== "undefined" && document.startViewTransition){ + var settlePromise = new Promise(function (_resolve, _reject) { + settleResolve = _resolve; + settleReject = _reject; + }); + // wrap the original doSwap() in a call to startViewTransition() + var innerDoSwap = doSwap; + doSwap = function() { + document.startViewTransition(function () { + innerDoSwap(); + return settlePromise; + }); + } + } + + if (swapSpec.swapDelay > 0) { setTimeout(doSwap, swapSpec.swapDelay) } else { @@ -2960,7 +3725,7 @@ return (function () { } } if (isError) { - triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.path}, responseInfo)); + triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo)); } } @@ -3048,9 +3813,22 @@ return (function () { //==================================================================== // Initialization //==================================================================== + var isReady = false + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true + }) + /** + * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. + * + * This function uses isReady because there is no realiable way to ask the browswer whether + * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded + * firing and readystate=complete. + */ function ready(fn) { - if (getDocument().readyState !== 'loading') { + // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by + // some means other than the initial page load. + if (isReady || getDocument().readyState === 'complete') { fn(); } else { getDocument().addEventListener('DOMContentLoaded', fn); @@ -3061,9 +3839,9 @@ return (function () { if (htmx.config.includeIndicatorStyles !== false) { getDocument().head.insertAdjacentHTML("beforeend", "<style>\ - ." + htmx.config.indicatorClass + "{opacity:0;transition: opacity 200ms ease-in;}\ - ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1}\ - ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1}\ + ." + htmx.config.indicatorClass + "{opacity:0}\ + ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ + ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ </style>"); } } @@ -3101,6 +3879,9 @@ return (function () { internalData.xhr.abort(); } }); + /** @type {(ev: PopStateEvent) => any} */ + const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null; + /** @type {(ev: PopStateEvent) => any} */ window.onpopstate = function (event) { if (event.state && event.state.htmx) { restoreHistory(); @@ -3110,10 +3891,15 @@ return (function () { 'triggerEvent': triggerEvent }); }); + } else { + if (originalPopstate) { + originalPopstate(event); + } } }; setTimeout(function () { triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event + body = null; // kill reference for gc }, 0); }) diff --git a/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.min.js b/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.min.js index 998414c..53bbdf6 100644 --- a/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.min.js +++ b/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.min.js @@ -1 +1,4 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(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 l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=k(e);e.classList.toggle(t)}function T(e,t){e=k(e);W(e.parentElement.children,function(e){q(e,t)});L(e,t)}function H(e,t){e=k(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function N(e,t){if(t.indexOf("closest ")===0){return[H(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[C(e,t.substr(5))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return z().querySelectorAll(t)}}function ee(e,t){if(t){return N(e,t)[0]}else{return N(z().body,e)[0]}}function k(e){if(p(e,"String")){return C(e)}else{return e}}function I(e,t,r){if(m(t)){return{target:z().body,event:e,listener:t}}else{return{target:k(e),event:t,listener:r}}}function M(t,r,n){lr(function(){var e=I(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function D(t,r,n){lr(function(){var e=I(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var te=z().createElement("output");function F(e,t){var r=G(e,t);if(r){if(r==="this"){return[re(e,t)]}else{var n=N(e,r);if(n.length===0){pt('The selector "'+r+'" on '+t+" returned no matches!");return[te]}else{return n}}}}function re(e,t){return h(e,function(e){return V(e,t)!=null})}function ne(e){var t=G(e,"hx-target");if(t){if(t==="this"){return re(e,"hx-target")}else{return ee(e,t)}}else{var r=_(e);if(r.boosted){return z().body}else{return e}}}function P(e){var t=U.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function X(t,r){W(t.attributes,function(e){if(!r.hasAttribute(e.name)&&P(e.name)){t.removeAttribute(e.name)}});W(r.attributes,function(e){if(P(e.name)){t.setAttribute(e.name,e.value)}})}function j(e,t){var r=sr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){pt(e)}}return e==="outerHTML"}function B(e,i,o){var t="#"+i.id;var a="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){a=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{a=e}var r=z().querySelectorAll(t);if(r){W(r,function(e){var t;var r=i.cloneNode(true);t=z().createDocumentFragment();t.appendChild(r);if(!j(a,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ye(a,e,e,t,o)}W(o.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(z().body,"htmx:oobErrorNoTarget",{content:i})}return e}function ie(e,r){W(R(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=V(e,"hx-swap-oob");if(t!=null){B(t,e,r)}})}function oe(e){W(R(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=V(e,"id");var r=z().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function ae(n,e,i){W(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();X(e,t);i.tasks.push(function(){X(e,r)})}}})}function se(e){return function(){q(e,U.config.addedClass);ct(e);at(e);le(e);$(e,"htmx:load")}}function le(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ue(e,t,r,n){ae(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(se(i))}}}function fe(t){var e=_(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){W(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){W(t.children,function(e){fe(e)})}}function ce(e,t,r){if(e.tagName==="BODY"){return me(e,t,r)}else{var n;var i=e.previousSibling;ue(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}_(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}fe(e);u(e).removeChild(e)}}function he(e,t,r){return ue(e,e.firstChild,t,r)}function de(e,t,r){return ue(u(e),e,t,r)}function ve(e,t,r){return ue(e,null,t,r)}function ge(e,t,r){return ue(u(e),e.nextSibling,t,r)}function pe(e,t,r){fe(e);return u(e).removeChild(e)}function me(e,t,r){var n=e.firstChild;ue(e,n,t,r);if(n){while(n.nextSibling){fe(n.nextSibling);e.removeChild(n.nextSibling)}fe(n);e.removeChild(n)}}function xe(e,t){var r=G(e,"hx-select");if(r){var n=z().createDocumentFragment();W(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function ye(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":ce(r,n,i);return;case"afterbegin":he(r,n,i);return;case"beforebegin":de(r,n,i);return;case"beforeend":ve(r,n,i);return;case"afterend":ge(r,n,i);return;case"delete":pe(r,n,i);return;default:var o=sr(t);for(var a=0;a<o.length;a++){var f=o[a];try{var s=f.handleSwap(e,r,n,i);if(s){if(typeof s.length!=="undefined"){for(var l=0;l<s.length;l++){var u=s[l];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){i.tasks.push(se(u))}}}return}}catch(e){pt(e)}}if(e==="innerHTML"){me(r,n,i)}else{ye(U.config.defaultSwapStyle,t,r,n,i)}}}function be(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function we(e,t,r,n,i){i.title=be(n);var o=g(n);if(o){ie(o,i);o=xe(r,o);oe(o);return ye(e,r,t,o,i)}}function Se(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!x(a)){a={value:a}}$(r,o,a)}}}else{$(r,n,[])}}var Ee=/\s/;var Ce=/[\s,]/;var Re=/[_$a-zA-Z]/;var Oe=/[_$a-zA-Z0-9]/;var Le=['"',"'","/"];var qe=/[^\s]/;function Ae(e){var t=[];var r=0;while(r<e.length){if(Re.exec(e.charAt(r))){var n=r;while(Oe.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Le.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function Te(e,t,r){return Re.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function He(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Jt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(z().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(Te(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var Ne="input, textarea, select";function ke(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=Ae(t);do{c(n,qe);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var o={trigger:"every"};c(n,qe);o.pollInterval=v(c(n,/[,\[\s]/));c(n,qe);var a=He(e,n,"event");if(a){o.eventFilter=a}r.push(o)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var a=He(e,n,"event");if(a){s.eventFilter=a}while(n.length>0&&n[0]!==","){c(n,qe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Ce))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Ce);if(u==="closest"||u==="find"){n.shift();u+=" "+c(n,Ce)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Ce)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Ce))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Ce)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Ce)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,qe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,Ne)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ie(e){_(e).cancelled=true}function Me(e,t,r,n){var i=_(e);i.timeout=setTimeout(function(){if(Y(e)&&i.cancelled!==true){if(!je(n,dt("hx:poll:trigger",{triggerSpec:n,target:e}))){Z(t,r,e)}Me(e,t,V(e,"hx-"+t),n)}},n.pollInterval)}function De(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&De(t)&&t.target===""||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href");r.pushURL=true}else{var o=f(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=f(t,"action")}e.forEach(function(e){Be(t,n,i,r,e,true)})}}function Pe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&H(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Xe(e,t){return _(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function je(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(z().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Be(o,a,s,e,l,u){var t;if(l.from){t=N(o,l.from)}else{t=[o]}W(t,function(n){var i=function(e){if(!Y(o)){n.removeEventListener(l.trigger,i);return}if(Xe(o,e)){return}if(u||Pe(e,o)){e.preventDefault()}if(je(l,e)){return}var t=_(e);t.triggerSpec=l;if(t.handledFor==null){t.handledFor=[]}var r=_(o);if(t.handledFor.indexOf(o)<0){t.handledFor.push(o);if(l.consume){e.stopPropagation()}if(l.target&&e.target){if(!d(e.target,l.target)){return}}if(l.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(l.changed){if(r.lastValue===o.value){return}else{r.lastValue=o.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(l.throttle){if(!r.throttle){Z(a,s,o,e);r.throttle=setTimeout(function(){r.throttle=null},l.throttle)}}else if(l.delay){r.delayed=setTimeout(function(){Z(a,s,o,e)},l.delay)}else{Z(a,s,o,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:l.trigger,listener:i,on:n});n.addEventListener(l.trigger,i)})}var Ue=false;var Ve=null;function ze(){if(!Ve){Ve=function(){Ue=true};window.addEventListener("scroll",Ve);setInterval(function(){if(Ue){Ue=false;W(z().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){_e(e)})}},200)}}function _e(e){if(!s(e,"data-hx-revealed")&&b(e)){e.setAttribute("data-hx-revealed","true");var t=_(e);if(t.initialized){Z(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Z(t.verb,t.path,e)},{once:true})}}}function We(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Je(e,o[1],0)}if(o[0]==="send"){Ze(e)}}}function Je(s,r,n){if(!Y(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=U.createWebSocket(r);t.onerror=function(e){J(s,"htmx:wsError",{error:e,socket:t});$e(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=Ge(n);setTimeout(function(){Je(s,r,n+1)},t)}};t.onopen=function(e){n=0};_(s).webSocket=t;t.addEventListener("message",function(e){if($e(s)){return}var t=e.data;gt(s,function(e){t=e.transformResponse(t,null,s)});var r=zt(s);var n=g(t);var i=y(n.children);for(var o=0;o<i.length;o++){var a=i[o];B(V(a,"hx-swap-oob")||"true",a,r)}Ct(r.tasks)})}function $e(e){if(!Y(e)){_(e).webSocket.close();return true}}function Ze(u){var f=h(u,function(e){return _(e).webSocket!=null});if(f){u.addEventListener(ke(u)[0].trigger,function(e){var t=_(f).webSocket;var r=Xt(u,f);var n=Mt(u,"post");var i=n.errors;var o=n.values;var a=Gt(u);var s=Q(o,a);var l=jt(s,u);l["HEADERS"]=r;if(i&&i.length>0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Pe(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ge(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}pt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ke(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Ye(e,o[1])}if(o[0]==="swap"){Qe(e,o[1])}}}function Ye(t,e){var r=U.createEventSource(e);r.onerror=function(e){J(t,"htmx:sseError",{error:e,source:r});tt(t)};_(t).sseEventSource=r}function Qe(o,a){var s=h(o,rt);if(s){var l=_(s).sseEventSource;var u=function(e){if(tt(s)){l.removeEventListener(a,u);return}var t=e.data;gt(o,function(e){t=e.transformResponse(t,null,o)});var r=Ut(o);var n=ne(o);var i=zt(o);we(r.swapStyle,o,n,t,i);Ct(i.tasks);$(o,"htmx:sseMessage",e)};_(o).sseListener=u;l.addEventListener(a,u)}else{J(o,"htmx:noSSESourceError")}}function et(e,t,r,n){var i=h(e,rt);if(i){var o=_(i).sseEventSource;var a=function(){if(!tt(i)){if(Y(e)){Z(t,r,e)}else{o.removeEventListener(n,a)}}};_(e).sseListener=a;o.addEventListener(n,a)}else{J(e,"htmx:noSSESourceError")}}function tt(e){if(!Y(e)){_(e).sseEventSource.close();return true}}function rt(e){return _(e).sseEventSource!=null}function nt(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Z(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function it(o,a,e){var t=false;W(n,function(n){if(s(o,"hx-"+n)){var i=V(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){et(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){ze();_e(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=ee(o,e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){$(o,"intersect");break}}},t);r.observe(o);Be(o,n,i,a,e)}else if(e.trigger==="load"){nt(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Me(o,n,i,e)}else{Be(o,n,i,a,e)}})}});return t}function ot(e){if(e.type==="text/javascript"||e.type==="module"||e.type===""){var t=z().createElement("script");W(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(U.config.inlineScriptNonce){t.nonce=U.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){pt(e)}finally{r.removeChild(e)}}}function at(e){if(d(e,"script")){ot(e)}W(R(e,"script"),function(e){ot(e)})}function st(){return document.querySelector("[hx-boost], [data-hx-boost]")}function lt(e){if(e.querySelectorAll){var t=st()?", a, form":"";var r=e.querySelectorAll(i+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [hx-data-ext]");return r}else{return[]}}function ut(r){var e=function(e){if(d(e.target,"button, input[type='submit']")){var t=_(r);t.lastButtonClicked=e.target}};r.addEventListener("click",e);r.addEventListener("focusin",e);r.addEventListener("focusout",function(e){var t=_(r);t.lastButtonClicked=null})}function ft(e){if(e.closest&&e.closest(U.config.disableSelector)){return}var t=_(e);if(!t.initialized){t.initialized=true;$(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=ke(e);var n=it(e,t,r);if(!n&&G(e,"hx-boost")==="true"){Fe(e,t,r)}if(e.tagName==="FORM"){ut(e)}var i=V(e,"hx-sse");if(i){Ke(e,t,i)}var o=V(e,"hx-ws");if(o){We(e,t,o)}$(e,"htmx:afterProcessNode")}}function ct(e){e=k(e);ft(e);W(lt(e),function(e){ft(e)})}function ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function dt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=z().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function J(e,t,r){$(e,t,Q({error:t},r))}function vt(e){return e==="htmx:afterProcessNode"}function gt(e,t){W(sr(e),function(e){try{t(e)}catch(e){pt(e)}})}function pt(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function $(e,t,r){e=k(e);if(r==null){r={}}r["elt"]=e;var n=dt(t,r);if(U.logger&&!vt(t)){U.logger(e,t,r)}if(r.error){pt(r.error);$(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=ht(t);if(i&&o!==t){var a=dt(o,n.detail);i=i&&e.dispatchEvent(a)}gt(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var mt=location.pathname+location.search;function xt(){var e=z().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||z().body}function yt(e,t,r,n){var i=S(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>U.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(z().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function bt(e){var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function wt(e){var t=U.config.requestClass;var r=e.cloneNode(true);W(R(r,"."+t),function(e){q(e,t)});return r.innerHTML}function St(){var e=xt();var t=mt||location.pathname+location.search;$(z().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(U.config.historyEnabled)history.replaceState({htmx:true},z().title,window.location.href);yt(t,wt(e),z().title,window.scrollY)}function Et(e){if(U.config.historyEnabled)history.pushState({htmx:true},"",e);mt=e}function Ct(e){W(e,function(e){e.call()})}function Rt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};$(z().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){$(z().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=xt();var r=zt(t);me(t,e,r);Ct(r.tasks);mt=n;$(z().body,"htmx:historyRestore",{path:n})}else{J(z().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Ot(e){St();e=e||location.pathname+location.search;var t=bt(e);if(t){var r=g(t.content);var n=xt();var i=zt(n);me(n,r,i);Ct(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);mt=e;$(z().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Rt(e)}}}function Lt(e){var t=G(e,"hx-push-url");return t&&t!=="false"||_(e).boosted&&_(e).pushURL}function qt(e){var t=G(e,"hx-push-url");return t==="true"||t==="false"?null:t}function At(e){var t=F(e,"hx-indicator");if(t==null){t=[e]}W(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Tt(e){W(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function Ht(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Nt(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 kt(t,r,n,e,i){if(e==null||Ht(t,e)){return}else{t.push(e)}if(Nt(e)){var o=f(e,"name");var a=e.value;if(e.multiple){a=y(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=y(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){It(e,n)}}if(d(e,"form")){var l=e.elements;W(l,function(e){kt(t,r,n,e,i)})}}function It(e,t){if(e.willValidate){$(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});$(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Mt(e,t){var r=[];var n={};var i={};var o=[];var a=_(e);var s=d(e,"form")&&e.noValidate!==true;if(a.lastButtonClicked){s=s&&a.lastButtonClicked.formNoValidate!==true}if(t!=="get"){kt(r,i,o,H(e,"form"),s)}kt(r,n,o,e,s);if(a.lastButtonClicked){var l=f(a.lastButtonClicked,"name");if(l){n[l]=a.lastButtonClicked.value}}var u=F(e,"hx-include");W(u,function(e){kt(r,n,o,e,s);if(!d(e,"form")){W(e.querySelectorAll(Ne),function(e){kt(r,n,o,e,s)})}});n=Q(n,i);return{errors:o,values:n}}function Dt(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function Ft(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=Dt(t,r,e)})}else{t=Dt(t,r,n)}}}return t}function Pt(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){W(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Xt(e,t,r){var n={"HX-Request":"true","HX-Trigger":f(e,"id"),"HX-Trigger-Name":f(e,"name"),"HX-Target":V(t,"id"),"HX-Current-URL":z().location.href};Wt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(_(e).boosted){n["HX-Boosted"]="true"}return n}function jt(t,e){var r=G(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){W(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};W(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Bt(e){return f(e,"href")&&f(e,"href").indexOf("#")>=0}function Ut(e,t){var r=t?t:G(e,"hx-swap");var n={swapStyle:_(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(_(e).boosted&&!Bt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var o=1;o<i.length;o++){var a=i[o];if(a.indexOf("swap:")===0){n["swapDelay"]=v(a.substr(5))}if(a.indexOf("settle:")===0){n["settleDelay"]=v(a.substr(7))}if(a.indexOf("scroll:")===0){var s=a.substr(7);var l=s.split(":");var f=l.pop();var u=l.length>0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(a.indexOf("show:")===0){var c=a.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(a.indexOf("focus-scroll:")===0){var d=a.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function Vt(t,r,n){var i=null;gt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(G(r,"hx-encoding")==="multipart/form-data"||d(r,"form")&&f(r,"enctype")==="multipart/form-data"){return Pt(n)}else{return Ft(n)}}}function zt(e){return{tasks:[],elts:[e]}}function _t(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ee(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var o=t.showTarget;if(t.showTarget==="window"){o="body"}i=ee(r,o)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function Wt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}else if(o.indexOf("js:")===0){o=o.substr(3);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Jt(e,function(){return Function("return ("+o+")")()},{})}else{s=S(o)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Wt(u(e),t,r,n)}function Jt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function $t(e,t){return Wt(e,"hx-vars",true,t)}function Zt(e,t){return Wt(e,"hx-vals",false,t)}function Gt(e){return Q($t(e),Zt(e))}function Kt(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Yt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(z().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Qt(e,t){return e.getAllResponseHeaders().match(t)}function er(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return Z(e,t,null,null,{targetOverride:k(r),returnPromise:true})}else{return Z(e,t,k(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:k(r.target),swapOverride:r.swap,returnPromise:true})}}else{return Z(e,t,null,null,{returnPromise:true})}}function tr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Z(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=z().body}var v=r.handler||rr;if(!Y(n)){return}var g=r.targetOverride||ne(n);if(g==null||g==te){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=_(n);var o=G(n,"hx-sync");var m=null;var x=false;if(o){var y=o.split(":");var b=y[0].trim();if(b==="this"){p=re(n,"hx-sync")}else{p=ee(n,b)}o=(y[1]||"drop").trim();i=_(p);if(o==="drop"&&i.xhr&&i.abortable!==true){return}else if(o==="abort"){if(i.xhr){return}else{x=true}}else if(o==="replace"){$(p,"htmx:abort")}else if(o.indexOf("queue")===0){var w=o.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=_(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){Z(e,t,n,f,r)})}return}}var a=new XMLHttpRequest;i.xhr=a;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=G(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){K(c);s();return d}}var R=G(n,"hx-confirm");if(R){if(!confirm(R)){K(c);s();return d}}var O=Xt(n,g,C);if(r.headers){O=Q(O,r.headers)}var L=Mt(n,e);var q=L.errors;var A=L.values;if(r.values){A=Q(A,r.values)}var T=Gt(n);var H=Q(A,T);var N=jt(H,n);if(e!=="get"&&G(n,"hx-encoding")==null){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=z().location.href}var k=Wt(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:q,withCredentials:r.credentials||k.credentials||U.config.withCredentials,timeout:r.timeout||k.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){K(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;q=l.errors;if(q&&q.length>0){$(n,"htmx:validation:halted",l);K(c);s();return d}var I=t.split("#");var M=I[0];var D=I[1];if(e==="get"){var F=M;var P=Object.keys(N).length!==0;if(P){if(F.indexOf("?")<0){F+="?"}else{F+="&"}F+=Ft(N);if(D){F+="#"+D}}a.open("GET",F,true)}else{a.open(e.toUpperCase(),t,true)}a.overrideMimeType("text/html");a.withCredentials=l.withCredentials;a.timeout=l.timeout;if(k.noHeaders){}else{for(var X in O){if(O.hasOwnProperty(X)){var j=O[X];Kt(a,X,j)}}}var u={xhr:a,target:g,requestConfig:l,etc:r,pathInfo:{path:t,finalPath:F,anchor:D}};a.onload=function(){try{var e=tr(n);v(n,u);Tt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!Y(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(Y(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}K(c);s()}catch(e){J(n,"htmx:onLoadError",Q({error:e},u));throw e}};a.onerror=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);K(h);s()};a.onabort=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);K(h);s()};a.ontimeout=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);K(h);s()};if(!$(n,"htmx:beforeRequest",u)){K(c);s();return d}var B=At(n);W(["loadstart","loadend","progress","abort"],function(t){W([a,a.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);a.send(e==="get"?null:Vt(a,n,N));return d}function rr(s,l){var u=l.xhr;var f=l.target;var r=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(Qt(u,/HX-Trigger:/i)){Se(u,"HX-Trigger",s)}if(Qt(u,/HX-Push:/i)){var c=u.getResponseHeader("HX-Push")}if(Qt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Qt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(Qt(u,/HX-Retarget:/i)){l.target=z().querySelector(u.getResponseHeader("HX-Retarget"))}var h;if(c=="false"){h=false}else{h=Lt(s)||c}var n=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var e=u.status>=400;var t=Q({shouldSwap:n,serverResponse:d,isError:e},l);if(!$(f,"htmx:beforeSwap",t))return;f=t.target;d=t.serverResponse;e=t.isError;l.failed=e;l.successful=!e;if(t.shouldSwap){if(u.status===286){Ie(s)}gt(s,function(e){d=e.transformResponse(d,u,s)});if(h){St()}var i=r.swapOverride;var v=Ut(s,i);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=zt(f);we(v.swapStyle,f,s,d,n);if(t.elt&&!Y(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);W(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(l.pathInfo.anchor){location.hash=l.pathInfo.anchor}if(Qt(u,/HX-Trigger-After-Swap:/i)){var o=s;if(!Y(s)){o=z().body}Se(u,"HX-Trigger-After-Swap",o)}var a=function(){W(n.tasks,function(e){e.call()});W(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h){var e=c||qt(s)||Yt(u)||l.pathInfo.finalPath||l.pathInfo.path;Et(e);$(z().body,"htmx:pushedIntoHistory",{path:e})}if(n.title){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}_t(n.elts,v);if(Qt(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!Y(s)){r=z().body}Se(u,"HX-Trigger-After-Settle",r)}};if(v.settleDelay>0){setTimeout(a,v.settleDelay)}else{a()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(v.swapDelay>0){setTimeout(o,v.swapDelay)}else{o()}}if(e){J(s,"htmx:responseError",Q({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var nr={};function ir(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function or(e,t){if(t.init){t.init(r)}nr[e]=Q(ir(),t)}function ar(e){delete nr[e]}function sr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){W(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=nr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return sr(u(e),r,n)}function lr(e){if(z().readyState!=="loading"){e()}else{z().addEventListener("DOMContentLoaded",e)}}function ur(){if(U.config.includeIndicatorStyles!==false){z().head.insertAdjacentHTML("beforeend","<style> ."+U.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+U.config.requestClass+" ."+U.config.indicatorClass+"{opacity:1} ."+U.config.requestClass+"."+U.config.indicatorClass+"{opacity:1} </style>")}}function fr(){var e=z().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function cr(){var e=fr();if(e){U.config=Q(U.config,e)}}lr(function(){cr();ur();var e=z().body;ct(e);var t=z().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=_(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){Ot();W(t,function(e){$(e,"htmx:restored",{document:z(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file +// /////////////////////////////////////////////////////////////////// +// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js +// +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(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 a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/<body/.test(e)}function l(e){var t=!N(e);var r=A(e);var n=e;if(r==="head"){n=n.replace(S,"")}if(Q.config.useTemplateFragments&&t){var i=a("<body><template>"+n+"</template></body>",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a("<table>"+n+"</table>",1);case"col":return a("<table><colgroup>"+n+"</colgroup></table>",2);case"tr":return a("<table><tbody>"+n+"</tbody></table>",2);case"td":case"th":return a("<table><tbody><tr>"+n+"</tr></tbody></table>",3);case"script":case"style":return a("<div>"+n+"</div>",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function oe(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function X(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var Y=function(e,t){var r=re().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function we(t,r){oe(t.attributes,function(e){if(!r.hasAttribute(e.name)&&be(e.name)){t.removeAttribute(e.name)}});oe(r.attributes,function(e){if(be(e.name)){t.setAttribute(e.name,e.value)}})}function Se(e,t){var r=Fr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){b(e)}}return e==="outerHTML"}function Ee(e,i,a){var t="#"+ee(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a<i.length;a++){var o=i[a].split(":",2);var s=o[0].trim();if(s.indexOf("#")===0){s=s.substring(1)}var l=o[1]||"true";var u=t.querySelector("#"+s);if(u){Ee(l,u,r)}}}oe(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=te(e,"hx-swap-oob");if(t!=null){Ee(t,e,r)}})}function Re(e){oe(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=te(e,"id");var r=re().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function Te(o,e,s){oe(e.querySelectorAll("[id]"),function(e){var t=ee(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Le(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=He(n.name,t);t=He(n.value,t)}}}return t}function Ae(e){var t=ae(e);if(t.onHandlers){for(var r=0;r<t.onHandlers.length;r++){const n=t.onHandlers[r];e.removeEventListener(n.event,n.listener)}delete t.onHandlers}}function Ne(e){var t=ae(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){oe(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}Ae(e);oe(Object.keys(t),function(e){delete t[e]})}function p(e){ce(e,"htmx:beforeCleanupElement");Ne(e);if(e.children){oe(e.children,function(e){p(e)})}}function Ie(t,e,r){if(t.tagName==="BODY"){return Ue(t,e,r)}else{var n;var i=t.previousSibling;m(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}p(t);u(t).removeChild(t)}}function ke(e,t,r){return m(e,e.firstChild,t,r)}function Pe(e,t,r){return m(u(e),e,t,r)}function Me(e,t,r){return m(e,null,t,r)}function Xe(e,t,r){return m(u(e),e.nextSibling,t,r)}function De(e,t,r){p(e);return u(e).removeChild(e)}function Ue(e,t,r){var n=e.firstChild;m(e,n,t,r);if(n){while(n.nextSibling){p(n.nextSibling);e.removeChild(n.nextSibling)}p(n);e.removeChild(n)}}function Be(e,t,r){var n=r||ne(e,"hx-select");if(n){var i=re().createDocumentFragment();oe(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function Fe(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Ie(r,n,i);return;case"afterbegin":ke(r,n,i);return;case"beforebegin":Pe(r,n,i);return;case"beforeend":Me(r,n,i);return;case"afterend":Xe(r,n,i);return;case"delete":De(r,n,i);return;default:var a=Fr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Oe(f))}}}return}}catch(e){b(e)}}if(e==="innerHTML"){Ue(r,n,i)}else{Fe(Q.config.defaultSwapStyle,t,r,n,i)}}}function Ve(e){if(e.indexOf("<title")>-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){ce(r,s[l].trim(),[])}}}var ze=/\s/;var x=/[\s,]/;var $e=/[_$a-zA-Z]/;var We=/[_$a-zA-Z0-9]/;var Ge=['"',"'","/"];var Je=/[^\s]/;var Ze=/[{(]/;var Ke=/[})]/;function Ye(e){var t=[];var r=0;while(r<e.length){if($e.exec(e.charAt(r))){var n=r;while(We.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ge.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function Qe(e,t,r){return $e.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function et(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){xt(e,a[1],0)}if(a[0]==="send"){bt(e)}}}function xt(s,r,n){if(!se(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=Q.createWebSocket(r);t.onerror=function(e){fe(s,"htmx:wsError",{error:e,socket:t});yt(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a<i.length;a++){var o=i[a];Ee(te(o,"hx-swap-oob")||"true",o,r)}nr(r.tasks)})}function yt(e){if(!se(e)){ae(e).webSocket.close();return true}}function bt(u){var f=c(u,function(e){return ae(e).webSocket!=null});if(f){u.addEventListener(it(u)[0].trigger,function(e){var t=ae(f).webSocket;var r=xr(u,f);var n=dr(u,"post");var i=n.errors;var a=n.values;var o=Hr(u);var s=le(a,o);var l=yr(s,u);l["HEADERS"]=r;if(i&&i.length>0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){Et(e,a[1])}if(a[0]==="swap"){Ct(e,a[1])}}}function Et(t,e){var r=Q.createEventSource(e);r.onerror=function(e){fe(t,"htmx:sseError",{error:e,source:r});Tt(t)};ae(t).sseEventSource=r}function Ct(a,o){var s=c(a,Ot);if(s){var l=ae(s).sseEventSource;var u=function(e){if(Tt(s)){return}if(!se(a)){l.removeEventListener(o,u);return}var t=e.data;R(a,function(e){t=e.transformResponse(t,null,a)});var r=wr(a);var n=ye(a);var i=T(a);je(r.swapStyle,n,a,t,i);nr(i.tasks);ce(a,"htmx:sseMessage",e)};ae(a).sseListener=u;l.addEventListener(o,u)}else{fe(a,"htmx:noSSESourceError")}}function Rt(e,t,r){var n=c(e,Ot);if(n){var i=ae(n).sseEventSource;var a=function(){if(!Tt(n)){if(se(e)){t(e)}else{i.removeEventListener(r,a)}}};ae(e).sseListener=a;i.addEventListener(r,a)}else{fe(e,"htmx:noSSESourceError")}}function Tt(e){if(!se(e)){ae(e).sseEventSource.close();return true}}function Ot(e){return ae(e).sseEventSource!=null}function qt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n>0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){ce(n,"intersect");break}}},i);a.observe(n);ht(n,r,t,e)}else if(e.trigger==="load"){if(!ct(e,n,Wt("load",{elt:n}))){qt(n,r,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r<t.length;r++){var n=t[r].name;if(s(n,"hx-on:")||s(n,"data-hx-on:")||s(n,"hx-on-")||s(n,"data-hx-on-")){return true}}return false}function kt(e){var t=null;var r=[];if(It(e)){r.push(e)}if(document.evaluate){var n=document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]',e);while(t=n.iterateNext())r.push(t)}else{var i=e.getElementsByTagName("*");for(var a=0;a<i.length;a++){if(It(i[a])){r.push(i[a])}}}return r}function Pt(e){if(e.querySelectorAll){var t=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";var r=e.querySelectorAll(i+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Mt(e){var t=v(e.target,"button, input[type='submit']");var r=Dt(e);if(r){r.lastButtonClicked=t}}function Xt(e){var t=Dt(e);if(t){t.lastButtonClicked=null}}function Dt(e){var t=v(e.target,"button, input[type='submit']");if(!t){return}var r=g("#"+ee(t,"form"))||v(t,"form");if(!r){return}return ae(r)}function Ut(e){e.addEventListener("click",Mt);e.addEventListener("focusin",Mt);e.addEventListener("focusout",Xt)}function Bt(e){var t=Ye(e);var r=0;for(var n=0;n<t.length;n++){const i=t[n];if(i==="{"){r++}else if(i==="}"){r--}}return r}function Ft(t,e,r){var n=ae(t);if(!Array.isArray(n.onHandlers)){n.onHandlers=[]}var i;var a=function(e){return Tr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Vt(e){var t=te(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;t<e.attributes.length;t++){var r=e.attributes[t].name;var n=e.attributes[t].value;if(s(r,"hx-on")||s(r,"data-hx-on")){var i=r.indexOf("-on")+3;var a=r.slice(i,i+1);if(a==="-"||a===":"){var o=r.slice(i+1);if(s(o,":")){o="htmx"+o}else if(s(o,"-")){o="htmx:"+o.slice(1)}else if(s(o,"htmx-")){o="htmx:"+o.slice(5)}Ft(e,o,n)}}}}function _t(t){if(v(t,Q.config.disableSelector)){p(t);return}var r=ae(t);if(r.initHash!==Le(t)){Ne(t);r.initHash=Le(t);Vt(t);ce(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=it(t);var n=Ht(t,r,e);if(!n){if(ne(t,"hx-boost")==="true"){lt(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){Lt(t,e,r,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&o(t,"form")){Ut(t)}var i=te(t,"hx-sse");if(i){St(t,r,i)}var a=te(t,"hx-ws");if(a){pt(t,r,a)}ce(t,"htmx:afterProcessNode")}}function zt(e){e=g(e);if(v(e,Q.config.disableSelector)){p(e);return}_t(e);oe(Pt(e),function(e){_t(e)});oe(kt(e),jt)}function $t(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=re().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function fe(e,t,r){ce(e,t,le({error:t},r))}function Gt(e){return e==="htmx:afterProcessNode"}function R(e,t){oe(Fr(e),function(e){try{t(e)}catch(e){b(e)}})}function b(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ce(e,t,r){e=g(e);if(r==null){r={}}r["elt"]=e;var n=Wt(t,r);if(Q.logger&&!Gt(t)){Q.logger(e,t,r)}if(r.error){b(r.error);ce(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=$t(t);if(i&&a!==t){var o=Wt(a,n.detail);i=i&&e.dispatchEvent(o)}R(e,function(e){i=i&&(e.onEvent(t,n)!==false&&!n.defaultPrevented)});return i}var Jt=location.pathname+location.search;function Zt(){var e=re().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||re().body}function Kt(e,t,r,n){if(!U()){return}if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}e=B(e);var i=E(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};ce(re().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Qt(e){var t=Q.config.requestClass;var r=e.cloneNode(true);oe(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function er(){var e=Zt();var t=Jt||location.pathname+location.search;var r;try{r=re().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){r=re().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!r){ce(re().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Kt(t,Qt(e),re().title,window.scrollY)}if(Q.config.historyEnabled)history.replaceState({htmx:true},re().title,window.location.href)}function tr(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(G(e,"&")||G(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Jt=e}function rr(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Jt=e}function nr(e){oe(e,function(e){e.call()})}function ir(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};ce(re().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",re().location.href);e.onload=function(){if(this.status>=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function fr(e){if(e.name===""||e.name==null||e.disabled||v(e,"fieldset[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 cr(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function hr(t,r,n,e,i){if(e==null||ur(t,e)){return}else{t.push(e)}if(fr(e)){var a=ee(e,"name");var o=e.value;if(e.multiple&&e.tagName==="SELECT"){o=M(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=M(e.files)}cr(a,o,r);if(i){vr(e,n)}}if(h(e,"form")){var s=e.elements;oe(s,function(e){hr(t,r,n,e,i)})}}function vr(e,t){if(e.willValidate){ce(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});ce(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function dr(e,t){var r=[];var n={};var i={};var a=[];var o=ae(e);if(o.lastButtonClicked&&!se(o.lastButtonClicked)){o.lastButtonClicked=null}var s=h(e,"form")&&e.noValidate!==true||te(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){hr(r,i,a,v(e,"form"),s)}hr(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=ee(l,"name");cr(u,l.value,i)}var f=pe(e,"hx-include");oe(f,function(e){hr(r,n,a,e,s);if(!h(e,"form")){oe(e.querySelectorAll(rt),function(e){hr(r,n,a,e,s)})}});n=le(n,i);return{errors:a,values:n}}function gr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function mr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t=gr(t,r,e)})}else{t=gr(t,r,n)}}}return t}function pr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function xr(e,t,r){var n={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":re().location.href};Rr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ae(e).boosted){n["HX-Boosted"]="true"}return n}function yr(t,e){var r=ne(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){oe(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};oe(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function br(e){return ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=d(o.substr(5))}else if(o.indexOf("settle:")===0){n["settleDelay"]=d(o.substr(7))}else if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}else if(o.indexOf("ignoreTitle:")===0){n["ignoreTitle"]=o.substr(12)==="true"}else if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","<style> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file diff --git a/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.js b/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.js index 27e57bc..86e7668 100644 --- a/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.js +++ b/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.js @@ -1,13 +1,23 @@ -//AMD insanity +// /////////////////////////////////////////////////////////////////// +// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.js +// + +// UMD insanity +// This code sets up support for (in order) AMD, ES6 modules, and globals. (function (root, factory) { //@ts-ignore if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. //@ts-ignore define([], factory); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); } else { // Browser globals - root.htmx = factory(); + root.htmx = root.htmx || factory(); } }(typeof self !== 'undefined' ? self : this, function () { return (function () { @@ -38,6 +48,7 @@ return (function () { defineExtension : defineExtension, removeExtension : removeExtension, logAll : logAll, + logNone : logNone, logger : null, config : { historyEnabled:true, @@ -53,15 +64,24 @@ return (function () { settlingClass:'htmx-settling', swappingClass:'htmx-swapping', allowEval:true, + allowScriptTags:true, inlineScriptNonce:'', attributesToSettle:["class", "style", "width", "height"], withCredentials:false, timeout:0, wsReconnectDelay: 'full-jitter', + wsBinaryType: 'blob', disableSelector: "[hx-disable], [data-hx-disable]", useTemplateFragments: false, scrollBehavior: 'smooth', defaultFocusScroll: false, + getCacheBusterParam: false, + globalViewTransitions: false, + methodsThatUseUrlParams: ["get"], + selfRequestsOnly: false, + ignoreTitle: false, + scrollIntoViewOnBoost: true, + triggerSpecsCache: null, }, parseInterval:parseInterval, _:internalEval, @@ -69,17 +89,23 @@ return (function () { return new EventSource(url, {withCredentials:true}) }, createWebSocket: function(url){ - return new WebSocket(url, []); + var sock = new WebSocket(url, []); + sock.binaryType = htmx.config.wsBinaryType; + return sock; }, - version: "1.7.0" + version: "1.9.10" }; /** @type {import("./htmx").HtmxInternalApi} */ var internalAPI = { + addTriggerHandler: addTriggerHandler, bodyContains: bodyContains, + canAccessLocalStorage: canAccessLocalStorage, + findThisElement: findThisElement, filterValues: filterValues, hasAttribute: hasAttribute, getAttributeValue: getAttributeValue, + getClosestAttributeValue: getClosestAttributeValue, getClosestMatch: getClosestMatch, getExpressionVars: getExpressionVars, getHeaders: getHeaders, @@ -92,6 +118,7 @@ return (function () { mergeObjects: mergeObjects, makeSettleInfo: makeSettleInfo, oobSwap: oobSwap, + querySelectorExt: querySelectorExt, selectAndSwap: selectAndSwap, settleImmediately: settleImmediately, shouldCancel: shouldCancel, @@ -105,21 +132,40 @@ return (function () { return "[hx-" + verb + "], [data-hx-" + verb + "]" }).join(", "); + var HEAD_TAG_REGEX = makeTagRegEx('head'), + TITLE_TAG_REGEX = makeTagRegEx('title'), + SVG_TAGS_REGEX = makeTagRegEx('svg', true); + //==================================================================== // Utilities //==================================================================== + /** + * @param {string} tag + * @param {boolean} global + * @returns {RegExp} + */ + function makeTagRegEx(tag, global = false) { + return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, + global ? 'gim' : 'im'); + } + function parseInterval(str) { if (str == undefined) { - return undefined + return undefined; } + + let interval = NaN; if (str.slice(-2) == "ms") { - return parseFloat(str.slice(0,-2)) || undefined - } - if (str.slice(-1) == "s") { - return (parseFloat(str.slice(0,-1)) * 1000) || undefined + interval = parseFloat(str.slice(0, -2)); + } else if (str.slice(-1) == "s") { + interval = parseFloat(str.slice(0, -1)) * 1000; + } else if (str.slice(-1) == "m") { + interval = parseFloat(str.slice(0, -1)) * 1000 * 60; + } else { + interval = parseFloat(str); } - return parseFloat(str) || undefined + return isNaN(interval) ? undefined : interval; } /** @@ -168,13 +214,11 @@ return (function () { * @returns {HTMLElement | null} */ function getClosestMatch(elt, condition) { - if (condition(elt)) { - return elt; - } else if (parentElt(elt)) { - return getClosestMatch(parentElt(elt), condition); - } else { - return null; + while (elt && !condition(elt)) { + elt = parentElt(elt); } + + return elt ? elt : null; } function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ @@ -208,7 +252,7 @@ return (function () { * @returns {boolean} */ function matches(elt, selector) { - // @ts-ignore: non-standard properties for browser compatability + // @ts-ignore: non-standard properties for browser compatibility // noinspection JSUnresolvedVariable var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; return matchesFunction && matchesFunction.call(elt, selector); @@ -252,38 +296,47 @@ return (function () { return responseNode; } + function aFullPageResponse(resp) { + return /<body/.test(resp) + } + /** * - * @param {string} resp + * @param {string} response * @returns {Element} */ - function makeFragment(resp) { - if (htmx.config.useTemplateFragments) { - var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0); + function makeFragment(response) { + var partialResponse = !aFullPageResponse(response); + var startTag = getStartTag(response); + var content = response; + if (startTag === 'head') { + content = content.replace(HEAD_TAG_REGEX, ''); + } + if (htmx.config.useTemplateFragments && partialResponse) { + var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0); // @ts-ignore type mismatch between DocumentFragment and Element. - // TODO: Are these close enough for htmx to use interchangably? + // TODO: Are these close enough for htmx to use interchangeably? return documentFragment.querySelector('template').content; - } else { - 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); - case "script": - return parseHTML("<div>" + resp + "</div>", 1); - default: - return parseHTML(resp, 0); - } + } + switch (startTag) { + case "thead": + case "tbody": + case "tfoot": + case "colgroup": + case "caption": + return parseHTML("<table>" + content + "</table>", 1); + case "col": + return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2); + case "tr": + return parseHTML("<table><tbody>" + content + "</tbody></table>", 2); + case "td": + case "th": + return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3); + case "script": + case "style": + return parseHTML("<div>" + content + "</div>", 1); + default: + return parseHTML(content, 0); } } @@ -365,13 +418,14 @@ return (function () { return elemTop < window.innerHeight && elemBottom >= 0; } - function bodyContains(elt) { - if (elt.getRootNode() instanceof ShadowRoot) { - return getDocument().body.contains(elt.getRootNode().host); - } else { - return getDocument().body.contains(elt); - } - } + function bodyContains(elt) { + // IE Fix + if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) { + return getDocument().body.contains(elt.getRootNode().host); + } else { + return getDocument().body.contains(elt); + } + } function splitOnWhitespace(trigger) { return trigger.trim().split(/\s+/); @@ -402,6 +456,34 @@ return (function () { } } + function canAccessLocalStorage() { + var test = 'htmx:localStorageTest'; + try { + localStorage.setItem(test, test); + localStorage.removeItem(test); + return true; + } catch(e) { + return false; + } + } + + function normalizePath(path) { + try { + var url = new URL(path); + if (url) { + path = url.pathname + url.search; + } + // remove trailing slash, unless index page + if (!(/^\/$/.test(path))) { + path = path.replace(/\/+$/, ''); + } + return path; + } catch (e) { + // be kind to IE11, which doesn't support URL() + return path; + } + } + //========================================================================================== // public API //========================================================================================== @@ -427,6 +509,10 @@ return (function () { } } + function logNone() { + htmx.logger = null + } + function find(eltOrSelector, selector) { if (selector) { return eltOrSelector.querySelector(selector); @@ -446,7 +532,10 @@ return (function () { function removeElement(elt, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeElement(elt);}, delay) + setTimeout(function(){ + removeElement(elt); + elt = null; + }, delay); } else { elt.parentElement.removeChild(elt); } @@ -455,7 +544,10 @@ return (function () { function addClassToElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){addClassToElement(elt, clazz);}, delay) + setTimeout(function(){ + addClassToElement(elt, clazz); + elt = null; + }, delay); } else { elt.classList && elt.classList.add(clazz); } @@ -464,7 +556,10 @@ return (function () { function removeClassFromElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) + setTimeout(function(){ + removeClassFromElement(elt, clazz); + elt = null; + }, delay); } else { if (elt.classList) { elt.classList.remove(clazz); @@ -494,26 +589,75 @@ return (function () { if (elt.closest) { return elt.closest(selector); } else { + // TODO remove when IE goes away do{ if (elt == null || matches(elt, selector)){ return elt; } } while (elt = elt && parentElt(elt)); + return null; + } + } + + function startsWith(str, prefix) { + return str.substring(0, prefix.length) === prefix + } + + function endsWith(str, suffix) { + return str.substring(str.length - suffix.length) === suffix + } + + function normalizeSelector(selector) { + var trimmedSelector = selector.trim(); + if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) { + return trimmedSelector.substring(1, trimmedSelector.length - 2); + } else { + return trimmedSelector; } } function querySelectorAllExt(elt, selector) { if (selector.indexOf("closest ") === 0) { - return [closest(elt, selector.substr(8))]; + return [closest(elt, normalizeSelector(selector.substr(8)))]; } else if (selector.indexOf("find ") === 0) { - return [find(elt, selector.substr(5))]; + return [find(elt, normalizeSelector(selector.substr(5)))]; + } else if (selector === "next") { + return [elt.nextElementSibling] + } else if (selector.indexOf("next ") === 0) { + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; + } else if (selector === "previous") { + return [elt.previousElementSibling] + } else if (selector.indexOf("previous ") === 0) { + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; } else if (selector === 'document') { return [document]; } else if (selector === 'window') { return [window]; + } else if (selector === 'body') { + return [document.body]; } else { - return getDocument().querySelectorAll(selector); + return getDocument().querySelectorAll(normalizeSelector(selector)); + } + } + + var scanForwardQuery = function(start, match) { + var results = getDocument().querySelectorAll(match); + for (var i = 0; i < results.length; i++) { + var elt = results[i]; + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { + return elt; + } + } + } + + var scanBackwardsQuery = function(start, match) { + var results = getDocument().querySelectorAll(match); + for (var i = results.length - 1; i >= 0; i--) { + var elt = results[i]; + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { + return elt; + } } } @@ -570,7 +714,7 @@ return (function () { //==================================================================== // Node processing //==================================================================== - + var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors function findAttributeTargets(elt, attrName) { var attrTarget = getClosestAttributeValue(elt, attrName); @@ -659,7 +803,7 @@ return (function () { * @returns */ function oobSwap(oobValue, oobElement, settleInfo) { - var selector = "#" + oobElement.id; + var selector = "#" + getRawAttribute(oobElement, "id"); var swapStyle = "outerHTML"; if (oobValue === "true") { // do nothing @@ -703,7 +847,23 @@ return (function () { return oobValue; } - function handleOutOfBandSwaps(fragment, settleInfo) { + function handleOutOfBandSwaps(elt, fragment, settleInfo) { + var oobSelects = getClosestAttributeValue(elt, "hx-select-oob"); + if (oobSelects) { + var oobSelectValues = oobSelects.split(","); + for (var i = 0; i < oobSelectValues.length; i++) { + var oobSelectValue = oobSelectValues[i].split(":", 2); + var id = oobSelectValue[0].trim(); + if (id.indexOf("#") === 0) { + id = id.substring(1); + } + var oobValue = oobSelectValue[1] || "true"; + var oobElement = fragment.querySelector("#" + id); + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo); + } + } + } forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) { var oobValue = getAttributeValue(oobElement, "hx-swap-oob"); if (oobValue != null) { @@ -724,8 +884,11 @@ return (function () { function handleAttributes(parentNode, fragment, settleInfo) { forEach(fragment.querySelectorAll("[id]"), function (newNode) { - if (newNode.id && newNode.id.length > 0) { - var oldNode = parentNode.querySelector(newNode.tagName + "[id='" + newNode.id + "']"); + var id = getRawAttribute(newNode, "id") + if (id && id.length > 0) { + var normalizedId = id.replace("'", "\\'"); + var normalizedTag = newNode.tagName.replace(':', '\\:'); + var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']"); if (oldNode && oldNode !== parentNode) { var newAttributes = newNode.cloneNode(); cloneAttributes(newNode, oldNode); @@ -767,24 +930,67 @@ return (function () { } } - function cleanUpElement(element) { + // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, + // derived from Java's string hashcode implementation + function stringHash(string, hash) { + var char = 0; + while (char < string.length){ + hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int + } + return hash; + } + + function attributeHash(elt) { + var hash = 0; + // IE fix + if (elt.attributes) { + for (var i = 0; i < elt.attributes.length; i++) { + var attribute = elt.attributes[i]; + if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent) + hash = stringHash(attribute.name, hash); + hash = stringHash(attribute.value, hash); + } + } + } + return hash; + } + + function deInitOnHandlers(elt) { + var internalData = getInternalData(elt); + if (internalData.onHandlers) { + for (var i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i]; + elt.removeEventListener(handlerInfo.event, handlerInfo.listener); + } + delete internalData.onHandlers + } + } + + function deInitNode(element) { var internalData = getInternalData(element); + if (internalData.timeout) { + clearTimeout(internalData.timeout); + } if (internalData.webSocket) { internalData.webSocket.close(); } if (internalData.sseEventSource) { internalData.sseEventSource.close(); } - - triggerEvent(element, "htmx:beforeCleanupElement") - if (internalData.listenerInfos) { - forEach(internalData.listenerInfos, function(info) { - if (element !== info.on) { + forEach(internalData.listenerInfos, function (info) { + if (info.on) { info.on.removeEventListener(info.trigger, info.listener); } }); } + deInitOnHandlers(element); + forEach(Object.keys(internalData), function(key) { delete internalData[key] }); + } + + function cleanUpElement(element) { + triggerEvent(element, "htmx:beforeCleanupElement") + deInitNode(element); if (element.children) { // IE forEach(element.children, function(child) { cleanUpElement(child) }); } @@ -803,8 +1009,7 @@ return (function () { } else { newElt = eltBeforeNewContent.nextSibling; } - getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later - settleInfo.elts = [] // clear existing elements + settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target }); while(newElt && newElt !== target) { if (newElt.nodeType === Node.ELEMENT_NODE) { settleInfo.elts.push(newElt); @@ -849,8 +1054,8 @@ return (function () { } } - function maybeSelectFromResponse(elt, fragment) { - var selector = getClosestAttributeValue(elt, "hx-select"); + function maybeSelectFromResponse(elt, fragment, selectOverride) { + var selector = selectOverride || getClosestAttributeValue(elt, "hx-select"); if (selector) { var newFragment = getDocument().createDocumentFragment(); forEach(fragment.querySelectorAll(selector), function (node) { @@ -915,21 +1120,20 @@ return (function () { function findTitle(content) { if (content.indexOf('<title') > -1) { - var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, ''); - var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im); - + var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, ''); + var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX); if (result) { return result[2]; } } } - function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) { + function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) { settleInfo.title = findTitle(responseText); var fragment = makeFragment(responseText); if (fragment) { - handleOutOfBandSwaps(fragment, settleInfo); - fragment = maybeSelectFromResponse(elt, fragment); + handleOutOfBandSwaps(elt, fragment, settleInfo); + fragment = maybeSelectFromResponse(elt, fragment, selectOverride); handlePreservedElements(fragment); return swap(swapStyle, elt, target, fragment, settleInfo); } @@ -949,7 +1153,10 @@ return (function () { } } } else { - triggerEvent(elt, triggerBody, []); + var eventNames = triggerBody.split(",") + for (var i = 0; i < eventNames.length; i++) { + triggerEvent(elt, eventNames[i].trim(), []); + } } } @@ -959,6 +1166,8 @@ return (function () { var SYMBOL_CONT = /[_$a-zA-Z0-9]/; var STRINGISH_START = ['"', "'", "/"]; var NOT_WHITESPACE = /[^\s]/; + var COMBINED_SELECTOR_START = /[{(]/; + var COMBINED_SELECTOR_END = /[})]/; function tokenizeString(str) { var tokens = []; var position = 0; @@ -1041,101 +1250,137 @@ return (function () { function consumeUntil(tokens, match) { var result = ""; - while (tokens.length > 0 && !tokens[0].match(match)) { + while (tokens.length > 0 && !match.test(tokens[0])) { result += tokens.shift(); } return result; } + function consumeCSSSelector(tokens) { + var result; + if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { + tokens.shift(); + result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim(); + tokens.shift(); + } else { + result = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } + return result; + } + var INPUT_SELECTOR = 'input, textarea, select'; /** * @param {HTMLElement} elt + * @param {string} explicitTrigger + * @param {cache} cache for trigger specs * @returns {import("./htmx").HtmxTriggerSpecification[]} */ - function getTriggerSpecs(elt) { - var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); + function parseAndCacheTrigger(elt, explicitTrigger, cache) { var triggerSpecs = []; - if (explicitTrigger) { - var tokens = tokenizeString(explicitTrigger); - do { - consumeUntil(tokens, NOT_WHITESPACE); - var initialLength = tokens.length; - var trigger = consumeUntil(tokens, /[,\[\s]/); - if (trigger !== "") { - if (trigger === "every") { - var every = {trigger: 'every'}; - consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); - consumeUntil(tokens, NOT_WHITESPACE); - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - every.eventFilter = eventFilter; - } - triggerSpecs.push(every); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); - } else { - var triggerSpec = {trigger: trigger}; - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - triggerSpec.eventFilter = eventFilter; - } - while (tokens.length > 0 && tokens[0] !== ",") { - consumeUntil(tokens, NOT_WHITESPACE) - var token = tokens.shift(); - if (token === "changed") { - triggerSpec.changed = true; - } else if (token === "once") { - triggerSpec.once = true; - } else if (token === "consume") { - triggerSpec.consume = true; - } else if (token === "delay" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "from" && tokens[0] === ":") { - tokens.shift(); + var tokens = tokenizeString(explicitTrigger); + do { + consumeUntil(tokens, NOT_WHITESPACE); + var initialLength = tokens.length; + var trigger = consumeUntil(tokens, /[,\[\s]/); + if (trigger !== "") { + if (trigger === "every") { + var every = {trigger: 'every'}; + consumeUntil(tokens, NOT_WHITESPACE); + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); + consumeUntil(tokens, NOT_WHITESPACE); + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + every.eventFilter = eventFilter; + } + triggerSpecs.push(every); + } else if (trigger.indexOf("sse:") === 0) { + triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); + } else { + var triggerSpec = {trigger: trigger}; + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + triggerSpec.eventFilter = eventFilter; + } + while (tokens.length > 0 && tokens[0] !== ",") { + consumeUntil(tokens, NOT_WHITESPACE) + var token = tokens.shift(); + if (token === "changed") { + triggerSpec.changed = true; + } else if (token === "once") { + triggerSpec.once = true; + } else if (token === "consume") { + triggerSpec.consume = true; + } else if (token === "delay" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); + } else if (token === "from" && tokens[0] === ":") { + tokens.shift(); + if (COMBINED_SELECTOR_START.test(tokens[0])) { + var from_arg = consumeCSSSelector(tokens); + } else { var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); - if (from_arg === "closest" || from_arg === "find") { + if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") { tokens.shift(); - from_arg += - " " + - consumeUntil( - tokens, - WHITESPACE_OR_COMMA - ); + var selector = consumeCSSSelector(tokens); + // `next` and `previous` allow a selector-less syntax + if (selector.length > 0) { + from_arg += " " + selector; + } } - triggerSpec.from = from_arg; - } else if (token === "target" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if (token === "throttle" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "queue" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if ((token === "root" || token === "threshold") && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); } + triggerSpec.from = from_arg; + } else if (token === "target" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.target = consumeCSSSelector(tokens); + } else if (token === "throttle" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); + } else if (token === "queue" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } else if (token === "root" && tokens[0] === ":") { + tokens.shift(); + triggerSpec[token] = consumeCSSSelector(tokens); + } else if (token === "threshold" && tokens[0] === ":") { + tokens.shift(); + triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } else { + triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); } - triggerSpecs.push(triggerSpec); } + triggerSpecs.push(triggerSpec); } - if (tokens.length === initialLength) { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - consumeUntil(tokens, NOT_WHITESPACE); - } while (tokens[0] === "," && tokens.shift()) + } + if (tokens.length === initialLength) { + triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); + } + consumeUntil(tokens, NOT_WHITESPACE); + } while (tokens[0] === "," && tokens.shift()) + if (cache) { + cache[explicitTrigger] = triggerSpecs + } + return triggerSpecs + } + + /** + * @param {HTMLElement} elt + * @returns {import("./htmx").HtmxTriggerSpecification[]} + */ + function getTriggerSpecs(elt) { + var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); + var triggerSpecs = []; + if (explicitTrigger) { + var cache = htmx.config.triggerSpecsCache + triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) } if (triggerSpecs.length > 0) { return triggerSpecs; } else if (matches(elt, 'form')) { return [{trigger: 'submit'}]; + } else if (matches(elt, 'input[type="button"], input[type="submit"]')){ + return [{trigger: 'click'}]; } else if (matches(elt, INPUT_SELECTOR)) { return [{trigger: 'change'}]; } else { @@ -1147,14 +1392,17 @@ return (function () { getInternalData(elt).cancelled = true; } - function processPolling(elt, verb, path, spec) { + function processPolling(elt, handler, spec) { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { - issueAjaxRequest(verb, path, elt); + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { + handler(elt); } - processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), spec); + processPolling(elt, handler, spec); } }, spec.pollInterval); } @@ -1166,23 +1414,27 @@ return (function () { } function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt) && elt.target === "") || elt.tagName === "FORM") { + if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || elt.tagName === "FORM") { nodeData.boosted = true; var verb, path; if (elt.tagName === "A") { verb = "get"; - path = getRawAttribute(elt, 'href'); - nodeData.pushURL = true; + path = getRawAttribute(elt, 'href') } else { var rawAttribute = getRawAttribute(elt, "method"); verb = rawAttribute ? rawAttribute.toLowerCase() : "get"; if (verb === "get") { - nodeData.pushURL = true; } path = getRawAttribute(elt, 'action'); } triggerSpecs.forEach(function(triggerSpec) { - addEventListener(elt, verb, path, nodeData, triggerSpec, true); + addEventListener(elt, function(elt, evt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + issueAjaxRequest(verb, path, elt, evt) + }, nodeData, triggerSpec, true); }); } } @@ -1213,11 +1465,11 @@ return (function () { return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); } - function maybeFilterEvent(triggerSpec, evt) { + function maybeFilterEvent(triggerSpec, elt, evt) { var eventFilter = triggerSpec.eventFilter; if(eventFilter){ try { - return eventFilter(evt) !== true; + return eventFilter.call(elt, evt) !== true; } catch(e) { triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); return true; @@ -1226,13 +1478,21 @@ return (function () { return false; } - function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { + function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { + var elementData = getInternalData(elt); var eltsToListenOn; if (triggerSpec.from) { eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); } else { eltsToListenOn = [elt]; } + // store the initial values of the elements, so we can tell if they change + if (triggerSpec.changed) { + eltsToListenOn.forEach(function (eltToListenOn) { + var eltToListenOnData = getInternalData(eltToListenOn); + eltToListenOnData.lastValue = eltToListenOn.value; + }) + } forEach(eltsToListenOn, function (eltToListenOn) { var eventListener = function (evt) { if (!bodyContains(elt)) { @@ -1245,7 +1505,7 @@ return (function () { if (explicitCancel || shouldCancel(evt, elt)) { evt.preventDefault(); } - if (maybeFilterEvent(triggerSpec, evt)) { + if (maybeFilterEvent(triggerSpec, elt, evt)) { return; } var eventData = getInternalData(evt); @@ -1253,7 +1513,6 @@ return (function () { if (eventData.handledFor == null) { eventData.handledFor = []; } - var elementData = getInternalData(elt); if (eventData.handledFor.indexOf(elt) < 0) { eventData.handledFor.push(elt); if (triggerSpec.consume) { @@ -1272,11 +1531,11 @@ return (function () { } } if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { + var eltToListenOnData = getInternalData(eltToListenOn) + if (eltToListenOnData.lastValue === eltToListenOn.value) { return; - } else { - elementData.lastValue = elt.value; } + eltToListenOnData.lastValue = eltToListenOn.value } if (elementData.delayed) { clearTimeout(elementData.delayed); @@ -1285,19 +1544,18 @@ return (function () { return; } - if (triggerSpec.throttle) { + if (triggerSpec.throttle > 0) { if (!elementData.throttle) { - issueAjaxRequest(verb, path, elt, evt); + handler(elt, evt); elementData.throttle = setTimeout(function () { elementData.throttle = null; }, triggerSpec.throttle); } - } else if (triggerSpec.delay) { - elementData.delayed = setTimeout(function () { - issueAjaxRequest(verb, path, elt, evt); - }, triggerSpec.delay); + } else if (triggerSpec.delay > 0) { + elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); } else { - issueAjaxRequest(verb, path, elt, evt); + triggerEvent(elt, 'htmx:trigger') + handler(elt, evt); } } }; @@ -1310,7 +1568,7 @@ return (function () { on: eltToListenOn }) eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); - }) + }); } var windowIsScrolling = false // used by initScrollHandler @@ -1336,14 +1594,11 @@ return (function () { if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { elt.setAttribute('data-hx-revealed', 'true'); var nodeData = getInternalData(elt); - if (nodeData.initialized) { - issueAjaxRequest(nodeData.verb, nodeData.path, elt); + if (nodeData.initHash) { + triggerEvent(elt, 'revealed'); } else { // if the node isn't initialized, wait for it before triggering the request - elt.addEventListener("htmx:afterProcessNode", - function () { - issueAjaxRequest(nodeData.verb, nodeData.path, elt); - }, {once: true}); + elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true}); } } } @@ -1502,6 +1757,9 @@ return (function () { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function (event) { if (maybeCloseSSESource(sseSourceElt)) { + return; + } + if (!bodyContains(elt)) { sseEventSource.removeEventListener(sseEventName, sseListener); return; } @@ -1518,7 +1776,7 @@ return (function () { var target = getTarget(elt) var settleInfo = makeSettleInfo(elt); - selectAndSwap(swapSpec.swapStyle, elt, target, response, settleInfo) + selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) settleImmediately(settleInfo.tasks) triggerEvent(elt, "htmx:sseMessage", event) }; @@ -1530,14 +1788,14 @@ return (function () { } } - function processSSETrigger(elt, verb, path, sseEventName) { + function processSSETrigger(elt, handler, sseEventName) { var sseSourceElt = getClosestMatch(elt, hasEventSource); if (sseSourceElt) { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function () { if (!maybeCloseSSESource(sseSourceElt)) { if (bodyContains(elt)) { - issueAjaxRequest(verb, path, elt); + handler(elt); } else { sseEventSource.removeEventListener(sseEventName, sseListener); } @@ -1563,14 +1821,14 @@ return (function () { //==================================================================== - function loadImmediately(elt, verb, path, nodeData, delay) { + function loadImmediately(elt, handler, nodeData, delay) { var load = function(){ if (!nodeData.loaded) { nodeData.loaded = true; - issueAjaxRequest(verb, path, elt); + handler(elt); } } - if (delay) { + if (delay > 0) { setTimeout(load, delay); } else { load(); @@ -1586,46 +1844,59 @@ return (function () { nodeData.path = path; nodeData.verb = verb; triggerSpecs.forEach(function(triggerSpec) { - if (triggerSpec.sseEvent) { - processSSETrigger(elt, verb, path, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - maybeReveal(elt); - } else if (triggerSpec.trigger === "intersect") { - var observerOptions = {}; - if (triggerSpec.root) { - observerOptions.root = querySelectorExt(elt, triggerSpec.root) - } - if (triggerSpec.threshold) { - observerOptions.threshold = parseFloat(triggerSpec.threshold); + addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return } - var observer = new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - if (entry.isIntersecting) { - triggerEvent(elt, "intersect"); - break; - } - } - }, observerOptions); - observer.observe(elt); - addEventListener(elt, verb, path, nodeData, triggerSpec); - } else if (triggerSpec.trigger === "load") { - loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); - } else if (triggerSpec.pollInterval) { - nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec); - } else { - addEventListener(elt, verb, path, nodeData, triggerSpec); - } + issueAjaxRequest(verb, path, elt, evt) + }) }); } }); return explicitAction; } + function addTriggerHandler(elt, triggerSpec, nodeData, handler) { + if (triggerSpec.sseEvent) { + processSSETrigger(elt, handler, triggerSpec.sseEvent); + } else if (triggerSpec.trigger === "revealed") { + initScrollHandler(); + addEventListener(elt, handler, nodeData, triggerSpec); + maybeReveal(elt); + } else if (triggerSpec.trigger === "intersect") { + var observerOptions = {}; + if (triggerSpec.root) { + observerOptions.root = querySelectorExt(elt, triggerSpec.root) + } + if (triggerSpec.threshold) { + observerOptions.threshold = parseFloat(triggerSpec.threshold); + } + var observer = new IntersectionObserver(function (entries) { + for (var i = 0; i < entries.length; i++) { + var entry = entries[i]; + if (entry.isIntersecting) { + triggerEvent(elt, "intersect"); + break; + } + } + }, observerOptions); + observer.observe(elt); + addEventListener(elt, handler, nodeData, triggerSpec); + } else if (triggerSpec.trigger === "load") { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { + loadImmediately(elt, handler, nodeData, triggerSpec.delay); + } + } else if (triggerSpec.pollInterval > 0) { + nodeData.polling = true; + processPolling(elt, handler, triggerSpec); + } else { + addEventListener(elt, handler, nodeData, triggerSpec); + } + } + function evalScript(script) { - if (script.type === "text/javascript" || script.type === "module" || script.type === "") { + if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) { var newScript = getDocument().createElement("script"); forEach(script.attributes, function (attr) { newScript.setAttribute(attr.name, attr.value); @@ -1642,7 +1913,10 @@ return (function () { } catch (e) { logError(e); } finally { - parent.removeChild(script); + // remove old script element, but only if it is still in DOM + if (script.parentElement) { + script.parentElement.removeChild(script); + } } } } @@ -1656,48 +1930,187 @@ return (function () { }); } - function hasChanceOfBeingBoosted() { - return document.querySelector("[hx-boost], [data-hx-boost]"); + function shouldProcessHxOn(elt) { + var attributes = elt.attributes + for (var j = 0; j < attributes.length; j++) { + var attrName = attributes[j].name + if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") || + startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) { + return true + } + } + return false + } + + function findHxOnWildcardElements(elt) { + var node = null + var elements = [] + + if (shouldProcessHxOn(elt)) { + elements.push(elt) + } + + if (document.evaluate) { + var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + + ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt) + while (node = iter.iterateNext()) elements.push(node) + } else { + var allElements = elt.getElementsByTagName("*") + for (var i = 0; i < allElements.length; i++) { + if (shouldProcessHxOn(allElements[i])) { + elements.push(allElements[i]) + } + } + } + + return elements } function findElementsToProcess(elt) { if (elt.querySelectorAll) { - var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; - var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [hx-data-ext]"); + var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; + var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," + + " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]"); return results; } else { return []; } } - function initButtonTracking(form){ - var maybeSetLastButtonClicked = function(evt){ - if (matches(evt.target, "button, input[type='submit']")) { - var internalData = getInternalData(form); - internalData.lastButtonClicked = evt.target; - } - }; - + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + function maybeSetLastButtonClicked(evt) { + var elt = closest(evt.target, "button, input[type='submit']"); + var internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = elt; + } + }; + function maybeUnsetLastButtonClicked(evt){ + var internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = null; + } + } + function getRelatedFormData(evt) { + var elt = closest(evt.target, "button, input[type='submit']"); + if (!elt) { + return; + } + var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form'); + if (!form) { + return; + } + return getInternalData(form); + } + function initButtonTracking(elt) { // need to handle both click and focus in: // focusin - in case someone tabs in to a button and hits the space bar // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + elt.addEventListener('click', maybeSetLastButtonClicked) + elt.addEventListener('focusin', maybeSetLastButtonClicked) + elt.addEventListener('focusout', maybeUnsetLastButtonClicked) + } - form.addEventListener('click', maybeSetLastButtonClicked) - form.addEventListener('focusin', maybeSetLastButtonClicked) - form.addEventListener('focusout', function(evt){ - var internalData = getInternalData(form); - internalData.lastButtonClicked = null; - }) + function countCurlies(line) { + var tokens = tokenizeString(line); + var netCurlies = 0; + for (var i = 0; i < tokens.length; i++) { + const token = tokens[i]; + if (token === "{") { + netCurlies++; + } else if (token === "}") { + netCurlies--; + } + } + return netCurlies; + } + + function addHxOnEventHandler(elt, eventName, code) { + var nodeData = getInternalData(elt); + if (!Array.isArray(nodeData.onHandlers)) { + nodeData.onHandlers = []; + } + var func; + var listener = function (e) { + return maybeEval(elt, function() { + if (!func) { + func = new Function("event", code); + } + func.call(elt, e); + }); + }; + elt.addEventListener(eventName, listener); + nodeData.onHandlers.push({event:eventName, listener:listener}); + } + + function processHxOn(elt) { + var hxOnValue = getAttributeValue(elt, 'hx-on'); + if (hxOnValue) { + var handlers = {} + var lines = hxOnValue.split("\n"); + var currentEvent = null; + var curlyCount = 0; + while (lines.length > 0) { + var line = lines.shift(); + var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/); + if (curlyCount === 0 && match) { + line.split(":") + currentEvent = match[1].slice(0, -1); // strip last colon + handlers[currentEvent] = match[2]; + } else { + handlers[currentEvent] += line; + } + curlyCount += countCurlies(line); + } + + for (var eventName in handlers) { + addHxOnEventHandler(elt, eventName, handlers[eventName]); + } + } + } + + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (var i = 0; i < elt.attributes.length; i++) { + var name = elt.attributes[i].name + var value = elt.attributes[i].value + if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) { + var afterOnPosition = name.indexOf("-on") + 3; + var nextChar = name.slice(afterOnPosition, afterOnPosition + 1); + if (nextChar === "-" || nextChar === ":") { + var eventName = name.slice(afterOnPosition + 1); + // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support + if (startsWith(eventName, ":")) { + eventName = "htmx" + eventName + } else if (startsWith(eventName, "-")) { + eventName = "htmx:" + eventName.slice(1); + } else if (startsWith(eventName, "htmx-")) { + eventName = "htmx:" + eventName.slice(5); + } + + addHxOnEventHandler(elt, eventName, value) + } + } + } } function initNode(elt) { - if (elt.closest && elt.closest(htmx.config.disableSelector)) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) return; } var nodeData = getInternalData(elt); - if (!nodeData.initialized) { - nodeData.initialized = true; + if (nodeData.initHash !== attributeHash(elt)) { + // clean up any previously processed info + deInitNode(elt); + + nodeData.initHash = attributeHash(elt); + + processHxOn(elt); + triggerEvent(elt, "htmx:beforeProcessNode") if (elt.value) { @@ -1705,14 +2118,24 @@ return (function () { } var triggerSpecs = getTriggerSpecs(elt); - var explicitAction = processVerbs(elt, nodeData, triggerSpecs); - - if (!explicitAction && getClosestAttributeValue(elt, "hx-boost") === "true") { - boostElement(elt, nodeData, triggerSpecs); + var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs); + + if (!hasExplicitHttpAction) { + if (getClosestAttributeValue(elt, "hx-boost") === "true") { + boostElement(elt, nodeData, triggerSpecs); + } else if (hasAttribute(elt, 'hx-trigger')) { + triggerSpecs.forEach(function (triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function () { + }) + }) + } } - if (elt.tagName === "FORM") { - initButtonTracking(elt); + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) { + initButtonTracking(elt) } var sseInfo = getAttributeValue(elt, 'hx-sse'); @@ -1730,8 +2153,15 @@ return (function () { function processNode(elt) { elt = resolveTarget(elt); + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return; + } initNode(elt); forEach(findElementsToProcess(elt), function(child) { initNode(child) }); + // Because it happens second, the new way of adding onHandlers superseeds the old one + // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored + forEach(findHxOnWildcardElements(elt), processHxOnWildcard); } //==================================================================== @@ -1809,7 +2239,7 @@ return (function () { eventResult = eventResult && elt.dispatchEvent(kebabedEvent) } withExtensions(elt, function (extension) { - eventResult = eventResult && (extension.onEvent(eventName, event) !== false) + eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) }); return eventResult; } @@ -1825,6 +2255,18 @@ return (function () { } function saveToHistoryCache(url, content, title, scroll) { + if (!canAccessLocalStorage()) { + return; + } + + if (htmx.config.historyCacheSize <= 0) { + // make sure that an eventually already existing cache is purged + localStorage.removeItem("htmx-history-cache"); + return; + } + + url = normalizePath(url); + var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { @@ -1832,7 +2274,9 @@ return (function () { break; } } - historyCache.push({url:url, content: content, title:title, scroll:scroll}) + var newHistoryItem = {url:url, content: content, title:title, scroll:scroll}; + triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache}) + historyCache.push(newHistoryItem) while (historyCache.length > htmx.config.historyCacheSize) { historyCache.shift(); } @@ -1848,6 +2292,12 @@ return (function () { } function getCachedHistory(url) { + if (!canAccessLocalStorage()) { + return null; + } + + url = normalizePath(url); + var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { @@ -1869,13 +2319,43 @@ return (function () { function saveCurrentPageToHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; - triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); - if(htmx.config.historyEnabled) history.replaceState({htmx:true}, getDocument().title, window.location.href); - saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); + + // Allow history snapshot feature to be disabled where hx-history="false" + // is present *anywhere* in the current document we're about to save, + // so we can prevent privileged data entering the cache. + // The page will still be reachable as a history entry, but htmx will fetch it + // live from the server onpopstate rather than look in the localStorage cache + var disableHistoryCache + try { + disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') + } catch (e) { + // IE11: insensitive modifier not supported so fallback to case sensitive selector + disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') + } + if (!disableHistoryCache) { + triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt}); + saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); + } + + if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href); } function pushUrlIntoHistory(path) { - if(htmx.config.historyEnabled) history.pushState({htmx:true}, "", path); + // remove the cache buster parameter, if any + if (htmx.config.getCacheBusterParam) { + path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') + if (endsWith(path, '&') || endsWith(path, "?")) { + path = path.slice(0, -1); + } + } + if(htmx.config.historyEnabled) { + history.pushState({htmx:true}, "", path); + } + currentPathForHistory = path; + } + + function replaceUrlInHistory(path) { + if(htmx.config.historyEnabled) history.replaceState({htmx:true}, "", path); currentPathForHistory = path; } @@ -1890,7 +2370,9 @@ return (function () { var details = {path: path, xhr:request}; triggerEvent(getDocument().body, "htmx:historyCacheMiss", details); request.open('GET', path, true); + request.setRequestHeader("HX-Request", "true"); request.setRequestHeader("HX-History-Restore-Request", "true"); + request.setRequestHeader("HX-Current-URL", getDocument().location.href); request.onload = function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); @@ -1899,11 +2381,20 @@ return (function () { fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; var historyElement = getHistoryElement(); var settleInfo = makeSettleInfo(historyElement); + var title = findTitle(this.response); + if (title) { + var titleElt = find("title"); + if (titleElt) { + titleElt.innerHTML = title; + } else { + window.document.title = title; + } + } // @ts-ignore swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); + triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response}); } else { triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details); } @@ -1922,9 +2413,11 @@ return (function () { swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); document.title = cached.title; - window.scrollTo(0, cached.scroll); + setTimeout(function () { + window.scrollTo(0, cached.scroll); + }, 0); // next 'tick', so browser has time to render layout currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); + triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); } else { if (htmx.config.refreshOnHistoryMiss) { @@ -1936,31 +2429,46 @@ return (function () { } } - function shouldPush(elt) { - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - return (pushUrl && pushUrl !== "false") || - (getInternalData(elt).boosted && getInternalData(elt).pushURL); - } - - function getPushUrl(elt) { - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - return (pushUrl === "true" || pushUrl === "false") ? null : pushUrl; - } - function addRequestIndicatorClasses(elt) { var indicators = findAttributeTargets(elt, 'hx-indicator'); if (indicators == null) { indicators = [elt]; } forEach(indicators, function (ic) { + var internalData = getInternalData(ic); + internalData.requestCount = (internalData.requestCount || 0) + 1; ic.classList["add"].call(ic.classList, htmx.config.requestClass); }); return indicators; } - function removeRequestIndicatorClasses(indicators) { + function disableElements(elt) { + var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt'); + if (disabledElts == null) { + disabledElts = []; + } + forEach(disabledElts, function (disabledElement) { + var internalData = getInternalData(disabledElement); + internalData.requestCount = (internalData.requestCount || 0) + 1; + disabledElement.setAttribute("disabled", ""); + }); + return disabledElts; + } + + function removeRequestIndicators(indicators, disabled) { forEach(indicators, function (ic) { - ic.classList["remove"].call(ic.classList, htmx.config.requestClass); + var internalData = getInternalData(ic); + internalData.requestCount = (internalData.requestCount || 0) - 1; + if (internalData.requestCount === 0) { + ic.classList["remove"].call(ic.classList, htmx.config.requestClass); + } + }); + forEach(disabled, function (disabledElement) { + var internalData = getInternalData(disabledElement); + internalData.requestCount = (internalData.requestCount || 0) - 1; + if (internalData.requestCount === 0) { + disabledElement.removeAttribute('disabled'); + } }); } @@ -1979,7 +2487,7 @@ return (function () { } function shouldInclude(elt) { - if(elt.name === "" || elt.name == null || elt.disabled) { + if(elt.name === "" || elt.name == null || elt.disabled || closest(elt, "fieldset[disabled]")) { return false; } // ignore "submitter" types (see jQuery src/serialize.js) @@ -1992,6 +2500,29 @@ return (function () { return true; } + function addValueToValues(name, value, values) { + // This is a little ugly because both the current value of the named value in the form + // and the new value could be arrays, so we have to handle all four cases :/ + if (name != null && value != null) { + var current = values[name]; + if (current === undefined) { + values[name] = value; + } else if (Array.isArray(current)) { + if (Array.isArray(value)) { + values[name] = current.concat(value); + } else { + current.push(value); + } + } else { + if (Array.isArray(value)) { + values[name] = [current].concat(value); + } else { + values[name] = [current, value]; + } + } + } + } + function processInputValue(processed, values, errors, elt, validate) { if (elt == null || haveSeenNode(processed, elt)) { return; @@ -2001,35 +2532,14 @@ return (function () { if (shouldInclude(elt)) { var name = getRawAttribute(elt,"name"); var value = elt.value; - if (elt.multiple) { + if (elt.multiple && elt.tagName === "SELECT") { value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value }); } // include file inputs if (elt.files) { value = toArray(elt.files); } - // This is a little ugly because both the current value of the named value in the form - // and the new value could be arrays, so we have to handle all four cases :/ - if (name != null && value != null) { - var current = values[name]; - if(current) { - if (Array.isArray(current)) { - if (Array.isArray(value)) { - values[name] = current.concat(value); - } else { - current.push(value); - } - } else { - if (Array.isArray(value)) { - values[name] = [current].concat(value); - } else { - values[name] = [current, value]; - } - } - } else { - values[name] = value; - } - } + addValueToValues(name, value, values); if (validate) { validateElement(elt, errors); } @@ -2062,9 +2572,13 @@ return (function () { var formValues = {}; var errors = []; var internalData = getInternalData(elt); + if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { + internalData.lastButtonClicked = null + } // only validate when form is directly submitted and novalidate or formnovalidate are not set - var validate = matches(elt, 'form') && elt.noValidate !== true; + // or if the element has an explicit hx-validate="true" on it + var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true"; if (internalData.lastButtonClicked) { validate = validate && internalData.lastButtonClicked.formNoValidate !== true; } @@ -2078,11 +2592,11 @@ return (function () { processInputValue(processed, values, errors, elt, validate); // if a button or submit was clicked last, include its value - if (internalData.lastButtonClicked) { - var name = getRawAttribute(internalData.lastButtonClicked,"name"); - if (name) { - values[name] = internalData.lastButtonClicked.value; - } + if (internalData.lastButtonClicked || elt.tagName === "BUTTON" || + (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) { + var button = internalData.lastButtonClicked || elt + var name = getRawAttribute(button, "name") + addValueToValues(name, button.value, formValues) } // include any explicit includes @@ -2228,40 +2742,43 @@ return (function () { "swapDelay" : htmx.config.defaultSwapDelay, "settleDelay" : htmx.config.defaultSettleDelay } - if (getInternalData(elt).boosted && !isAnchorLink(elt)) { + if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { swapSpec["show"] = "top" } 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)); - } - if (modifier.indexOf("scroll:") === 0) { - var scrollSpec = modifier.substr(7); + for (var i = 0; i < split.length; i++) { + var value = split[i]; + if (value.indexOf("swap:") === 0) { + swapSpec["swapDelay"] = parseInterval(value.substr(5)); + } else if (value.indexOf("settle:") === 0) { + swapSpec["settleDelay"] = parseInterval(value.substr(7)); + } else if (value.indexOf("transition:") === 0) { + swapSpec["transition"] = value.substr(11) === "true"; + } else if (value.indexOf("ignoreTitle:") === 0) { + swapSpec["ignoreTitle"] = value.substr(12) === "true"; + } else if (value.indexOf("scroll:") === 0) { + var scrollSpec = value.substr(7); var splitSpec = scrollSpec.split(":"); var scrollVal = splitSpec.pop(); var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; swapSpec["scroll"] = scrollVal; swapSpec["scrollTarget"] = selectorVal; - } - if (modifier.indexOf("show:") === 0) { - var showSpec = modifier.substr(5); + } else if (value.indexOf("show:") === 0) { + var showSpec = value.substr(5); var splitSpec = showSpec.split(":"); var showVal = splitSpec.pop(); var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; swapSpec["show"] = showVal; swapSpec["showTarget"] = selectorVal; - } - if (modifier.indexOf("focus-scroll:") === 0) { - var focusScrollVal = modifier.substr("focus-scroll:".length); + } else if (value.indexOf("focus-scroll:") === 0) { + var focusScrollVal = value.substr("focus-scroll:".length); swapSpec["focusScroll"] = focusScrollVal == "true"; + } else if (i == 0) { + swapSpec["swapStyle"] = value; + } else { + logError('Unknown modifier in hx-swap: ' + value); } } } @@ -2269,6 +2786,11 @@ return (function () { return swapSpec; } + function usesFormData(elt) { + return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || + (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data"); + } + function encodeParamsForBody(xhr, elt, filteredParameters) { var encodedParameters = null; withExtensions(elt, function (extension) { @@ -2279,8 +2801,7 @@ return (function () { if (encodedParameters != null) { return encodedParameters; } else { - if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || - (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) { + if (usesFormData(elt)) { return makeFormData(filteredParameters); } else { return urlEncode(filteredParameters); @@ -2352,6 +2873,9 @@ return (function () { if (attributeValue) { var str = attributeValue.trim(); var evaluateValue = evalAsDefault; + if (str === "unset") { + return null; + } if (str.indexOf("javascript:") === 0) { str = str.substr(11); evaluateValue = true; @@ -2426,7 +2950,7 @@ return (function () { } } - function getResponseURL(xhr) { + function getPathFromResponse(xhr) { // NB: IE11 does not support this stuff if (xhr.responseURL && typeof(URL) !== "undefined") { try { @@ -2439,7 +2963,7 @@ return (function () { } function hasHeader(xhr, regexp) { - return xhr.getAllResponseHeaders().match(regexp); + return regexp.test(xhr.getAllResponseHeaders()) } function ajaxHelper(verb, path, context) { @@ -2458,6 +2982,7 @@ return (function () { values : context.values, targetOverride: resolveTarget(context.target), swapOverride: context.swap, + select: context.select, returnPromise: true }); } @@ -2477,7 +3002,28 @@ return (function () { return arr; } - function issueAjaxRequest(verb, path, elt, event, etc) { + function verifyPath(elt, path, requestConfig) { + var sameHost + var url + if (typeof URL === "function") { + url = new URL(path, document.location.href); + var origin = document.location.origin; + sameHost = origin === url.origin; + } else { + // IE11 doesn't support URL + url = path + sameHost = startsWith(path, document.location.origin) + } + + if (htmx.config.selfRequestsOnly) { + if (!sameHost) { + return false; + } + } + return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig)); + } + + function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { var resolve = null; var reject = null; etc = etc != null ? etc : {}; @@ -2491,18 +3037,52 @@ return (function () { elt = getDocument().body; } var responseHandler = etc.handler || handleAjaxResponse; + var select = etc.select || null; if (!bodyContains(elt)) { - return; // do not issue requests for elements removed from the DOM + // do not issue requests for elements removed from the DOM + maybeCall(resolve); + return promise; } var target = etc.targetOverride || getTarget(elt); if (target == null || target == DUMMY_ELT) { triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); - return; + maybeCall(reject); + return promise; } - var syncElt = elt; var eltData = getInternalData(elt); + var submitter = eltData.lastButtonClicked; + + if (submitter) { + var buttonPath = getRawAttribute(submitter, "formaction"); + if (buttonPath != null) { + path = buttonPath; + } + + var buttonVerb = getRawAttribute(submitter, "formmethod") + if (buttonVerb != null) { + // ignore buttons with formmethod="dialog" + if (buttonVerb.toLowerCase() !== "dialog") { + verb = buttonVerb; + } + } + } + + var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); + // allow event-based confirmation w/ a callback + if (confirmed === undefined) { + var issueRequest = function(skipConfirmation) { + return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation); + } + var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion}; + if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { + maybeCall(resolve); + return promise; + } + } + + var syncElt = elt; var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); var queueStrategy = null; var abortable = false; @@ -2518,10 +3098,12 @@ return (function () { syncStrategy = (syncStrings[1] || 'drop').trim(); eltData = getInternalData(syncElt); if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { - return; + maybeCall(resolve); + return promise; } else if (syncStrategy === "abort") { if (eltData.xhr) { - return; + maybeCall(resolve); + return promise; } else { abortable = true; } @@ -2565,7 +3147,8 @@ return (function () { issueAjaxRequest(verb, path, elt, event, etc) }); } - return; + maybeCall(resolve); + return promise; } } @@ -2593,8 +3176,7 @@ return (function () { } } - var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); - if (confirmQuestion) { + if (confirmQuestion && !confirmed) { if(!confirm(confirmQuestion)) { maybeCall(resolve); endRequestLock() @@ -2604,6 +3186,11 @@ return (function () { var headers = getHeaders(elt, target, promptResponse); + + if (verb !== 'get' && !usesFormData(elt)) { + headers['Content-Type'] = 'application/x-www-form-urlencoded'; + } + if (etc.headers) { headers = mergeObjects(headers, etc.headers); } @@ -2617,8 +3204,8 @@ return (function () { var allParameters = mergeObjects(rawParameters, expressionVars); var filteredParameters = filterValues(allParameters, elt); - if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null) { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; + if (htmx.config.getCacheBusterParam && verb === 'get') { + filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true"; } // behavior of anchors w/ empty href is to use the current URL @@ -2626,9 +3213,16 @@ return (function () { path = getDocument().location.href; } + var requestAttrValues = getValuesForElement(elt, 'hx-request'); + var eltIsBoosted = getInternalData(elt).boosted; + + var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + var requestConfig = { + boosted: eltIsBoosted, + useUrlParams: useUrlParams, parameters: filteredParameters, unfilteredParameters: allParameters, headers:headers, @@ -2653,6 +3247,7 @@ return (function () { headers = requestConfig.headers; filteredParameters = requestConfig.parameters; errors = requestConfig.errors; + useUrlParams = requestConfig.useUrlParams; if(errors && errors.length > 0){ triggerEvent(elt, 'htmx:validation:halted', requestConfig) @@ -2664,25 +3259,31 @@ return (function () { var splitPath = path.split("#"); var pathNoAnchor = splitPath[0]; var anchor = splitPath[1]; - if (verb === 'get') { - var finalPathForGet = pathNoAnchor; + + var finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor; var values = Object.keys(filteredParameters).length !== 0; if (values) { - if (finalPathForGet.indexOf("?") < 0) { - finalPathForGet += "?"; + if (finalPath.indexOf("?") < 0) { + finalPath += "?"; } else { - finalPathForGet += "&"; + finalPath += "&"; } - finalPathForGet += urlEncode(filteredParameters); + finalPath += urlEncode(filteredParameters); if (anchor) { - finalPathForGet += "#" + anchor; + finalPath += "#" + anchor; } } - xhr.open('GET', finalPathForGet, true); - } else { - xhr.open(verb.toUpperCase(), path, true); } + if (!verifyPath(elt, finalPath, requestConfig)) { + triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) + maybeCall(reject); + return promise; + }; + + xhr.open(verb.toUpperCase(), finalPath, true); xhr.overrideMimeType("text/html"); xhr.withCredentials = requestConfig.withCredentials; xhr.timeout = requestConfig.timeout; @@ -2699,19 +3300,24 @@ return (function () { } } - var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, etc:etc, pathInfo:{ - path:path, finalPath:finalPathForGet, anchor:anchor + var responseInfo = { + xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select, + pathInfo: { + requestPath: path, + finalRequestPath: finalPath, + anchor: anchor } }; xhr.onload = function () { try { var hierarchy = hierarchyForElt(elt); + responseInfo.pathInfo.responsePath = getPathFromResponse(xhr); responseHandler(elt, responseInfo); - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerEvent(elt, 'htmx:afterRequest', responseInfo); triggerEvent(elt, 'htmx:afterOnLoad', responseInfo); - // if the body no longer contains the element, trigger the even on the closest parent + // if the body no longer contains the element, trigger the event on the closest parent // remaining in the DOM if (!bodyContains(elt)) { var secondaryTriggerElt = null; @@ -2734,21 +3340,21 @@ return (function () { } } xhr.onerror = function () { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:sendError', responseInfo); maybeCall(reject); endRequestLock(); } xhr.onabort = function() { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo); maybeCall(reject); endRequestLock(); } xhr.ontimeout = function() { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:timeout', responseInfo); maybeCall(reject); @@ -2760,6 +3366,7 @@ return (function () { return promise } var indicators = addRequestIndicatorClasses(elt); + var disableElts = disableElements(elt); forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { forEach([xhr, xhr.upload], function (target) { @@ -2773,14 +3380,99 @@ return (function () { }); }); triggerEvent(elt, 'htmx:beforeSend', responseInfo); - xhr.send(verb === 'get' ? null : encodeParamsForBody(xhr, elt, filteredParameters)); + var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) + xhr.send(params); return promise; } + function determineHistoryUpdates(elt, responseInfo) { + + var xhr = responseInfo.xhr; + + //=========================================== + // First consult response headers + //=========================================== + var pathFromHeaders = null; + var typeFromHeaders = null; + if (hasHeader(xhr,/HX-Push:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Push"); + typeFromHeaders = "push"; + } else if (hasHeader(xhr,/HX-Push-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Push-Url"); + typeFromHeaders = "push"; + } else if (hasHeader(xhr,/HX-Replace-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url"); + typeFromHeaders = "replace"; + } + + // if there was a response header, that has priority + if (pathFromHeaders) { + if (pathFromHeaders === "false") { + return {} + } else { + return { + type: typeFromHeaders, + path : pathFromHeaders + } + } + } + + //=========================================== + // Next resolve via DOM values + //=========================================== + var requestPath = responseInfo.pathInfo.finalRequestPath; + var responsePath = responseInfo.pathInfo.responsePath; + + var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); + var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url"); + var elementIsBoosted = getInternalData(elt).boosted; + + var saveType = null; + var path = null; + + if (pushUrl) { + saveType = "push"; + path = pushUrl; + } else if (replaceUrl) { + saveType = "replace"; + path = replaceUrl; + } else if (elementIsBoosted) { + saveType = "push"; + path = responsePath || requestPath; // if there is no response path, go with the original request path + } + + if (path) { + // false indicates no push, return empty object + if (path === "false") { + return {}; + } + + // true indicates we want to follow wherever the server ended up sending us + if (path === "true") { + path = responsePath || requestPath; // if there is no response path, go with the original request path + } + + // restore any anchor associated with the request + if (responseInfo.pathInfo.anchor && + path.indexOf("#") === -1) { + path = path + "#" + responseInfo.pathInfo.anchor; + } + + return { + type:saveType, + path: path + } + } else { + return {}; + } + } + function handleAjaxResponse(elt, responseInfo) { var xhr = responseInfo.xhr; var target = responseInfo.target; var etc = responseInfo.etc; + var requestConfig = responseInfo.requestConfig; + var select = responseInfo.select; if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; @@ -2788,33 +3480,44 @@ return (function () { handleTrigger(xhr, "HX-Trigger", elt); } - if (hasHeader(xhr,/HX-Push:/i)) { - var pushedUrl = xhr.getResponseHeader("HX-Push"); + if (hasHeader(xhr, /HX-Location:/i)) { + saveCurrentPageToHistory(); + var redirectPath = xhr.getResponseHeader("HX-Location"); + var swapSpec; + if (redirectPath.indexOf("{") === 0) { + swapSpec = parseJSON(redirectPath); + // what's the best way to throw an error if the user didn't include this + redirectPath = swapSpec['path']; + delete swapSpec['path']; + } + ajaxHelper('GET', redirectPath, swapSpec).then(function(){ + pushUrlIntoHistory(redirectPath); + }); + return; } + var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh"); + if (hasHeader(xhr, /HX-Redirect:/i)) { - window.location.href = xhr.getResponseHeader("HX-Redirect"); + location.href = xhr.getResponseHeader("HX-Redirect"); + shouldRefresh && location.reload(); return; } - if (hasHeader(xhr,/HX-Refresh:/i)) { - if ("true" === xhr.getResponseHeader("HX-Refresh")) { - location.reload(); - return; - } + if (shouldRefresh) { + location.reload(); + return; } if (hasHeader(xhr,/HX-Retarget:/i)) { - responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget")); + if (xhr.getResponseHeader("HX-Retarget") === "this") { + responseInfo.target = elt; + } else { + responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget")); + } } - /** @type {boolean} */ - var shouldSaveHistory - if (pushedUrl == "false") { - shouldSaveHistory = false - } else { - shouldSaveHistory = shouldPush(elt) || pushedUrl; - } + var historyUpdate = determineHistoryUpdates(elt, responseInfo); // by default htmx only swaps on 200 return codes and does not swap // on 204 'No Content' @@ -2823,15 +3526,18 @@ return (function () { var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; var serverResponse = xhr.response; var isError = xhr.status >= 400; - var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo); + var ignoreTitle = htmx.config.ignoreTitle + var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo); if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; target = beforeSwapDetails.target; // allow re-targeting serverResponse = beforeSwapDetails.serverResponse; // allow updating content isError = beforeSwapDetails.isError; // allow updating error - + ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title + + responseInfo.target = target; // Make updated target available to response events responseInfo.failed = isError; // Make failed property available to response events - responseInfo.successful = !isError; // Make successful property available to response events + responseInfo.successful = !isError; // Make successful property available to response events if (beforeSwapDetails.shouldSwap) { if (xhr.status === 286) { @@ -2842,18 +3548,29 @@ return (function () { serverResponse = extension.transformResponse(serverResponse, xhr, elt); }); - // Save current page - if (shouldSaveHistory) { + // Save current page if there will be a history update + if (historyUpdate.type) { saveCurrentPageToHistory(); } var swapOverride = etc.swapOverride; + if (hasHeader(xhr,/HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader("HX-Reswap"); + } var swapSpec = getSwapSpecification(elt, swapOverride); + if (swapSpec.hasOwnProperty('ignoreTitle')) { + ignoreTitle = swapSpec.ignoreTitle; + } + target.classList.add(htmx.config.swappingClass); + + // optional transition API promise callbacks + var settleResolve = null; + var settleReject = null; + var doSwap = function () { try { - var activeElt = document.activeElement; var selectionInfo = {}; try { @@ -2868,19 +3585,44 @@ return (function () { // safari issue - see https://github.com/microsoft/playwright/issues/5894 } + var selectOverride; + if (select) { + selectOverride = select; + } + + if (hasHeader(xhr, /HX-Reselect:/i)) { + selectOverride = xhr.getResponseHeader("HX-Reselect"); + } + + // if we need to save history, do so, before swapping so that relative resources have the correct base URL + if (historyUpdate.type) { + triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)); + if (historyUpdate.type === "push") { + pushUrlIntoHistory(historyUpdate.path); + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path}); + } else { + replaceUrlInHistory(historyUpdate.path); + triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path}); + } + } + var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride); if (selectionInfo.elt && !bodyContains(selectionInfo.elt) && - selectionInfo.elt.id) { - var newActiveElt = document.getElementById(selectionInfo.elt.id); + getRawAttribute(selectionInfo.elt, "id")) { + var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id")); var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; if (newActiveElt) { // @ts-ignore if (selectionInfo.start && newActiveElt.setSelectionRange) { // @ts-ignore - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + try { + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + } catch (e) { + // the setSelectionRange method is present on fields that don't support it, so just let this fail + } } newActiveElt.focus(focusOptions); } @@ -2893,9 +3635,6 @@ return (function () { } triggerEvent(elt, 'htmx:afterSwap', responseInfo); }); - if (responseInfo.pathInfo.anchor) { - location.hash = responseInfo.pathInfo.anchor; - } if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { var finalElt = elt; @@ -2915,14 +3654,15 @@ return (function () { } triggerEvent(elt, 'htmx:afterSettle', responseInfo); }); - // push URL and save new page - if (shouldSaveHistory) { - var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; - pushUrlIntoHistory(pathToPush); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: pathToPush}); + + if (responseInfo.pathInfo.anchor) { + var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor); + if(anchorTarget) { + anchorTarget.scrollIntoView({block:'start', behavior: "auto"}); + } } - if(settleInfo.title) { + if(settleInfo.title && !ignoreTitle) { var titleElt = find("title"); if(titleElt) { titleElt.innerHTML = settleInfo.title; @@ -2940,6 +3680,7 @@ return (function () { } handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); } + maybeCall(settleResolve); } if (swapSpec.settleDelay > 0) { @@ -2949,10 +3690,34 @@ return (function () { } } catch (e) { triggerErrorEvent(elt, 'htmx:swapError', responseInfo); + maybeCall(settleReject); throw e; } }; + var shouldTransition = htmx.config.globalViewTransitions + if(swapSpec.hasOwnProperty('transition')){ + shouldTransition = swapSpec.transition; + } + + if(shouldTransition && + triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && + typeof Promise !== "undefined" && document.startViewTransition){ + var settlePromise = new Promise(function (_resolve, _reject) { + settleResolve = _resolve; + settleReject = _reject; + }); + // wrap the original doSwap() in a call to startViewTransition() + var innerDoSwap = doSwap; + doSwap = function() { + document.startViewTransition(function () { + innerDoSwap(); + return settlePromise; + }); + } + } + + if (swapSpec.swapDelay > 0) { setTimeout(doSwap, swapSpec.swapDelay) } else { @@ -2960,7 +3725,7 @@ return (function () { } } if (isError) { - triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.path}, responseInfo)); + triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo)); } } @@ -3048,9 +3813,22 @@ return (function () { //==================================================================== // Initialization //==================================================================== + var isReady = false + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true + }) + /** + * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. + * + * This function uses isReady because there is no realiable way to ask the browswer whether + * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded + * firing and readystate=complete. + */ function ready(fn) { - if (getDocument().readyState !== 'loading') { + // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by + // some means other than the initial page load. + if (isReady || getDocument().readyState === 'complete') { fn(); } else { getDocument().addEventListener('DOMContentLoaded', fn); @@ -3061,9 +3839,9 @@ return (function () { if (htmx.config.includeIndicatorStyles !== false) { getDocument().head.insertAdjacentHTML("beforeend", "<style>\ - ." + htmx.config.indicatorClass + "{opacity:0;transition: opacity 200ms ease-in;}\ - ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1}\ - ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1}\ + ." + htmx.config.indicatorClass + "{opacity:0}\ + ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ + ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ </style>"); } } @@ -3101,6 +3879,9 @@ return (function () { internalData.xhr.abort(); } }); + /** @type {(ev: PopStateEvent) => any} */ + const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null; + /** @type {(ev: PopStateEvent) => any} */ window.onpopstate = function (event) { if (event.state && event.state.htmx) { restoreHistory(); @@ -3110,10 +3891,15 @@ return (function () { 'triggerEvent': triggerEvent }); }); + } else { + if (originalPopstate) { + originalPopstate(event); + } } }; setTimeout(function () { triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event + body = null; // kill reference for gc }, 0); }) diff --git a/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.min.js b/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.min.js index 998414c..53bbdf6 100644 --- a/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.min.js +++ b/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.min.js @@ -1 +1,4 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(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 l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=k(e);e.classList.toggle(t)}function T(e,t){e=k(e);W(e.parentElement.children,function(e){q(e,t)});L(e,t)}function H(e,t){e=k(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function N(e,t){if(t.indexOf("closest ")===0){return[H(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[C(e,t.substr(5))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return z().querySelectorAll(t)}}function ee(e,t){if(t){return N(e,t)[0]}else{return N(z().body,e)[0]}}function k(e){if(p(e,"String")){return C(e)}else{return e}}function I(e,t,r){if(m(t)){return{target:z().body,event:e,listener:t}}else{return{target:k(e),event:t,listener:r}}}function M(t,r,n){lr(function(){var e=I(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function D(t,r,n){lr(function(){var e=I(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var te=z().createElement("output");function F(e,t){var r=G(e,t);if(r){if(r==="this"){return[re(e,t)]}else{var n=N(e,r);if(n.length===0){pt('The selector "'+r+'" on '+t+" returned no matches!");return[te]}else{return n}}}}function re(e,t){return h(e,function(e){return V(e,t)!=null})}function ne(e){var t=G(e,"hx-target");if(t){if(t==="this"){return re(e,"hx-target")}else{return ee(e,t)}}else{var r=_(e);if(r.boosted){return z().body}else{return e}}}function P(e){var t=U.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function X(t,r){W(t.attributes,function(e){if(!r.hasAttribute(e.name)&&P(e.name)){t.removeAttribute(e.name)}});W(r.attributes,function(e){if(P(e.name)){t.setAttribute(e.name,e.value)}})}function j(e,t){var r=sr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){pt(e)}}return e==="outerHTML"}function B(e,i,o){var t="#"+i.id;var a="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){a=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{a=e}var r=z().querySelectorAll(t);if(r){W(r,function(e){var t;var r=i.cloneNode(true);t=z().createDocumentFragment();t.appendChild(r);if(!j(a,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ye(a,e,e,t,o)}W(o.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(z().body,"htmx:oobErrorNoTarget",{content:i})}return e}function ie(e,r){W(R(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=V(e,"hx-swap-oob");if(t!=null){B(t,e,r)}})}function oe(e){W(R(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=V(e,"id");var r=z().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function ae(n,e,i){W(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();X(e,t);i.tasks.push(function(){X(e,r)})}}})}function se(e){return function(){q(e,U.config.addedClass);ct(e);at(e);le(e);$(e,"htmx:load")}}function le(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ue(e,t,r,n){ae(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(se(i))}}}function fe(t){var e=_(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){W(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){W(t.children,function(e){fe(e)})}}function ce(e,t,r){if(e.tagName==="BODY"){return me(e,t,r)}else{var n;var i=e.previousSibling;ue(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}_(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}fe(e);u(e).removeChild(e)}}function he(e,t,r){return ue(e,e.firstChild,t,r)}function de(e,t,r){return ue(u(e),e,t,r)}function ve(e,t,r){return ue(e,null,t,r)}function ge(e,t,r){return ue(u(e),e.nextSibling,t,r)}function pe(e,t,r){fe(e);return u(e).removeChild(e)}function me(e,t,r){var n=e.firstChild;ue(e,n,t,r);if(n){while(n.nextSibling){fe(n.nextSibling);e.removeChild(n.nextSibling)}fe(n);e.removeChild(n)}}function xe(e,t){var r=G(e,"hx-select");if(r){var n=z().createDocumentFragment();W(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function ye(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":ce(r,n,i);return;case"afterbegin":he(r,n,i);return;case"beforebegin":de(r,n,i);return;case"beforeend":ve(r,n,i);return;case"afterend":ge(r,n,i);return;case"delete":pe(r,n,i);return;default:var o=sr(t);for(var a=0;a<o.length;a++){var f=o[a];try{var s=f.handleSwap(e,r,n,i);if(s){if(typeof s.length!=="undefined"){for(var l=0;l<s.length;l++){var u=s[l];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){i.tasks.push(se(u))}}}return}}catch(e){pt(e)}}if(e==="innerHTML"){me(r,n,i)}else{ye(U.config.defaultSwapStyle,t,r,n,i)}}}function be(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function we(e,t,r,n,i){i.title=be(n);var o=g(n);if(o){ie(o,i);o=xe(r,o);oe(o);return ye(e,r,t,o,i)}}function Se(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!x(a)){a={value:a}}$(r,o,a)}}}else{$(r,n,[])}}var Ee=/\s/;var Ce=/[\s,]/;var Re=/[_$a-zA-Z]/;var Oe=/[_$a-zA-Z0-9]/;var Le=['"',"'","/"];var qe=/[^\s]/;function Ae(e){var t=[];var r=0;while(r<e.length){if(Re.exec(e.charAt(r))){var n=r;while(Oe.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Le.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function Te(e,t,r){return Re.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function He(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Jt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(z().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(Te(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var Ne="input, textarea, select";function ke(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=Ae(t);do{c(n,qe);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var o={trigger:"every"};c(n,qe);o.pollInterval=v(c(n,/[,\[\s]/));c(n,qe);var a=He(e,n,"event");if(a){o.eventFilter=a}r.push(o)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var a=He(e,n,"event");if(a){s.eventFilter=a}while(n.length>0&&n[0]!==","){c(n,qe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Ce))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Ce);if(u==="closest"||u==="find"){n.shift();u+=" "+c(n,Ce)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Ce)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Ce))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Ce)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Ce)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,qe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,Ne)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ie(e){_(e).cancelled=true}function Me(e,t,r,n){var i=_(e);i.timeout=setTimeout(function(){if(Y(e)&&i.cancelled!==true){if(!je(n,dt("hx:poll:trigger",{triggerSpec:n,target:e}))){Z(t,r,e)}Me(e,t,V(e,"hx-"+t),n)}},n.pollInterval)}function De(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&De(t)&&t.target===""||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href");r.pushURL=true}else{var o=f(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=f(t,"action")}e.forEach(function(e){Be(t,n,i,r,e,true)})}}function Pe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&H(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Xe(e,t){return _(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function je(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(z().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Be(o,a,s,e,l,u){var t;if(l.from){t=N(o,l.from)}else{t=[o]}W(t,function(n){var i=function(e){if(!Y(o)){n.removeEventListener(l.trigger,i);return}if(Xe(o,e)){return}if(u||Pe(e,o)){e.preventDefault()}if(je(l,e)){return}var t=_(e);t.triggerSpec=l;if(t.handledFor==null){t.handledFor=[]}var r=_(o);if(t.handledFor.indexOf(o)<0){t.handledFor.push(o);if(l.consume){e.stopPropagation()}if(l.target&&e.target){if(!d(e.target,l.target)){return}}if(l.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(l.changed){if(r.lastValue===o.value){return}else{r.lastValue=o.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(l.throttle){if(!r.throttle){Z(a,s,o,e);r.throttle=setTimeout(function(){r.throttle=null},l.throttle)}}else if(l.delay){r.delayed=setTimeout(function(){Z(a,s,o,e)},l.delay)}else{Z(a,s,o,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:l.trigger,listener:i,on:n});n.addEventListener(l.trigger,i)})}var Ue=false;var Ve=null;function ze(){if(!Ve){Ve=function(){Ue=true};window.addEventListener("scroll",Ve);setInterval(function(){if(Ue){Ue=false;W(z().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){_e(e)})}},200)}}function _e(e){if(!s(e,"data-hx-revealed")&&b(e)){e.setAttribute("data-hx-revealed","true");var t=_(e);if(t.initialized){Z(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Z(t.verb,t.path,e)},{once:true})}}}function We(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Je(e,o[1],0)}if(o[0]==="send"){Ze(e)}}}function Je(s,r,n){if(!Y(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=U.createWebSocket(r);t.onerror=function(e){J(s,"htmx:wsError",{error:e,socket:t});$e(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=Ge(n);setTimeout(function(){Je(s,r,n+1)},t)}};t.onopen=function(e){n=0};_(s).webSocket=t;t.addEventListener("message",function(e){if($e(s)){return}var t=e.data;gt(s,function(e){t=e.transformResponse(t,null,s)});var r=zt(s);var n=g(t);var i=y(n.children);for(var o=0;o<i.length;o++){var a=i[o];B(V(a,"hx-swap-oob")||"true",a,r)}Ct(r.tasks)})}function $e(e){if(!Y(e)){_(e).webSocket.close();return true}}function Ze(u){var f=h(u,function(e){return _(e).webSocket!=null});if(f){u.addEventListener(ke(u)[0].trigger,function(e){var t=_(f).webSocket;var r=Xt(u,f);var n=Mt(u,"post");var i=n.errors;var o=n.values;var a=Gt(u);var s=Q(o,a);var l=jt(s,u);l["HEADERS"]=r;if(i&&i.length>0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Pe(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ge(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}pt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ke(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Ye(e,o[1])}if(o[0]==="swap"){Qe(e,o[1])}}}function Ye(t,e){var r=U.createEventSource(e);r.onerror=function(e){J(t,"htmx:sseError",{error:e,source:r});tt(t)};_(t).sseEventSource=r}function Qe(o,a){var s=h(o,rt);if(s){var l=_(s).sseEventSource;var u=function(e){if(tt(s)){l.removeEventListener(a,u);return}var t=e.data;gt(o,function(e){t=e.transformResponse(t,null,o)});var r=Ut(o);var n=ne(o);var i=zt(o);we(r.swapStyle,o,n,t,i);Ct(i.tasks);$(o,"htmx:sseMessage",e)};_(o).sseListener=u;l.addEventListener(a,u)}else{J(o,"htmx:noSSESourceError")}}function et(e,t,r,n){var i=h(e,rt);if(i){var o=_(i).sseEventSource;var a=function(){if(!tt(i)){if(Y(e)){Z(t,r,e)}else{o.removeEventListener(n,a)}}};_(e).sseListener=a;o.addEventListener(n,a)}else{J(e,"htmx:noSSESourceError")}}function tt(e){if(!Y(e)){_(e).sseEventSource.close();return true}}function rt(e){return _(e).sseEventSource!=null}function nt(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Z(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function it(o,a,e){var t=false;W(n,function(n){if(s(o,"hx-"+n)){var i=V(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){et(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){ze();_e(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=ee(o,e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){$(o,"intersect");break}}},t);r.observe(o);Be(o,n,i,a,e)}else if(e.trigger==="load"){nt(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Me(o,n,i,e)}else{Be(o,n,i,a,e)}})}});return t}function ot(e){if(e.type==="text/javascript"||e.type==="module"||e.type===""){var t=z().createElement("script");W(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(U.config.inlineScriptNonce){t.nonce=U.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){pt(e)}finally{r.removeChild(e)}}}function at(e){if(d(e,"script")){ot(e)}W(R(e,"script"),function(e){ot(e)})}function st(){return document.querySelector("[hx-boost], [data-hx-boost]")}function lt(e){if(e.querySelectorAll){var t=st()?", a, form":"";var r=e.querySelectorAll(i+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [hx-data-ext]");return r}else{return[]}}function ut(r){var e=function(e){if(d(e.target,"button, input[type='submit']")){var t=_(r);t.lastButtonClicked=e.target}};r.addEventListener("click",e);r.addEventListener("focusin",e);r.addEventListener("focusout",function(e){var t=_(r);t.lastButtonClicked=null})}function ft(e){if(e.closest&&e.closest(U.config.disableSelector)){return}var t=_(e);if(!t.initialized){t.initialized=true;$(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=ke(e);var n=it(e,t,r);if(!n&&G(e,"hx-boost")==="true"){Fe(e,t,r)}if(e.tagName==="FORM"){ut(e)}var i=V(e,"hx-sse");if(i){Ke(e,t,i)}var o=V(e,"hx-ws");if(o){We(e,t,o)}$(e,"htmx:afterProcessNode")}}function ct(e){e=k(e);ft(e);W(lt(e),function(e){ft(e)})}function ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function dt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=z().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function J(e,t,r){$(e,t,Q({error:t},r))}function vt(e){return e==="htmx:afterProcessNode"}function gt(e,t){W(sr(e),function(e){try{t(e)}catch(e){pt(e)}})}function pt(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function $(e,t,r){e=k(e);if(r==null){r={}}r["elt"]=e;var n=dt(t,r);if(U.logger&&!vt(t)){U.logger(e,t,r)}if(r.error){pt(r.error);$(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=ht(t);if(i&&o!==t){var a=dt(o,n.detail);i=i&&e.dispatchEvent(a)}gt(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var mt=location.pathname+location.search;function xt(){var e=z().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||z().body}function yt(e,t,r,n){var i=S(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>U.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(z().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function bt(e){var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function wt(e){var t=U.config.requestClass;var r=e.cloneNode(true);W(R(r,"."+t),function(e){q(e,t)});return r.innerHTML}function St(){var e=xt();var t=mt||location.pathname+location.search;$(z().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(U.config.historyEnabled)history.replaceState({htmx:true},z().title,window.location.href);yt(t,wt(e),z().title,window.scrollY)}function Et(e){if(U.config.historyEnabled)history.pushState({htmx:true},"",e);mt=e}function Ct(e){W(e,function(e){e.call()})}function Rt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};$(z().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){$(z().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=xt();var r=zt(t);me(t,e,r);Ct(r.tasks);mt=n;$(z().body,"htmx:historyRestore",{path:n})}else{J(z().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Ot(e){St();e=e||location.pathname+location.search;var t=bt(e);if(t){var r=g(t.content);var n=xt();var i=zt(n);me(n,r,i);Ct(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);mt=e;$(z().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Rt(e)}}}function Lt(e){var t=G(e,"hx-push-url");return t&&t!=="false"||_(e).boosted&&_(e).pushURL}function qt(e){var t=G(e,"hx-push-url");return t==="true"||t==="false"?null:t}function At(e){var t=F(e,"hx-indicator");if(t==null){t=[e]}W(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Tt(e){W(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function Ht(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Nt(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 kt(t,r,n,e,i){if(e==null||Ht(t,e)){return}else{t.push(e)}if(Nt(e)){var o=f(e,"name");var a=e.value;if(e.multiple){a=y(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=y(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){It(e,n)}}if(d(e,"form")){var l=e.elements;W(l,function(e){kt(t,r,n,e,i)})}}function It(e,t){if(e.willValidate){$(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});$(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Mt(e,t){var r=[];var n={};var i={};var o=[];var a=_(e);var s=d(e,"form")&&e.noValidate!==true;if(a.lastButtonClicked){s=s&&a.lastButtonClicked.formNoValidate!==true}if(t!=="get"){kt(r,i,o,H(e,"form"),s)}kt(r,n,o,e,s);if(a.lastButtonClicked){var l=f(a.lastButtonClicked,"name");if(l){n[l]=a.lastButtonClicked.value}}var u=F(e,"hx-include");W(u,function(e){kt(r,n,o,e,s);if(!d(e,"form")){W(e.querySelectorAll(Ne),function(e){kt(r,n,o,e,s)})}});n=Q(n,i);return{errors:o,values:n}}function Dt(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function Ft(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=Dt(t,r,e)})}else{t=Dt(t,r,n)}}}return t}function Pt(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){W(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Xt(e,t,r){var n={"HX-Request":"true","HX-Trigger":f(e,"id"),"HX-Trigger-Name":f(e,"name"),"HX-Target":V(t,"id"),"HX-Current-URL":z().location.href};Wt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(_(e).boosted){n["HX-Boosted"]="true"}return n}function jt(t,e){var r=G(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){W(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};W(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Bt(e){return f(e,"href")&&f(e,"href").indexOf("#")>=0}function Ut(e,t){var r=t?t:G(e,"hx-swap");var n={swapStyle:_(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(_(e).boosted&&!Bt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var o=1;o<i.length;o++){var a=i[o];if(a.indexOf("swap:")===0){n["swapDelay"]=v(a.substr(5))}if(a.indexOf("settle:")===0){n["settleDelay"]=v(a.substr(7))}if(a.indexOf("scroll:")===0){var s=a.substr(7);var l=s.split(":");var f=l.pop();var u=l.length>0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(a.indexOf("show:")===0){var c=a.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(a.indexOf("focus-scroll:")===0){var d=a.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function Vt(t,r,n){var i=null;gt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(G(r,"hx-encoding")==="multipart/form-data"||d(r,"form")&&f(r,"enctype")==="multipart/form-data"){return Pt(n)}else{return Ft(n)}}}function zt(e){return{tasks:[],elts:[e]}}function _t(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ee(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var o=t.showTarget;if(t.showTarget==="window"){o="body"}i=ee(r,o)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function Wt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}else if(o.indexOf("js:")===0){o=o.substr(3);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Jt(e,function(){return Function("return ("+o+")")()},{})}else{s=S(o)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Wt(u(e),t,r,n)}function Jt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function $t(e,t){return Wt(e,"hx-vars",true,t)}function Zt(e,t){return Wt(e,"hx-vals",false,t)}function Gt(e){return Q($t(e),Zt(e))}function Kt(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Yt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(z().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Qt(e,t){return e.getAllResponseHeaders().match(t)}function er(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return Z(e,t,null,null,{targetOverride:k(r),returnPromise:true})}else{return Z(e,t,k(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:k(r.target),swapOverride:r.swap,returnPromise:true})}}else{return Z(e,t,null,null,{returnPromise:true})}}function tr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Z(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=z().body}var v=r.handler||rr;if(!Y(n)){return}var g=r.targetOverride||ne(n);if(g==null||g==te){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=_(n);var o=G(n,"hx-sync");var m=null;var x=false;if(o){var y=o.split(":");var b=y[0].trim();if(b==="this"){p=re(n,"hx-sync")}else{p=ee(n,b)}o=(y[1]||"drop").trim();i=_(p);if(o==="drop"&&i.xhr&&i.abortable!==true){return}else if(o==="abort"){if(i.xhr){return}else{x=true}}else if(o==="replace"){$(p,"htmx:abort")}else if(o.indexOf("queue")===0){var w=o.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=_(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){Z(e,t,n,f,r)})}return}}var a=new XMLHttpRequest;i.xhr=a;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=G(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){K(c);s();return d}}var R=G(n,"hx-confirm");if(R){if(!confirm(R)){K(c);s();return d}}var O=Xt(n,g,C);if(r.headers){O=Q(O,r.headers)}var L=Mt(n,e);var q=L.errors;var A=L.values;if(r.values){A=Q(A,r.values)}var T=Gt(n);var H=Q(A,T);var N=jt(H,n);if(e!=="get"&&G(n,"hx-encoding")==null){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=z().location.href}var k=Wt(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:q,withCredentials:r.credentials||k.credentials||U.config.withCredentials,timeout:r.timeout||k.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){K(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;q=l.errors;if(q&&q.length>0){$(n,"htmx:validation:halted",l);K(c);s();return d}var I=t.split("#");var M=I[0];var D=I[1];if(e==="get"){var F=M;var P=Object.keys(N).length!==0;if(P){if(F.indexOf("?")<0){F+="?"}else{F+="&"}F+=Ft(N);if(D){F+="#"+D}}a.open("GET",F,true)}else{a.open(e.toUpperCase(),t,true)}a.overrideMimeType("text/html");a.withCredentials=l.withCredentials;a.timeout=l.timeout;if(k.noHeaders){}else{for(var X in O){if(O.hasOwnProperty(X)){var j=O[X];Kt(a,X,j)}}}var u={xhr:a,target:g,requestConfig:l,etc:r,pathInfo:{path:t,finalPath:F,anchor:D}};a.onload=function(){try{var e=tr(n);v(n,u);Tt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!Y(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(Y(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}K(c);s()}catch(e){J(n,"htmx:onLoadError",Q({error:e},u));throw e}};a.onerror=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);K(h);s()};a.onabort=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);K(h);s()};a.ontimeout=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);K(h);s()};if(!$(n,"htmx:beforeRequest",u)){K(c);s();return d}var B=At(n);W(["loadstart","loadend","progress","abort"],function(t){W([a,a.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);a.send(e==="get"?null:Vt(a,n,N));return d}function rr(s,l){var u=l.xhr;var f=l.target;var r=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(Qt(u,/HX-Trigger:/i)){Se(u,"HX-Trigger",s)}if(Qt(u,/HX-Push:/i)){var c=u.getResponseHeader("HX-Push")}if(Qt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Qt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(Qt(u,/HX-Retarget:/i)){l.target=z().querySelector(u.getResponseHeader("HX-Retarget"))}var h;if(c=="false"){h=false}else{h=Lt(s)||c}var n=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var e=u.status>=400;var t=Q({shouldSwap:n,serverResponse:d,isError:e},l);if(!$(f,"htmx:beforeSwap",t))return;f=t.target;d=t.serverResponse;e=t.isError;l.failed=e;l.successful=!e;if(t.shouldSwap){if(u.status===286){Ie(s)}gt(s,function(e){d=e.transformResponse(d,u,s)});if(h){St()}var i=r.swapOverride;var v=Ut(s,i);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=zt(f);we(v.swapStyle,f,s,d,n);if(t.elt&&!Y(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);W(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(l.pathInfo.anchor){location.hash=l.pathInfo.anchor}if(Qt(u,/HX-Trigger-After-Swap:/i)){var o=s;if(!Y(s)){o=z().body}Se(u,"HX-Trigger-After-Swap",o)}var a=function(){W(n.tasks,function(e){e.call()});W(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h){var e=c||qt(s)||Yt(u)||l.pathInfo.finalPath||l.pathInfo.path;Et(e);$(z().body,"htmx:pushedIntoHistory",{path:e})}if(n.title){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}_t(n.elts,v);if(Qt(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!Y(s)){r=z().body}Se(u,"HX-Trigger-After-Settle",r)}};if(v.settleDelay>0){setTimeout(a,v.settleDelay)}else{a()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(v.swapDelay>0){setTimeout(o,v.swapDelay)}else{o()}}if(e){J(s,"htmx:responseError",Q({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var nr={};function ir(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function or(e,t){if(t.init){t.init(r)}nr[e]=Q(ir(),t)}function ar(e){delete nr[e]}function sr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){W(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=nr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return sr(u(e),r,n)}function lr(e){if(z().readyState!=="loading"){e()}else{z().addEventListener("DOMContentLoaded",e)}}function ur(){if(U.config.includeIndicatorStyles!==false){z().head.insertAdjacentHTML("beforeend","<style> ."+U.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+U.config.requestClass+" ."+U.config.indicatorClass+"{opacity:1} ."+U.config.requestClass+"."+U.config.indicatorClass+"{opacity:1} </style>")}}function fr(){var e=z().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function cr(){var e=fr();if(e){U.config=Q(U.config,e)}}lr(function(){cr();ur();var e=z().body;ct(e);var t=z().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=_(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){Ot();W(t,function(e){$(e,"htmx:restored",{document:z(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file +// /////////////////////////////////////////////////////////////////// +// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js +// +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(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 a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/<body/.test(e)}function l(e){var t=!N(e);var r=A(e);var n=e;if(r==="head"){n=n.replace(S,"")}if(Q.config.useTemplateFragments&&t){var i=a("<body><template>"+n+"</template></body>",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a("<table>"+n+"</table>",1);case"col":return a("<table><colgroup>"+n+"</colgroup></table>",2);case"tr":return a("<table><tbody>"+n+"</tbody></table>",2);case"td":case"th":return a("<table><tbody><tr>"+n+"</tr></tbody></table>",3);case"script":case"style":return a("<div>"+n+"</div>",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function oe(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function X(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var Y=function(e,t){var r=re().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function we(t,r){oe(t.attributes,function(e){if(!r.hasAttribute(e.name)&&be(e.name)){t.removeAttribute(e.name)}});oe(r.attributes,function(e){if(be(e.name)){t.setAttribute(e.name,e.value)}})}function Se(e,t){var r=Fr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){b(e)}}return e==="outerHTML"}function Ee(e,i,a){var t="#"+ee(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a<i.length;a++){var o=i[a].split(":",2);var s=o[0].trim();if(s.indexOf("#")===0){s=s.substring(1)}var l=o[1]||"true";var u=t.querySelector("#"+s);if(u){Ee(l,u,r)}}}oe(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=te(e,"hx-swap-oob");if(t!=null){Ee(t,e,r)}})}function Re(e){oe(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=te(e,"id");var r=re().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function Te(o,e,s){oe(e.querySelectorAll("[id]"),function(e){var t=ee(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Le(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=He(n.name,t);t=He(n.value,t)}}}return t}function Ae(e){var t=ae(e);if(t.onHandlers){for(var r=0;r<t.onHandlers.length;r++){const n=t.onHandlers[r];e.removeEventListener(n.event,n.listener)}delete t.onHandlers}}function Ne(e){var t=ae(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){oe(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}Ae(e);oe(Object.keys(t),function(e){delete t[e]})}function p(e){ce(e,"htmx:beforeCleanupElement");Ne(e);if(e.children){oe(e.children,function(e){p(e)})}}function Ie(t,e,r){if(t.tagName==="BODY"){return Ue(t,e,r)}else{var n;var i=t.previousSibling;m(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}p(t);u(t).removeChild(t)}}function ke(e,t,r){return m(e,e.firstChild,t,r)}function Pe(e,t,r){return m(u(e),e,t,r)}function Me(e,t,r){return m(e,null,t,r)}function Xe(e,t,r){return m(u(e),e.nextSibling,t,r)}function De(e,t,r){p(e);return u(e).removeChild(e)}function Ue(e,t,r){var n=e.firstChild;m(e,n,t,r);if(n){while(n.nextSibling){p(n.nextSibling);e.removeChild(n.nextSibling)}p(n);e.removeChild(n)}}function Be(e,t,r){var n=r||ne(e,"hx-select");if(n){var i=re().createDocumentFragment();oe(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function Fe(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Ie(r,n,i);return;case"afterbegin":ke(r,n,i);return;case"beforebegin":Pe(r,n,i);return;case"beforeend":Me(r,n,i);return;case"afterend":Xe(r,n,i);return;case"delete":De(r,n,i);return;default:var a=Fr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Oe(f))}}}return}}catch(e){b(e)}}if(e==="innerHTML"){Ue(r,n,i)}else{Fe(Q.config.defaultSwapStyle,t,r,n,i)}}}function Ve(e){if(e.indexOf("<title")>-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){ce(r,s[l].trim(),[])}}}var ze=/\s/;var x=/[\s,]/;var $e=/[_$a-zA-Z]/;var We=/[_$a-zA-Z0-9]/;var Ge=['"',"'","/"];var Je=/[^\s]/;var Ze=/[{(]/;var Ke=/[})]/;function Ye(e){var t=[];var r=0;while(r<e.length){if($e.exec(e.charAt(r))){var n=r;while(We.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ge.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function Qe(e,t,r){return $e.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function et(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){xt(e,a[1],0)}if(a[0]==="send"){bt(e)}}}function xt(s,r,n){if(!se(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=Q.createWebSocket(r);t.onerror=function(e){fe(s,"htmx:wsError",{error:e,socket:t});yt(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a<i.length;a++){var o=i[a];Ee(te(o,"hx-swap-oob")||"true",o,r)}nr(r.tasks)})}function yt(e){if(!se(e)){ae(e).webSocket.close();return true}}function bt(u){var f=c(u,function(e){return ae(e).webSocket!=null});if(f){u.addEventListener(it(u)[0].trigger,function(e){var t=ae(f).webSocket;var r=xr(u,f);var n=dr(u,"post");var i=n.errors;var a=n.values;var o=Hr(u);var s=le(a,o);var l=yr(s,u);l["HEADERS"]=r;if(i&&i.length>0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){Et(e,a[1])}if(a[0]==="swap"){Ct(e,a[1])}}}function Et(t,e){var r=Q.createEventSource(e);r.onerror=function(e){fe(t,"htmx:sseError",{error:e,source:r});Tt(t)};ae(t).sseEventSource=r}function Ct(a,o){var s=c(a,Ot);if(s){var l=ae(s).sseEventSource;var u=function(e){if(Tt(s)){return}if(!se(a)){l.removeEventListener(o,u);return}var t=e.data;R(a,function(e){t=e.transformResponse(t,null,a)});var r=wr(a);var n=ye(a);var i=T(a);je(r.swapStyle,n,a,t,i);nr(i.tasks);ce(a,"htmx:sseMessage",e)};ae(a).sseListener=u;l.addEventListener(o,u)}else{fe(a,"htmx:noSSESourceError")}}function Rt(e,t,r){var n=c(e,Ot);if(n){var i=ae(n).sseEventSource;var a=function(){if(!Tt(n)){if(se(e)){t(e)}else{i.removeEventListener(r,a)}}};ae(e).sseListener=a;i.addEventListener(r,a)}else{fe(e,"htmx:noSSESourceError")}}function Tt(e){if(!se(e)){ae(e).sseEventSource.close();return true}}function Ot(e){return ae(e).sseEventSource!=null}function qt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n>0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){ce(n,"intersect");break}}},i);a.observe(n);ht(n,r,t,e)}else if(e.trigger==="load"){if(!ct(e,n,Wt("load",{elt:n}))){qt(n,r,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r<t.length;r++){var n=t[r].name;if(s(n,"hx-on:")||s(n,"data-hx-on:")||s(n,"hx-on-")||s(n,"data-hx-on-")){return true}}return false}function kt(e){var t=null;var r=[];if(It(e)){r.push(e)}if(document.evaluate){var n=document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]',e);while(t=n.iterateNext())r.push(t)}else{var i=e.getElementsByTagName("*");for(var a=0;a<i.length;a++){if(It(i[a])){r.push(i[a])}}}return r}function Pt(e){if(e.querySelectorAll){var t=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";var r=e.querySelectorAll(i+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Mt(e){var t=v(e.target,"button, input[type='submit']");var r=Dt(e);if(r){r.lastButtonClicked=t}}function Xt(e){var t=Dt(e);if(t){t.lastButtonClicked=null}}function Dt(e){var t=v(e.target,"button, input[type='submit']");if(!t){return}var r=g("#"+ee(t,"form"))||v(t,"form");if(!r){return}return ae(r)}function Ut(e){e.addEventListener("click",Mt);e.addEventListener("focusin",Mt);e.addEventListener("focusout",Xt)}function Bt(e){var t=Ye(e);var r=0;for(var n=0;n<t.length;n++){const i=t[n];if(i==="{"){r++}else if(i==="}"){r--}}return r}function Ft(t,e,r){var n=ae(t);if(!Array.isArray(n.onHandlers)){n.onHandlers=[]}var i;var a=function(e){return Tr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Vt(e){var t=te(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;t<e.attributes.length;t++){var r=e.attributes[t].name;var n=e.attributes[t].value;if(s(r,"hx-on")||s(r,"data-hx-on")){var i=r.indexOf("-on")+3;var a=r.slice(i,i+1);if(a==="-"||a===":"){var o=r.slice(i+1);if(s(o,":")){o="htmx"+o}else if(s(o,"-")){o="htmx:"+o.slice(1)}else if(s(o,"htmx-")){o="htmx:"+o.slice(5)}Ft(e,o,n)}}}}function _t(t){if(v(t,Q.config.disableSelector)){p(t);return}var r=ae(t);if(r.initHash!==Le(t)){Ne(t);r.initHash=Le(t);Vt(t);ce(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=it(t);var n=Ht(t,r,e);if(!n){if(ne(t,"hx-boost")==="true"){lt(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){Lt(t,e,r,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&o(t,"form")){Ut(t)}var i=te(t,"hx-sse");if(i){St(t,r,i)}var a=te(t,"hx-ws");if(a){pt(t,r,a)}ce(t,"htmx:afterProcessNode")}}function zt(e){e=g(e);if(v(e,Q.config.disableSelector)){p(e);return}_t(e);oe(Pt(e),function(e){_t(e)});oe(kt(e),jt)}function $t(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=re().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function fe(e,t,r){ce(e,t,le({error:t},r))}function Gt(e){return e==="htmx:afterProcessNode"}function R(e,t){oe(Fr(e),function(e){try{t(e)}catch(e){b(e)}})}function b(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ce(e,t,r){e=g(e);if(r==null){r={}}r["elt"]=e;var n=Wt(t,r);if(Q.logger&&!Gt(t)){Q.logger(e,t,r)}if(r.error){b(r.error);ce(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=$t(t);if(i&&a!==t){var o=Wt(a,n.detail);i=i&&e.dispatchEvent(o)}R(e,function(e){i=i&&(e.onEvent(t,n)!==false&&!n.defaultPrevented)});return i}var Jt=location.pathname+location.search;function Zt(){var e=re().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||re().body}function Kt(e,t,r,n){if(!U()){return}if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}e=B(e);var i=E(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};ce(re().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Qt(e){var t=Q.config.requestClass;var r=e.cloneNode(true);oe(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function er(){var e=Zt();var t=Jt||location.pathname+location.search;var r;try{r=re().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){r=re().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!r){ce(re().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Kt(t,Qt(e),re().title,window.scrollY)}if(Q.config.historyEnabled)history.replaceState({htmx:true},re().title,window.location.href)}function tr(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(G(e,"&")||G(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Jt=e}function rr(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Jt=e}function nr(e){oe(e,function(e){e.call()})}function ir(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};ce(re().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",re().location.href);e.onload=function(){if(this.status>=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function fr(e){if(e.name===""||e.name==null||e.disabled||v(e,"fieldset[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 cr(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function hr(t,r,n,e,i){if(e==null||ur(t,e)){return}else{t.push(e)}if(fr(e)){var a=ee(e,"name");var o=e.value;if(e.multiple&&e.tagName==="SELECT"){o=M(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=M(e.files)}cr(a,o,r);if(i){vr(e,n)}}if(h(e,"form")){var s=e.elements;oe(s,function(e){hr(t,r,n,e,i)})}}function vr(e,t){if(e.willValidate){ce(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});ce(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function dr(e,t){var r=[];var n={};var i={};var a=[];var o=ae(e);if(o.lastButtonClicked&&!se(o.lastButtonClicked)){o.lastButtonClicked=null}var s=h(e,"form")&&e.noValidate!==true||te(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){hr(r,i,a,v(e,"form"),s)}hr(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=ee(l,"name");cr(u,l.value,i)}var f=pe(e,"hx-include");oe(f,function(e){hr(r,n,a,e,s);if(!h(e,"form")){oe(e.querySelectorAll(rt),function(e){hr(r,n,a,e,s)})}});n=le(n,i);return{errors:a,values:n}}function gr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function mr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t=gr(t,r,e)})}else{t=gr(t,r,n)}}}return t}function pr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function xr(e,t,r){var n={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":re().location.href};Rr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ae(e).boosted){n["HX-Boosted"]="true"}return n}function yr(t,e){var r=ne(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){oe(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};oe(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function br(e){return ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=d(o.substr(5))}else if(o.indexOf("settle:")===0){n["settleDelay"]=d(o.substr(7))}else if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}else if(o.indexOf("ignoreTitle:")===0){n["ignoreTitle"]=o.substr(12)==="true"}else if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","<style> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file diff --git a/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.js b/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.js index 27e57bc..86e7668 100644 --- a/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.js +++ b/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.js @@ -1,13 +1,23 @@ -//AMD insanity +// /////////////////////////////////////////////////////////////////// +// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.js +// + +// UMD insanity +// This code sets up support for (in order) AMD, ES6 modules, and globals. (function (root, factory) { //@ts-ignore if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. //@ts-ignore define([], factory); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); } else { // Browser globals - root.htmx = factory(); + root.htmx = root.htmx || factory(); } }(typeof self !== 'undefined' ? self : this, function () { return (function () { @@ -38,6 +48,7 @@ return (function () { defineExtension : defineExtension, removeExtension : removeExtension, logAll : logAll, + logNone : logNone, logger : null, config : { historyEnabled:true, @@ -53,15 +64,24 @@ return (function () { settlingClass:'htmx-settling', swappingClass:'htmx-swapping', allowEval:true, + allowScriptTags:true, inlineScriptNonce:'', attributesToSettle:["class", "style", "width", "height"], withCredentials:false, timeout:0, wsReconnectDelay: 'full-jitter', + wsBinaryType: 'blob', disableSelector: "[hx-disable], [data-hx-disable]", useTemplateFragments: false, scrollBehavior: 'smooth', defaultFocusScroll: false, + getCacheBusterParam: false, + globalViewTransitions: false, + methodsThatUseUrlParams: ["get"], + selfRequestsOnly: false, + ignoreTitle: false, + scrollIntoViewOnBoost: true, + triggerSpecsCache: null, }, parseInterval:parseInterval, _:internalEval, @@ -69,17 +89,23 @@ return (function () { return new EventSource(url, {withCredentials:true}) }, createWebSocket: function(url){ - return new WebSocket(url, []); + var sock = new WebSocket(url, []); + sock.binaryType = htmx.config.wsBinaryType; + return sock; }, - version: "1.7.0" + version: "1.9.10" }; /** @type {import("./htmx").HtmxInternalApi} */ var internalAPI = { + addTriggerHandler: addTriggerHandler, bodyContains: bodyContains, + canAccessLocalStorage: canAccessLocalStorage, + findThisElement: findThisElement, filterValues: filterValues, hasAttribute: hasAttribute, getAttributeValue: getAttributeValue, + getClosestAttributeValue: getClosestAttributeValue, getClosestMatch: getClosestMatch, getExpressionVars: getExpressionVars, getHeaders: getHeaders, @@ -92,6 +118,7 @@ return (function () { mergeObjects: mergeObjects, makeSettleInfo: makeSettleInfo, oobSwap: oobSwap, + querySelectorExt: querySelectorExt, selectAndSwap: selectAndSwap, settleImmediately: settleImmediately, shouldCancel: shouldCancel, @@ -105,21 +132,40 @@ return (function () { return "[hx-" + verb + "], [data-hx-" + verb + "]" }).join(", "); + var HEAD_TAG_REGEX = makeTagRegEx('head'), + TITLE_TAG_REGEX = makeTagRegEx('title'), + SVG_TAGS_REGEX = makeTagRegEx('svg', true); + //==================================================================== // Utilities //==================================================================== + /** + * @param {string} tag + * @param {boolean} global + * @returns {RegExp} + */ + function makeTagRegEx(tag, global = false) { + return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, + global ? 'gim' : 'im'); + } + function parseInterval(str) { if (str == undefined) { - return undefined + return undefined; } + + let interval = NaN; if (str.slice(-2) == "ms") { - return parseFloat(str.slice(0,-2)) || undefined - } - if (str.slice(-1) == "s") { - return (parseFloat(str.slice(0,-1)) * 1000) || undefined + interval = parseFloat(str.slice(0, -2)); + } else if (str.slice(-1) == "s") { + interval = parseFloat(str.slice(0, -1)) * 1000; + } else if (str.slice(-1) == "m") { + interval = parseFloat(str.slice(0, -1)) * 1000 * 60; + } else { + interval = parseFloat(str); } - return parseFloat(str) || undefined + return isNaN(interval) ? undefined : interval; } /** @@ -168,13 +214,11 @@ return (function () { * @returns {HTMLElement | null} */ function getClosestMatch(elt, condition) { - if (condition(elt)) { - return elt; - } else if (parentElt(elt)) { - return getClosestMatch(parentElt(elt), condition); - } else { - return null; + while (elt && !condition(elt)) { + elt = parentElt(elt); } + + return elt ? elt : null; } function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ @@ -208,7 +252,7 @@ return (function () { * @returns {boolean} */ function matches(elt, selector) { - // @ts-ignore: non-standard properties for browser compatability + // @ts-ignore: non-standard properties for browser compatibility // noinspection JSUnresolvedVariable var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; return matchesFunction && matchesFunction.call(elt, selector); @@ -252,38 +296,47 @@ return (function () { return responseNode; } + function aFullPageResponse(resp) { + return /<body/.test(resp) + } + /** * - * @param {string} resp + * @param {string} response * @returns {Element} */ - function makeFragment(resp) { - if (htmx.config.useTemplateFragments) { - var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0); + function makeFragment(response) { + var partialResponse = !aFullPageResponse(response); + var startTag = getStartTag(response); + var content = response; + if (startTag === 'head') { + content = content.replace(HEAD_TAG_REGEX, ''); + } + if (htmx.config.useTemplateFragments && partialResponse) { + var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0); // @ts-ignore type mismatch between DocumentFragment and Element. - // TODO: Are these close enough for htmx to use interchangably? + // TODO: Are these close enough for htmx to use interchangeably? return documentFragment.querySelector('template').content; - } else { - 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); - case "script": - return parseHTML("<div>" + resp + "</div>", 1); - default: - return parseHTML(resp, 0); - } + } + switch (startTag) { + case "thead": + case "tbody": + case "tfoot": + case "colgroup": + case "caption": + return parseHTML("<table>" + content + "</table>", 1); + case "col": + return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2); + case "tr": + return parseHTML("<table><tbody>" + content + "</tbody></table>", 2); + case "td": + case "th": + return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3); + case "script": + case "style": + return parseHTML("<div>" + content + "</div>", 1); + default: + return parseHTML(content, 0); } } @@ -365,13 +418,14 @@ return (function () { return elemTop < window.innerHeight && elemBottom >= 0; } - function bodyContains(elt) { - if (elt.getRootNode() instanceof ShadowRoot) { - return getDocument().body.contains(elt.getRootNode().host); - } else { - return getDocument().body.contains(elt); - } - } + function bodyContains(elt) { + // IE Fix + if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) { + return getDocument().body.contains(elt.getRootNode().host); + } else { + return getDocument().body.contains(elt); + } + } function splitOnWhitespace(trigger) { return trigger.trim().split(/\s+/); @@ -402,6 +456,34 @@ return (function () { } } + function canAccessLocalStorage() { + var test = 'htmx:localStorageTest'; + try { + localStorage.setItem(test, test); + localStorage.removeItem(test); + return true; + } catch(e) { + return false; + } + } + + function normalizePath(path) { + try { + var url = new URL(path); + if (url) { + path = url.pathname + url.search; + } + // remove trailing slash, unless index page + if (!(/^\/$/.test(path))) { + path = path.replace(/\/+$/, ''); + } + return path; + } catch (e) { + // be kind to IE11, which doesn't support URL() + return path; + } + } + //========================================================================================== // public API //========================================================================================== @@ -427,6 +509,10 @@ return (function () { } } + function logNone() { + htmx.logger = null + } + function find(eltOrSelector, selector) { if (selector) { return eltOrSelector.querySelector(selector); @@ -446,7 +532,10 @@ return (function () { function removeElement(elt, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeElement(elt);}, delay) + setTimeout(function(){ + removeElement(elt); + elt = null; + }, delay); } else { elt.parentElement.removeChild(elt); } @@ -455,7 +544,10 @@ return (function () { function addClassToElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){addClassToElement(elt, clazz);}, delay) + setTimeout(function(){ + addClassToElement(elt, clazz); + elt = null; + }, delay); } else { elt.classList && elt.classList.add(clazz); } @@ -464,7 +556,10 @@ return (function () { function removeClassFromElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) + setTimeout(function(){ + removeClassFromElement(elt, clazz); + elt = null; + }, delay); } else { if (elt.classList) { elt.classList.remove(clazz); @@ -494,26 +589,75 @@ return (function () { if (elt.closest) { return elt.closest(selector); } else { + // TODO remove when IE goes away do{ if (elt == null || matches(elt, selector)){ return elt; } } while (elt = elt && parentElt(elt)); + return null; + } + } + + function startsWith(str, prefix) { + return str.substring(0, prefix.length) === prefix + } + + function endsWith(str, suffix) { + return str.substring(str.length - suffix.length) === suffix + } + + function normalizeSelector(selector) { + var trimmedSelector = selector.trim(); + if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) { + return trimmedSelector.substring(1, trimmedSelector.length - 2); + } else { + return trimmedSelector; } } function querySelectorAllExt(elt, selector) { if (selector.indexOf("closest ") === 0) { - return [closest(elt, selector.substr(8))]; + return [closest(elt, normalizeSelector(selector.substr(8)))]; } else if (selector.indexOf("find ") === 0) { - return [find(elt, selector.substr(5))]; + return [find(elt, normalizeSelector(selector.substr(5)))]; + } else if (selector === "next") { + return [elt.nextElementSibling] + } else if (selector.indexOf("next ") === 0) { + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; + } else if (selector === "previous") { + return [elt.previousElementSibling] + } else if (selector.indexOf("previous ") === 0) { + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; } else if (selector === 'document') { return [document]; } else if (selector === 'window') { return [window]; + } else if (selector === 'body') { + return [document.body]; } else { - return getDocument().querySelectorAll(selector); + return getDocument().querySelectorAll(normalizeSelector(selector)); + } + } + + var scanForwardQuery = function(start, match) { + var results = getDocument().querySelectorAll(match); + for (var i = 0; i < results.length; i++) { + var elt = results[i]; + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { + return elt; + } + } + } + + var scanBackwardsQuery = function(start, match) { + var results = getDocument().querySelectorAll(match); + for (var i = results.length - 1; i >= 0; i--) { + var elt = results[i]; + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { + return elt; + } } } @@ -570,7 +714,7 @@ return (function () { //==================================================================== // Node processing //==================================================================== - + var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors function findAttributeTargets(elt, attrName) { var attrTarget = getClosestAttributeValue(elt, attrName); @@ -659,7 +803,7 @@ return (function () { * @returns */ function oobSwap(oobValue, oobElement, settleInfo) { - var selector = "#" + oobElement.id; + var selector = "#" + getRawAttribute(oobElement, "id"); var swapStyle = "outerHTML"; if (oobValue === "true") { // do nothing @@ -703,7 +847,23 @@ return (function () { return oobValue; } - function handleOutOfBandSwaps(fragment, settleInfo) { + function handleOutOfBandSwaps(elt, fragment, settleInfo) { + var oobSelects = getClosestAttributeValue(elt, "hx-select-oob"); + if (oobSelects) { + var oobSelectValues = oobSelects.split(","); + for (var i = 0; i < oobSelectValues.length; i++) { + var oobSelectValue = oobSelectValues[i].split(":", 2); + var id = oobSelectValue[0].trim(); + if (id.indexOf("#") === 0) { + id = id.substring(1); + } + var oobValue = oobSelectValue[1] || "true"; + var oobElement = fragment.querySelector("#" + id); + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo); + } + } + } forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) { var oobValue = getAttributeValue(oobElement, "hx-swap-oob"); if (oobValue != null) { @@ -724,8 +884,11 @@ return (function () { function handleAttributes(parentNode, fragment, settleInfo) { forEach(fragment.querySelectorAll("[id]"), function (newNode) { - if (newNode.id && newNode.id.length > 0) { - var oldNode = parentNode.querySelector(newNode.tagName + "[id='" + newNode.id + "']"); + var id = getRawAttribute(newNode, "id") + if (id && id.length > 0) { + var normalizedId = id.replace("'", "\\'"); + var normalizedTag = newNode.tagName.replace(':', '\\:'); + var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']"); if (oldNode && oldNode !== parentNode) { var newAttributes = newNode.cloneNode(); cloneAttributes(newNode, oldNode); @@ -767,24 +930,67 @@ return (function () { } } - function cleanUpElement(element) { + // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, + // derived from Java's string hashcode implementation + function stringHash(string, hash) { + var char = 0; + while (char < string.length){ + hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int + } + return hash; + } + + function attributeHash(elt) { + var hash = 0; + // IE fix + if (elt.attributes) { + for (var i = 0; i < elt.attributes.length; i++) { + var attribute = elt.attributes[i]; + if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent) + hash = stringHash(attribute.name, hash); + hash = stringHash(attribute.value, hash); + } + } + } + return hash; + } + + function deInitOnHandlers(elt) { + var internalData = getInternalData(elt); + if (internalData.onHandlers) { + for (var i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i]; + elt.removeEventListener(handlerInfo.event, handlerInfo.listener); + } + delete internalData.onHandlers + } + } + + function deInitNode(element) { var internalData = getInternalData(element); + if (internalData.timeout) { + clearTimeout(internalData.timeout); + } if (internalData.webSocket) { internalData.webSocket.close(); } if (internalData.sseEventSource) { internalData.sseEventSource.close(); } - - triggerEvent(element, "htmx:beforeCleanupElement") - if (internalData.listenerInfos) { - forEach(internalData.listenerInfos, function(info) { - if (element !== info.on) { + forEach(internalData.listenerInfos, function (info) { + if (info.on) { info.on.removeEventListener(info.trigger, info.listener); } }); } + deInitOnHandlers(element); + forEach(Object.keys(internalData), function(key) { delete internalData[key] }); + } + + function cleanUpElement(element) { + triggerEvent(element, "htmx:beforeCleanupElement") + deInitNode(element); if (element.children) { // IE forEach(element.children, function(child) { cleanUpElement(child) }); } @@ -803,8 +1009,7 @@ return (function () { } else { newElt = eltBeforeNewContent.nextSibling; } - getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later - settleInfo.elts = [] // clear existing elements + settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target }); while(newElt && newElt !== target) { if (newElt.nodeType === Node.ELEMENT_NODE) { settleInfo.elts.push(newElt); @@ -849,8 +1054,8 @@ return (function () { } } - function maybeSelectFromResponse(elt, fragment) { - var selector = getClosestAttributeValue(elt, "hx-select"); + function maybeSelectFromResponse(elt, fragment, selectOverride) { + var selector = selectOverride || getClosestAttributeValue(elt, "hx-select"); if (selector) { var newFragment = getDocument().createDocumentFragment(); forEach(fragment.querySelectorAll(selector), function (node) { @@ -915,21 +1120,20 @@ return (function () { function findTitle(content) { if (content.indexOf('<title') > -1) { - var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, ''); - var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im); - + var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, ''); + var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX); if (result) { return result[2]; } } } - function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) { + function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) { settleInfo.title = findTitle(responseText); var fragment = makeFragment(responseText); if (fragment) { - handleOutOfBandSwaps(fragment, settleInfo); - fragment = maybeSelectFromResponse(elt, fragment); + handleOutOfBandSwaps(elt, fragment, settleInfo); + fragment = maybeSelectFromResponse(elt, fragment, selectOverride); handlePreservedElements(fragment); return swap(swapStyle, elt, target, fragment, settleInfo); } @@ -949,7 +1153,10 @@ return (function () { } } } else { - triggerEvent(elt, triggerBody, []); + var eventNames = triggerBody.split(",") + for (var i = 0; i < eventNames.length; i++) { + triggerEvent(elt, eventNames[i].trim(), []); + } } } @@ -959,6 +1166,8 @@ return (function () { var SYMBOL_CONT = /[_$a-zA-Z0-9]/; var STRINGISH_START = ['"', "'", "/"]; var NOT_WHITESPACE = /[^\s]/; + var COMBINED_SELECTOR_START = /[{(]/; + var COMBINED_SELECTOR_END = /[})]/; function tokenizeString(str) { var tokens = []; var position = 0; @@ -1041,101 +1250,137 @@ return (function () { function consumeUntil(tokens, match) { var result = ""; - while (tokens.length > 0 && !tokens[0].match(match)) { + while (tokens.length > 0 && !match.test(tokens[0])) { result += tokens.shift(); } return result; } + function consumeCSSSelector(tokens) { + var result; + if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { + tokens.shift(); + result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim(); + tokens.shift(); + } else { + result = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } + return result; + } + var INPUT_SELECTOR = 'input, textarea, select'; /** * @param {HTMLElement} elt + * @param {string} explicitTrigger + * @param {cache} cache for trigger specs * @returns {import("./htmx").HtmxTriggerSpecification[]} */ - function getTriggerSpecs(elt) { - var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); + function parseAndCacheTrigger(elt, explicitTrigger, cache) { var triggerSpecs = []; - if (explicitTrigger) { - var tokens = tokenizeString(explicitTrigger); - do { - consumeUntil(tokens, NOT_WHITESPACE); - var initialLength = tokens.length; - var trigger = consumeUntil(tokens, /[,\[\s]/); - if (trigger !== "") { - if (trigger === "every") { - var every = {trigger: 'every'}; - consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); - consumeUntil(tokens, NOT_WHITESPACE); - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - every.eventFilter = eventFilter; - } - triggerSpecs.push(every); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); - } else { - var triggerSpec = {trigger: trigger}; - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - triggerSpec.eventFilter = eventFilter; - } - while (tokens.length > 0 && tokens[0] !== ",") { - consumeUntil(tokens, NOT_WHITESPACE) - var token = tokens.shift(); - if (token === "changed") { - triggerSpec.changed = true; - } else if (token === "once") { - triggerSpec.once = true; - } else if (token === "consume") { - triggerSpec.consume = true; - } else if (token === "delay" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "from" && tokens[0] === ":") { - tokens.shift(); + var tokens = tokenizeString(explicitTrigger); + do { + consumeUntil(tokens, NOT_WHITESPACE); + var initialLength = tokens.length; + var trigger = consumeUntil(tokens, /[,\[\s]/); + if (trigger !== "") { + if (trigger === "every") { + var every = {trigger: 'every'}; + consumeUntil(tokens, NOT_WHITESPACE); + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); + consumeUntil(tokens, NOT_WHITESPACE); + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + every.eventFilter = eventFilter; + } + triggerSpecs.push(every); + } else if (trigger.indexOf("sse:") === 0) { + triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); + } else { + var triggerSpec = {trigger: trigger}; + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + triggerSpec.eventFilter = eventFilter; + } + while (tokens.length > 0 && tokens[0] !== ",") { + consumeUntil(tokens, NOT_WHITESPACE) + var token = tokens.shift(); + if (token === "changed") { + triggerSpec.changed = true; + } else if (token === "once") { + triggerSpec.once = true; + } else if (token === "consume") { + triggerSpec.consume = true; + } else if (token === "delay" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); + } else if (token === "from" && tokens[0] === ":") { + tokens.shift(); + if (COMBINED_SELECTOR_START.test(tokens[0])) { + var from_arg = consumeCSSSelector(tokens); + } else { var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); - if (from_arg === "closest" || from_arg === "find") { + if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") { tokens.shift(); - from_arg += - " " + - consumeUntil( - tokens, - WHITESPACE_OR_COMMA - ); + var selector = consumeCSSSelector(tokens); + // `next` and `previous` allow a selector-less syntax + if (selector.length > 0) { + from_arg += " " + selector; + } } - triggerSpec.from = from_arg; - } else if (token === "target" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if (token === "throttle" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "queue" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if ((token === "root" || token === "threshold") && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); } + triggerSpec.from = from_arg; + } else if (token === "target" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.target = consumeCSSSelector(tokens); + } else if (token === "throttle" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); + } else if (token === "queue" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } else if (token === "root" && tokens[0] === ":") { + tokens.shift(); + triggerSpec[token] = consumeCSSSelector(tokens); + } else if (token === "threshold" && tokens[0] === ":") { + tokens.shift(); + triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } else { + triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); } - triggerSpecs.push(triggerSpec); } + triggerSpecs.push(triggerSpec); } - if (tokens.length === initialLength) { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - consumeUntil(tokens, NOT_WHITESPACE); - } while (tokens[0] === "," && tokens.shift()) + } + if (tokens.length === initialLength) { + triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); + } + consumeUntil(tokens, NOT_WHITESPACE); + } while (tokens[0] === "," && tokens.shift()) + if (cache) { + cache[explicitTrigger] = triggerSpecs + } + return triggerSpecs + } + + /** + * @param {HTMLElement} elt + * @returns {import("./htmx").HtmxTriggerSpecification[]} + */ + function getTriggerSpecs(elt) { + var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); + var triggerSpecs = []; + if (explicitTrigger) { + var cache = htmx.config.triggerSpecsCache + triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) } if (triggerSpecs.length > 0) { return triggerSpecs; } else if (matches(elt, 'form')) { return [{trigger: 'submit'}]; + } else if (matches(elt, 'input[type="button"], input[type="submit"]')){ + return [{trigger: 'click'}]; } else if (matches(elt, INPUT_SELECTOR)) { return [{trigger: 'change'}]; } else { @@ -1147,14 +1392,17 @@ return (function () { getInternalData(elt).cancelled = true; } - function processPolling(elt, verb, path, spec) { + function processPolling(elt, handler, spec) { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { - issueAjaxRequest(verb, path, elt); + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { + handler(elt); } - processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), spec); + processPolling(elt, handler, spec); } }, spec.pollInterval); } @@ -1166,23 +1414,27 @@ return (function () { } function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt) && elt.target === "") || elt.tagName === "FORM") { + if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || elt.tagName === "FORM") { nodeData.boosted = true; var verb, path; if (elt.tagName === "A") { verb = "get"; - path = getRawAttribute(elt, 'href'); - nodeData.pushURL = true; + path = getRawAttribute(elt, 'href') } else { var rawAttribute = getRawAttribute(elt, "method"); verb = rawAttribute ? rawAttribute.toLowerCase() : "get"; if (verb === "get") { - nodeData.pushURL = true; } path = getRawAttribute(elt, 'action'); } triggerSpecs.forEach(function(triggerSpec) { - addEventListener(elt, verb, path, nodeData, triggerSpec, true); + addEventListener(elt, function(elt, evt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + issueAjaxRequest(verb, path, elt, evt) + }, nodeData, triggerSpec, true); }); } } @@ -1213,11 +1465,11 @@ return (function () { return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); } - function maybeFilterEvent(triggerSpec, evt) { + function maybeFilterEvent(triggerSpec, elt, evt) { var eventFilter = triggerSpec.eventFilter; if(eventFilter){ try { - return eventFilter(evt) !== true; + return eventFilter.call(elt, evt) !== true; } catch(e) { triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); return true; @@ -1226,13 +1478,21 @@ return (function () { return false; } - function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { + function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { + var elementData = getInternalData(elt); var eltsToListenOn; if (triggerSpec.from) { eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); } else { eltsToListenOn = [elt]; } + // store the initial values of the elements, so we can tell if they change + if (triggerSpec.changed) { + eltsToListenOn.forEach(function (eltToListenOn) { + var eltToListenOnData = getInternalData(eltToListenOn); + eltToListenOnData.lastValue = eltToListenOn.value; + }) + } forEach(eltsToListenOn, function (eltToListenOn) { var eventListener = function (evt) { if (!bodyContains(elt)) { @@ -1245,7 +1505,7 @@ return (function () { if (explicitCancel || shouldCancel(evt, elt)) { evt.preventDefault(); } - if (maybeFilterEvent(triggerSpec, evt)) { + if (maybeFilterEvent(triggerSpec, elt, evt)) { return; } var eventData = getInternalData(evt); @@ -1253,7 +1513,6 @@ return (function () { if (eventData.handledFor == null) { eventData.handledFor = []; } - var elementData = getInternalData(elt); if (eventData.handledFor.indexOf(elt) < 0) { eventData.handledFor.push(elt); if (triggerSpec.consume) { @@ -1272,11 +1531,11 @@ return (function () { } } if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { + var eltToListenOnData = getInternalData(eltToListenOn) + if (eltToListenOnData.lastValue === eltToListenOn.value) { return; - } else { - elementData.lastValue = elt.value; } + eltToListenOnData.lastValue = eltToListenOn.value } if (elementData.delayed) { clearTimeout(elementData.delayed); @@ -1285,19 +1544,18 @@ return (function () { return; } - if (triggerSpec.throttle) { + if (triggerSpec.throttle > 0) { if (!elementData.throttle) { - issueAjaxRequest(verb, path, elt, evt); + handler(elt, evt); elementData.throttle = setTimeout(function () { elementData.throttle = null; }, triggerSpec.throttle); } - } else if (triggerSpec.delay) { - elementData.delayed = setTimeout(function () { - issueAjaxRequest(verb, path, elt, evt); - }, triggerSpec.delay); + } else if (triggerSpec.delay > 0) { + elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); } else { - issueAjaxRequest(verb, path, elt, evt); + triggerEvent(elt, 'htmx:trigger') + handler(elt, evt); } } }; @@ -1310,7 +1568,7 @@ return (function () { on: eltToListenOn }) eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); - }) + }); } var windowIsScrolling = false // used by initScrollHandler @@ -1336,14 +1594,11 @@ return (function () { if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { elt.setAttribute('data-hx-revealed', 'true'); var nodeData = getInternalData(elt); - if (nodeData.initialized) { - issueAjaxRequest(nodeData.verb, nodeData.path, elt); + if (nodeData.initHash) { + triggerEvent(elt, 'revealed'); } else { // if the node isn't initialized, wait for it before triggering the request - elt.addEventListener("htmx:afterProcessNode", - function () { - issueAjaxRequest(nodeData.verb, nodeData.path, elt); - }, {once: true}); + elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true}); } } } @@ -1502,6 +1757,9 @@ return (function () { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function (event) { if (maybeCloseSSESource(sseSourceElt)) { + return; + } + if (!bodyContains(elt)) { sseEventSource.removeEventListener(sseEventName, sseListener); return; } @@ -1518,7 +1776,7 @@ return (function () { var target = getTarget(elt) var settleInfo = makeSettleInfo(elt); - selectAndSwap(swapSpec.swapStyle, elt, target, response, settleInfo) + selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) settleImmediately(settleInfo.tasks) triggerEvent(elt, "htmx:sseMessage", event) }; @@ -1530,14 +1788,14 @@ return (function () { } } - function processSSETrigger(elt, verb, path, sseEventName) { + function processSSETrigger(elt, handler, sseEventName) { var sseSourceElt = getClosestMatch(elt, hasEventSource); if (sseSourceElt) { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function () { if (!maybeCloseSSESource(sseSourceElt)) { if (bodyContains(elt)) { - issueAjaxRequest(verb, path, elt); + handler(elt); } else { sseEventSource.removeEventListener(sseEventName, sseListener); } @@ -1563,14 +1821,14 @@ return (function () { //==================================================================== - function loadImmediately(elt, verb, path, nodeData, delay) { + function loadImmediately(elt, handler, nodeData, delay) { var load = function(){ if (!nodeData.loaded) { nodeData.loaded = true; - issueAjaxRequest(verb, path, elt); + handler(elt); } } - if (delay) { + if (delay > 0) { setTimeout(load, delay); } else { load(); @@ -1586,46 +1844,59 @@ return (function () { nodeData.path = path; nodeData.verb = verb; triggerSpecs.forEach(function(triggerSpec) { - if (triggerSpec.sseEvent) { - processSSETrigger(elt, verb, path, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - maybeReveal(elt); - } else if (triggerSpec.trigger === "intersect") { - var observerOptions = {}; - if (triggerSpec.root) { - observerOptions.root = querySelectorExt(elt, triggerSpec.root) - } - if (triggerSpec.threshold) { - observerOptions.threshold = parseFloat(triggerSpec.threshold); + addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return } - var observer = new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - if (entry.isIntersecting) { - triggerEvent(elt, "intersect"); - break; - } - } - }, observerOptions); - observer.observe(elt); - addEventListener(elt, verb, path, nodeData, triggerSpec); - } else if (triggerSpec.trigger === "load") { - loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); - } else if (triggerSpec.pollInterval) { - nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec); - } else { - addEventListener(elt, verb, path, nodeData, triggerSpec); - } + issueAjaxRequest(verb, path, elt, evt) + }) }); } }); return explicitAction; } + function addTriggerHandler(elt, triggerSpec, nodeData, handler) { + if (triggerSpec.sseEvent) { + processSSETrigger(elt, handler, triggerSpec.sseEvent); + } else if (triggerSpec.trigger === "revealed") { + initScrollHandler(); + addEventListener(elt, handler, nodeData, triggerSpec); + maybeReveal(elt); + } else if (triggerSpec.trigger === "intersect") { + var observerOptions = {}; + if (triggerSpec.root) { + observerOptions.root = querySelectorExt(elt, triggerSpec.root) + } + if (triggerSpec.threshold) { + observerOptions.threshold = parseFloat(triggerSpec.threshold); + } + var observer = new IntersectionObserver(function (entries) { + for (var i = 0; i < entries.length; i++) { + var entry = entries[i]; + if (entry.isIntersecting) { + triggerEvent(elt, "intersect"); + break; + } + } + }, observerOptions); + observer.observe(elt); + addEventListener(elt, handler, nodeData, triggerSpec); + } else if (triggerSpec.trigger === "load") { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { + loadImmediately(elt, handler, nodeData, triggerSpec.delay); + } + } else if (triggerSpec.pollInterval > 0) { + nodeData.polling = true; + processPolling(elt, handler, triggerSpec); + } else { + addEventListener(elt, handler, nodeData, triggerSpec); + } + } + function evalScript(script) { - if (script.type === "text/javascript" || script.type === "module" || script.type === "") { + if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) { var newScript = getDocument().createElement("script"); forEach(script.attributes, function (attr) { newScript.setAttribute(attr.name, attr.value); @@ -1642,7 +1913,10 @@ return (function () { } catch (e) { logError(e); } finally { - parent.removeChild(script); + // remove old script element, but only if it is still in DOM + if (script.parentElement) { + script.parentElement.removeChild(script); + } } } } @@ -1656,48 +1930,187 @@ return (function () { }); } - function hasChanceOfBeingBoosted() { - return document.querySelector("[hx-boost], [data-hx-boost]"); + function shouldProcessHxOn(elt) { + var attributes = elt.attributes + for (var j = 0; j < attributes.length; j++) { + var attrName = attributes[j].name + if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") || + startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) { + return true + } + } + return false + } + + function findHxOnWildcardElements(elt) { + var node = null + var elements = [] + + if (shouldProcessHxOn(elt)) { + elements.push(elt) + } + + if (document.evaluate) { + var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + + ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt) + while (node = iter.iterateNext()) elements.push(node) + } else { + var allElements = elt.getElementsByTagName("*") + for (var i = 0; i < allElements.length; i++) { + if (shouldProcessHxOn(allElements[i])) { + elements.push(allElements[i]) + } + } + } + + return elements } function findElementsToProcess(elt) { if (elt.querySelectorAll) { - var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; - var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [hx-data-ext]"); + var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; + var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," + + " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]"); return results; } else { return []; } } - function initButtonTracking(form){ - var maybeSetLastButtonClicked = function(evt){ - if (matches(evt.target, "button, input[type='submit']")) { - var internalData = getInternalData(form); - internalData.lastButtonClicked = evt.target; - } - }; - + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + function maybeSetLastButtonClicked(evt) { + var elt = closest(evt.target, "button, input[type='submit']"); + var internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = elt; + } + }; + function maybeUnsetLastButtonClicked(evt){ + var internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = null; + } + } + function getRelatedFormData(evt) { + var elt = closest(evt.target, "button, input[type='submit']"); + if (!elt) { + return; + } + var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form'); + if (!form) { + return; + } + return getInternalData(form); + } + function initButtonTracking(elt) { // need to handle both click and focus in: // focusin - in case someone tabs in to a button and hits the space bar // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + elt.addEventListener('click', maybeSetLastButtonClicked) + elt.addEventListener('focusin', maybeSetLastButtonClicked) + elt.addEventListener('focusout', maybeUnsetLastButtonClicked) + } - form.addEventListener('click', maybeSetLastButtonClicked) - form.addEventListener('focusin', maybeSetLastButtonClicked) - form.addEventListener('focusout', function(evt){ - var internalData = getInternalData(form); - internalData.lastButtonClicked = null; - }) + function countCurlies(line) { + var tokens = tokenizeString(line); + var netCurlies = 0; + for (var i = 0; i < tokens.length; i++) { + const token = tokens[i]; + if (token === "{") { + netCurlies++; + } else if (token === "}") { + netCurlies--; + } + } + return netCurlies; + } + + function addHxOnEventHandler(elt, eventName, code) { + var nodeData = getInternalData(elt); + if (!Array.isArray(nodeData.onHandlers)) { + nodeData.onHandlers = []; + } + var func; + var listener = function (e) { + return maybeEval(elt, function() { + if (!func) { + func = new Function("event", code); + } + func.call(elt, e); + }); + }; + elt.addEventListener(eventName, listener); + nodeData.onHandlers.push({event:eventName, listener:listener}); + } + + function processHxOn(elt) { + var hxOnValue = getAttributeValue(elt, 'hx-on'); + if (hxOnValue) { + var handlers = {} + var lines = hxOnValue.split("\n"); + var currentEvent = null; + var curlyCount = 0; + while (lines.length > 0) { + var line = lines.shift(); + var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/); + if (curlyCount === 0 && match) { + line.split(":") + currentEvent = match[1].slice(0, -1); // strip last colon + handlers[currentEvent] = match[2]; + } else { + handlers[currentEvent] += line; + } + curlyCount += countCurlies(line); + } + + for (var eventName in handlers) { + addHxOnEventHandler(elt, eventName, handlers[eventName]); + } + } + } + + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (var i = 0; i < elt.attributes.length; i++) { + var name = elt.attributes[i].name + var value = elt.attributes[i].value + if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) { + var afterOnPosition = name.indexOf("-on") + 3; + var nextChar = name.slice(afterOnPosition, afterOnPosition + 1); + if (nextChar === "-" || nextChar === ":") { + var eventName = name.slice(afterOnPosition + 1); + // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support + if (startsWith(eventName, ":")) { + eventName = "htmx" + eventName + } else if (startsWith(eventName, "-")) { + eventName = "htmx:" + eventName.slice(1); + } else if (startsWith(eventName, "htmx-")) { + eventName = "htmx:" + eventName.slice(5); + } + + addHxOnEventHandler(elt, eventName, value) + } + } + } } function initNode(elt) { - if (elt.closest && elt.closest(htmx.config.disableSelector)) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) return; } var nodeData = getInternalData(elt); - if (!nodeData.initialized) { - nodeData.initialized = true; + if (nodeData.initHash !== attributeHash(elt)) { + // clean up any previously processed info + deInitNode(elt); + + nodeData.initHash = attributeHash(elt); + + processHxOn(elt); + triggerEvent(elt, "htmx:beforeProcessNode") if (elt.value) { @@ -1705,14 +2118,24 @@ return (function () { } var triggerSpecs = getTriggerSpecs(elt); - var explicitAction = processVerbs(elt, nodeData, triggerSpecs); - - if (!explicitAction && getClosestAttributeValue(elt, "hx-boost") === "true") { - boostElement(elt, nodeData, triggerSpecs); + var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs); + + if (!hasExplicitHttpAction) { + if (getClosestAttributeValue(elt, "hx-boost") === "true") { + boostElement(elt, nodeData, triggerSpecs); + } else if (hasAttribute(elt, 'hx-trigger')) { + triggerSpecs.forEach(function (triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function () { + }) + }) + } } - if (elt.tagName === "FORM") { - initButtonTracking(elt); + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) { + initButtonTracking(elt) } var sseInfo = getAttributeValue(elt, 'hx-sse'); @@ -1730,8 +2153,15 @@ return (function () { function processNode(elt) { elt = resolveTarget(elt); + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return; + } initNode(elt); forEach(findElementsToProcess(elt), function(child) { initNode(child) }); + // Because it happens second, the new way of adding onHandlers superseeds the old one + // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored + forEach(findHxOnWildcardElements(elt), processHxOnWildcard); } //==================================================================== @@ -1809,7 +2239,7 @@ return (function () { eventResult = eventResult && elt.dispatchEvent(kebabedEvent) } withExtensions(elt, function (extension) { - eventResult = eventResult && (extension.onEvent(eventName, event) !== false) + eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) }); return eventResult; } @@ -1825,6 +2255,18 @@ return (function () { } function saveToHistoryCache(url, content, title, scroll) { + if (!canAccessLocalStorage()) { + return; + } + + if (htmx.config.historyCacheSize <= 0) { + // make sure that an eventually already existing cache is purged + localStorage.removeItem("htmx-history-cache"); + return; + } + + url = normalizePath(url); + var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { @@ -1832,7 +2274,9 @@ return (function () { break; } } - historyCache.push({url:url, content: content, title:title, scroll:scroll}) + var newHistoryItem = {url:url, content: content, title:title, scroll:scroll}; + triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache}) + historyCache.push(newHistoryItem) while (historyCache.length > htmx.config.historyCacheSize) { historyCache.shift(); } @@ -1848,6 +2292,12 @@ return (function () { } function getCachedHistory(url) { + if (!canAccessLocalStorage()) { + return null; + } + + url = normalizePath(url); + var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { @@ -1869,13 +2319,43 @@ return (function () { function saveCurrentPageToHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; - triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); - if(htmx.config.historyEnabled) history.replaceState({htmx:true}, getDocument().title, window.location.href); - saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); + + // Allow history snapshot feature to be disabled where hx-history="false" + // is present *anywhere* in the current document we're about to save, + // so we can prevent privileged data entering the cache. + // The page will still be reachable as a history entry, but htmx will fetch it + // live from the server onpopstate rather than look in the localStorage cache + var disableHistoryCache + try { + disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') + } catch (e) { + // IE11: insensitive modifier not supported so fallback to case sensitive selector + disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') + } + if (!disableHistoryCache) { + triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt}); + saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); + } + + if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href); } function pushUrlIntoHistory(path) { - if(htmx.config.historyEnabled) history.pushState({htmx:true}, "", path); + // remove the cache buster parameter, if any + if (htmx.config.getCacheBusterParam) { + path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') + if (endsWith(path, '&') || endsWith(path, "?")) { + path = path.slice(0, -1); + } + } + if(htmx.config.historyEnabled) { + history.pushState({htmx:true}, "", path); + } + currentPathForHistory = path; + } + + function replaceUrlInHistory(path) { + if(htmx.config.historyEnabled) history.replaceState({htmx:true}, "", path); currentPathForHistory = path; } @@ -1890,7 +2370,9 @@ return (function () { var details = {path: path, xhr:request}; triggerEvent(getDocument().body, "htmx:historyCacheMiss", details); request.open('GET', path, true); + request.setRequestHeader("HX-Request", "true"); request.setRequestHeader("HX-History-Restore-Request", "true"); + request.setRequestHeader("HX-Current-URL", getDocument().location.href); request.onload = function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); @@ -1899,11 +2381,20 @@ return (function () { fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; var historyElement = getHistoryElement(); var settleInfo = makeSettleInfo(historyElement); + var title = findTitle(this.response); + if (title) { + var titleElt = find("title"); + if (titleElt) { + titleElt.innerHTML = title; + } else { + window.document.title = title; + } + } // @ts-ignore swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); + triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response}); } else { triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details); } @@ -1922,9 +2413,11 @@ return (function () { swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); document.title = cached.title; - window.scrollTo(0, cached.scroll); + setTimeout(function () { + window.scrollTo(0, cached.scroll); + }, 0); // next 'tick', so browser has time to render layout currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); + triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); } else { if (htmx.config.refreshOnHistoryMiss) { @@ -1936,31 +2429,46 @@ return (function () { } } - function shouldPush(elt) { - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - return (pushUrl && pushUrl !== "false") || - (getInternalData(elt).boosted && getInternalData(elt).pushURL); - } - - function getPushUrl(elt) { - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - return (pushUrl === "true" || pushUrl === "false") ? null : pushUrl; - } - function addRequestIndicatorClasses(elt) { var indicators = findAttributeTargets(elt, 'hx-indicator'); if (indicators == null) { indicators = [elt]; } forEach(indicators, function (ic) { + var internalData = getInternalData(ic); + internalData.requestCount = (internalData.requestCount || 0) + 1; ic.classList["add"].call(ic.classList, htmx.config.requestClass); }); return indicators; } - function removeRequestIndicatorClasses(indicators) { + function disableElements(elt) { + var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt'); + if (disabledElts == null) { + disabledElts = []; + } + forEach(disabledElts, function (disabledElement) { + var internalData = getInternalData(disabledElement); + internalData.requestCount = (internalData.requestCount || 0) + 1; + disabledElement.setAttribute("disabled", ""); + }); + return disabledElts; + } + + function removeRequestIndicators(indicators, disabled) { forEach(indicators, function (ic) { - ic.classList["remove"].call(ic.classList, htmx.config.requestClass); + var internalData = getInternalData(ic); + internalData.requestCount = (internalData.requestCount || 0) - 1; + if (internalData.requestCount === 0) { + ic.classList["remove"].call(ic.classList, htmx.config.requestClass); + } + }); + forEach(disabled, function (disabledElement) { + var internalData = getInternalData(disabledElement); + internalData.requestCount = (internalData.requestCount || 0) - 1; + if (internalData.requestCount === 0) { + disabledElement.removeAttribute('disabled'); + } }); } @@ -1979,7 +2487,7 @@ return (function () { } function shouldInclude(elt) { - if(elt.name === "" || elt.name == null || elt.disabled) { + if(elt.name === "" || elt.name == null || elt.disabled || closest(elt, "fieldset[disabled]")) { return false; } // ignore "submitter" types (see jQuery src/serialize.js) @@ -1992,6 +2500,29 @@ return (function () { return true; } + function addValueToValues(name, value, values) { + // This is a little ugly because both the current value of the named value in the form + // and the new value could be arrays, so we have to handle all four cases :/ + if (name != null && value != null) { + var current = values[name]; + if (current === undefined) { + values[name] = value; + } else if (Array.isArray(current)) { + if (Array.isArray(value)) { + values[name] = current.concat(value); + } else { + current.push(value); + } + } else { + if (Array.isArray(value)) { + values[name] = [current].concat(value); + } else { + values[name] = [current, value]; + } + } + } + } + function processInputValue(processed, values, errors, elt, validate) { if (elt == null || haveSeenNode(processed, elt)) { return; @@ -2001,35 +2532,14 @@ return (function () { if (shouldInclude(elt)) { var name = getRawAttribute(elt,"name"); var value = elt.value; - if (elt.multiple) { + if (elt.multiple && elt.tagName === "SELECT") { value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value }); } // include file inputs if (elt.files) { value = toArray(elt.files); } - // This is a little ugly because both the current value of the named value in the form - // and the new value could be arrays, so we have to handle all four cases :/ - if (name != null && value != null) { - var current = values[name]; - if(current) { - if (Array.isArray(current)) { - if (Array.isArray(value)) { - values[name] = current.concat(value); - } else { - current.push(value); - } - } else { - if (Array.isArray(value)) { - values[name] = [current].concat(value); - } else { - values[name] = [current, value]; - } - } - } else { - values[name] = value; - } - } + addValueToValues(name, value, values); if (validate) { validateElement(elt, errors); } @@ -2062,9 +2572,13 @@ return (function () { var formValues = {}; var errors = []; var internalData = getInternalData(elt); + if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { + internalData.lastButtonClicked = null + } // only validate when form is directly submitted and novalidate or formnovalidate are not set - var validate = matches(elt, 'form') && elt.noValidate !== true; + // or if the element has an explicit hx-validate="true" on it + var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true"; if (internalData.lastButtonClicked) { validate = validate && internalData.lastButtonClicked.formNoValidate !== true; } @@ -2078,11 +2592,11 @@ return (function () { processInputValue(processed, values, errors, elt, validate); // if a button or submit was clicked last, include its value - if (internalData.lastButtonClicked) { - var name = getRawAttribute(internalData.lastButtonClicked,"name"); - if (name) { - values[name] = internalData.lastButtonClicked.value; - } + if (internalData.lastButtonClicked || elt.tagName === "BUTTON" || + (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) { + var button = internalData.lastButtonClicked || elt + var name = getRawAttribute(button, "name") + addValueToValues(name, button.value, formValues) } // include any explicit includes @@ -2228,40 +2742,43 @@ return (function () { "swapDelay" : htmx.config.defaultSwapDelay, "settleDelay" : htmx.config.defaultSettleDelay } - if (getInternalData(elt).boosted && !isAnchorLink(elt)) { + if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { swapSpec["show"] = "top" } 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)); - } - if (modifier.indexOf("scroll:") === 0) { - var scrollSpec = modifier.substr(7); + for (var i = 0; i < split.length; i++) { + var value = split[i]; + if (value.indexOf("swap:") === 0) { + swapSpec["swapDelay"] = parseInterval(value.substr(5)); + } else if (value.indexOf("settle:") === 0) { + swapSpec["settleDelay"] = parseInterval(value.substr(7)); + } else if (value.indexOf("transition:") === 0) { + swapSpec["transition"] = value.substr(11) === "true"; + } else if (value.indexOf("ignoreTitle:") === 0) { + swapSpec["ignoreTitle"] = value.substr(12) === "true"; + } else if (value.indexOf("scroll:") === 0) { + var scrollSpec = value.substr(7); var splitSpec = scrollSpec.split(":"); var scrollVal = splitSpec.pop(); var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; swapSpec["scroll"] = scrollVal; swapSpec["scrollTarget"] = selectorVal; - } - if (modifier.indexOf("show:") === 0) { - var showSpec = modifier.substr(5); + } else if (value.indexOf("show:") === 0) { + var showSpec = value.substr(5); var splitSpec = showSpec.split(":"); var showVal = splitSpec.pop(); var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; swapSpec["show"] = showVal; swapSpec["showTarget"] = selectorVal; - } - if (modifier.indexOf("focus-scroll:") === 0) { - var focusScrollVal = modifier.substr("focus-scroll:".length); + } else if (value.indexOf("focus-scroll:") === 0) { + var focusScrollVal = value.substr("focus-scroll:".length); swapSpec["focusScroll"] = focusScrollVal == "true"; + } else if (i == 0) { + swapSpec["swapStyle"] = value; + } else { + logError('Unknown modifier in hx-swap: ' + value); } } } @@ -2269,6 +2786,11 @@ return (function () { return swapSpec; } + function usesFormData(elt) { + return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || + (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data"); + } + function encodeParamsForBody(xhr, elt, filteredParameters) { var encodedParameters = null; withExtensions(elt, function (extension) { @@ -2279,8 +2801,7 @@ return (function () { if (encodedParameters != null) { return encodedParameters; } else { - if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || - (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) { + if (usesFormData(elt)) { return makeFormData(filteredParameters); } else { return urlEncode(filteredParameters); @@ -2352,6 +2873,9 @@ return (function () { if (attributeValue) { var str = attributeValue.trim(); var evaluateValue = evalAsDefault; + if (str === "unset") { + return null; + } if (str.indexOf("javascript:") === 0) { str = str.substr(11); evaluateValue = true; @@ -2426,7 +2950,7 @@ return (function () { } } - function getResponseURL(xhr) { + function getPathFromResponse(xhr) { // NB: IE11 does not support this stuff if (xhr.responseURL && typeof(URL) !== "undefined") { try { @@ -2439,7 +2963,7 @@ return (function () { } function hasHeader(xhr, regexp) { - return xhr.getAllResponseHeaders().match(regexp); + return regexp.test(xhr.getAllResponseHeaders()) } function ajaxHelper(verb, path, context) { @@ -2458,6 +2982,7 @@ return (function () { values : context.values, targetOverride: resolveTarget(context.target), swapOverride: context.swap, + select: context.select, returnPromise: true }); } @@ -2477,7 +3002,28 @@ return (function () { return arr; } - function issueAjaxRequest(verb, path, elt, event, etc) { + function verifyPath(elt, path, requestConfig) { + var sameHost + var url + if (typeof URL === "function") { + url = new URL(path, document.location.href); + var origin = document.location.origin; + sameHost = origin === url.origin; + } else { + // IE11 doesn't support URL + url = path + sameHost = startsWith(path, document.location.origin) + } + + if (htmx.config.selfRequestsOnly) { + if (!sameHost) { + return false; + } + } + return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig)); + } + + function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { var resolve = null; var reject = null; etc = etc != null ? etc : {}; @@ -2491,18 +3037,52 @@ return (function () { elt = getDocument().body; } var responseHandler = etc.handler || handleAjaxResponse; + var select = etc.select || null; if (!bodyContains(elt)) { - return; // do not issue requests for elements removed from the DOM + // do not issue requests for elements removed from the DOM + maybeCall(resolve); + return promise; } var target = etc.targetOverride || getTarget(elt); if (target == null || target == DUMMY_ELT) { triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); - return; + maybeCall(reject); + return promise; } - var syncElt = elt; var eltData = getInternalData(elt); + var submitter = eltData.lastButtonClicked; + + if (submitter) { + var buttonPath = getRawAttribute(submitter, "formaction"); + if (buttonPath != null) { + path = buttonPath; + } + + var buttonVerb = getRawAttribute(submitter, "formmethod") + if (buttonVerb != null) { + // ignore buttons with formmethod="dialog" + if (buttonVerb.toLowerCase() !== "dialog") { + verb = buttonVerb; + } + } + } + + var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); + // allow event-based confirmation w/ a callback + if (confirmed === undefined) { + var issueRequest = function(skipConfirmation) { + return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation); + } + var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion}; + if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { + maybeCall(resolve); + return promise; + } + } + + var syncElt = elt; var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); var queueStrategy = null; var abortable = false; @@ -2518,10 +3098,12 @@ return (function () { syncStrategy = (syncStrings[1] || 'drop').trim(); eltData = getInternalData(syncElt); if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { - return; + maybeCall(resolve); + return promise; } else if (syncStrategy === "abort") { if (eltData.xhr) { - return; + maybeCall(resolve); + return promise; } else { abortable = true; } @@ -2565,7 +3147,8 @@ return (function () { issueAjaxRequest(verb, path, elt, event, etc) }); } - return; + maybeCall(resolve); + return promise; } } @@ -2593,8 +3176,7 @@ return (function () { } } - var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); - if (confirmQuestion) { + if (confirmQuestion && !confirmed) { if(!confirm(confirmQuestion)) { maybeCall(resolve); endRequestLock() @@ -2604,6 +3186,11 @@ return (function () { var headers = getHeaders(elt, target, promptResponse); + + if (verb !== 'get' && !usesFormData(elt)) { + headers['Content-Type'] = 'application/x-www-form-urlencoded'; + } + if (etc.headers) { headers = mergeObjects(headers, etc.headers); } @@ -2617,8 +3204,8 @@ return (function () { var allParameters = mergeObjects(rawParameters, expressionVars); var filteredParameters = filterValues(allParameters, elt); - if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null) { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; + if (htmx.config.getCacheBusterParam && verb === 'get') { + filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true"; } // behavior of anchors w/ empty href is to use the current URL @@ -2626,9 +3213,16 @@ return (function () { path = getDocument().location.href; } + var requestAttrValues = getValuesForElement(elt, 'hx-request'); + var eltIsBoosted = getInternalData(elt).boosted; + + var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + var requestConfig = { + boosted: eltIsBoosted, + useUrlParams: useUrlParams, parameters: filteredParameters, unfilteredParameters: allParameters, headers:headers, @@ -2653,6 +3247,7 @@ return (function () { headers = requestConfig.headers; filteredParameters = requestConfig.parameters; errors = requestConfig.errors; + useUrlParams = requestConfig.useUrlParams; if(errors && errors.length > 0){ triggerEvent(elt, 'htmx:validation:halted', requestConfig) @@ -2664,25 +3259,31 @@ return (function () { var splitPath = path.split("#"); var pathNoAnchor = splitPath[0]; var anchor = splitPath[1]; - if (verb === 'get') { - var finalPathForGet = pathNoAnchor; + + var finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor; var values = Object.keys(filteredParameters).length !== 0; if (values) { - if (finalPathForGet.indexOf("?") < 0) { - finalPathForGet += "?"; + if (finalPath.indexOf("?") < 0) { + finalPath += "?"; } else { - finalPathForGet += "&"; + finalPath += "&"; } - finalPathForGet += urlEncode(filteredParameters); + finalPath += urlEncode(filteredParameters); if (anchor) { - finalPathForGet += "#" + anchor; + finalPath += "#" + anchor; } } - xhr.open('GET', finalPathForGet, true); - } else { - xhr.open(verb.toUpperCase(), path, true); } + if (!verifyPath(elt, finalPath, requestConfig)) { + triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) + maybeCall(reject); + return promise; + }; + + xhr.open(verb.toUpperCase(), finalPath, true); xhr.overrideMimeType("text/html"); xhr.withCredentials = requestConfig.withCredentials; xhr.timeout = requestConfig.timeout; @@ -2699,19 +3300,24 @@ return (function () { } } - var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, etc:etc, pathInfo:{ - path:path, finalPath:finalPathForGet, anchor:anchor + var responseInfo = { + xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select, + pathInfo: { + requestPath: path, + finalRequestPath: finalPath, + anchor: anchor } }; xhr.onload = function () { try { var hierarchy = hierarchyForElt(elt); + responseInfo.pathInfo.responsePath = getPathFromResponse(xhr); responseHandler(elt, responseInfo); - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerEvent(elt, 'htmx:afterRequest', responseInfo); triggerEvent(elt, 'htmx:afterOnLoad', responseInfo); - // if the body no longer contains the element, trigger the even on the closest parent + // if the body no longer contains the element, trigger the event on the closest parent // remaining in the DOM if (!bodyContains(elt)) { var secondaryTriggerElt = null; @@ -2734,21 +3340,21 @@ return (function () { } } xhr.onerror = function () { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:sendError', responseInfo); maybeCall(reject); endRequestLock(); } xhr.onabort = function() { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo); maybeCall(reject); endRequestLock(); } xhr.ontimeout = function() { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:timeout', responseInfo); maybeCall(reject); @@ -2760,6 +3366,7 @@ return (function () { return promise } var indicators = addRequestIndicatorClasses(elt); + var disableElts = disableElements(elt); forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { forEach([xhr, xhr.upload], function (target) { @@ -2773,14 +3380,99 @@ return (function () { }); }); triggerEvent(elt, 'htmx:beforeSend', responseInfo); - xhr.send(verb === 'get' ? null : encodeParamsForBody(xhr, elt, filteredParameters)); + var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) + xhr.send(params); return promise; } + function determineHistoryUpdates(elt, responseInfo) { + + var xhr = responseInfo.xhr; + + //=========================================== + // First consult response headers + //=========================================== + var pathFromHeaders = null; + var typeFromHeaders = null; + if (hasHeader(xhr,/HX-Push:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Push"); + typeFromHeaders = "push"; + } else if (hasHeader(xhr,/HX-Push-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Push-Url"); + typeFromHeaders = "push"; + } else if (hasHeader(xhr,/HX-Replace-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url"); + typeFromHeaders = "replace"; + } + + // if there was a response header, that has priority + if (pathFromHeaders) { + if (pathFromHeaders === "false") { + return {} + } else { + return { + type: typeFromHeaders, + path : pathFromHeaders + } + } + } + + //=========================================== + // Next resolve via DOM values + //=========================================== + var requestPath = responseInfo.pathInfo.finalRequestPath; + var responsePath = responseInfo.pathInfo.responsePath; + + var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); + var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url"); + var elementIsBoosted = getInternalData(elt).boosted; + + var saveType = null; + var path = null; + + if (pushUrl) { + saveType = "push"; + path = pushUrl; + } else if (replaceUrl) { + saveType = "replace"; + path = replaceUrl; + } else if (elementIsBoosted) { + saveType = "push"; + path = responsePath || requestPath; // if there is no response path, go with the original request path + } + + if (path) { + // false indicates no push, return empty object + if (path === "false") { + return {}; + } + + // true indicates we want to follow wherever the server ended up sending us + if (path === "true") { + path = responsePath || requestPath; // if there is no response path, go with the original request path + } + + // restore any anchor associated with the request + if (responseInfo.pathInfo.anchor && + path.indexOf("#") === -1) { + path = path + "#" + responseInfo.pathInfo.anchor; + } + + return { + type:saveType, + path: path + } + } else { + return {}; + } + } + function handleAjaxResponse(elt, responseInfo) { var xhr = responseInfo.xhr; var target = responseInfo.target; var etc = responseInfo.etc; + var requestConfig = responseInfo.requestConfig; + var select = responseInfo.select; if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; @@ -2788,33 +3480,44 @@ return (function () { handleTrigger(xhr, "HX-Trigger", elt); } - if (hasHeader(xhr,/HX-Push:/i)) { - var pushedUrl = xhr.getResponseHeader("HX-Push"); + if (hasHeader(xhr, /HX-Location:/i)) { + saveCurrentPageToHistory(); + var redirectPath = xhr.getResponseHeader("HX-Location"); + var swapSpec; + if (redirectPath.indexOf("{") === 0) { + swapSpec = parseJSON(redirectPath); + // what's the best way to throw an error if the user didn't include this + redirectPath = swapSpec['path']; + delete swapSpec['path']; + } + ajaxHelper('GET', redirectPath, swapSpec).then(function(){ + pushUrlIntoHistory(redirectPath); + }); + return; } + var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh"); + if (hasHeader(xhr, /HX-Redirect:/i)) { - window.location.href = xhr.getResponseHeader("HX-Redirect"); + location.href = xhr.getResponseHeader("HX-Redirect"); + shouldRefresh && location.reload(); return; } - if (hasHeader(xhr,/HX-Refresh:/i)) { - if ("true" === xhr.getResponseHeader("HX-Refresh")) { - location.reload(); - return; - } + if (shouldRefresh) { + location.reload(); + return; } if (hasHeader(xhr,/HX-Retarget:/i)) { - responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget")); + if (xhr.getResponseHeader("HX-Retarget") === "this") { + responseInfo.target = elt; + } else { + responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget")); + } } - /** @type {boolean} */ - var shouldSaveHistory - if (pushedUrl == "false") { - shouldSaveHistory = false - } else { - shouldSaveHistory = shouldPush(elt) || pushedUrl; - } + var historyUpdate = determineHistoryUpdates(elt, responseInfo); // by default htmx only swaps on 200 return codes and does not swap // on 204 'No Content' @@ -2823,15 +3526,18 @@ return (function () { var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; var serverResponse = xhr.response; var isError = xhr.status >= 400; - var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo); + var ignoreTitle = htmx.config.ignoreTitle + var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo); if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; target = beforeSwapDetails.target; // allow re-targeting serverResponse = beforeSwapDetails.serverResponse; // allow updating content isError = beforeSwapDetails.isError; // allow updating error - + ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title + + responseInfo.target = target; // Make updated target available to response events responseInfo.failed = isError; // Make failed property available to response events - responseInfo.successful = !isError; // Make successful property available to response events + responseInfo.successful = !isError; // Make successful property available to response events if (beforeSwapDetails.shouldSwap) { if (xhr.status === 286) { @@ -2842,18 +3548,29 @@ return (function () { serverResponse = extension.transformResponse(serverResponse, xhr, elt); }); - // Save current page - if (shouldSaveHistory) { + // Save current page if there will be a history update + if (historyUpdate.type) { saveCurrentPageToHistory(); } var swapOverride = etc.swapOverride; + if (hasHeader(xhr,/HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader("HX-Reswap"); + } var swapSpec = getSwapSpecification(elt, swapOverride); + if (swapSpec.hasOwnProperty('ignoreTitle')) { + ignoreTitle = swapSpec.ignoreTitle; + } + target.classList.add(htmx.config.swappingClass); + + // optional transition API promise callbacks + var settleResolve = null; + var settleReject = null; + var doSwap = function () { try { - var activeElt = document.activeElement; var selectionInfo = {}; try { @@ -2868,19 +3585,44 @@ return (function () { // safari issue - see https://github.com/microsoft/playwright/issues/5894 } + var selectOverride; + if (select) { + selectOverride = select; + } + + if (hasHeader(xhr, /HX-Reselect:/i)) { + selectOverride = xhr.getResponseHeader("HX-Reselect"); + } + + // if we need to save history, do so, before swapping so that relative resources have the correct base URL + if (historyUpdate.type) { + triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)); + if (historyUpdate.type === "push") { + pushUrlIntoHistory(historyUpdate.path); + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path}); + } else { + replaceUrlInHistory(historyUpdate.path); + triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path}); + } + } + var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride); if (selectionInfo.elt && !bodyContains(selectionInfo.elt) && - selectionInfo.elt.id) { - var newActiveElt = document.getElementById(selectionInfo.elt.id); + getRawAttribute(selectionInfo.elt, "id")) { + var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id")); var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; if (newActiveElt) { // @ts-ignore if (selectionInfo.start && newActiveElt.setSelectionRange) { // @ts-ignore - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + try { + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + } catch (e) { + // the setSelectionRange method is present on fields that don't support it, so just let this fail + } } newActiveElt.focus(focusOptions); } @@ -2893,9 +3635,6 @@ return (function () { } triggerEvent(elt, 'htmx:afterSwap', responseInfo); }); - if (responseInfo.pathInfo.anchor) { - location.hash = responseInfo.pathInfo.anchor; - } if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { var finalElt = elt; @@ -2915,14 +3654,15 @@ return (function () { } triggerEvent(elt, 'htmx:afterSettle', responseInfo); }); - // push URL and save new page - if (shouldSaveHistory) { - var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; - pushUrlIntoHistory(pathToPush); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: pathToPush}); + + if (responseInfo.pathInfo.anchor) { + var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor); + if(anchorTarget) { + anchorTarget.scrollIntoView({block:'start', behavior: "auto"}); + } } - if(settleInfo.title) { + if(settleInfo.title && !ignoreTitle) { var titleElt = find("title"); if(titleElt) { titleElt.innerHTML = settleInfo.title; @@ -2940,6 +3680,7 @@ return (function () { } handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); } + maybeCall(settleResolve); } if (swapSpec.settleDelay > 0) { @@ -2949,10 +3690,34 @@ return (function () { } } catch (e) { triggerErrorEvent(elt, 'htmx:swapError', responseInfo); + maybeCall(settleReject); throw e; } }; + var shouldTransition = htmx.config.globalViewTransitions + if(swapSpec.hasOwnProperty('transition')){ + shouldTransition = swapSpec.transition; + } + + if(shouldTransition && + triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && + typeof Promise !== "undefined" && document.startViewTransition){ + var settlePromise = new Promise(function (_resolve, _reject) { + settleResolve = _resolve; + settleReject = _reject; + }); + // wrap the original doSwap() in a call to startViewTransition() + var innerDoSwap = doSwap; + doSwap = function() { + document.startViewTransition(function () { + innerDoSwap(); + return settlePromise; + }); + } + } + + if (swapSpec.swapDelay > 0) { setTimeout(doSwap, swapSpec.swapDelay) } else { @@ -2960,7 +3725,7 @@ return (function () { } } if (isError) { - triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.path}, responseInfo)); + triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo)); } } @@ -3048,9 +3813,22 @@ return (function () { //==================================================================== // Initialization //==================================================================== + var isReady = false + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true + }) + /** + * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. + * + * This function uses isReady because there is no realiable way to ask the browswer whether + * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded + * firing and readystate=complete. + */ function ready(fn) { - if (getDocument().readyState !== 'loading') { + // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by + // some means other than the initial page load. + if (isReady || getDocument().readyState === 'complete') { fn(); } else { getDocument().addEventListener('DOMContentLoaded', fn); @@ -3061,9 +3839,9 @@ return (function () { if (htmx.config.includeIndicatorStyles !== false) { getDocument().head.insertAdjacentHTML("beforeend", "<style>\ - ." + htmx.config.indicatorClass + "{opacity:0;transition: opacity 200ms ease-in;}\ - ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1}\ - ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1}\ + ." + htmx.config.indicatorClass + "{opacity:0}\ + ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ + ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ </style>"); } } @@ -3101,6 +3879,9 @@ return (function () { internalData.xhr.abort(); } }); + /** @type {(ev: PopStateEvent) => any} */ + const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null; + /** @type {(ev: PopStateEvent) => any} */ window.onpopstate = function (event) { if (event.state && event.state.htmx) { restoreHistory(); @@ -3110,10 +3891,15 @@ return (function () { 'triggerEvent': triggerEvent }); }); + } else { + if (originalPopstate) { + originalPopstate(event); + } } }; setTimeout(function () { triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event + body = null; // kill reference for gc }, 0); }) diff --git a/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.min.js b/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.min.js index 998414c..53bbdf6 100644 --- a/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.min.js +++ b/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.min.js @@ -1 +1,4 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(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 l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=k(e);e.classList.toggle(t)}function T(e,t){e=k(e);W(e.parentElement.children,function(e){q(e,t)});L(e,t)}function H(e,t){e=k(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function N(e,t){if(t.indexOf("closest ")===0){return[H(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[C(e,t.substr(5))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return z().querySelectorAll(t)}}function ee(e,t){if(t){return N(e,t)[0]}else{return N(z().body,e)[0]}}function k(e){if(p(e,"String")){return C(e)}else{return e}}function I(e,t,r){if(m(t)){return{target:z().body,event:e,listener:t}}else{return{target:k(e),event:t,listener:r}}}function M(t,r,n){lr(function(){var e=I(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function D(t,r,n){lr(function(){var e=I(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var te=z().createElement("output");function F(e,t){var r=G(e,t);if(r){if(r==="this"){return[re(e,t)]}else{var n=N(e,r);if(n.length===0){pt('The selector "'+r+'" on '+t+" returned no matches!");return[te]}else{return n}}}}function re(e,t){return h(e,function(e){return V(e,t)!=null})}function ne(e){var t=G(e,"hx-target");if(t){if(t==="this"){return re(e,"hx-target")}else{return ee(e,t)}}else{var r=_(e);if(r.boosted){return z().body}else{return e}}}function P(e){var t=U.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function X(t,r){W(t.attributes,function(e){if(!r.hasAttribute(e.name)&&P(e.name)){t.removeAttribute(e.name)}});W(r.attributes,function(e){if(P(e.name)){t.setAttribute(e.name,e.value)}})}function j(e,t){var r=sr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){pt(e)}}return e==="outerHTML"}function B(e,i,o){var t="#"+i.id;var a="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){a=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{a=e}var r=z().querySelectorAll(t);if(r){W(r,function(e){var t;var r=i.cloneNode(true);t=z().createDocumentFragment();t.appendChild(r);if(!j(a,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ye(a,e,e,t,o)}W(o.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(z().body,"htmx:oobErrorNoTarget",{content:i})}return e}function ie(e,r){W(R(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=V(e,"hx-swap-oob");if(t!=null){B(t,e,r)}})}function oe(e){W(R(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=V(e,"id");var r=z().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function ae(n,e,i){W(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();X(e,t);i.tasks.push(function(){X(e,r)})}}})}function se(e){return function(){q(e,U.config.addedClass);ct(e);at(e);le(e);$(e,"htmx:load")}}function le(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ue(e,t,r,n){ae(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(se(i))}}}function fe(t){var e=_(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){W(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){W(t.children,function(e){fe(e)})}}function ce(e,t,r){if(e.tagName==="BODY"){return me(e,t,r)}else{var n;var i=e.previousSibling;ue(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}_(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}fe(e);u(e).removeChild(e)}}function he(e,t,r){return ue(e,e.firstChild,t,r)}function de(e,t,r){return ue(u(e),e,t,r)}function ve(e,t,r){return ue(e,null,t,r)}function ge(e,t,r){return ue(u(e),e.nextSibling,t,r)}function pe(e,t,r){fe(e);return u(e).removeChild(e)}function me(e,t,r){var n=e.firstChild;ue(e,n,t,r);if(n){while(n.nextSibling){fe(n.nextSibling);e.removeChild(n.nextSibling)}fe(n);e.removeChild(n)}}function xe(e,t){var r=G(e,"hx-select");if(r){var n=z().createDocumentFragment();W(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function ye(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":ce(r,n,i);return;case"afterbegin":he(r,n,i);return;case"beforebegin":de(r,n,i);return;case"beforeend":ve(r,n,i);return;case"afterend":ge(r,n,i);return;case"delete":pe(r,n,i);return;default:var o=sr(t);for(var a=0;a<o.length;a++){var f=o[a];try{var s=f.handleSwap(e,r,n,i);if(s){if(typeof s.length!=="undefined"){for(var l=0;l<s.length;l++){var u=s[l];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){i.tasks.push(se(u))}}}return}}catch(e){pt(e)}}if(e==="innerHTML"){me(r,n,i)}else{ye(U.config.defaultSwapStyle,t,r,n,i)}}}function be(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function we(e,t,r,n,i){i.title=be(n);var o=g(n);if(o){ie(o,i);o=xe(r,o);oe(o);return ye(e,r,t,o,i)}}function Se(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!x(a)){a={value:a}}$(r,o,a)}}}else{$(r,n,[])}}var Ee=/\s/;var Ce=/[\s,]/;var Re=/[_$a-zA-Z]/;var Oe=/[_$a-zA-Z0-9]/;var Le=['"',"'","/"];var qe=/[^\s]/;function Ae(e){var t=[];var r=0;while(r<e.length){if(Re.exec(e.charAt(r))){var n=r;while(Oe.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Le.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function Te(e,t,r){return Re.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function He(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Jt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(z().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(Te(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var Ne="input, textarea, select";function ke(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=Ae(t);do{c(n,qe);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var o={trigger:"every"};c(n,qe);o.pollInterval=v(c(n,/[,\[\s]/));c(n,qe);var a=He(e,n,"event");if(a){o.eventFilter=a}r.push(o)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var a=He(e,n,"event");if(a){s.eventFilter=a}while(n.length>0&&n[0]!==","){c(n,qe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Ce))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Ce);if(u==="closest"||u==="find"){n.shift();u+=" "+c(n,Ce)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Ce)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Ce))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Ce)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Ce)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,qe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,Ne)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ie(e){_(e).cancelled=true}function Me(e,t,r,n){var i=_(e);i.timeout=setTimeout(function(){if(Y(e)&&i.cancelled!==true){if(!je(n,dt("hx:poll:trigger",{triggerSpec:n,target:e}))){Z(t,r,e)}Me(e,t,V(e,"hx-"+t),n)}},n.pollInterval)}function De(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&De(t)&&t.target===""||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href");r.pushURL=true}else{var o=f(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=f(t,"action")}e.forEach(function(e){Be(t,n,i,r,e,true)})}}function Pe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&H(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Xe(e,t){return _(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function je(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(z().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Be(o,a,s,e,l,u){var t;if(l.from){t=N(o,l.from)}else{t=[o]}W(t,function(n){var i=function(e){if(!Y(o)){n.removeEventListener(l.trigger,i);return}if(Xe(o,e)){return}if(u||Pe(e,o)){e.preventDefault()}if(je(l,e)){return}var t=_(e);t.triggerSpec=l;if(t.handledFor==null){t.handledFor=[]}var r=_(o);if(t.handledFor.indexOf(o)<0){t.handledFor.push(o);if(l.consume){e.stopPropagation()}if(l.target&&e.target){if(!d(e.target,l.target)){return}}if(l.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(l.changed){if(r.lastValue===o.value){return}else{r.lastValue=o.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(l.throttle){if(!r.throttle){Z(a,s,o,e);r.throttle=setTimeout(function(){r.throttle=null},l.throttle)}}else if(l.delay){r.delayed=setTimeout(function(){Z(a,s,o,e)},l.delay)}else{Z(a,s,o,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:l.trigger,listener:i,on:n});n.addEventListener(l.trigger,i)})}var Ue=false;var Ve=null;function ze(){if(!Ve){Ve=function(){Ue=true};window.addEventListener("scroll",Ve);setInterval(function(){if(Ue){Ue=false;W(z().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){_e(e)})}},200)}}function _e(e){if(!s(e,"data-hx-revealed")&&b(e)){e.setAttribute("data-hx-revealed","true");var t=_(e);if(t.initialized){Z(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Z(t.verb,t.path,e)},{once:true})}}}function We(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Je(e,o[1],0)}if(o[0]==="send"){Ze(e)}}}function Je(s,r,n){if(!Y(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=U.createWebSocket(r);t.onerror=function(e){J(s,"htmx:wsError",{error:e,socket:t});$e(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=Ge(n);setTimeout(function(){Je(s,r,n+1)},t)}};t.onopen=function(e){n=0};_(s).webSocket=t;t.addEventListener("message",function(e){if($e(s)){return}var t=e.data;gt(s,function(e){t=e.transformResponse(t,null,s)});var r=zt(s);var n=g(t);var i=y(n.children);for(var o=0;o<i.length;o++){var a=i[o];B(V(a,"hx-swap-oob")||"true",a,r)}Ct(r.tasks)})}function $e(e){if(!Y(e)){_(e).webSocket.close();return true}}function Ze(u){var f=h(u,function(e){return _(e).webSocket!=null});if(f){u.addEventListener(ke(u)[0].trigger,function(e){var t=_(f).webSocket;var r=Xt(u,f);var n=Mt(u,"post");var i=n.errors;var o=n.values;var a=Gt(u);var s=Q(o,a);var l=jt(s,u);l["HEADERS"]=r;if(i&&i.length>0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Pe(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ge(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}pt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ke(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Ye(e,o[1])}if(o[0]==="swap"){Qe(e,o[1])}}}function Ye(t,e){var r=U.createEventSource(e);r.onerror=function(e){J(t,"htmx:sseError",{error:e,source:r});tt(t)};_(t).sseEventSource=r}function Qe(o,a){var s=h(o,rt);if(s){var l=_(s).sseEventSource;var u=function(e){if(tt(s)){l.removeEventListener(a,u);return}var t=e.data;gt(o,function(e){t=e.transformResponse(t,null,o)});var r=Ut(o);var n=ne(o);var i=zt(o);we(r.swapStyle,o,n,t,i);Ct(i.tasks);$(o,"htmx:sseMessage",e)};_(o).sseListener=u;l.addEventListener(a,u)}else{J(o,"htmx:noSSESourceError")}}function et(e,t,r,n){var i=h(e,rt);if(i){var o=_(i).sseEventSource;var a=function(){if(!tt(i)){if(Y(e)){Z(t,r,e)}else{o.removeEventListener(n,a)}}};_(e).sseListener=a;o.addEventListener(n,a)}else{J(e,"htmx:noSSESourceError")}}function tt(e){if(!Y(e)){_(e).sseEventSource.close();return true}}function rt(e){return _(e).sseEventSource!=null}function nt(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Z(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function it(o,a,e){var t=false;W(n,function(n){if(s(o,"hx-"+n)){var i=V(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){et(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){ze();_e(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=ee(o,e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){$(o,"intersect");break}}},t);r.observe(o);Be(o,n,i,a,e)}else if(e.trigger==="load"){nt(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Me(o,n,i,e)}else{Be(o,n,i,a,e)}})}});return t}function ot(e){if(e.type==="text/javascript"||e.type==="module"||e.type===""){var t=z().createElement("script");W(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(U.config.inlineScriptNonce){t.nonce=U.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){pt(e)}finally{r.removeChild(e)}}}function at(e){if(d(e,"script")){ot(e)}W(R(e,"script"),function(e){ot(e)})}function st(){return document.querySelector("[hx-boost], [data-hx-boost]")}function lt(e){if(e.querySelectorAll){var t=st()?", a, form":"";var r=e.querySelectorAll(i+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [hx-data-ext]");return r}else{return[]}}function ut(r){var e=function(e){if(d(e.target,"button, input[type='submit']")){var t=_(r);t.lastButtonClicked=e.target}};r.addEventListener("click",e);r.addEventListener("focusin",e);r.addEventListener("focusout",function(e){var t=_(r);t.lastButtonClicked=null})}function ft(e){if(e.closest&&e.closest(U.config.disableSelector)){return}var t=_(e);if(!t.initialized){t.initialized=true;$(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=ke(e);var n=it(e,t,r);if(!n&&G(e,"hx-boost")==="true"){Fe(e,t,r)}if(e.tagName==="FORM"){ut(e)}var i=V(e,"hx-sse");if(i){Ke(e,t,i)}var o=V(e,"hx-ws");if(o){We(e,t,o)}$(e,"htmx:afterProcessNode")}}function ct(e){e=k(e);ft(e);W(lt(e),function(e){ft(e)})}function ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function dt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=z().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function J(e,t,r){$(e,t,Q({error:t},r))}function vt(e){return e==="htmx:afterProcessNode"}function gt(e,t){W(sr(e),function(e){try{t(e)}catch(e){pt(e)}})}function pt(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function $(e,t,r){e=k(e);if(r==null){r={}}r["elt"]=e;var n=dt(t,r);if(U.logger&&!vt(t)){U.logger(e,t,r)}if(r.error){pt(r.error);$(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=ht(t);if(i&&o!==t){var a=dt(o,n.detail);i=i&&e.dispatchEvent(a)}gt(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var mt=location.pathname+location.search;function xt(){var e=z().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||z().body}function yt(e,t,r,n){var i=S(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>U.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(z().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function bt(e){var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function wt(e){var t=U.config.requestClass;var r=e.cloneNode(true);W(R(r,"."+t),function(e){q(e,t)});return r.innerHTML}function St(){var e=xt();var t=mt||location.pathname+location.search;$(z().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(U.config.historyEnabled)history.replaceState({htmx:true},z().title,window.location.href);yt(t,wt(e),z().title,window.scrollY)}function Et(e){if(U.config.historyEnabled)history.pushState({htmx:true},"",e);mt=e}function Ct(e){W(e,function(e){e.call()})}function Rt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};$(z().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){$(z().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=xt();var r=zt(t);me(t,e,r);Ct(r.tasks);mt=n;$(z().body,"htmx:historyRestore",{path:n})}else{J(z().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Ot(e){St();e=e||location.pathname+location.search;var t=bt(e);if(t){var r=g(t.content);var n=xt();var i=zt(n);me(n,r,i);Ct(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);mt=e;$(z().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Rt(e)}}}function Lt(e){var t=G(e,"hx-push-url");return t&&t!=="false"||_(e).boosted&&_(e).pushURL}function qt(e){var t=G(e,"hx-push-url");return t==="true"||t==="false"?null:t}function At(e){var t=F(e,"hx-indicator");if(t==null){t=[e]}W(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Tt(e){W(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function Ht(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Nt(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 kt(t,r,n,e,i){if(e==null||Ht(t,e)){return}else{t.push(e)}if(Nt(e)){var o=f(e,"name");var a=e.value;if(e.multiple){a=y(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=y(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){It(e,n)}}if(d(e,"form")){var l=e.elements;W(l,function(e){kt(t,r,n,e,i)})}}function It(e,t){if(e.willValidate){$(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});$(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Mt(e,t){var r=[];var n={};var i={};var o=[];var a=_(e);var s=d(e,"form")&&e.noValidate!==true;if(a.lastButtonClicked){s=s&&a.lastButtonClicked.formNoValidate!==true}if(t!=="get"){kt(r,i,o,H(e,"form"),s)}kt(r,n,o,e,s);if(a.lastButtonClicked){var l=f(a.lastButtonClicked,"name");if(l){n[l]=a.lastButtonClicked.value}}var u=F(e,"hx-include");W(u,function(e){kt(r,n,o,e,s);if(!d(e,"form")){W(e.querySelectorAll(Ne),function(e){kt(r,n,o,e,s)})}});n=Q(n,i);return{errors:o,values:n}}function Dt(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function Ft(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=Dt(t,r,e)})}else{t=Dt(t,r,n)}}}return t}function Pt(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){W(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Xt(e,t,r){var n={"HX-Request":"true","HX-Trigger":f(e,"id"),"HX-Trigger-Name":f(e,"name"),"HX-Target":V(t,"id"),"HX-Current-URL":z().location.href};Wt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(_(e).boosted){n["HX-Boosted"]="true"}return n}function jt(t,e){var r=G(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){W(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};W(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Bt(e){return f(e,"href")&&f(e,"href").indexOf("#")>=0}function Ut(e,t){var r=t?t:G(e,"hx-swap");var n={swapStyle:_(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(_(e).boosted&&!Bt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var o=1;o<i.length;o++){var a=i[o];if(a.indexOf("swap:")===0){n["swapDelay"]=v(a.substr(5))}if(a.indexOf("settle:")===0){n["settleDelay"]=v(a.substr(7))}if(a.indexOf("scroll:")===0){var s=a.substr(7);var l=s.split(":");var f=l.pop();var u=l.length>0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(a.indexOf("show:")===0){var c=a.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(a.indexOf("focus-scroll:")===0){var d=a.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function Vt(t,r,n){var i=null;gt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(G(r,"hx-encoding")==="multipart/form-data"||d(r,"form")&&f(r,"enctype")==="multipart/form-data"){return Pt(n)}else{return Ft(n)}}}function zt(e){return{tasks:[],elts:[e]}}function _t(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ee(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var o=t.showTarget;if(t.showTarget==="window"){o="body"}i=ee(r,o)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function Wt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}else if(o.indexOf("js:")===0){o=o.substr(3);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Jt(e,function(){return Function("return ("+o+")")()},{})}else{s=S(o)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Wt(u(e),t,r,n)}function Jt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function $t(e,t){return Wt(e,"hx-vars",true,t)}function Zt(e,t){return Wt(e,"hx-vals",false,t)}function Gt(e){return Q($t(e),Zt(e))}function Kt(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Yt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(z().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Qt(e,t){return e.getAllResponseHeaders().match(t)}function er(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return Z(e,t,null,null,{targetOverride:k(r),returnPromise:true})}else{return Z(e,t,k(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:k(r.target),swapOverride:r.swap,returnPromise:true})}}else{return Z(e,t,null,null,{returnPromise:true})}}function tr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Z(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=z().body}var v=r.handler||rr;if(!Y(n)){return}var g=r.targetOverride||ne(n);if(g==null||g==te){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=_(n);var o=G(n,"hx-sync");var m=null;var x=false;if(o){var y=o.split(":");var b=y[0].trim();if(b==="this"){p=re(n,"hx-sync")}else{p=ee(n,b)}o=(y[1]||"drop").trim();i=_(p);if(o==="drop"&&i.xhr&&i.abortable!==true){return}else if(o==="abort"){if(i.xhr){return}else{x=true}}else if(o==="replace"){$(p,"htmx:abort")}else if(o.indexOf("queue")===0){var w=o.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=_(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){Z(e,t,n,f,r)})}return}}var a=new XMLHttpRequest;i.xhr=a;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=G(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){K(c);s();return d}}var R=G(n,"hx-confirm");if(R){if(!confirm(R)){K(c);s();return d}}var O=Xt(n,g,C);if(r.headers){O=Q(O,r.headers)}var L=Mt(n,e);var q=L.errors;var A=L.values;if(r.values){A=Q(A,r.values)}var T=Gt(n);var H=Q(A,T);var N=jt(H,n);if(e!=="get"&&G(n,"hx-encoding")==null){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=z().location.href}var k=Wt(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:q,withCredentials:r.credentials||k.credentials||U.config.withCredentials,timeout:r.timeout||k.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){K(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;q=l.errors;if(q&&q.length>0){$(n,"htmx:validation:halted",l);K(c);s();return d}var I=t.split("#");var M=I[0];var D=I[1];if(e==="get"){var F=M;var P=Object.keys(N).length!==0;if(P){if(F.indexOf("?")<0){F+="?"}else{F+="&"}F+=Ft(N);if(D){F+="#"+D}}a.open("GET",F,true)}else{a.open(e.toUpperCase(),t,true)}a.overrideMimeType("text/html");a.withCredentials=l.withCredentials;a.timeout=l.timeout;if(k.noHeaders){}else{for(var X in O){if(O.hasOwnProperty(X)){var j=O[X];Kt(a,X,j)}}}var u={xhr:a,target:g,requestConfig:l,etc:r,pathInfo:{path:t,finalPath:F,anchor:D}};a.onload=function(){try{var e=tr(n);v(n,u);Tt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!Y(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(Y(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}K(c);s()}catch(e){J(n,"htmx:onLoadError",Q({error:e},u));throw e}};a.onerror=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);K(h);s()};a.onabort=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);K(h);s()};a.ontimeout=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);K(h);s()};if(!$(n,"htmx:beforeRequest",u)){K(c);s();return d}var B=At(n);W(["loadstart","loadend","progress","abort"],function(t){W([a,a.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);a.send(e==="get"?null:Vt(a,n,N));return d}function rr(s,l){var u=l.xhr;var f=l.target;var r=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(Qt(u,/HX-Trigger:/i)){Se(u,"HX-Trigger",s)}if(Qt(u,/HX-Push:/i)){var c=u.getResponseHeader("HX-Push")}if(Qt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Qt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(Qt(u,/HX-Retarget:/i)){l.target=z().querySelector(u.getResponseHeader("HX-Retarget"))}var h;if(c=="false"){h=false}else{h=Lt(s)||c}var n=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var e=u.status>=400;var t=Q({shouldSwap:n,serverResponse:d,isError:e},l);if(!$(f,"htmx:beforeSwap",t))return;f=t.target;d=t.serverResponse;e=t.isError;l.failed=e;l.successful=!e;if(t.shouldSwap){if(u.status===286){Ie(s)}gt(s,function(e){d=e.transformResponse(d,u,s)});if(h){St()}var i=r.swapOverride;var v=Ut(s,i);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=zt(f);we(v.swapStyle,f,s,d,n);if(t.elt&&!Y(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);W(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(l.pathInfo.anchor){location.hash=l.pathInfo.anchor}if(Qt(u,/HX-Trigger-After-Swap:/i)){var o=s;if(!Y(s)){o=z().body}Se(u,"HX-Trigger-After-Swap",o)}var a=function(){W(n.tasks,function(e){e.call()});W(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h){var e=c||qt(s)||Yt(u)||l.pathInfo.finalPath||l.pathInfo.path;Et(e);$(z().body,"htmx:pushedIntoHistory",{path:e})}if(n.title){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}_t(n.elts,v);if(Qt(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!Y(s)){r=z().body}Se(u,"HX-Trigger-After-Settle",r)}};if(v.settleDelay>0){setTimeout(a,v.settleDelay)}else{a()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(v.swapDelay>0){setTimeout(o,v.swapDelay)}else{o()}}if(e){J(s,"htmx:responseError",Q({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var nr={};function ir(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function or(e,t){if(t.init){t.init(r)}nr[e]=Q(ir(),t)}function ar(e){delete nr[e]}function sr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){W(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=nr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return sr(u(e),r,n)}function lr(e){if(z().readyState!=="loading"){e()}else{z().addEventListener("DOMContentLoaded",e)}}function ur(){if(U.config.includeIndicatorStyles!==false){z().head.insertAdjacentHTML("beforeend","<style> ."+U.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+U.config.requestClass+" ."+U.config.indicatorClass+"{opacity:1} ."+U.config.requestClass+"."+U.config.indicatorClass+"{opacity:1} </style>")}}function fr(){var e=z().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function cr(){var e=fr();if(e){U.config=Q(U.config,e)}}lr(function(){cr();ur();var e=z().body;ct(e);var t=z().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=_(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){Ot();W(t,function(e){$(e,"htmx:restored",{document:z(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file +// /////////////////////////////////////////////////////////////////// +// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js +// +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(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 a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/<body/.test(e)}function l(e){var t=!N(e);var r=A(e);var n=e;if(r==="head"){n=n.replace(S,"")}if(Q.config.useTemplateFragments&&t){var i=a("<body><template>"+n+"</template></body>",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a("<table>"+n+"</table>",1);case"col":return a("<table><colgroup>"+n+"</colgroup></table>",2);case"tr":return a("<table><tbody>"+n+"</tbody></table>",2);case"td":case"th":return a("<table><tbody><tr>"+n+"</tr></tbody></table>",3);case"script":case"style":return a("<div>"+n+"</div>",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function oe(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function X(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var Y=function(e,t){var r=re().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function we(t,r){oe(t.attributes,function(e){if(!r.hasAttribute(e.name)&&be(e.name)){t.removeAttribute(e.name)}});oe(r.attributes,function(e){if(be(e.name)){t.setAttribute(e.name,e.value)}})}function Se(e,t){var r=Fr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){b(e)}}return e==="outerHTML"}function Ee(e,i,a){var t="#"+ee(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a<i.length;a++){var o=i[a].split(":",2);var s=o[0].trim();if(s.indexOf("#")===0){s=s.substring(1)}var l=o[1]||"true";var u=t.querySelector("#"+s);if(u){Ee(l,u,r)}}}oe(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=te(e,"hx-swap-oob");if(t!=null){Ee(t,e,r)}})}function Re(e){oe(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=te(e,"id");var r=re().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function Te(o,e,s){oe(e.querySelectorAll("[id]"),function(e){var t=ee(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Le(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=He(n.name,t);t=He(n.value,t)}}}return t}function Ae(e){var t=ae(e);if(t.onHandlers){for(var r=0;r<t.onHandlers.length;r++){const n=t.onHandlers[r];e.removeEventListener(n.event,n.listener)}delete t.onHandlers}}function Ne(e){var t=ae(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){oe(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}Ae(e);oe(Object.keys(t),function(e){delete t[e]})}function p(e){ce(e,"htmx:beforeCleanupElement");Ne(e);if(e.children){oe(e.children,function(e){p(e)})}}function Ie(t,e,r){if(t.tagName==="BODY"){return Ue(t,e,r)}else{var n;var i=t.previousSibling;m(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}p(t);u(t).removeChild(t)}}function ke(e,t,r){return m(e,e.firstChild,t,r)}function Pe(e,t,r){return m(u(e),e,t,r)}function Me(e,t,r){return m(e,null,t,r)}function Xe(e,t,r){return m(u(e),e.nextSibling,t,r)}function De(e,t,r){p(e);return u(e).removeChild(e)}function Ue(e,t,r){var n=e.firstChild;m(e,n,t,r);if(n){while(n.nextSibling){p(n.nextSibling);e.removeChild(n.nextSibling)}p(n);e.removeChild(n)}}function Be(e,t,r){var n=r||ne(e,"hx-select");if(n){var i=re().createDocumentFragment();oe(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function Fe(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Ie(r,n,i);return;case"afterbegin":ke(r,n,i);return;case"beforebegin":Pe(r,n,i);return;case"beforeend":Me(r,n,i);return;case"afterend":Xe(r,n,i);return;case"delete":De(r,n,i);return;default:var a=Fr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Oe(f))}}}return}}catch(e){b(e)}}if(e==="innerHTML"){Ue(r,n,i)}else{Fe(Q.config.defaultSwapStyle,t,r,n,i)}}}function Ve(e){if(e.indexOf("<title")>-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){ce(r,s[l].trim(),[])}}}var ze=/\s/;var x=/[\s,]/;var $e=/[_$a-zA-Z]/;var We=/[_$a-zA-Z0-9]/;var Ge=['"',"'","/"];var Je=/[^\s]/;var Ze=/[{(]/;var Ke=/[})]/;function Ye(e){var t=[];var r=0;while(r<e.length){if($e.exec(e.charAt(r))){var n=r;while(We.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ge.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function Qe(e,t,r){return $e.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function et(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){xt(e,a[1],0)}if(a[0]==="send"){bt(e)}}}function xt(s,r,n){if(!se(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=Q.createWebSocket(r);t.onerror=function(e){fe(s,"htmx:wsError",{error:e,socket:t});yt(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a<i.length;a++){var o=i[a];Ee(te(o,"hx-swap-oob")||"true",o,r)}nr(r.tasks)})}function yt(e){if(!se(e)){ae(e).webSocket.close();return true}}function bt(u){var f=c(u,function(e){return ae(e).webSocket!=null});if(f){u.addEventListener(it(u)[0].trigger,function(e){var t=ae(f).webSocket;var r=xr(u,f);var n=dr(u,"post");var i=n.errors;var a=n.values;var o=Hr(u);var s=le(a,o);var l=yr(s,u);l["HEADERS"]=r;if(i&&i.length>0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){Et(e,a[1])}if(a[0]==="swap"){Ct(e,a[1])}}}function Et(t,e){var r=Q.createEventSource(e);r.onerror=function(e){fe(t,"htmx:sseError",{error:e,source:r});Tt(t)};ae(t).sseEventSource=r}function Ct(a,o){var s=c(a,Ot);if(s){var l=ae(s).sseEventSource;var u=function(e){if(Tt(s)){return}if(!se(a)){l.removeEventListener(o,u);return}var t=e.data;R(a,function(e){t=e.transformResponse(t,null,a)});var r=wr(a);var n=ye(a);var i=T(a);je(r.swapStyle,n,a,t,i);nr(i.tasks);ce(a,"htmx:sseMessage",e)};ae(a).sseListener=u;l.addEventListener(o,u)}else{fe(a,"htmx:noSSESourceError")}}function Rt(e,t,r){var n=c(e,Ot);if(n){var i=ae(n).sseEventSource;var a=function(){if(!Tt(n)){if(se(e)){t(e)}else{i.removeEventListener(r,a)}}};ae(e).sseListener=a;i.addEventListener(r,a)}else{fe(e,"htmx:noSSESourceError")}}function Tt(e){if(!se(e)){ae(e).sseEventSource.close();return true}}function Ot(e){return ae(e).sseEventSource!=null}function qt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n>0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){ce(n,"intersect");break}}},i);a.observe(n);ht(n,r,t,e)}else if(e.trigger==="load"){if(!ct(e,n,Wt("load",{elt:n}))){qt(n,r,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r<t.length;r++){var n=t[r].name;if(s(n,"hx-on:")||s(n,"data-hx-on:")||s(n,"hx-on-")||s(n,"data-hx-on-")){return true}}return false}function kt(e){var t=null;var r=[];if(It(e)){r.push(e)}if(document.evaluate){var n=document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]',e);while(t=n.iterateNext())r.push(t)}else{var i=e.getElementsByTagName("*");for(var a=0;a<i.length;a++){if(It(i[a])){r.push(i[a])}}}return r}function Pt(e){if(e.querySelectorAll){var t=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";var r=e.querySelectorAll(i+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Mt(e){var t=v(e.target,"button, input[type='submit']");var r=Dt(e);if(r){r.lastButtonClicked=t}}function Xt(e){var t=Dt(e);if(t){t.lastButtonClicked=null}}function Dt(e){var t=v(e.target,"button, input[type='submit']");if(!t){return}var r=g("#"+ee(t,"form"))||v(t,"form");if(!r){return}return ae(r)}function Ut(e){e.addEventListener("click",Mt);e.addEventListener("focusin",Mt);e.addEventListener("focusout",Xt)}function Bt(e){var t=Ye(e);var r=0;for(var n=0;n<t.length;n++){const i=t[n];if(i==="{"){r++}else if(i==="}"){r--}}return r}function Ft(t,e,r){var n=ae(t);if(!Array.isArray(n.onHandlers)){n.onHandlers=[]}var i;var a=function(e){return Tr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Vt(e){var t=te(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;t<e.attributes.length;t++){var r=e.attributes[t].name;var n=e.attributes[t].value;if(s(r,"hx-on")||s(r,"data-hx-on")){var i=r.indexOf("-on")+3;var a=r.slice(i,i+1);if(a==="-"||a===":"){var o=r.slice(i+1);if(s(o,":")){o="htmx"+o}else if(s(o,"-")){o="htmx:"+o.slice(1)}else if(s(o,"htmx-")){o="htmx:"+o.slice(5)}Ft(e,o,n)}}}}function _t(t){if(v(t,Q.config.disableSelector)){p(t);return}var r=ae(t);if(r.initHash!==Le(t)){Ne(t);r.initHash=Le(t);Vt(t);ce(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=it(t);var n=Ht(t,r,e);if(!n){if(ne(t,"hx-boost")==="true"){lt(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){Lt(t,e,r,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&o(t,"form")){Ut(t)}var i=te(t,"hx-sse");if(i){St(t,r,i)}var a=te(t,"hx-ws");if(a){pt(t,r,a)}ce(t,"htmx:afterProcessNode")}}function zt(e){e=g(e);if(v(e,Q.config.disableSelector)){p(e);return}_t(e);oe(Pt(e),function(e){_t(e)});oe(kt(e),jt)}function $t(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=re().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function fe(e,t,r){ce(e,t,le({error:t},r))}function Gt(e){return e==="htmx:afterProcessNode"}function R(e,t){oe(Fr(e),function(e){try{t(e)}catch(e){b(e)}})}function b(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ce(e,t,r){e=g(e);if(r==null){r={}}r["elt"]=e;var n=Wt(t,r);if(Q.logger&&!Gt(t)){Q.logger(e,t,r)}if(r.error){b(r.error);ce(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=$t(t);if(i&&a!==t){var o=Wt(a,n.detail);i=i&&e.dispatchEvent(o)}R(e,function(e){i=i&&(e.onEvent(t,n)!==false&&!n.defaultPrevented)});return i}var Jt=location.pathname+location.search;function Zt(){var e=re().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||re().body}function Kt(e,t,r,n){if(!U()){return}if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}e=B(e);var i=E(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};ce(re().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Qt(e){var t=Q.config.requestClass;var r=e.cloneNode(true);oe(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function er(){var e=Zt();var t=Jt||location.pathname+location.search;var r;try{r=re().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){r=re().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!r){ce(re().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Kt(t,Qt(e),re().title,window.scrollY)}if(Q.config.historyEnabled)history.replaceState({htmx:true},re().title,window.location.href)}function tr(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(G(e,"&")||G(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Jt=e}function rr(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Jt=e}function nr(e){oe(e,function(e){e.call()})}function ir(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};ce(re().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",re().location.href);e.onload=function(){if(this.status>=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function fr(e){if(e.name===""||e.name==null||e.disabled||v(e,"fieldset[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 cr(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function hr(t,r,n,e,i){if(e==null||ur(t,e)){return}else{t.push(e)}if(fr(e)){var a=ee(e,"name");var o=e.value;if(e.multiple&&e.tagName==="SELECT"){o=M(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=M(e.files)}cr(a,o,r);if(i){vr(e,n)}}if(h(e,"form")){var s=e.elements;oe(s,function(e){hr(t,r,n,e,i)})}}function vr(e,t){if(e.willValidate){ce(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});ce(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function dr(e,t){var r=[];var n={};var i={};var a=[];var o=ae(e);if(o.lastButtonClicked&&!se(o.lastButtonClicked)){o.lastButtonClicked=null}var s=h(e,"form")&&e.noValidate!==true||te(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){hr(r,i,a,v(e,"form"),s)}hr(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=ee(l,"name");cr(u,l.value,i)}var f=pe(e,"hx-include");oe(f,function(e){hr(r,n,a,e,s);if(!h(e,"form")){oe(e.querySelectorAll(rt),function(e){hr(r,n,a,e,s)})}});n=le(n,i);return{errors:a,values:n}}function gr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function mr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t=gr(t,r,e)})}else{t=gr(t,r,n)}}}return t}function pr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function xr(e,t,r){var n={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":re().location.href};Rr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ae(e).boosted){n["HX-Boosted"]="true"}return n}function yr(t,e){var r=ne(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){oe(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};oe(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function br(e){return ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=d(o.substr(5))}else if(o.indexOf("settle:")===0){n["settleDelay"]=d(o.substr(7))}else if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}else if(o.indexOf("ignoreTitle:")===0){n["ignoreTitle"]=o.substr(12)==="true"}else if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","<style> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.js b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.js index 27e57bc..86e7668 100644 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.js +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.js @@ -1,13 +1,23 @@ -//AMD insanity +// /////////////////////////////////////////////////////////////////// +// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.js +// + +// UMD insanity +// This code sets up support for (in order) AMD, ES6 modules, and globals. (function (root, factory) { //@ts-ignore if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. //@ts-ignore define([], factory); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); } else { // Browser globals - root.htmx = factory(); + root.htmx = root.htmx || factory(); } }(typeof self !== 'undefined' ? self : this, function () { return (function () { @@ -38,6 +48,7 @@ return (function () { defineExtension : defineExtension, removeExtension : removeExtension, logAll : logAll, + logNone : logNone, logger : null, config : { historyEnabled:true, @@ -53,15 +64,24 @@ return (function () { settlingClass:'htmx-settling', swappingClass:'htmx-swapping', allowEval:true, + allowScriptTags:true, inlineScriptNonce:'', attributesToSettle:["class", "style", "width", "height"], withCredentials:false, timeout:0, wsReconnectDelay: 'full-jitter', + wsBinaryType: 'blob', disableSelector: "[hx-disable], [data-hx-disable]", useTemplateFragments: false, scrollBehavior: 'smooth', defaultFocusScroll: false, + getCacheBusterParam: false, + globalViewTransitions: false, + methodsThatUseUrlParams: ["get"], + selfRequestsOnly: false, + ignoreTitle: false, + scrollIntoViewOnBoost: true, + triggerSpecsCache: null, }, parseInterval:parseInterval, _:internalEval, @@ -69,17 +89,23 @@ return (function () { return new EventSource(url, {withCredentials:true}) }, createWebSocket: function(url){ - return new WebSocket(url, []); + var sock = new WebSocket(url, []); + sock.binaryType = htmx.config.wsBinaryType; + return sock; }, - version: "1.7.0" + version: "1.9.10" }; /** @type {import("./htmx").HtmxInternalApi} */ var internalAPI = { + addTriggerHandler: addTriggerHandler, bodyContains: bodyContains, + canAccessLocalStorage: canAccessLocalStorage, + findThisElement: findThisElement, filterValues: filterValues, hasAttribute: hasAttribute, getAttributeValue: getAttributeValue, + getClosestAttributeValue: getClosestAttributeValue, getClosestMatch: getClosestMatch, getExpressionVars: getExpressionVars, getHeaders: getHeaders, @@ -92,6 +118,7 @@ return (function () { mergeObjects: mergeObjects, makeSettleInfo: makeSettleInfo, oobSwap: oobSwap, + querySelectorExt: querySelectorExt, selectAndSwap: selectAndSwap, settleImmediately: settleImmediately, shouldCancel: shouldCancel, @@ -105,21 +132,40 @@ return (function () { return "[hx-" + verb + "], [data-hx-" + verb + "]" }).join(", "); + var HEAD_TAG_REGEX = makeTagRegEx('head'), + TITLE_TAG_REGEX = makeTagRegEx('title'), + SVG_TAGS_REGEX = makeTagRegEx('svg', true); + //==================================================================== // Utilities //==================================================================== + /** + * @param {string} tag + * @param {boolean} global + * @returns {RegExp} + */ + function makeTagRegEx(tag, global = false) { + return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, + global ? 'gim' : 'im'); + } + function parseInterval(str) { if (str == undefined) { - return undefined + return undefined; } + + let interval = NaN; if (str.slice(-2) == "ms") { - return parseFloat(str.slice(0,-2)) || undefined - } - if (str.slice(-1) == "s") { - return (parseFloat(str.slice(0,-1)) * 1000) || undefined + interval = parseFloat(str.slice(0, -2)); + } else if (str.slice(-1) == "s") { + interval = parseFloat(str.slice(0, -1)) * 1000; + } else if (str.slice(-1) == "m") { + interval = parseFloat(str.slice(0, -1)) * 1000 * 60; + } else { + interval = parseFloat(str); } - return parseFloat(str) || undefined + return isNaN(interval) ? undefined : interval; } /** @@ -168,13 +214,11 @@ return (function () { * @returns {HTMLElement | null} */ function getClosestMatch(elt, condition) { - if (condition(elt)) { - return elt; - } else if (parentElt(elt)) { - return getClosestMatch(parentElt(elt), condition); - } else { - return null; + while (elt && !condition(elt)) { + elt = parentElt(elt); } + + return elt ? elt : null; } function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ @@ -208,7 +252,7 @@ return (function () { * @returns {boolean} */ function matches(elt, selector) { - // @ts-ignore: non-standard properties for browser compatability + // @ts-ignore: non-standard properties for browser compatibility // noinspection JSUnresolvedVariable var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; return matchesFunction && matchesFunction.call(elt, selector); @@ -252,38 +296,47 @@ return (function () { return responseNode; } + function aFullPageResponse(resp) { + return /<body/.test(resp) + } + /** * - * @param {string} resp + * @param {string} response * @returns {Element} */ - function makeFragment(resp) { - if (htmx.config.useTemplateFragments) { - var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0); + function makeFragment(response) { + var partialResponse = !aFullPageResponse(response); + var startTag = getStartTag(response); + var content = response; + if (startTag === 'head') { + content = content.replace(HEAD_TAG_REGEX, ''); + } + if (htmx.config.useTemplateFragments && partialResponse) { + var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0); // @ts-ignore type mismatch between DocumentFragment and Element. - // TODO: Are these close enough for htmx to use interchangably? + // TODO: Are these close enough for htmx to use interchangeably? return documentFragment.querySelector('template').content; - } else { - 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); - case "script": - return parseHTML("<div>" + resp + "</div>", 1); - default: - return parseHTML(resp, 0); - } + } + switch (startTag) { + case "thead": + case "tbody": + case "tfoot": + case "colgroup": + case "caption": + return parseHTML("<table>" + content + "</table>", 1); + case "col": + return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2); + case "tr": + return parseHTML("<table><tbody>" + content + "</tbody></table>", 2); + case "td": + case "th": + return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3); + case "script": + case "style": + return parseHTML("<div>" + content + "</div>", 1); + default: + return parseHTML(content, 0); } } @@ -365,13 +418,14 @@ return (function () { return elemTop < window.innerHeight && elemBottom >= 0; } - function bodyContains(elt) { - if (elt.getRootNode() instanceof ShadowRoot) { - return getDocument().body.contains(elt.getRootNode().host); - } else { - return getDocument().body.contains(elt); - } - } + function bodyContains(elt) { + // IE Fix + if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) { + return getDocument().body.contains(elt.getRootNode().host); + } else { + return getDocument().body.contains(elt); + } + } function splitOnWhitespace(trigger) { return trigger.trim().split(/\s+/); @@ -402,6 +456,34 @@ return (function () { } } + function canAccessLocalStorage() { + var test = 'htmx:localStorageTest'; + try { + localStorage.setItem(test, test); + localStorage.removeItem(test); + return true; + } catch(e) { + return false; + } + } + + function normalizePath(path) { + try { + var url = new URL(path); + if (url) { + path = url.pathname + url.search; + } + // remove trailing slash, unless index page + if (!(/^\/$/.test(path))) { + path = path.replace(/\/+$/, ''); + } + return path; + } catch (e) { + // be kind to IE11, which doesn't support URL() + return path; + } + } + //========================================================================================== // public API //========================================================================================== @@ -427,6 +509,10 @@ return (function () { } } + function logNone() { + htmx.logger = null + } + function find(eltOrSelector, selector) { if (selector) { return eltOrSelector.querySelector(selector); @@ -446,7 +532,10 @@ return (function () { function removeElement(elt, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeElement(elt);}, delay) + setTimeout(function(){ + removeElement(elt); + elt = null; + }, delay); } else { elt.parentElement.removeChild(elt); } @@ -455,7 +544,10 @@ return (function () { function addClassToElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){addClassToElement(elt, clazz);}, delay) + setTimeout(function(){ + addClassToElement(elt, clazz); + elt = null; + }, delay); } else { elt.classList && elt.classList.add(clazz); } @@ -464,7 +556,10 @@ return (function () { function removeClassFromElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) + setTimeout(function(){ + removeClassFromElement(elt, clazz); + elt = null; + }, delay); } else { if (elt.classList) { elt.classList.remove(clazz); @@ -494,26 +589,75 @@ return (function () { if (elt.closest) { return elt.closest(selector); } else { + // TODO remove when IE goes away do{ if (elt == null || matches(elt, selector)){ return elt; } } while (elt = elt && parentElt(elt)); + return null; + } + } + + function startsWith(str, prefix) { + return str.substring(0, prefix.length) === prefix + } + + function endsWith(str, suffix) { + return str.substring(str.length - suffix.length) === suffix + } + + function normalizeSelector(selector) { + var trimmedSelector = selector.trim(); + if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) { + return trimmedSelector.substring(1, trimmedSelector.length - 2); + } else { + return trimmedSelector; } } function querySelectorAllExt(elt, selector) { if (selector.indexOf("closest ") === 0) { - return [closest(elt, selector.substr(8))]; + return [closest(elt, normalizeSelector(selector.substr(8)))]; } else if (selector.indexOf("find ") === 0) { - return [find(elt, selector.substr(5))]; + return [find(elt, normalizeSelector(selector.substr(5)))]; + } else if (selector === "next") { + return [elt.nextElementSibling] + } else if (selector.indexOf("next ") === 0) { + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; + } else if (selector === "previous") { + return [elt.previousElementSibling] + } else if (selector.indexOf("previous ") === 0) { + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; } else if (selector === 'document') { return [document]; } else if (selector === 'window') { return [window]; + } else if (selector === 'body') { + return [document.body]; } else { - return getDocument().querySelectorAll(selector); + return getDocument().querySelectorAll(normalizeSelector(selector)); + } + } + + var scanForwardQuery = function(start, match) { + var results = getDocument().querySelectorAll(match); + for (var i = 0; i < results.length; i++) { + var elt = results[i]; + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { + return elt; + } + } + } + + var scanBackwardsQuery = function(start, match) { + var results = getDocument().querySelectorAll(match); + for (var i = results.length - 1; i >= 0; i--) { + var elt = results[i]; + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { + return elt; + } } } @@ -570,7 +714,7 @@ return (function () { //==================================================================== // Node processing //==================================================================== - + var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors function findAttributeTargets(elt, attrName) { var attrTarget = getClosestAttributeValue(elt, attrName); @@ -659,7 +803,7 @@ return (function () { * @returns */ function oobSwap(oobValue, oobElement, settleInfo) { - var selector = "#" + oobElement.id; + var selector = "#" + getRawAttribute(oobElement, "id"); var swapStyle = "outerHTML"; if (oobValue === "true") { // do nothing @@ -703,7 +847,23 @@ return (function () { return oobValue; } - function handleOutOfBandSwaps(fragment, settleInfo) { + function handleOutOfBandSwaps(elt, fragment, settleInfo) { + var oobSelects = getClosestAttributeValue(elt, "hx-select-oob"); + if (oobSelects) { + var oobSelectValues = oobSelects.split(","); + for (var i = 0; i < oobSelectValues.length; i++) { + var oobSelectValue = oobSelectValues[i].split(":", 2); + var id = oobSelectValue[0].trim(); + if (id.indexOf("#") === 0) { + id = id.substring(1); + } + var oobValue = oobSelectValue[1] || "true"; + var oobElement = fragment.querySelector("#" + id); + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo); + } + } + } forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) { var oobValue = getAttributeValue(oobElement, "hx-swap-oob"); if (oobValue != null) { @@ -724,8 +884,11 @@ return (function () { function handleAttributes(parentNode, fragment, settleInfo) { forEach(fragment.querySelectorAll("[id]"), function (newNode) { - if (newNode.id && newNode.id.length > 0) { - var oldNode = parentNode.querySelector(newNode.tagName + "[id='" + newNode.id + "']"); + var id = getRawAttribute(newNode, "id") + if (id && id.length > 0) { + var normalizedId = id.replace("'", "\\'"); + var normalizedTag = newNode.tagName.replace(':', '\\:'); + var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']"); if (oldNode && oldNode !== parentNode) { var newAttributes = newNode.cloneNode(); cloneAttributes(newNode, oldNode); @@ -767,24 +930,67 @@ return (function () { } } - function cleanUpElement(element) { + // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, + // derived from Java's string hashcode implementation + function stringHash(string, hash) { + var char = 0; + while (char < string.length){ + hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int + } + return hash; + } + + function attributeHash(elt) { + var hash = 0; + // IE fix + if (elt.attributes) { + for (var i = 0; i < elt.attributes.length; i++) { + var attribute = elt.attributes[i]; + if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent) + hash = stringHash(attribute.name, hash); + hash = stringHash(attribute.value, hash); + } + } + } + return hash; + } + + function deInitOnHandlers(elt) { + var internalData = getInternalData(elt); + if (internalData.onHandlers) { + for (var i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i]; + elt.removeEventListener(handlerInfo.event, handlerInfo.listener); + } + delete internalData.onHandlers + } + } + + function deInitNode(element) { var internalData = getInternalData(element); + if (internalData.timeout) { + clearTimeout(internalData.timeout); + } if (internalData.webSocket) { internalData.webSocket.close(); } if (internalData.sseEventSource) { internalData.sseEventSource.close(); } - - triggerEvent(element, "htmx:beforeCleanupElement") - if (internalData.listenerInfos) { - forEach(internalData.listenerInfos, function(info) { - if (element !== info.on) { + forEach(internalData.listenerInfos, function (info) { + if (info.on) { info.on.removeEventListener(info.trigger, info.listener); } }); } + deInitOnHandlers(element); + forEach(Object.keys(internalData), function(key) { delete internalData[key] }); + } + + function cleanUpElement(element) { + triggerEvent(element, "htmx:beforeCleanupElement") + deInitNode(element); if (element.children) { // IE forEach(element.children, function(child) { cleanUpElement(child) }); } @@ -803,8 +1009,7 @@ return (function () { } else { newElt = eltBeforeNewContent.nextSibling; } - getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later - settleInfo.elts = [] // clear existing elements + settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target }); while(newElt && newElt !== target) { if (newElt.nodeType === Node.ELEMENT_NODE) { settleInfo.elts.push(newElt); @@ -849,8 +1054,8 @@ return (function () { } } - function maybeSelectFromResponse(elt, fragment) { - var selector = getClosestAttributeValue(elt, "hx-select"); + function maybeSelectFromResponse(elt, fragment, selectOverride) { + var selector = selectOverride || getClosestAttributeValue(elt, "hx-select"); if (selector) { var newFragment = getDocument().createDocumentFragment(); forEach(fragment.querySelectorAll(selector), function (node) { @@ -915,21 +1120,20 @@ return (function () { function findTitle(content) { if (content.indexOf('<title') > -1) { - var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, ''); - var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im); - + var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, ''); + var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX); if (result) { return result[2]; } } } - function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) { + function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) { settleInfo.title = findTitle(responseText); var fragment = makeFragment(responseText); if (fragment) { - handleOutOfBandSwaps(fragment, settleInfo); - fragment = maybeSelectFromResponse(elt, fragment); + handleOutOfBandSwaps(elt, fragment, settleInfo); + fragment = maybeSelectFromResponse(elt, fragment, selectOverride); handlePreservedElements(fragment); return swap(swapStyle, elt, target, fragment, settleInfo); } @@ -949,7 +1153,10 @@ return (function () { } } } else { - triggerEvent(elt, triggerBody, []); + var eventNames = triggerBody.split(",") + for (var i = 0; i < eventNames.length; i++) { + triggerEvent(elt, eventNames[i].trim(), []); + } } } @@ -959,6 +1166,8 @@ return (function () { var SYMBOL_CONT = /[_$a-zA-Z0-9]/; var STRINGISH_START = ['"', "'", "/"]; var NOT_WHITESPACE = /[^\s]/; + var COMBINED_SELECTOR_START = /[{(]/; + var COMBINED_SELECTOR_END = /[})]/; function tokenizeString(str) { var tokens = []; var position = 0; @@ -1041,101 +1250,137 @@ return (function () { function consumeUntil(tokens, match) { var result = ""; - while (tokens.length > 0 && !tokens[0].match(match)) { + while (tokens.length > 0 && !match.test(tokens[0])) { result += tokens.shift(); } return result; } + function consumeCSSSelector(tokens) { + var result; + if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { + tokens.shift(); + result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim(); + tokens.shift(); + } else { + result = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } + return result; + } + var INPUT_SELECTOR = 'input, textarea, select'; /** * @param {HTMLElement} elt + * @param {string} explicitTrigger + * @param {cache} cache for trigger specs * @returns {import("./htmx").HtmxTriggerSpecification[]} */ - function getTriggerSpecs(elt) { - var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); + function parseAndCacheTrigger(elt, explicitTrigger, cache) { var triggerSpecs = []; - if (explicitTrigger) { - var tokens = tokenizeString(explicitTrigger); - do { - consumeUntil(tokens, NOT_WHITESPACE); - var initialLength = tokens.length; - var trigger = consumeUntil(tokens, /[,\[\s]/); - if (trigger !== "") { - if (trigger === "every") { - var every = {trigger: 'every'}; - consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); - consumeUntil(tokens, NOT_WHITESPACE); - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - every.eventFilter = eventFilter; - } - triggerSpecs.push(every); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); - } else { - var triggerSpec = {trigger: trigger}; - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - triggerSpec.eventFilter = eventFilter; - } - while (tokens.length > 0 && tokens[0] !== ",") { - consumeUntil(tokens, NOT_WHITESPACE) - var token = tokens.shift(); - if (token === "changed") { - triggerSpec.changed = true; - } else if (token === "once") { - triggerSpec.once = true; - } else if (token === "consume") { - triggerSpec.consume = true; - } else if (token === "delay" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "from" && tokens[0] === ":") { - tokens.shift(); + var tokens = tokenizeString(explicitTrigger); + do { + consumeUntil(tokens, NOT_WHITESPACE); + var initialLength = tokens.length; + var trigger = consumeUntil(tokens, /[,\[\s]/); + if (trigger !== "") { + if (trigger === "every") { + var every = {trigger: 'every'}; + consumeUntil(tokens, NOT_WHITESPACE); + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); + consumeUntil(tokens, NOT_WHITESPACE); + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + every.eventFilter = eventFilter; + } + triggerSpecs.push(every); + } else if (trigger.indexOf("sse:") === 0) { + triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); + } else { + var triggerSpec = {trigger: trigger}; + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + triggerSpec.eventFilter = eventFilter; + } + while (tokens.length > 0 && tokens[0] !== ",") { + consumeUntil(tokens, NOT_WHITESPACE) + var token = tokens.shift(); + if (token === "changed") { + triggerSpec.changed = true; + } else if (token === "once") { + triggerSpec.once = true; + } else if (token === "consume") { + triggerSpec.consume = true; + } else if (token === "delay" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); + } else if (token === "from" && tokens[0] === ":") { + tokens.shift(); + if (COMBINED_SELECTOR_START.test(tokens[0])) { + var from_arg = consumeCSSSelector(tokens); + } else { var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); - if (from_arg === "closest" || from_arg === "find") { + if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") { tokens.shift(); - from_arg += - " " + - consumeUntil( - tokens, - WHITESPACE_OR_COMMA - ); + var selector = consumeCSSSelector(tokens); + // `next` and `previous` allow a selector-less syntax + if (selector.length > 0) { + from_arg += " " + selector; + } } - triggerSpec.from = from_arg; - } else if (token === "target" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if (token === "throttle" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "queue" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if ((token === "root" || token === "threshold") && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); } + triggerSpec.from = from_arg; + } else if (token === "target" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.target = consumeCSSSelector(tokens); + } else if (token === "throttle" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); + } else if (token === "queue" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } else if (token === "root" && tokens[0] === ":") { + tokens.shift(); + triggerSpec[token] = consumeCSSSelector(tokens); + } else if (token === "threshold" && tokens[0] === ":") { + tokens.shift(); + triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } else { + triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); } - triggerSpecs.push(triggerSpec); } + triggerSpecs.push(triggerSpec); } - if (tokens.length === initialLength) { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - consumeUntil(tokens, NOT_WHITESPACE); - } while (tokens[0] === "," && tokens.shift()) + } + if (tokens.length === initialLength) { + triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); + } + consumeUntil(tokens, NOT_WHITESPACE); + } while (tokens[0] === "," && tokens.shift()) + if (cache) { + cache[explicitTrigger] = triggerSpecs + } + return triggerSpecs + } + + /** + * @param {HTMLElement} elt + * @returns {import("./htmx").HtmxTriggerSpecification[]} + */ + function getTriggerSpecs(elt) { + var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); + var triggerSpecs = []; + if (explicitTrigger) { + var cache = htmx.config.triggerSpecsCache + triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) } if (triggerSpecs.length > 0) { return triggerSpecs; } else if (matches(elt, 'form')) { return [{trigger: 'submit'}]; + } else if (matches(elt, 'input[type="button"], input[type="submit"]')){ + return [{trigger: 'click'}]; } else if (matches(elt, INPUT_SELECTOR)) { return [{trigger: 'change'}]; } else { @@ -1147,14 +1392,17 @@ return (function () { getInternalData(elt).cancelled = true; } - function processPolling(elt, verb, path, spec) { + function processPolling(elt, handler, spec) { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { - issueAjaxRequest(verb, path, elt); + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { + handler(elt); } - processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), spec); + processPolling(elt, handler, spec); } }, spec.pollInterval); } @@ -1166,23 +1414,27 @@ return (function () { } function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt) && elt.target === "") || elt.tagName === "FORM") { + if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || elt.tagName === "FORM") { nodeData.boosted = true; var verb, path; if (elt.tagName === "A") { verb = "get"; - path = getRawAttribute(elt, 'href'); - nodeData.pushURL = true; + path = getRawAttribute(elt, 'href') } else { var rawAttribute = getRawAttribute(elt, "method"); verb = rawAttribute ? rawAttribute.toLowerCase() : "get"; if (verb === "get") { - nodeData.pushURL = true; } path = getRawAttribute(elt, 'action'); } triggerSpecs.forEach(function(triggerSpec) { - addEventListener(elt, verb, path, nodeData, triggerSpec, true); + addEventListener(elt, function(elt, evt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + issueAjaxRequest(verb, path, elt, evt) + }, nodeData, triggerSpec, true); }); } } @@ -1213,11 +1465,11 @@ return (function () { return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); } - function maybeFilterEvent(triggerSpec, evt) { + function maybeFilterEvent(triggerSpec, elt, evt) { var eventFilter = triggerSpec.eventFilter; if(eventFilter){ try { - return eventFilter(evt) !== true; + return eventFilter.call(elt, evt) !== true; } catch(e) { triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); return true; @@ -1226,13 +1478,21 @@ return (function () { return false; } - function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { + function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { + var elementData = getInternalData(elt); var eltsToListenOn; if (triggerSpec.from) { eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); } else { eltsToListenOn = [elt]; } + // store the initial values of the elements, so we can tell if they change + if (triggerSpec.changed) { + eltsToListenOn.forEach(function (eltToListenOn) { + var eltToListenOnData = getInternalData(eltToListenOn); + eltToListenOnData.lastValue = eltToListenOn.value; + }) + } forEach(eltsToListenOn, function (eltToListenOn) { var eventListener = function (evt) { if (!bodyContains(elt)) { @@ -1245,7 +1505,7 @@ return (function () { if (explicitCancel || shouldCancel(evt, elt)) { evt.preventDefault(); } - if (maybeFilterEvent(triggerSpec, evt)) { + if (maybeFilterEvent(triggerSpec, elt, evt)) { return; } var eventData = getInternalData(evt); @@ -1253,7 +1513,6 @@ return (function () { if (eventData.handledFor == null) { eventData.handledFor = []; } - var elementData = getInternalData(elt); if (eventData.handledFor.indexOf(elt) < 0) { eventData.handledFor.push(elt); if (triggerSpec.consume) { @@ -1272,11 +1531,11 @@ return (function () { } } if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { + var eltToListenOnData = getInternalData(eltToListenOn) + if (eltToListenOnData.lastValue === eltToListenOn.value) { return; - } else { - elementData.lastValue = elt.value; } + eltToListenOnData.lastValue = eltToListenOn.value } if (elementData.delayed) { clearTimeout(elementData.delayed); @@ -1285,19 +1544,18 @@ return (function () { return; } - if (triggerSpec.throttle) { + if (triggerSpec.throttle > 0) { if (!elementData.throttle) { - issueAjaxRequest(verb, path, elt, evt); + handler(elt, evt); elementData.throttle = setTimeout(function () { elementData.throttle = null; }, triggerSpec.throttle); } - } else if (triggerSpec.delay) { - elementData.delayed = setTimeout(function () { - issueAjaxRequest(verb, path, elt, evt); - }, triggerSpec.delay); + } else if (triggerSpec.delay > 0) { + elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); } else { - issueAjaxRequest(verb, path, elt, evt); + triggerEvent(elt, 'htmx:trigger') + handler(elt, evt); } } }; @@ -1310,7 +1568,7 @@ return (function () { on: eltToListenOn }) eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); - }) + }); } var windowIsScrolling = false // used by initScrollHandler @@ -1336,14 +1594,11 @@ return (function () { if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { elt.setAttribute('data-hx-revealed', 'true'); var nodeData = getInternalData(elt); - if (nodeData.initialized) { - issueAjaxRequest(nodeData.verb, nodeData.path, elt); + if (nodeData.initHash) { + triggerEvent(elt, 'revealed'); } else { // if the node isn't initialized, wait for it before triggering the request - elt.addEventListener("htmx:afterProcessNode", - function () { - issueAjaxRequest(nodeData.verb, nodeData.path, elt); - }, {once: true}); + elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true}); } } } @@ -1502,6 +1757,9 @@ return (function () { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function (event) { if (maybeCloseSSESource(sseSourceElt)) { + return; + } + if (!bodyContains(elt)) { sseEventSource.removeEventListener(sseEventName, sseListener); return; } @@ -1518,7 +1776,7 @@ return (function () { var target = getTarget(elt) var settleInfo = makeSettleInfo(elt); - selectAndSwap(swapSpec.swapStyle, elt, target, response, settleInfo) + selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) settleImmediately(settleInfo.tasks) triggerEvent(elt, "htmx:sseMessage", event) }; @@ -1530,14 +1788,14 @@ return (function () { } } - function processSSETrigger(elt, verb, path, sseEventName) { + function processSSETrigger(elt, handler, sseEventName) { var sseSourceElt = getClosestMatch(elt, hasEventSource); if (sseSourceElt) { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function () { if (!maybeCloseSSESource(sseSourceElt)) { if (bodyContains(elt)) { - issueAjaxRequest(verb, path, elt); + handler(elt); } else { sseEventSource.removeEventListener(sseEventName, sseListener); } @@ -1563,14 +1821,14 @@ return (function () { //==================================================================== - function loadImmediately(elt, verb, path, nodeData, delay) { + function loadImmediately(elt, handler, nodeData, delay) { var load = function(){ if (!nodeData.loaded) { nodeData.loaded = true; - issueAjaxRequest(verb, path, elt); + handler(elt); } } - if (delay) { + if (delay > 0) { setTimeout(load, delay); } else { load(); @@ -1586,46 +1844,59 @@ return (function () { nodeData.path = path; nodeData.verb = verb; triggerSpecs.forEach(function(triggerSpec) { - if (triggerSpec.sseEvent) { - processSSETrigger(elt, verb, path, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - maybeReveal(elt); - } else if (triggerSpec.trigger === "intersect") { - var observerOptions = {}; - if (triggerSpec.root) { - observerOptions.root = querySelectorExt(elt, triggerSpec.root) - } - if (triggerSpec.threshold) { - observerOptions.threshold = parseFloat(triggerSpec.threshold); + addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return } - var observer = new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - if (entry.isIntersecting) { - triggerEvent(elt, "intersect"); - break; - } - } - }, observerOptions); - observer.observe(elt); - addEventListener(elt, verb, path, nodeData, triggerSpec); - } else if (triggerSpec.trigger === "load") { - loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); - } else if (triggerSpec.pollInterval) { - nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec); - } else { - addEventListener(elt, verb, path, nodeData, triggerSpec); - } + issueAjaxRequest(verb, path, elt, evt) + }) }); } }); return explicitAction; } + function addTriggerHandler(elt, triggerSpec, nodeData, handler) { + if (triggerSpec.sseEvent) { + processSSETrigger(elt, handler, triggerSpec.sseEvent); + } else if (triggerSpec.trigger === "revealed") { + initScrollHandler(); + addEventListener(elt, handler, nodeData, triggerSpec); + maybeReveal(elt); + } else if (triggerSpec.trigger === "intersect") { + var observerOptions = {}; + if (triggerSpec.root) { + observerOptions.root = querySelectorExt(elt, triggerSpec.root) + } + if (triggerSpec.threshold) { + observerOptions.threshold = parseFloat(triggerSpec.threshold); + } + var observer = new IntersectionObserver(function (entries) { + for (var i = 0; i < entries.length; i++) { + var entry = entries[i]; + if (entry.isIntersecting) { + triggerEvent(elt, "intersect"); + break; + } + } + }, observerOptions); + observer.observe(elt); + addEventListener(elt, handler, nodeData, triggerSpec); + } else if (triggerSpec.trigger === "load") { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { + loadImmediately(elt, handler, nodeData, triggerSpec.delay); + } + } else if (triggerSpec.pollInterval > 0) { + nodeData.polling = true; + processPolling(elt, handler, triggerSpec); + } else { + addEventListener(elt, handler, nodeData, triggerSpec); + } + } + function evalScript(script) { - if (script.type === "text/javascript" || script.type === "module" || script.type === "") { + if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) { var newScript = getDocument().createElement("script"); forEach(script.attributes, function (attr) { newScript.setAttribute(attr.name, attr.value); @@ -1642,7 +1913,10 @@ return (function () { } catch (e) { logError(e); } finally { - parent.removeChild(script); + // remove old script element, but only if it is still in DOM + if (script.parentElement) { + script.parentElement.removeChild(script); + } } } } @@ -1656,48 +1930,187 @@ return (function () { }); } - function hasChanceOfBeingBoosted() { - return document.querySelector("[hx-boost], [data-hx-boost]"); + function shouldProcessHxOn(elt) { + var attributes = elt.attributes + for (var j = 0; j < attributes.length; j++) { + var attrName = attributes[j].name + if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") || + startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) { + return true + } + } + return false + } + + function findHxOnWildcardElements(elt) { + var node = null + var elements = [] + + if (shouldProcessHxOn(elt)) { + elements.push(elt) + } + + if (document.evaluate) { + var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + + ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt) + while (node = iter.iterateNext()) elements.push(node) + } else { + var allElements = elt.getElementsByTagName("*") + for (var i = 0; i < allElements.length; i++) { + if (shouldProcessHxOn(allElements[i])) { + elements.push(allElements[i]) + } + } + } + + return elements } function findElementsToProcess(elt) { if (elt.querySelectorAll) { - var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; - var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [hx-data-ext]"); + var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; + var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," + + " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]"); return results; } else { return []; } } - function initButtonTracking(form){ - var maybeSetLastButtonClicked = function(evt){ - if (matches(evt.target, "button, input[type='submit']")) { - var internalData = getInternalData(form); - internalData.lastButtonClicked = evt.target; - } - }; - + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + function maybeSetLastButtonClicked(evt) { + var elt = closest(evt.target, "button, input[type='submit']"); + var internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = elt; + } + }; + function maybeUnsetLastButtonClicked(evt){ + var internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = null; + } + } + function getRelatedFormData(evt) { + var elt = closest(evt.target, "button, input[type='submit']"); + if (!elt) { + return; + } + var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form'); + if (!form) { + return; + } + return getInternalData(form); + } + function initButtonTracking(elt) { // need to handle both click and focus in: // focusin - in case someone tabs in to a button and hits the space bar // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + elt.addEventListener('click', maybeSetLastButtonClicked) + elt.addEventListener('focusin', maybeSetLastButtonClicked) + elt.addEventListener('focusout', maybeUnsetLastButtonClicked) + } - form.addEventListener('click', maybeSetLastButtonClicked) - form.addEventListener('focusin', maybeSetLastButtonClicked) - form.addEventListener('focusout', function(evt){ - var internalData = getInternalData(form); - internalData.lastButtonClicked = null; - }) + function countCurlies(line) { + var tokens = tokenizeString(line); + var netCurlies = 0; + for (var i = 0; i < tokens.length; i++) { + const token = tokens[i]; + if (token === "{") { + netCurlies++; + } else if (token === "}") { + netCurlies--; + } + } + return netCurlies; + } + + function addHxOnEventHandler(elt, eventName, code) { + var nodeData = getInternalData(elt); + if (!Array.isArray(nodeData.onHandlers)) { + nodeData.onHandlers = []; + } + var func; + var listener = function (e) { + return maybeEval(elt, function() { + if (!func) { + func = new Function("event", code); + } + func.call(elt, e); + }); + }; + elt.addEventListener(eventName, listener); + nodeData.onHandlers.push({event:eventName, listener:listener}); + } + + function processHxOn(elt) { + var hxOnValue = getAttributeValue(elt, 'hx-on'); + if (hxOnValue) { + var handlers = {} + var lines = hxOnValue.split("\n"); + var currentEvent = null; + var curlyCount = 0; + while (lines.length > 0) { + var line = lines.shift(); + var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/); + if (curlyCount === 0 && match) { + line.split(":") + currentEvent = match[1].slice(0, -1); // strip last colon + handlers[currentEvent] = match[2]; + } else { + handlers[currentEvent] += line; + } + curlyCount += countCurlies(line); + } + + for (var eventName in handlers) { + addHxOnEventHandler(elt, eventName, handlers[eventName]); + } + } + } + + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (var i = 0; i < elt.attributes.length; i++) { + var name = elt.attributes[i].name + var value = elt.attributes[i].value + if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) { + var afterOnPosition = name.indexOf("-on") + 3; + var nextChar = name.slice(afterOnPosition, afterOnPosition + 1); + if (nextChar === "-" || nextChar === ":") { + var eventName = name.slice(afterOnPosition + 1); + // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support + if (startsWith(eventName, ":")) { + eventName = "htmx" + eventName + } else if (startsWith(eventName, "-")) { + eventName = "htmx:" + eventName.slice(1); + } else if (startsWith(eventName, "htmx-")) { + eventName = "htmx:" + eventName.slice(5); + } + + addHxOnEventHandler(elt, eventName, value) + } + } + } } function initNode(elt) { - if (elt.closest && elt.closest(htmx.config.disableSelector)) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) return; } var nodeData = getInternalData(elt); - if (!nodeData.initialized) { - nodeData.initialized = true; + if (nodeData.initHash !== attributeHash(elt)) { + // clean up any previously processed info + deInitNode(elt); + + nodeData.initHash = attributeHash(elt); + + processHxOn(elt); + triggerEvent(elt, "htmx:beforeProcessNode") if (elt.value) { @@ -1705,14 +2118,24 @@ return (function () { } var triggerSpecs = getTriggerSpecs(elt); - var explicitAction = processVerbs(elt, nodeData, triggerSpecs); - - if (!explicitAction && getClosestAttributeValue(elt, "hx-boost") === "true") { - boostElement(elt, nodeData, triggerSpecs); + var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs); + + if (!hasExplicitHttpAction) { + if (getClosestAttributeValue(elt, "hx-boost") === "true") { + boostElement(elt, nodeData, triggerSpecs); + } else if (hasAttribute(elt, 'hx-trigger')) { + triggerSpecs.forEach(function (triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function () { + }) + }) + } } - if (elt.tagName === "FORM") { - initButtonTracking(elt); + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) { + initButtonTracking(elt) } var sseInfo = getAttributeValue(elt, 'hx-sse'); @@ -1730,8 +2153,15 @@ return (function () { function processNode(elt) { elt = resolveTarget(elt); + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return; + } initNode(elt); forEach(findElementsToProcess(elt), function(child) { initNode(child) }); + // Because it happens second, the new way of adding onHandlers superseeds the old one + // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored + forEach(findHxOnWildcardElements(elt), processHxOnWildcard); } //==================================================================== @@ -1809,7 +2239,7 @@ return (function () { eventResult = eventResult && elt.dispatchEvent(kebabedEvent) } withExtensions(elt, function (extension) { - eventResult = eventResult && (extension.onEvent(eventName, event) !== false) + eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) }); return eventResult; } @@ -1825,6 +2255,18 @@ return (function () { } function saveToHistoryCache(url, content, title, scroll) { + if (!canAccessLocalStorage()) { + return; + } + + if (htmx.config.historyCacheSize <= 0) { + // make sure that an eventually already existing cache is purged + localStorage.removeItem("htmx-history-cache"); + return; + } + + url = normalizePath(url); + var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { @@ -1832,7 +2274,9 @@ return (function () { break; } } - historyCache.push({url:url, content: content, title:title, scroll:scroll}) + var newHistoryItem = {url:url, content: content, title:title, scroll:scroll}; + triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache}) + historyCache.push(newHistoryItem) while (historyCache.length > htmx.config.historyCacheSize) { historyCache.shift(); } @@ -1848,6 +2292,12 @@ return (function () { } function getCachedHistory(url) { + if (!canAccessLocalStorage()) { + return null; + } + + url = normalizePath(url); + var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { @@ -1869,13 +2319,43 @@ return (function () { function saveCurrentPageToHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; - triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); - if(htmx.config.historyEnabled) history.replaceState({htmx:true}, getDocument().title, window.location.href); - saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); + + // Allow history snapshot feature to be disabled where hx-history="false" + // is present *anywhere* in the current document we're about to save, + // so we can prevent privileged data entering the cache. + // The page will still be reachable as a history entry, but htmx will fetch it + // live from the server onpopstate rather than look in the localStorage cache + var disableHistoryCache + try { + disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') + } catch (e) { + // IE11: insensitive modifier not supported so fallback to case sensitive selector + disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') + } + if (!disableHistoryCache) { + triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt}); + saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); + } + + if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href); } function pushUrlIntoHistory(path) { - if(htmx.config.historyEnabled) history.pushState({htmx:true}, "", path); + // remove the cache buster parameter, if any + if (htmx.config.getCacheBusterParam) { + path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') + if (endsWith(path, '&') || endsWith(path, "?")) { + path = path.slice(0, -1); + } + } + if(htmx.config.historyEnabled) { + history.pushState({htmx:true}, "", path); + } + currentPathForHistory = path; + } + + function replaceUrlInHistory(path) { + if(htmx.config.historyEnabled) history.replaceState({htmx:true}, "", path); currentPathForHistory = path; } @@ -1890,7 +2370,9 @@ return (function () { var details = {path: path, xhr:request}; triggerEvent(getDocument().body, "htmx:historyCacheMiss", details); request.open('GET', path, true); + request.setRequestHeader("HX-Request", "true"); request.setRequestHeader("HX-History-Restore-Request", "true"); + request.setRequestHeader("HX-Current-URL", getDocument().location.href); request.onload = function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); @@ -1899,11 +2381,20 @@ return (function () { fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; var historyElement = getHistoryElement(); var settleInfo = makeSettleInfo(historyElement); + var title = findTitle(this.response); + if (title) { + var titleElt = find("title"); + if (titleElt) { + titleElt.innerHTML = title; + } else { + window.document.title = title; + } + } // @ts-ignore swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); + triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response}); } else { triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details); } @@ -1922,9 +2413,11 @@ return (function () { swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); document.title = cached.title; - window.scrollTo(0, cached.scroll); + setTimeout(function () { + window.scrollTo(0, cached.scroll); + }, 0); // next 'tick', so browser has time to render layout currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); + triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); } else { if (htmx.config.refreshOnHistoryMiss) { @@ -1936,31 +2429,46 @@ return (function () { } } - function shouldPush(elt) { - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - return (pushUrl && pushUrl !== "false") || - (getInternalData(elt).boosted && getInternalData(elt).pushURL); - } - - function getPushUrl(elt) { - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - return (pushUrl === "true" || pushUrl === "false") ? null : pushUrl; - } - function addRequestIndicatorClasses(elt) { var indicators = findAttributeTargets(elt, 'hx-indicator'); if (indicators == null) { indicators = [elt]; } forEach(indicators, function (ic) { + var internalData = getInternalData(ic); + internalData.requestCount = (internalData.requestCount || 0) + 1; ic.classList["add"].call(ic.classList, htmx.config.requestClass); }); return indicators; } - function removeRequestIndicatorClasses(indicators) { + function disableElements(elt) { + var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt'); + if (disabledElts == null) { + disabledElts = []; + } + forEach(disabledElts, function (disabledElement) { + var internalData = getInternalData(disabledElement); + internalData.requestCount = (internalData.requestCount || 0) + 1; + disabledElement.setAttribute("disabled", ""); + }); + return disabledElts; + } + + function removeRequestIndicators(indicators, disabled) { forEach(indicators, function (ic) { - ic.classList["remove"].call(ic.classList, htmx.config.requestClass); + var internalData = getInternalData(ic); + internalData.requestCount = (internalData.requestCount || 0) - 1; + if (internalData.requestCount === 0) { + ic.classList["remove"].call(ic.classList, htmx.config.requestClass); + } + }); + forEach(disabled, function (disabledElement) { + var internalData = getInternalData(disabledElement); + internalData.requestCount = (internalData.requestCount || 0) - 1; + if (internalData.requestCount === 0) { + disabledElement.removeAttribute('disabled'); + } }); } @@ -1979,7 +2487,7 @@ return (function () { } function shouldInclude(elt) { - if(elt.name === "" || elt.name == null || elt.disabled) { + if(elt.name === "" || elt.name == null || elt.disabled || closest(elt, "fieldset[disabled]")) { return false; } // ignore "submitter" types (see jQuery src/serialize.js) @@ -1992,6 +2500,29 @@ return (function () { return true; } + function addValueToValues(name, value, values) { + // This is a little ugly because both the current value of the named value in the form + // and the new value could be arrays, so we have to handle all four cases :/ + if (name != null && value != null) { + var current = values[name]; + if (current === undefined) { + values[name] = value; + } else if (Array.isArray(current)) { + if (Array.isArray(value)) { + values[name] = current.concat(value); + } else { + current.push(value); + } + } else { + if (Array.isArray(value)) { + values[name] = [current].concat(value); + } else { + values[name] = [current, value]; + } + } + } + } + function processInputValue(processed, values, errors, elt, validate) { if (elt == null || haveSeenNode(processed, elt)) { return; @@ -2001,35 +2532,14 @@ return (function () { if (shouldInclude(elt)) { var name = getRawAttribute(elt,"name"); var value = elt.value; - if (elt.multiple) { + if (elt.multiple && elt.tagName === "SELECT") { value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value }); } // include file inputs if (elt.files) { value = toArray(elt.files); } - // This is a little ugly because both the current value of the named value in the form - // and the new value could be arrays, so we have to handle all four cases :/ - if (name != null && value != null) { - var current = values[name]; - if(current) { - if (Array.isArray(current)) { - if (Array.isArray(value)) { - values[name] = current.concat(value); - } else { - current.push(value); - } - } else { - if (Array.isArray(value)) { - values[name] = [current].concat(value); - } else { - values[name] = [current, value]; - } - } - } else { - values[name] = value; - } - } + addValueToValues(name, value, values); if (validate) { validateElement(elt, errors); } @@ -2062,9 +2572,13 @@ return (function () { var formValues = {}; var errors = []; var internalData = getInternalData(elt); + if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { + internalData.lastButtonClicked = null + } // only validate when form is directly submitted and novalidate or formnovalidate are not set - var validate = matches(elt, 'form') && elt.noValidate !== true; + // or if the element has an explicit hx-validate="true" on it + var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true"; if (internalData.lastButtonClicked) { validate = validate && internalData.lastButtonClicked.formNoValidate !== true; } @@ -2078,11 +2592,11 @@ return (function () { processInputValue(processed, values, errors, elt, validate); // if a button or submit was clicked last, include its value - if (internalData.lastButtonClicked) { - var name = getRawAttribute(internalData.lastButtonClicked,"name"); - if (name) { - values[name] = internalData.lastButtonClicked.value; - } + if (internalData.lastButtonClicked || elt.tagName === "BUTTON" || + (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) { + var button = internalData.lastButtonClicked || elt + var name = getRawAttribute(button, "name") + addValueToValues(name, button.value, formValues) } // include any explicit includes @@ -2228,40 +2742,43 @@ return (function () { "swapDelay" : htmx.config.defaultSwapDelay, "settleDelay" : htmx.config.defaultSettleDelay } - if (getInternalData(elt).boosted && !isAnchorLink(elt)) { + if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { swapSpec["show"] = "top" } 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)); - } - if (modifier.indexOf("scroll:") === 0) { - var scrollSpec = modifier.substr(7); + for (var i = 0; i < split.length; i++) { + var value = split[i]; + if (value.indexOf("swap:") === 0) { + swapSpec["swapDelay"] = parseInterval(value.substr(5)); + } else if (value.indexOf("settle:") === 0) { + swapSpec["settleDelay"] = parseInterval(value.substr(7)); + } else if (value.indexOf("transition:") === 0) { + swapSpec["transition"] = value.substr(11) === "true"; + } else if (value.indexOf("ignoreTitle:") === 0) { + swapSpec["ignoreTitle"] = value.substr(12) === "true"; + } else if (value.indexOf("scroll:") === 0) { + var scrollSpec = value.substr(7); var splitSpec = scrollSpec.split(":"); var scrollVal = splitSpec.pop(); var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; swapSpec["scroll"] = scrollVal; swapSpec["scrollTarget"] = selectorVal; - } - if (modifier.indexOf("show:") === 0) { - var showSpec = modifier.substr(5); + } else if (value.indexOf("show:") === 0) { + var showSpec = value.substr(5); var splitSpec = showSpec.split(":"); var showVal = splitSpec.pop(); var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; swapSpec["show"] = showVal; swapSpec["showTarget"] = selectorVal; - } - if (modifier.indexOf("focus-scroll:") === 0) { - var focusScrollVal = modifier.substr("focus-scroll:".length); + } else if (value.indexOf("focus-scroll:") === 0) { + var focusScrollVal = value.substr("focus-scroll:".length); swapSpec["focusScroll"] = focusScrollVal == "true"; + } else if (i == 0) { + swapSpec["swapStyle"] = value; + } else { + logError('Unknown modifier in hx-swap: ' + value); } } } @@ -2269,6 +2786,11 @@ return (function () { return swapSpec; } + function usesFormData(elt) { + return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || + (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data"); + } + function encodeParamsForBody(xhr, elt, filteredParameters) { var encodedParameters = null; withExtensions(elt, function (extension) { @@ -2279,8 +2801,7 @@ return (function () { if (encodedParameters != null) { return encodedParameters; } else { - if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || - (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) { + if (usesFormData(elt)) { return makeFormData(filteredParameters); } else { return urlEncode(filteredParameters); @@ -2352,6 +2873,9 @@ return (function () { if (attributeValue) { var str = attributeValue.trim(); var evaluateValue = evalAsDefault; + if (str === "unset") { + return null; + } if (str.indexOf("javascript:") === 0) { str = str.substr(11); evaluateValue = true; @@ -2426,7 +2950,7 @@ return (function () { } } - function getResponseURL(xhr) { + function getPathFromResponse(xhr) { // NB: IE11 does not support this stuff if (xhr.responseURL && typeof(URL) !== "undefined") { try { @@ -2439,7 +2963,7 @@ return (function () { } function hasHeader(xhr, regexp) { - return xhr.getAllResponseHeaders().match(regexp); + return regexp.test(xhr.getAllResponseHeaders()) } function ajaxHelper(verb, path, context) { @@ -2458,6 +2982,7 @@ return (function () { values : context.values, targetOverride: resolveTarget(context.target), swapOverride: context.swap, + select: context.select, returnPromise: true }); } @@ -2477,7 +3002,28 @@ return (function () { return arr; } - function issueAjaxRequest(verb, path, elt, event, etc) { + function verifyPath(elt, path, requestConfig) { + var sameHost + var url + if (typeof URL === "function") { + url = new URL(path, document.location.href); + var origin = document.location.origin; + sameHost = origin === url.origin; + } else { + // IE11 doesn't support URL + url = path + sameHost = startsWith(path, document.location.origin) + } + + if (htmx.config.selfRequestsOnly) { + if (!sameHost) { + return false; + } + } + return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig)); + } + + function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { var resolve = null; var reject = null; etc = etc != null ? etc : {}; @@ -2491,18 +3037,52 @@ return (function () { elt = getDocument().body; } var responseHandler = etc.handler || handleAjaxResponse; + var select = etc.select || null; if (!bodyContains(elt)) { - return; // do not issue requests for elements removed from the DOM + // do not issue requests for elements removed from the DOM + maybeCall(resolve); + return promise; } var target = etc.targetOverride || getTarget(elt); if (target == null || target == DUMMY_ELT) { triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); - return; + maybeCall(reject); + return promise; } - var syncElt = elt; var eltData = getInternalData(elt); + var submitter = eltData.lastButtonClicked; + + if (submitter) { + var buttonPath = getRawAttribute(submitter, "formaction"); + if (buttonPath != null) { + path = buttonPath; + } + + var buttonVerb = getRawAttribute(submitter, "formmethod") + if (buttonVerb != null) { + // ignore buttons with formmethod="dialog" + if (buttonVerb.toLowerCase() !== "dialog") { + verb = buttonVerb; + } + } + } + + var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); + // allow event-based confirmation w/ a callback + if (confirmed === undefined) { + var issueRequest = function(skipConfirmation) { + return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation); + } + var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion}; + if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { + maybeCall(resolve); + return promise; + } + } + + var syncElt = elt; var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); var queueStrategy = null; var abortable = false; @@ -2518,10 +3098,12 @@ return (function () { syncStrategy = (syncStrings[1] || 'drop').trim(); eltData = getInternalData(syncElt); if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { - return; + maybeCall(resolve); + return promise; } else if (syncStrategy === "abort") { if (eltData.xhr) { - return; + maybeCall(resolve); + return promise; } else { abortable = true; } @@ -2565,7 +3147,8 @@ return (function () { issueAjaxRequest(verb, path, elt, event, etc) }); } - return; + maybeCall(resolve); + return promise; } } @@ -2593,8 +3176,7 @@ return (function () { } } - var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); - if (confirmQuestion) { + if (confirmQuestion && !confirmed) { if(!confirm(confirmQuestion)) { maybeCall(resolve); endRequestLock() @@ -2604,6 +3186,11 @@ return (function () { var headers = getHeaders(elt, target, promptResponse); + + if (verb !== 'get' && !usesFormData(elt)) { + headers['Content-Type'] = 'application/x-www-form-urlencoded'; + } + if (etc.headers) { headers = mergeObjects(headers, etc.headers); } @@ -2617,8 +3204,8 @@ return (function () { var allParameters = mergeObjects(rawParameters, expressionVars); var filteredParameters = filterValues(allParameters, elt); - if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null) { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; + if (htmx.config.getCacheBusterParam && verb === 'get') { + filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true"; } // behavior of anchors w/ empty href is to use the current URL @@ -2626,9 +3213,16 @@ return (function () { path = getDocument().location.href; } + var requestAttrValues = getValuesForElement(elt, 'hx-request'); + var eltIsBoosted = getInternalData(elt).boosted; + + var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + var requestConfig = { + boosted: eltIsBoosted, + useUrlParams: useUrlParams, parameters: filteredParameters, unfilteredParameters: allParameters, headers:headers, @@ -2653,6 +3247,7 @@ return (function () { headers = requestConfig.headers; filteredParameters = requestConfig.parameters; errors = requestConfig.errors; + useUrlParams = requestConfig.useUrlParams; if(errors && errors.length > 0){ triggerEvent(elt, 'htmx:validation:halted', requestConfig) @@ -2664,25 +3259,31 @@ return (function () { var splitPath = path.split("#"); var pathNoAnchor = splitPath[0]; var anchor = splitPath[1]; - if (verb === 'get') { - var finalPathForGet = pathNoAnchor; + + var finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor; var values = Object.keys(filteredParameters).length !== 0; if (values) { - if (finalPathForGet.indexOf("?") < 0) { - finalPathForGet += "?"; + if (finalPath.indexOf("?") < 0) { + finalPath += "?"; } else { - finalPathForGet += "&"; + finalPath += "&"; } - finalPathForGet += urlEncode(filteredParameters); + finalPath += urlEncode(filteredParameters); if (anchor) { - finalPathForGet += "#" + anchor; + finalPath += "#" + anchor; } } - xhr.open('GET', finalPathForGet, true); - } else { - xhr.open(verb.toUpperCase(), path, true); } + if (!verifyPath(elt, finalPath, requestConfig)) { + triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) + maybeCall(reject); + return promise; + }; + + xhr.open(verb.toUpperCase(), finalPath, true); xhr.overrideMimeType("text/html"); xhr.withCredentials = requestConfig.withCredentials; xhr.timeout = requestConfig.timeout; @@ -2699,19 +3300,24 @@ return (function () { } } - var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, etc:etc, pathInfo:{ - path:path, finalPath:finalPathForGet, anchor:anchor + var responseInfo = { + xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select, + pathInfo: { + requestPath: path, + finalRequestPath: finalPath, + anchor: anchor } }; xhr.onload = function () { try { var hierarchy = hierarchyForElt(elt); + responseInfo.pathInfo.responsePath = getPathFromResponse(xhr); responseHandler(elt, responseInfo); - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerEvent(elt, 'htmx:afterRequest', responseInfo); triggerEvent(elt, 'htmx:afterOnLoad', responseInfo); - // if the body no longer contains the element, trigger the even on the closest parent + // if the body no longer contains the element, trigger the event on the closest parent // remaining in the DOM if (!bodyContains(elt)) { var secondaryTriggerElt = null; @@ -2734,21 +3340,21 @@ return (function () { } } xhr.onerror = function () { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:sendError', responseInfo); maybeCall(reject); endRequestLock(); } xhr.onabort = function() { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo); maybeCall(reject); endRequestLock(); } xhr.ontimeout = function() { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:timeout', responseInfo); maybeCall(reject); @@ -2760,6 +3366,7 @@ return (function () { return promise } var indicators = addRequestIndicatorClasses(elt); + var disableElts = disableElements(elt); forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { forEach([xhr, xhr.upload], function (target) { @@ -2773,14 +3380,99 @@ return (function () { }); }); triggerEvent(elt, 'htmx:beforeSend', responseInfo); - xhr.send(verb === 'get' ? null : encodeParamsForBody(xhr, elt, filteredParameters)); + var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) + xhr.send(params); return promise; } + function determineHistoryUpdates(elt, responseInfo) { + + var xhr = responseInfo.xhr; + + //=========================================== + // First consult response headers + //=========================================== + var pathFromHeaders = null; + var typeFromHeaders = null; + if (hasHeader(xhr,/HX-Push:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Push"); + typeFromHeaders = "push"; + } else if (hasHeader(xhr,/HX-Push-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Push-Url"); + typeFromHeaders = "push"; + } else if (hasHeader(xhr,/HX-Replace-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url"); + typeFromHeaders = "replace"; + } + + // if there was a response header, that has priority + if (pathFromHeaders) { + if (pathFromHeaders === "false") { + return {} + } else { + return { + type: typeFromHeaders, + path : pathFromHeaders + } + } + } + + //=========================================== + // Next resolve via DOM values + //=========================================== + var requestPath = responseInfo.pathInfo.finalRequestPath; + var responsePath = responseInfo.pathInfo.responsePath; + + var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); + var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url"); + var elementIsBoosted = getInternalData(elt).boosted; + + var saveType = null; + var path = null; + + if (pushUrl) { + saveType = "push"; + path = pushUrl; + } else if (replaceUrl) { + saveType = "replace"; + path = replaceUrl; + } else if (elementIsBoosted) { + saveType = "push"; + path = responsePath || requestPath; // if there is no response path, go with the original request path + } + + if (path) { + // false indicates no push, return empty object + if (path === "false") { + return {}; + } + + // true indicates we want to follow wherever the server ended up sending us + if (path === "true") { + path = responsePath || requestPath; // if there is no response path, go with the original request path + } + + // restore any anchor associated with the request + if (responseInfo.pathInfo.anchor && + path.indexOf("#") === -1) { + path = path + "#" + responseInfo.pathInfo.anchor; + } + + return { + type:saveType, + path: path + } + } else { + return {}; + } + } + function handleAjaxResponse(elt, responseInfo) { var xhr = responseInfo.xhr; var target = responseInfo.target; var etc = responseInfo.etc; + var requestConfig = responseInfo.requestConfig; + var select = responseInfo.select; if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; @@ -2788,33 +3480,44 @@ return (function () { handleTrigger(xhr, "HX-Trigger", elt); } - if (hasHeader(xhr,/HX-Push:/i)) { - var pushedUrl = xhr.getResponseHeader("HX-Push"); + if (hasHeader(xhr, /HX-Location:/i)) { + saveCurrentPageToHistory(); + var redirectPath = xhr.getResponseHeader("HX-Location"); + var swapSpec; + if (redirectPath.indexOf("{") === 0) { + swapSpec = parseJSON(redirectPath); + // what's the best way to throw an error if the user didn't include this + redirectPath = swapSpec['path']; + delete swapSpec['path']; + } + ajaxHelper('GET', redirectPath, swapSpec).then(function(){ + pushUrlIntoHistory(redirectPath); + }); + return; } + var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh"); + if (hasHeader(xhr, /HX-Redirect:/i)) { - window.location.href = xhr.getResponseHeader("HX-Redirect"); + location.href = xhr.getResponseHeader("HX-Redirect"); + shouldRefresh && location.reload(); return; } - if (hasHeader(xhr,/HX-Refresh:/i)) { - if ("true" === xhr.getResponseHeader("HX-Refresh")) { - location.reload(); - return; - } + if (shouldRefresh) { + location.reload(); + return; } if (hasHeader(xhr,/HX-Retarget:/i)) { - responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget")); + if (xhr.getResponseHeader("HX-Retarget") === "this") { + responseInfo.target = elt; + } else { + responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget")); + } } - /** @type {boolean} */ - var shouldSaveHistory - if (pushedUrl == "false") { - shouldSaveHistory = false - } else { - shouldSaveHistory = shouldPush(elt) || pushedUrl; - } + var historyUpdate = determineHistoryUpdates(elt, responseInfo); // by default htmx only swaps on 200 return codes and does not swap // on 204 'No Content' @@ -2823,15 +3526,18 @@ return (function () { var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; var serverResponse = xhr.response; var isError = xhr.status >= 400; - var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo); + var ignoreTitle = htmx.config.ignoreTitle + var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo); if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; target = beforeSwapDetails.target; // allow re-targeting serverResponse = beforeSwapDetails.serverResponse; // allow updating content isError = beforeSwapDetails.isError; // allow updating error - + ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title + + responseInfo.target = target; // Make updated target available to response events responseInfo.failed = isError; // Make failed property available to response events - responseInfo.successful = !isError; // Make successful property available to response events + responseInfo.successful = !isError; // Make successful property available to response events if (beforeSwapDetails.shouldSwap) { if (xhr.status === 286) { @@ -2842,18 +3548,29 @@ return (function () { serverResponse = extension.transformResponse(serverResponse, xhr, elt); }); - // Save current page - if (shouldSaveHistory) { + // Save current page if there will be a history update + if (historyUpdate.type) { saveCurrentPageToHistory(); } var swapOverride = etc.swapOverride; + if (hasHeader(xhr,/HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader("HX-Reswap"); + } var swapSpec = getSwapSpecification(elt, swapOverride); + if (swapSpec.hasOwnProperty('ignoreTitle')) { + ignoreTitle = swapSpec.ignoreTitle; + } + target.classList.add(htmx.config.swappingClass); + + // optional transition API promise callbacks + var settleResolve = null; + var settleReject = null; + var doSwap = function () { try { - var activeElt = document.activeElement; var selectionInfo = {}; try { @@ -2868,19 +3585,44 @@ return (function () { // safari issue - see https://github.com/microsoft/playwright/issues/5894 } + var selectOverride; + if (select) { + selectOverride = select; + } + + if (hasHeader(xhr, /HX-Reselect:/i)) { + selectOverride = xhr.getResponseHeader("HX-Reselect"); + } + + // if we need to save history, do so, before swapping so that relative resources have the correct base URL + if (historyUpdate.type) { + triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)); + if (historyUpdate.type === "push") { + pushUrlIntoHistory(historyUpdate.path); + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path}); + } else { + replaceUrlInHistory(historyUpdate.path); + triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path}); + } + } + var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride); if (selectionInfo.elt && !bodyContains(selectionInfo.elt) && - selectionInfo.elt.id) { - var newActiveElt = document.getElementById(selectionInfo.elt.id); + getRawAttribute(selectionInfo.elt, "id")) { + var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id")); var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; if (newActiveElt) { // @ts-ignore if (selectionInfo.start && newActiveElt.setSelectionRange) { // @ts-ignore - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + try { + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + } catch (e) { + // the setSelectionRange method is present on fields that don't support it, so just let this fail + } } newActiveElt.focus(focusOptions); } @@ -2893,9 +3635,6 @@ return (function () { } triggerEvent(elt, 'htmx:afterSwap', responseInfo); }); - if (responseInfo.pathInfo.anchor) { - location.hash = responseInfo.pathInfo.anchor; - } if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { var finalElt = elt; @@ -2915,14 +3654,15 @@ return (function () { } triggerEvent(elt, 'htmx:afterSettle', responseInfo); }); - // push URL and save new page - if (shouldSaveHistory) { - var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; - pushUrlIntoHistory(pathToPush); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: pathToPush}); + + if (responseInfo.pathInfo.anchor) { + var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor); + if(anchorTarget) { + anchorTarget.scrollIntoView({block:'start', behavior: "auto"}); + } } - if(settleInfo.title) { + if(settleInfo.title && !ignoreTitle) { var titleElt = find("title"); if(titleElt) { titleElt.innerHTML = settleInfo.title; @@ -2940,6 +3680,7 @@ return (function () { } handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); } + maybeCall(settleResolve); } if (swapSpec.settleDelay > 0) { @@ -2949,10 +3690,34 @@ return (function () { } } catch (e) { triggerErrorEvent(elt, 'htmx:swapError', responseInfo); + maybeCall(settleReject); throw e; } }; + var shouldTransition = htmx.config.globalViewTransitions + if(swapSpec.hasOwnProperty('transition')){ + shouldTransition = swapSpec.transition; + } + + if(shouldTransition && + triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && + typeof Promise !== "undefined" && document.startViewTransition){ + var settlePromise = new Promise(function (_resolve, _reject) { + settleResolve = _resolve; + settleReject = _reject; + }); + // wrap the original doSwap() in a call to startViewTransition() + var innerDoSwap = doSwap; + doSwap = function() { + document.startViewTransition(function () { + innerDoSwap(); + return settlePromise; + }); + } + } + + if (swapSpec.swapDelay > 0) { setTimeout(doSwap, swapSpec.swapDelay) } else { @@ -2960,7 +3725,7 @@ return (function () { } } if (isError) { - triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.path}, responseInfo)); + triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo)); } } @@ -3048,9 +3813,22 @@ return (function () { //==================================================================== // Initialization //==================================================================== + var isReady = false + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true + }) + /** + * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. + * + * This function uses isReady because there is no realiable way to ask the browswer whether + * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded + * firing and readystate=complete. + */ function ready(fn) { - if (getDocument().readyState !== 'loading') { + // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by + // some means other than the initial page load. + if (isReady || getDocument().readyState === 'complete') { fn(); } else { getDocument().addEventListener('DOMContentLoaded', fn); @@ -3061,9 +3839,9 @@ return (function () { if (htmx.config.includeIndicatorStyles !== false) { getDocument().head.insertAdjacentHTML("beforeend", "<style>\ - ." + htmx.config.indicatorClass + "{opacity:0;transition: opacity 200ms ease-in;}\ - ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1}\ - ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1}\ + ." + htmx.config.indicatorClass + "{opacity:0}\ + ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ + ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ </style>"); } } @@ -3101,6 +3879,9 @@ return (function () { internalData.xhr.abort(); } }); + /** @type {(ev: PopStateEvent) => any} */ + const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null; + /** @type {(ev: PopStateEvent) => any} */ window.onpopstate = function (event) { if (event.state && event.state.htmx) { restoreHistory(); @@ -3110,10 +3891,15 @@ return (function () { 'triggerEvent': triggerEvent }); }); + } else { + if (originalPopstate) { + originalPopstate(event); + } } }; setTimeout(function () { triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event + body = null; // kill reference for gc }, 0); }) diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.min.js b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.min.js index 998414c..53bbdf6 100644 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.min.js +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.min.js @@ -1 +1,4 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(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 l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=k(e);e.classList.toggle(t)}function T(e,t){e=k(e);W(e.parentElement.children,function(e){q(e,t)});L(e,t)}function H(e,t){e=k(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function N(e,t){if(t.indexOf("closest ")===0){return[H(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[C(e,t.substr(5))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return z().querySelectorAll(t)}}function ee(e,t){if(t){return N(e,t)[0]}else{return N(z().body,e)[0]}}function k(e){if(p(e,"String")){return C(e)}else{return e}}function I(e,t,r){if(m(t)){return{target:z().body,event:e,listener:t}}else{return{target:k(e),event:t,listener:r}}}function M(t,r,n){lr(function(){var e=I(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function D(t,r,n){lr(function(){var e=I(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var te=z().createElement("output");function F(e,t){var r=G(e,t);if(r){if(r==="this"){return[re(e,t)]}else{var n=N(e,r);if(n.length===0){pt('The selector "'+r+'" on '+t+" returned no matches!");return[te]}else{return n}}}}function re(e,t){return h(e,function(e){return V(e,t)!=null})}function ne(e){var t=G(e,"hx-target");if(t){if(t==="this"){return re(e,"hx-target")}else{return ee(e,t)}}else{var r=_(e);if(r.boosted){return z().body}else{return e}}}function P(e){var t=U.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function X(t,r){W(t.attributes,function(e){if(!r.hasAttribute(e.name)&&P(e.name)){t.removeAttribute(e.name)}});W(r.attributes,function(e){if(P(e.name)){t.setAttribute(e.name,e.value)}})}function j(e,t){var r=sr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){pt(e)}}return e==="outerHTML"}function B(e,i,o){var t="#"+i.id;var a="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){a=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{a=e}var r=z().querySelectorAll(t);if(r){W(r,function(e){var t;var r=i.cloneNode(true);t=z().createDocumentFragment();t.appendChild(r);if(!j(a,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ye(a,e,e,t,o)}W(o.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(z().body,"htmx:oobErrorNoTarget",{content:i})}return e}function ie(e,r){W(R(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=V(e,"hx-swap-oob");if(t!=null){B(t,e,r)}})}function oe(e){W(R(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=V(e,"id");var r=z().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function ae(n,e,i){W(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();X(e,t);i.tasks.push(function(){X(e,r)})}}})}function se(e){return function(){q(e,U.config.addedClass);ct(e);at(e);le(e);$(e,"htmx:load")}}function le(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ue(e,t,r,n){ae(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(se(i))}}}function fe(t){var e=_(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){W(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){W(t.children,function(e){fe(e)})}}function ce(e,t,r){if(e.tagName==="BODY"){return me(e,t,r)}else{var n;var i=e.previousSibling;ue(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}_(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}fe(e);u(e).removeChild(e)}}function he(e,t,r){return ue(e,e.firstChild,t,r)}function de(e,t,r){return ue(u(e),e,t,r)}function ve(e,t,r){return ue(e,null,t,r)}function ge(e,t,r){return ue(u(e),e.nextSibling,t,r)}function pe(e,t,r){fe(e);return u(e).removeChild(e)}function me(e,t,r){var n=e.firstChild;ue(e,n,t,r);if(n){while(n.nextSibling){fe(n.nextSibling);e.removeChild(n.nextSibling)}fe(n);e.removeChild(n)}}function xe(e,t){var r=G(e,"hx-select");if(r){var n=z().createDocumentFragment();W(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function ye(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":ce(r,n,i);return;case"afterbegin":he(r,n,i);return;case"beforebegin":de(r,n,i);return;case"beforeend":ve(r,n,i);return;case"afterend":ge(r,n,i);return;case"delete":pe(r,n,i);return;default:var o=sr(t);for(var a=0;a<o.length;a++){var f=o[a];try{var s=f.handleSwap(e,r,n,i);if(s){if(typeof s.length!=="undefined"){for(var l=0;l<s.length;l++){var u=s[l];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){i.tasks.push(se(u))}}}return}}catch(e){pt(e)}}if(e==="innerHTML"){me(r,n,i)}else{ye(U.config.defaultSwapStyle,t,r,n,i)}}}function be(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function we(e,t,r,n,i){i.title=be(n);var o=g(n);if(o){ie(o,i);o=xe(r,o);oe(o);return ye(e,r,t,o,i)}}function Se(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!x(a)){a={value:a}}$(r,o,a)}}}else{$(r,n,[])}}var Ee=/\s/;var Ce=/[\s,]/;var Re=/[_$a-zA-Z]/;var Oe=/[_$a-zA-Z0-9]/;var Le=['"',"'","/"];var qe=/[^\s]/;function Ae(e){var t=[];var r=0;while(r<e.length){if(Re.exec(e.charAt(r))){var n=r;while(Oe.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Le.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function Te(e,t,r){return Re.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function He(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Jt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(z().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(Te(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var Ne="input, textarea, select";function ke(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=Ae(t);do{c(n,qe);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var o={trigger:"every"};c(n,qe);o.pollInterval=v(c(n,/[,\[\s]/));c(n,qe);var a=He(e,n,"event");if(a){o.eventFilter=a}r.push(o)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var a=He(e,n,"event");if(a){s.eventFilter=a}while(n.length>0&&n[0]!==","){c(n,qe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Ce))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Ce);if(u==="closest"||u==="find"){n.shift();u+=" "+c(n,Ce)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Ce)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Ce))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Ce)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Ce)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,qe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,Ne)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ie(e){_(e).cancelled=true}function Me(e,t,r,n){var i=_(e);i.timeout=setTimeout(function(){if(Y(e)&&i.cancelled!==true){if(!je(n,dt("hx:poll:trigger",{triggerSpec:n,target:e}))){Z(t,r,e)}Me(e,t,V(e,"hx-"+t),n)}},n.pollInterval)}function De(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&De(t)&&t.target===""||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href");r.pushURL=true}else{var o=f(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=f(t,"action")}e.forEach(function(e){Be(t,n,i,r,e,true)})}}function Pe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&H(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Xe(e,t){return _(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function je(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(z().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Be(o,a,s,e,l,u){var t;if(l.from){t=N(o,l.from)}else{t=[o]}W(t,function(n){var i=function(e){if(!Y(o)){n.removeEventListener(l.trigger,i);return}if(Xe(o,e)){return}if(u||Pe(e,o)){e.preventDefault()}if(je(l,e)){return}var t=_(e);t.triggerSpec=l;if(t.handledFor==null){t.handledFor=[]}var r=_(o);if(t.handledFor.indexOf(o)<0){t.handledFor.push(o);if(l.consume){e.stopPropagation()}if(l.target&&e.target){if(!d(e.target,l.target)){return}}if(l.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(l.changed){if(r.lastValue===o.value){return}else{r.lastValue=o.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(l.throttle){if(!r.throttle){Z(a,s,o,e);r.throttle=setTimeout(function(){r.throttle=null},l.throttle)}}else if(l.delay){r.delayed=setTimeout(function(){Z(a,s,o,e)},l.delay)}else{Z(a,s,o,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:l.trigger,listener:i,on:n});n.addEventListener(l.trigger,i)})}var Ue=false;var Ve=null;function ze(){if(!Ve){Ve=function(){Ue=true};window.addEventListener("scroll",Ve);setInterval(function(){if(Ue){Ue=false;W(z().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){_e(e)})}},200)}}function _e(e){if(!s(e,"data-hx-revealed")&&b(e)){e.setAttribute("data-hx-revealed","true");var t=_(e);if(t.initialized){Z(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Z(t.verb,t.path,e)},{once:true})}}}function We(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Je(e,o[1],0)}if(o[0]==="send"){Ze(e)}}}function Je(s,r,n){if(!Y(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=U.createWebSocket(r);t.onerror=function(e){J(s,"htmx:wsError",{error:e,socket:t});$e(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=Ge(n);setTimeout(function(){Je(s,r,n+1)},t)}};t.onopen=function(e){n=0};_(s).webSocket=t;t.addEventListener("message",function(e){if($e(s)){return}var t=e.data;gt(s,function(e){t=e.transformResponse(t,null,s)});var r=zt(s);var n=g(t);var i=y(n.children);for(var o=0;o<i.length;o++){var a=i[o];B(V(a,"hx-swap-oob")||"true",a,r)}Ct(r.tasks)})}function $e(e){if(!Y(e)){_(e).webSocket.close();return true}}function Ze(u){var f=h(u,function(e){return _(e).webSocket!=null});if(f){u.addEventListener(ke(u)[0].trigger,function(e){var t=_(f).webSocket;var r=Xt(u,f);var n=Mt(u,"post");var i=n.errors;var o=n.values;var a=Gt(u);var s=Q(o,a);var l=jt(s,u);l["HEADERS"]=r;if(i&&i.length>0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Pe(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ge(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}pt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ke(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Ye(e,o[1])}if(o[0]==="swap"){Qe(e,o[1])}}}function Ye(t,e){var r=U.createEventSource(e);r.onerror=function(e){J(t,"htmx:sseError",{error:e,source:r});tt(t)};_(t).sseEventSource=r}function Qe(o,a){var s=h(o,rt);if(s){var l=_(s).sseEventSource;var u=function(e){if(tt(s)){l.removeEventListener(a,u);return}var t=e.data;gt(o,function(e){t=e.transformResponse(t,null,o)});var r=Ut(o);var n=ne(o);var i=zt(o);we(r.swapStyle,o,n,t,i);Ct(i.tasks);$(o,"htmx:sseMessage",e)};_(o).sseListener=u;l.addEventListener(a,u)}else{J(o,"htmx:noSSESourceError")}}function et(e,t,r,n){var i=h(e,rt);if(i){var o=_(i).sseEventSource;var a=function(){if(!tt(i)){if(Y(e)){Z(t,r,e)}else{o.removeEventListener(n,a)}}};_(e).sseListener=a;o.addEventListener(n,a)}else{J(e,"htmx:noSSESourceError")}}function tt(e){if(!Y(e)){_(e).sseEventSource.close();return true}}function rt(e){return _(e).sseEventSource!=null}function nt(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Z(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function it(o,a,e){var t=false;W(n,function(n){if(s(o,"hx-"+n)){var i=V(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){et(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){ze();_e(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=ee(o,e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){$(o,"intersect");break}}},t);r.observe(o);Be(o,n,i,a,e)}else if(e.trigger==="load"){nt(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Me(o,n,i,e)}else{Be(o,n,i,a,e)}})}});return t}function ot(e){if(e.type==="text/javascript"||e.type==="module"||e.type===""){var t=z().createElement("script");W(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(U.config.inlineScriptNonce){t.nonce=U.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){pt(e)}finally{r.removeChild(e)}}}function at(e){if(d(e,"script")){ot(e)}W(R(e,"script"),function(e){ot(e)})}function st(){return document.querySelector("[hx-boost], [data-hx-boost]")}function lt(e){if(e.querySelectorAll){var t=st()?", a, form":"";var r=e.querySelectorAll(i+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [hx-data-ext]");return r}else{return[]}}function ut(r){var e=function(e){if(d(e.target,"button, input[type='submit']")){var t=_(r);t.lastButtonClicked=e.target}};r.addEventListener("click",e);r.addEventListener("focusin",e);r.addEventListener("focusout",function(e){var t=_(r);t.lastButtonClicked=null})}function ft(e){if(e.closest&&e.closest(U.config.disableSelector)){return}var t=_(e);if(!t.initialized){t.initialized=true;$(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=ke(e);var n=it(e,t,r);if(!n&&G(e,"hx-boost")==="true"){Fe(e,t,r)}if(e.tagName==="FORM"){ut(e)}var i=V(e,"hx-sse");if(i){Ke(e,t,i)}var o=V(e,"hx-ws");if(o){We(e,t,o)}$(e,"htmx:afterProcessNode")}}function ct(e){e=k(e);ft(e);W(lt(e),function(e){ft(e)})}function ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function dt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=z().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function J(e,t,r){$(e,t,Q({error:t},r))}function vt(e){return e==="htmx:afterProcessNode"}function gt(e,t){W(sr(e),function(e){try{t(e)}catch(e){pt(e)}})}function pt(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function $(e,t,r){e=k(e);if(r==null){r={}}r["elt"]=e;var n=dt(t,r);if(U.logger&&!vt(t)){U.logger(e,t,r)}if(r.error){pt(r.error);$(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=ht(t);if(i&&o!==t){var a=dt(o,n.detail);i=i&&e.dispatchEvent(a)}gt(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var mt=location.pathname+location.search;function xt(){var e=z().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||z().body}function yt(e,t,r,n){var i=S(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>U.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(z().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function bt(e){var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function wt(e){var t=U.config.requestClass;var r=e.cloneNode(true);W(R(r,"."+t),function(e){q(e,t)});return r.innerHTML}function St(){var e=xt();var t=mt||location.pathname+location.search;$(z().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(U.config.historyEnabled)history.replaceState({htmx:true},z().title,window.location.href);yt(t,wt(e),z().title,window.scrollY)}function Et(e){if(U.config.historyEnabled)history.pushState({htmx:true},"",e);mt=e}function Ct(e){W(e,function(e){e.call()})}function Rt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};$(z().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){$(z().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=xt();var r=zt(t);me(t,e,r);Ct(r.tasks);mt=n;$(z().body,"htmx:historyRestore",{path:n})}else{J(z().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Ot(e){St();e=e||location.pathname+location.search;var t=bt(e);if(t){var r=g(t.content);var n=xt();var i=zt(n);me(n,r,i);Ct(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);mt=e;$(z().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Rt(e)}}}function Lt(e){var t=G(e,"hx-push-url");return t&&t!=="false"||_(e).boosted&&_(e).pushURL}function qt(e){var t=G(e,"hx-push-url");return t==="true"||t==="false"?null:t}function At(e){var t=F(e,"hx-indicator");if(t==null){t=[e]}W(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Tt(e){W(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function Ht(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Nt(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 kt(t,r,n,e,i){if(e==null||Ht(t,e)){return}else{t.push(e)}if(Nt(e)){var o=f(e,"name");var a=e.value;if(e.multiple){a=y(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=y(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){It(e,n)}}if(d(e,"form")){var l=e.elements;W(l,function(e){kt(t,r,n,e,i)})}}function It(e,t){if(e.willValidate){$(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});$(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Mt(e,t){var r=[];var n={};var i={};var o=[];var a=_(e);var s=d(e,"form")&&e.noValidate!==true;if(a.lastButtonClicked){s=s&&a.lastButtonClicked.formNoValidate!==true}if(t!=="get"){kt(r,i,o,H(e,"form"),s)}kt(r,n,o,e,s);if(a.lastButtonClicked){var l=f(a.lastButtonClicked,"name");if(l){n[l]=a.lastButtonClicked.value}}var u=F(e,"hx-include");W(u,function(e){kt(r,n,o,e,s);if(!d(e,"form")){W(e.querySelectorAll(Ne),function(e){kt(r,n,o,e,s)})}});n=Q(n,i);return{errors:o,values:n}}function Dt(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function Ft(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=Dt(t,r,e)})}else{t=Dt(t,r,n)}}}return t}function Pt(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){W(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Xt(e,t,r){var n={"HX-Request":"true","HX-Trigger":f(e,"id"),"HX-Trigger-Name":f(e,"name"),"HX-Target":V(t,"id"),"HX-Current-URL":z().location.href};Wt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(_(e).boosted){n["HX-Boosted"]="true"}return n}function jt(t,e){var r=G(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){W(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};W(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Bt(e){return f(e,"href")&&f(e,"href").indexOf("#")>=0}function Ut(e,t){var r=t?t:G(e,"hx-swap");var n={swapStyle:_(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(_(e).boosted&&!Bt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var o=1;o<i.length;o++){var a=i[o];if(a.indexOf("swap:")===0){n["swapDelay"]=v(a.substr(5))}if(a.indexOf("settle:")===0){n["settleDelay"]=v(a.substr(7))}if(a.indexOf("scroll:")===0){var s=a.substr(7);var l=s.split(":");var f=l.pop();var u=l.length>0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(a.indexOf("show:")===0){var c=a.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(a.indexOf("focus-scroll:")===0){var d=a.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function Vt(t,r,n){var i=null;gt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(G(r,"hx-encoding")==="multipart/form-data"||d(r,"form")&&f(r,"enctype")==="multipart/form-data"){return Pt(n)}else{return Ft(n)}}}function zt(e){return{tasks:[],elts:[e]}}function _t(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ee(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var o=t.showTarget;if(t.showTarget==="window"){o="body"}i=ee(r,o)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function Wt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}else if(o.indexOf("js:")===0){o=o.substr(3);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Jt(e,function(){return Function("return ("+o+")")()},{})}else{s=S(o)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Wt(u(e),t,r,n)}function Jt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function $t(e,t){return Wt(e,"hx-vars",true,t)}function Zt(e,t){return Wt(e,"hx-vals",false,t)}function Gt(e){return Q($t(e),Zt(e))}function Kt(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Yt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(z().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Qt(e,t){return e.getAllResponseHeaders().match(t)}function er(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return Z(e,t,null,null,{targetOverride:k(r),returnPromise:true})}else{return Z(e,t,k(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:k(r.target),swapOverride:r.swap,returnPromise:true})}}else{return Z(e,t,null,null,{returnPromise:true})}}function tr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Z(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=z().body}var v=r.handler||rr;if(!Y(n)){return}var g=r.targetOverride||ne(n);if(g==null||g==te){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=_(n);var o=G(n,"hx-sync");var m=null;var x=false;if(o){var y=o.split(":");var b=y[0].trim();if(b==="this"){p=re(n,"hx-sync")}else{p=ee(n,b)}o=(y[1]||"drop").trim();i=_(p);if(o==="drop"&&i.xhr&&i.abortable!==true){return}else if(o==="abort"){if(i.xhr){return}else{x=true}}else if(o==="replace"){$(p,"htmx:abort")}else if(o.indexOf("queue")===0){var w=o.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=_(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){Z(e,t,n,f,r)})}return}}var a=new XMLHttpRequest;i.xhr=a;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=G(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){K(c);s();return d}}var R=G(n,"hx-confirm");if(R){if(!confirm(R)){K(c);s();return d}}var O=Xt(n,g,C);if(r.headers){O=Q(O,r.headers)}var L=Mt(n,e);var q=L.errors;var A=L.values;if(r.values){A=Q(A,r.values)}var T=Gt(n);var H=Q(A,T);var N=jt(H,n);if(e!=="get"&&G(n,"hx-encoding")==null){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=z().location.href}var k=Wt(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:q,withCredentials:r.credentials||k.credentials||U.config.withCredentials,timeout:r.timeout||k.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){K(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;q=l.errors;if(q&&q.length>0){$(n,"htmx:validation:halted",l);K(c);s();return d}var I=t.split("#");var M=I[0];var D=I[1];if(e==="get"){var F=M;var P=Object.keys(N).length!==0;if(P){if(F.indexOf("?")<0){F+="?"}else{F+="&"}F+=Ft(N);if(D){F+="#"+D}}a.open("GET",F,true)}else{a.open(e.toUpperCase(),t,true)}a.overrideMimeType("text/html");a.withCredentials=l.withCredentials;a.timeout=l.timeout;if(k.noHeaders){}else{for(var X in O){if(O.hasOwnProperty(X)){var j=O[X];Kt(a,X,j)}}}var u={xhr:a,target:g,requestConfig:l,etc:r,pathInfo:{path:t,finalPath:F,anchor:D}};a.onload=function(){try{var e=tr(n);v(n,u);Tt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!Y(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(Y(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}K(c);s()}catch(e){J(n,"htmx:onLoadError",Q({error:e},u));throw e}};a.onerror=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);K(h);s()};a.onabort=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);K(h);s()};a.ontimeout=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);K(h);s()};if(!$(n,"htmx:beforeRequest",u)){K(c);s();return d}var B=At(n);W(["loadstart","loadend","progress","abort"],function(t){W([a,a.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);a.send(e==="get"?null:Vt(a,n,N));return d}function rr(s,l){var u=l.xhr;var f=l.target;var r=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(Qt(u,/HX-Trigger:/i)){Se(u,"HX-Trigger",s)}if(Qt(u,/HX-Push:/i)){var c=u.getResponseHeader("HX-Push")}if(Qt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Qt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(Qt(u,/HX-Retarget:/i)){l.target=z().querySelector(u.getResponseHeader("HX-Retarget"))}var h;if(c=="false"){h=false}else{h=Lt(s)||c}var n=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var e=u.status>=400;var t=Q({shouldSwap:n,serverResponse:d,isError:e},l);if(!$(f,"htmx:beforeSwap",t))return;f=t.target;d=t.serverResponse;e=t.isError;l.failed=e;l.successful=!e;if(t.shouldSwap){if(u.status===286){Ie(s)}gt(s,function(e){d=e.transformResponse(d,u,s)});if(h){St()}var i=r.swapOverride;var v=Ut(s,i);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=zt(f);we(v.swapStyle,f,s,d,n);if(t.elt&&!Y(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);W(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(l.pathInfo.anchor){location.hash=l.pathInfo.anchor}if(Qt(u,/HX-Trigger-After-Swap:/i)){var o=s;if(!Y(s)){o=z().body}Se(u,"HX-Trigger-After-Swap",o)}var a=function(){W(n.tasks,function(e){e.call()});W(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h){var e=c||qt(s)||Yt(u)||l.pathInfo.finalPath||l.pathInfo.path;Et(e);$(z().body,"htmx:pushedIntoHistory",{path:e})}if(n.title){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}_t(n.elts,v);if(Qt(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!Y(s)){r=z().body}Se(u,"HX-Trigger-After-Settle",r)}};if(v.settleDelay>0){setTimeout(a,v.settleDelay)}else{a()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(v.swapDelay>0){setTimeout(o,v.swapDelay)}else{o()}}if(e){J(s,"htmx:responseError",Q({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var nr={};function ir(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function or(e,t){if(t.init){t.init(r)}nr[e]=Q(ir(),t)}function ar(e){delete nr[e]}function sr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){W(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=nr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return sr(u(e),r,n)}function lr(e){if(z().readyState!=="loading"){e()}else{z().addEventListener("DOMContentLoaded",e)}}function ur(){if(U.config.includeIndicatorStyles!==false){z().head.insertAdjacentHTML("beforeend","<style> ."+U.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+U.config.requestClass+" ."+U.config.indicatorClass+"{opacity:1} ."+U.config.requestClass+"."+U.config.indicatorClass+"{opacity:1} </style>")}}function fr(){var e=z().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function cr(){var e=fr();if(e){U.config=Q(U.config,e)}}lr(function(){cr();ur();var e=z().body;ct(e);var t=z().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=_(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){Ot();W(t,function(e){$(e,"htmx:restored",{document:z(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file +// /////////////////////////////////////////////////////////////////// +// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js +// +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(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 a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/<body/.test(e)}function l(e){var t=!N(e);var r=A(e);var n=e;if(r==="head"){n=n.replace(S,"")}if(Q.config.useTemplateFragments&&t){var i=a("<body><template>"+n+"</template></body>",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a("<table>"+n+"</table>",1);case"col":return a("<table><colgroup>"+n+"</colgroup></table>",2);case"tr":return a("<table><tbody>"+n+"</tbody></table>",2);case"td":case"th":return a("<table><tbody><tr>"+n+"</tr></tbody></table>",3);case"script":case"style":return a("<div>"+n+"</div>",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function oe(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function X(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var Y=function(e,t){var r=re().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function we(t,r){oe(t.attributes,function(e){if(!r.hasAttribute(e.name)&&be(e.name)){t.removeAttribute(e.name)}});oe(r.attributes,function(e){if(be(e.name)){t.setAttribute(e.name,e.value)}})}function Se(e,t){var r=Fr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){b(e)}}return e==="outerHTML"}function Ee(e,i,a){var t="#"+ee(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a<i.length;a++){var o=i[a].split(":",2);var s=o[0].trim();if(s.indexOf("#")===0){s=s.substring(1)}var l=o[1]||"true";var u=t.querySelector("#"+s);if(u){Ee(l,u,r)}}}oe(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=te(e,"hx-swap-oob");if(t!=null){Ee(t,e,r)}})}function Re(e){oe(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=te(e,"id");var r=re().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function Te(o,e,s){oe(e.querySelectorAll("[id]"),function(e){var t=ee(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Le(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=He(n.name,t);t=He(n.value,t)}}}return t}function Ae(e){var t=ae(e);if(t.onHandlers){for(var r=0;r<t.onHandlers.length;r++){const n=t.onHandlers[r];e.removeEventListener(n.event,n.listener)}delete t.onHandlers}}function Ne(e){var t=ae(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){oe(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}Ae(e);oe(Object.keys(t),function(e){delete t[e]})}function p(e){ce(e,"htmx:beforeCleanupElement");Ne(e);if(e.children){oe(e.children,function(e){p(e)})}}function Ie(t,e,r){if(t.tagName==="BODY"){return Ue(t,e,r)}else{var n;var i=t.previousSibling;m(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}p(t);u(t).removeChild(t)}}function ke(e,t,r){return m(e,e.firstChild,t,r)}function Pe(e,t,r){return m(u(e),e,t,r)}function Me(e,t,r){return m(e,null,t,r)}function Xe(e,t,r){return m(u(e),e.nextSibling,t,r)}function De(e,t,r){p(e);return u(e).removeChild(e)}function Ue(e,t,r){var n=e.firstChild;m(e,n,t,r);if(n){while(n.nextSibling){p(n.nextSibling);e.removeChild(n.nextSibling)}p(n);e.removeChild(n)}}function Be(e,t,r){var n=r||ne(e,"hx-select");if(n){var i=re().createDocumentFragment();oe(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function Fe(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Ie(r,n,i);return;case"afterbegin":ke(r,n,i);return;case"beforebegin":Pe(r,n,i);return;case"beforeend":Me(r,n,i);return;case"afterend":Xe(r,n,i);return;case"delete":De(r,n,i);return;default:var a=Fr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Oe(f))}}}return}}catch(e){b(e)}}if(e==="innerHTML"){Ue(r,n,i)}else{Fe(Q.config.defaultSwapStyle,t,r,n,i)}}}function Ve(e){if(e.indexOf("<title")>-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){ce(r,s[l].trim(),[])}}}var ze=/\s/;var x=/[\s,]/;var $e=/[_$a-zA-Z]/;var We=/[_$a-zA-Z0-9]/;var Ge=['"',"'","/"];var Je=/[^\s]/;var Ze=/[{(]/;var Ke=/[})]/;function Ye(e){var t=[];var r=0;while(r<e.length){if($e.exec(e.charAt(r))){var n=r;while(We.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ge.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function Qe(e,t,r){return $e.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function et(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){xt(e,a[1],0)}if(a[0]==="send"){bt(e)}}}function xt(s,r,n){if(!se(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=Q.createWebSocket(r);t.onerror=function(e){fe(s,"htmx:wsError",{error:e,socket:t});yt(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a<i.length;a++){var o=i[a];Ee(te(o,"hx-swap-oob")||"true",o,r)}nr(r.tasks)})}function yt(e){if(!se(e)){ae(e).webSocket.close();return true}}function bt(u){var f=c(u,function(e){return ae(e).webSocket!=null});if(f){u.addEventListener(it(u)[0].trigger,function(e){var t=ae(f).webSocket;var r=xr(u,f);var n=dr(u,"post");var i=n.errors;var a=n.values;var o=Hr(u);var s=le(a,o);var l=yr(s,u);l["HEADERS"]=r;if(i&&i.length>0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){Et(e,a[1])}if(a[0]==="swap"){Ct(e,a[1])}}}function Et(t,e){var r=Q.createEventSource(e);r.onerror=function(e){fe(t,"htmx:sseError",{error:e,source:r});Tt(t)};ae(t).sseEventSource=r}function Ct(a,o){var s=c(a,Ot);if(s){var l=ae(s).sseEventSource;var u=function(e){if(Tt(s)){return}if(!se(a)){l.removeEventListener(o,u);return}var t=e.data;R(a,function(e){t=e.transformResponse(t,null,a)});var r=wr(a);var n=ye(a);var i=T(a);je(r.swapStyle,n,a,t,i);nr(i.tasks);ce(a,"htmx:sseMessage",e)};ae(a).sseListener=u;l.addEventListener(o,u)}else{fe(a,"htmx:noSSESourceError")}}function Rt(e,t,r){var n=c(e,Ot);if(n){var i=ae(n).sseEventSource;var a=function(){if(!Tt(n)){if(se(e)){t(e)}else{i.removeEventListener(r,a)}}};ae(e).sseListener=a;i.addEventListener(r,a)}else{fe(e,"htmx:noSSESourceError")}}function Tt(e){if(!se(e)){ae(e).sseEventSource.close();return true}}function Ot(e){return ae(e).sseEventSource!=null}function qt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n>0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){ce(n,"intersect");break}}},i);a.observe(n);ht(n,r,t,e)}else if(e.trigger==="load"){if(!ct(e,n,Wt("load",{elt:n}))){qt(n,r,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r<t.length;r++){var n=t[r].name;if(s(n,"hx-on:")||s(n,"data-hx-on:")||s(n,"hx-on-")||s(n,"data-hx-on-")){return true}}return false}function kt(e){var t=null;var r=[];if(It(e)){r.push(e)}if(document.evaluate){var n=document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]',e);while(t=n.iterateNext())r.push(t)}else{var i=e.getElementsByTagName("*");for(var a=0;a<i.length;a++){if(It(i[a])){r.push(i[a])}}}return r}function Pt(e){if(e.querySelectorAll){var t=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";var r=e.querySelectorAll(i+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Mt(e){var t=v(e.target,"button, input[type='submit']");var r=Dt(e);if(r){r.lastButtonClicked=t}}function Xt(e){var t=Dt(e);if(t){t.lastButtonClicked=null}}function Dt(e){var t=v(e.target,"button, input[type='submit']");if(!t){return}var r=g("#"+ee(t,"form"))||v(t,"form");if(!r){return}return ae(r)}function Ut(e){e.addEventListener("click",Mt);e.addEventListener("focusin",Mt);e.addEventListener("focusout",Xt)}function Bt(e){var t=Ye(e);var r=0;for(var n=0;n<t.length;n++){const i=t[n];if(i==="{"){r++}else if(i==="}"){r--}}return r}function Ft(t,e,r){var n=ae(t);if(!Array.isArray(n.onHandlers)){n.onHandlers=[]}var i;var a=function(e){return Tr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Vt(e){var t=te(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;t<e.attributes.length;t++){var r=e.attributes[t].name;var n=e.attributes[t].value;if(s(r,"hx-on")||s(r,"data-hx-on")){var i=r.indexOf("-on")+3;var a=r.slice(i,i+1);if(a==="-"||a===":"){var o=r.slice(i+1);if(s(o,":")){o="htmx"+o}else if(s(o,"-")){o="htmx:"+o.slice(1)}else if(s(o,"htmx-")){o="htmx:"+o.slice(5)}Ft(e,o,n)}}}}function _t(t){if(v(t,Q.config.disableSelector)){p(t);return}var r=ae(t);if(r.initHash!==Le(t)){Ne(t);r.initHash=Le(t);Vt(t);ce(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=it(t);var n=Ht(t,r,e);if(!n){if(ne(t,"hx-boost")==="true"){lt(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){Lt(t,e,r,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&o(t,"form")){Ut(t)}var i=te(t,"hx-sse");if(i){St(t,r,i)}var a=te(t,"hx-ws");if(a){pt(t,r,a)}ce(t,"htmx:afterProcessNode")}}function zt(e){e=g(e);if(v(e,Q.config.disableSelector)){p(e);return}_t(e);oe(Pt(e),function(e){_t(e)});oe(kt(e),jt)}function $t(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=re().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function fe(e,t,r){ce(e,t,le({error:t},r))}function Gt(e){return e==="htmx:afterProcessNode"}function R(e,t){oe(Fr(e),function(e){try{t(e)}catch(e){b(e)}})}function b(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ce(e,t,r){e=g(e);if(r==null){r={}}r["elt"]=e;var n=Wt(t,r);if(Q.logger&&!Gt(t)){Q.logger(e,t,r)}if(r.error){b(r.error);ce(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=$t(t);if(i&&a!==t){var o=Wt(a,n.detail);i=i&&e.dispatchEvent(o)}R(e,function(e){i=i&&(e.onEvent(t,n)!==false&&!n.defaultPrevented)});return i}var Jt=location.pathname+location.search;function Zt(){var e=re().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||re().body}function Kt(e,t,r,n){if(!U()){return}if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}e=B(e);var i=E(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};ce(re().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Qt(e){var t=Q.config.requestClass;var r=e.cloneNode(true);oe(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function er(){var e=Zt();var t=Jt||location.pathname+location.search;var r;try{r=re().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){r=re().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!r){ce(re().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Kt(t,Qt(e),re().title,window.scrollY)}if(Q.config.historyEnabled)history.replaceState({htmx:true},re().title,window.location.href)}function tr(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(G(e,"&")||G(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Jt=e}function rr(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Jt=e}function nr(e){oe(e,function(e){e.call()})}function ir(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};ce(re().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",re().location.href);e.onload=function(){if(this.status>=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function fr(e){if(e.name===""||e.name==null||e.disabled||v(e,"fieldset[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 cr(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function hr(t,r,n,e,i){if(e==null||ur(t,e)){return}else{t.push(e)}if(fr(e)){var a=ee(e,"name");var o=e.value;if(e.multiple&&e.tagName==="SELECT"){o=M(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=M(e.files)}cr(a,o,r);if(i){vr(e,n)}}if(h(e,"form")){var s=e.elements;oe(s,function(e){hr(t,r,n,e,i)})}}function vr(e,t){if(e.willValidate){ce(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});ce(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function dr(e,t){var r=[];var n={};var i={};var a=[];var o=ae(e);if(o.lastButtonClicked&&!se(o.lastButtonClicked)){o.lastButtonClicked=null}var s=h(e,"form")&&e.noValidate!==true||te(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){hr(r,i,a,v(e,"form"),s)}hr(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=ee(l,"name");cr(u,l.value,i)}var f=pe(e,"hx-include");oe(f,function(e){hr(r,n,a,e,s);if(!h(e,"form")){oe(e.querySelectorAll(rt),function(e){hr(r,n,a,e,s)})}});n=le(n,i);return{errors:a,values:n}}function gr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function mr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t=gr(t,r,e)})}else{t=gr(t,r,n)}}}return t}function pr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function xr(e,t,r){var n={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":re().location.href};Rr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ae(e).boosted){n["HX-Boosted"]="true"}return n}function yr(t,e){var r=ne(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){oe(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};oe(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function br(e){return ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=d(o.substr(5))}else if(o.indexOf("settle:")===0){n["settleDelay"]=d(o.substr(7))}else if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}else if(o.indexOf("ignoreTitle:")===0){n["ignoreTitle"]=o.substr(12)==="true"}else if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","<style> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.js b/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.js index 27e57bc..86e7668 100644 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.js +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.js @@ -1,13 +1,23 @@ -//AMD insanity +// /////////////////////////////////////////////////////////////////// +// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.js +// + +// UMD insanity +// This code sets up support for (in order) AMD, ES6 modules, and globals. (function (root, factory) { //@ts-ignore if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. //@ts-ignore define([], factory); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); } else { // Browser globals - root.htmx = factory(); + root.htmx = root.htmx || factory(); } }(typeof self !== 'undefined' ? self : this, function () { return (function () { @@ -38,6 +48,7 @@ return (function () { defineExtension : defineExtension, removeExtension : removeExtension, logAll : logAll, + logNone : logNone, logger : null, config : { historyEnabled:true, @@ -53,15 +64,24 @@ return (function () { settlingClass:'htmx-settling', swappingClass:'htmx-swapping', allowEval:true, + allowScriptTags:true, inlineScriptNonce:'', attributesToSettle:["class", "style", "width", "height"], withCredentials:false, timeout:0, wsReconnectDelay: 'full-jitter', + wsBinaryType: 'blob', disableSelector: "[hx-disable], [data-hx-disable]", useTemplateFragments: false, scrollBehavior: 'smooth', defaultFocusScroll: false, + getCacheBusterParam: false, + globalViewTransitions: false, + methodsThatUseUrlParams: ["get"], + selfRequestsOnly: false, + ignoreTitle: false, + scrollIntoViewOnBoost: true, + triggerSpecsCache: null, }, parseInterval:parseInterval, _:internalEval, @@ -69,17 +89,23 @@ return (function () { return new EventSource(url, {withCredentials:true}) }, createWebSocket: function(url){ - return new WebSocket(url, []); + var sock = new WebSocket(url, []); + sock.binaryType = htmx.config.wsBinaryType; + return sock; }, - version: "1.7.0" + version: "1.9.10" }; /** @type {import("./htmx").HtmxInternalApi} */ var internalAPI = { + addTriggerHandler: addTriggerHandler, bodyContains: bodyContains, + canAccessLocalStorage: canAccessLocalStorage, + findThisElement: findThisElement, filterValues: filterValues, hasAttribute: hasAttribute, getAttributeValue: getAttributeValue, + getClosestAttributeValue: getClosestAttributeValue, getClosestMatch: getClosestMatch, getExpressionVars: getExpressionVars, getHeaders: getHeaders, @@ -92,6 +118,7 @@ return (function () { mergeObjects: mergeObjects, makeSettleInfo: makeSettleInfo, oobSwap: oobSwap, + querySelectorExt: querySelectorExt, selectAndSwap: selectAndSwap, settleImmediately: settleImmediately, shouldCancel: shouldCancel, @@ -105,21 +132,40 @@ return (function () { return "[hx-" + verb + "], [data-hx-" + verb + "]" }).join(", "); + var HEAD_TAG_REGEX = makeTagRegEx('head'), + TITLE_TAG_REGEX = makeTagRegEx('title'), + SVG_TAGS_REGEX = makeTagRegEx('svg', true); + //==================================================================== // Utilities //==================================================================== + /** + * @param {string} tag + * @param {boolean} global + * @returns {RegExp} + */ + function makeTagRegEx(tag, global = false) { + return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, + global ? 'gim' : 'im'); + } + function parseInterval(str) { if (str == undefined) { - return undefined + return undefined; } + + let interval = NaN; if (str.slice(-2) == "ms") { - return parseFloat(str.slice(0,-2)) || undefined - } - if (str.slice(-1) == "s") { - return (parseFloat(str.slice(0,-1)) * 1000) || undefined + interval = parseFloat(str.slice(0, -2)); + } else if (str.slice(-1) == "s") { + interval = parseFloat(str.slice(0, -1)) * 1000; + } else if (str.slice(-1) == "m") { + interval = parseFloat(str.slice(0, -1)) * 1000 * 60; + } else { + interval = parseFloat(str); } - return parseFloat(str) || undefined + return isNaN(interval) ? undefined : interval; } /** @@ -168,13 +214,11 @@ return (function () { * @returns {HTMLElement | null} */ function getClosestMatch(elt, condition) { - if (condition(elt)) { - return elt; - } else if (parentElt(elt)) { - return getClosestMatch(parentElt(elt), condition); - } else { - return null; + while (elt && !condition(elt)) { + elt = parentElt(elt); } + + return elt ? elt : null; } function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ @@ -208,7 +252,7 @@ return (function () { * @returns {boolean} */ function matches(elt, selector) { - // @ts-ignore: non-standard properties for browser compatability + // @ts-ignore: non-standard properties for browser compatibility // noinspection JSUnresolvedVariable var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; return matchesFunction && matchesFunction.call(elt, selector); @@ -252,38 +296,47 @@ return (function () { return responseNode; } + function aFullPageResponse(resp) { + return /<body/.test(resp) + } + /** * - * @param {string} resp + * @param {string} response * @returns {Element} */ - function makeFragment(resp) { - if (htmx.config.useTemplateFragments) { - var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0); + function makeFragment(response) { + var partialResponse = !aFullPageResponse(response); + var startTag = getStartTag(response); + var content = response; + if (startTag === 'head') { + content = content.replace(HEAD_TAG_REGEX, ''); + } + if (htmx.config.useTemplateFragments && partialResponse) { + var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0); // @ts-ignore type mismatch between DocumentFragment and Element. - // TODO: Are these close enough for htmx to use interchangably? + // TODO: Are these close enough for htmx to use interchangeably? return documentFragment.querySelector('template').content; - } else { - 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); - case "script": - return parseHTML("<div>" + resp + "</div>", 1); - default: - return parseHTML(resp, 0); - } + } + switch (startTag) { + case "thead": + case "tbody": + case "tfoot": + case "colgroup": + case "caption": + return parseHTML("<table>" + content + "</table>", 1); + case "col": + return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2); + case "tr": + return parseHTML("<table><tbody>" + content + "</tbody></table>", 2); + case "td": + case "th": + return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3); + case "script": + case "style": + return parseHTML("<div>" + content + "</div>", 1); + default: + return parseHTML(content, 0); } } @@ -365,13 +418,14 @@ return (function () { return elemTop < window.innerHeight && elemBottom >= 0; } - function bodyContains(elt) { - if (elt.getRootNode() instanceof ShadowRoot) { - return getDocument().body.contains(elt.getRootNode().host); - } else { - return getDocument().body.contains(elt); - } - } + function bodyContains(elt) { + // IE Fix + if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) { + return getDocument().body.contains(elt.getRootNode().host); + } else { + return getDocument().body.contains(elt); + } + } function splitOnWhitespace(trigger) { return trigger.trim().split(/\s+/); @@ -402,6 +456,34 @@ return (function () { } } + function canAccessLocalStorage() { + var test = 'htmx:localStorageTest'; + try { + localStorage.setItem(test, test); + localStorage.removeItem(test); + return true; + } catch(e) { + return false; + } + } + + function normalizePath(path) { + try { + var url = new URL(path); + if (url) { + path = url.pathname + url.search; + } + // remove trailing slash, unless index page + if (!(/^\/$/.test(path))) { + path = path.replace(/\/+$/, ''); + } + return path; + } catch (e) { + // be kind to IE11, which doesn't support URL() + return path; + } + } + //========================================================================================== // public API //========================================================================================== @@ -427,6 +509,10 @@ return (function () { } } + function logNone() { + htmx.logger = null + } + function find(eltOrSelector, selector) { if (selector) { return eltOrSelector.querySelector(selector); @@ -446,7 +532,10 @@ return (function () { function removeElement(elt, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeElement(elt);}, delay) + setTimeout(function(){ + removeElement(elt); + elt = null; + }, delay); } else { elt.parentElement.removeChild(elt); } @@ -455,7 +544,10 @@ return (function () { function addClassToElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){addClassToElement(elt, clazz);}, delay) + setTimeout(function(){ + addClassToElement(elt, clazz); + elt = null; + }, delay); } else { elt.classList && elt.classList.add(clazz); } @@ -464,7 +556,10 @@ return (function () { function removeClassFromElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) + setTimeout(function(){ + removeClassFromElement(elt, clazz); + elt = null; + }, delay); } else { if (elt.classList) { elt.classList.remove(clazz); @@ -494,26 +589,75 @@ return (function () { if (elt.closest) { return elt.closest(selector); } else { + // TODO remove when IE goes away do{ if (elt == null || matches(elt, selector)){ return elt; } } while (elt = elt && parentElt(elt)); + return null; + } + } + + function startsWith(str, prefix) { + return str.substring(0, prefix.length) === prefix + } + + function endsWith(str, suffix) { + return str.substring(str.length - suffix.length) === suffix + } + + function normalizeSelector(selector) { + var trimmedSelector = selector.trim(); + if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) { + return trimmedSelector.substring(1, trimmedSelector.length - 2); + } else { + return trimmedSelector; } } function querySelectorAllExt(elt, selector) { if (selector.indexOf("closest ") === 0) { - return [closest(elt, selector.substr(8))]; + return [closest(elt, normalizeSelector(selector.substr(8)))]; } else if (selector.indexOf("find ") === 0) { - return [find(elt, selector.substr(5))]; + return [find(elt, normalizeSelector(selector.substr(5)))]; + } else if (selector === "next") { + return [elt.nextElementSibling] + } else if (selector.indexOf("next ") === 0) { + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; + } else if (selector === "previous") { + return [elt.previousElementSibling] + } else if (selector.indexOf("previous ") === 0) { + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; } else if (selector === 'document') { return [document]; } else if (selector === 'window') { return [window]; + } else if (selector === 'body') { + return [document.body]; } else { - return getDocument().querySelectorAll(selector); + return getDocument().querySelectorAll(normalizeSelector(selector)); + } + } + + var scanForwardQuery = function(start, match) { + var results = getDocument().querySelectorAll(match); + for (var i = 0; i < results.length; i++) { + var elt = results[i]; + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { + return elt; + } + } + } + + var scanBackwardsQuery = function(start, match) { + var results = getDocument().querySelectorAll(match); + for (var i = results.length - 1; i >= 0; i--) { + var elt = results[i]; + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { + return elt; + } } } @@ -570,7 +714,7 @@ return (function () { //==================================================================== // Node processing //==================================================================== - + var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors function findAttributeTargets(elt, attrName) { var attrTarget = getClosestAttributeValue(elt, attrName); @@ -659,7 +803,7 @@ return (function () { * @returns */ function oobSwap(oobValue, oobElement, settleInfo) { - var selector = "#" + oobElement.id; + var selector = "#" + getRawAttribute(oobElement, "id"); var swapStyle = "outerHTML"; if (oobValue === "true") { // do nothing @@ -703,7 +847,23 @@ return (function () { return oobValue; } - function handleOutOfBandSwaps(fragment, settleInfo) { + function handleOutOfBandSwaps(elt, fragment, settleInfo) { + var oobSelects = getClosestAttributeValue(elt, "hx-select-oob"); + if (oobSelects) { + var oobSelectValues = oobSelects.split(","); + for (var i = 0; i < oobSelectValues.length; i++) { + var oobSelectValue = oobSelectValues[i].split(":", 2); + var id = oobSelectValue[0].trim(); + if (id.indexOf("#") === 0) { + id = id.substring(1); + } + var oobValue = oobSelectValue[1] || "true"; + var oobElement = fragment.querySelector("#" + id); + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo); + } + } + } forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) { var oobValue = getAttributeValue(oobElement, "hx-swap-oob"); if (oobValue != null) { @@ -724,8 +884,11 @@ return (function () { function handleAttributes(parentNode, fragment, settleInfo) { forEach(fragment.querySelectorAll("[id]"), function (newNode) { - if (newNode.id && newNode.id.length > 0) { - var oldNode = parentNode.querySelector(newNode.tagName + "[id='" + newNode.id + "']"); + var id = getRawAttribute(newNode, "id") + if (id && id.length > 0) { + var normalizedId = id.replace("'", "\\'"); + var normalizedTag = newNode.tagName.replace(':', '\\:'); + var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']"); if (oldNode && oldNode !== parentNode) { var newAttributes = newNode.cloneNode(); cloneAttributes(newNode, oldNode); @@ -767,24 +930,67 @@ return (function () { } } - function cleanUpElement(element) { + // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, + // derived from Java's string hashcode implementation + function stringHash(string, hash) { + var char = 0; + while (char < string.length){ + hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int + } + return hash; + } + + function attributeHash(elt) { + var hash = 0; + // IE fix + if (elt.attributes) { + for (var i = 0; i < elt.attributes.length; i++) { + var attribute = elt.attributes[i]; + if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent) + hash = stringHash(attribute.name, hash); + hash = stringHash(attribute.value, hash); + } + } + } + return hash; + } + + function deInitOnHandlers(elt) { + var internalData = getInternalData(elt); + if (internalData.onHandlers) { + for (var i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i]; + elt.removeEventListener(handlerInfo.event, handlerInfo.listener); + } + delete internalData.onHandlers + } + } + + function deInitNode(element) { var internalData = getInternalData(element); + if (internalData.timeout) { + clearTimeout(internalData.timeout); + } if (internalData.webSocket) { internalData.webSocket.close(); } if (internalData.sseEventSource) { internalData.sseEventSource.close(); } - - triggerEvent(element, "htmx:beforeCleanupElement") - if (internalData.listenerInfos) { - forEach(internalData.listenerInfos, function(info) { - if (element !== info.on) { + forEach(internalData.listenerInfos, function (info) { + if (info.on) { info.on.removeEventListener(info.trigger, info.listener); } }); } + deInitOnHandlers(element); + forEach(Object.keys(internalData), function(key) { delete internalData[key] }); + } + + function cleanUpElement(element) { + triggerEvent(element, "htmx:beforeCleanupElement") + deInitNode(element); if (element.children) { // IE forEach(element.children, function(child) { cleanUpElement(child) }); } @@ -803,8 +1009,7 @@ return (function () { } else { newElt = eltBeforeNewContent.nextSibling; } - getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later - settleInfo.elts = [] // clear existing elements + settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target }); while(newElt && newElt !== target) { if (newElt.nodeType === Node.ELEMENT_NODE) { settleInfo.elts.push(newElt); @@ -849,8 +1054,8 @@ return (function () { } } - function maybeSelectFromResponse(elt, fragment) { - var selector = getClosestAttributeValue(elt, "hx-select"); + function maybeSelectFromResponse(elt, fragment, selectOverride) { + var selector = selectOverride || getClosestAttributeValue(elt, "hx-select"); if (selector) { var newFragment = getDocument().createDocumentFragment(); forEach(fragment.querySelectorAll(selector), function (node) { @@ -915,21 +1120,20 @@ return (function () { function findTitle(content) { if (content.indexOf('<title') > -1) { - var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, ''); - var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im); - + var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, ''); + var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX); if (result) { return result[2]; } } } - function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) { + function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) { settleInfo.title = findTitle(responseText); var fragment = makeFragment(responseText); if (fragment) { - handleOutOfBandSwaps(fragment, settleInfo); - fragment = maybeSelectFromResponse(elt, fragment); + handleOutOfBandSwaps(elt, fragment, settleInfo); + fragment = maybeSelectFromResponse(elt, fragment, selectOverride); handlePreservedElements(fragment); return swap(swapStyle, elt, target, fragment, settleInfo); } @@ -949,7 +1153,10 @@ return (function () { } } } else { - triggerEvent(elt, triggerBody, []); + var eventNames = triggerBody.split(",") + for (var i = 0; i < eventNames.length; i++) { + triggerEvent(elt, eventNames[i].trim(), []); + } } } @@ -959,6 +1166,8 @@ return (function () { var SYMBOL_CONT = /[_$a-zA-Z0-9]/; var STRINGISH_START = ['"', "'", "/"]; var NOT_WHITESPACE = /[^\s]/; + var COMBINED_SELECTOR_START = /[{(]/; + var COMBINED_SELECTOR_END = /[})]/; function tokenizeString(str) { var tokens = []; var position = 0; @@ -1041,101 +1250,137 @@ return (function () { function consumeUntil(tokens, match) { var result = ""; - while (tokens.length > 0 && !tokens[0].match(match)) { + while (tokens.length > 0 && !match.test(tokens[0])) { result += tokens.shift(); } return result; } + function consumeCSSSelector(tokens) { + var result; + if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { + tokens.shift(); + result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim(); + tokens.shift(); + } else { + result = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } + return result; + } + var INPUT_SELECTOR = 'input, textarea, select'; /** * @param {HTMLElement} elt + * @param {string} explicitTrigger + * @param {cache} cache for trigger specs * @returns {import("./htmx").HtmxTriggerSpecification[]} */ - function getTriggerSpecs(elt) { - var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); + function parseAndCacheTrigger(elt, explicitTrigger, cache) { var triggerSpecs = []; - if (explicitTrigger) { - var tokens = tokenizeString(explicitTrigger); - do { - consumeUntil(tokens, NOT_WHITESPACE); - var initialLength = tokens.length; - var trigger = consumeUntil(tokens, /[,\[\s]/); - if (trigger !== "") { - if (trigger === "every") { - var every = {trigger: 'every'}; - consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); - consumeUntil(tokens, NOT_WHITESPACE); - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - every.eventFilter = eventFilter; - } - triggerSpecs.push(every); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); - } else { - var triggerSpec = {trigger: trigger}; - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - triggerSpec.eventFilter = eventFilter; - } - while (tokens.length > 0 && tokens[0] !== ",") { - consumeUntil(tokens, NOT_WHITESPACE) - var token = tokens.shift(); - if (token === "changed") { - triggerSpec.changed = true; - } else if (token === "once") { - triggerSpec.once = true; - } else if (token === "consume") { - triggerSpec.consume = true; - } else if (token === "delay" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "from" && tokens[0] === ":") { - tokens.shift(); + var tokens = tokenizeString(explicitTrigger); + do { + consumeUntil(tokens, NOT_WHITESPACE); + var initialLength = tokens.length; + var trigger = consumeUntil(tokens, /[,\[\s]/); + if (trigger !== "") { + if (trigger === "every") { + var every = {trigger: 'every'}; + consumeUntil(tokens, NOT_WHITESPACE); + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); + consumeUntil(tokens, NOT_WHITESPACE); + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + every.eventFilter = eventFilter; + } + triggerSpecs.push(every); + } else if (trigger.indexOf("sse:") === 0) { + triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); + } else { + var triggerSpec = {trigger: trigger}; + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + triggerSpec.eventFilter = eventFilter; + } + while (tokens.length > 0 && tokens[0] !== ",") { + consumeUntil(tokens, NOT_WHITESPACE) + var token = tokens.shift(); + if (token === "changed") { + triggerSpec.changed = true; + } else if (token === "once") { + triggerSpec.once = true; + } else if (token === "consume") { + triggerSpec.consume = true; + } else if (token === "delay" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); + } else if (token === "from" && tokens[0] === ":") { + tokens.shift(); + if (COMBINED_SELECTOR_START.test(tokens[0])) { + var from_arg = consumeCSSSelector(tokens); + } else { var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); - if (from_arg === "closest" || from_arg === "find") { + if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") { tokens.shift(); - from_arg += - " " + - consumeUntil( - tokens, - WHITESPACE_OR_COMMA - ); + var selector = consumeCSSSelector(tokens); + // `next` and `previous` allow a selector-less syntax + if (selector.length > 0) { + from_arg += " " + selector; + } } - triggerSpec.from = from_arg; - } else if (token === "target" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if (token === "throttle" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "queue" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if ((token === "root" || token === "threshold") && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); } + triggerSpec.from = from_arg; + } else if (token === "target" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.target = consumeCSSSelector(tokens); + } else if (token === "throttle" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); + } else if (token === "queue" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } else if (token === "root" && tokens[0] === ":") { + tokens.shift(); + triggerSpec[token] = consumeCSSSelector(tokens); + } else if (token === "threshold" && tokens[0] === ":") { + tokens.shift(); + triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } else { + triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); } - triggerSpecs.push(triggerSpec); } + triggerSpecs.push(triggerSpec); } - if (tokens.length === initialLength) { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - consumeUntil(tokens, NOT_WHITESPACE); - } while (tokens[0] === "," && tokens.shift()) + } + if (tokens.length === initialLength) { + triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); + } + consumeUntil(tokens, NOT_WHITESPACE); + } while (tokens[0] === "," && tokens.shift()) + if (cache) { + cache[explicitTrigger] = triggerSpecs + } + return triggerSpecs + } + + /** + * @param {HTMLElement} elt + * @returns {import("./htmx").HtmxTriggerSpecification[]} + */ + function getTriggerSpecs(elt) { + var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); + var triggerSpecs = []; + if (explicitTrigger) { + var cache = htmx.config.triggerSpecsCache + triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) } if (triggerSpecs.length > 0) { return triggerSpecs; } else if (matches(elt, 'form')) { return [{trigger: 'submit'}]; + } else if (matches(elt, 'input[type="button"], input[type="submit"]')){ + return [{trigger: 'click'}]; } else if (matches(elt, INPUT_SELECTOR)) { return [{trigger: 'change'}]; } else { @@ -1147,14 +1392,17 @@ return (function () { getInternalData(elt).cancelled = true; } - function processPolling(elt, verb, path, spec) { + function processPolling(elt, handler, spec) { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { - issueAjaxRequest(verb, path, elt); + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { + handler(elt); } - processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), spec); + processPolling(elt, handler, spec); } }, spec.pollInterval); } @@ -1166,23 +1414,27 @@ return (function () { } function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt) && elt.target === "") || elt.tagName === "FORM") { + if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || elt.tagName === "FORM") { nodeData.boosted = true; var verb, path; if (elt.tagName === "A") { verb = "get"; - path = getRawAttribute(elt, 'href'); - nodeData.pushURL = true; + path = getRawAttribute(elt, 'href') } else { var rawAttribute = getRawAttribute(elt, "method"); verb = rawAttribute ? rawAttribute.toLowerCase() : "get"; if (verb === "get") { - nodeData.pushURL = true; } path = getRawAttribute(elt, 'action'); } triggerSpecs.forEach(function(triggerSpec) { - addEventListener(elt, verb, path, nodeData, triggerSpec, true); + addEventListener(elt, function(elt, evt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + issueAjaxRequest(verb, path, elt, evt) + }, nodeData, triggerSpec, true); }); } } @@ -1213,11 +1465,11 @@ return (function () { return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); } - function maybeFilterEvent(triggerSpec, evt) { + function maybeFilterEvent(triggerSpec, elt, evt) { var eventFilter = triggerSpec.eventFilter; if(eventFilter){ try { - return eventFilter(evt) !== true; + return eventFilter.call(elt, evt) !== true; } catch(e) { triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); return true; @@ -1226,13 +1478,21 @@ return (function () { return false; } - function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { + function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { + var elementData = getInternalData(elt); var eltsToListenOn; if (triggerSpec.from) { eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); } else { eltsToListenOn = [elt]; } + // store the initial values of the elements, so we can tell if they change + if (triggerSpec.changed) { + eltsToListenOn.forEach(function (eltToListenOn) { + var eltToListenOnData = getInternalData(eltToListenOn); + eltToListenOnData.lastValue = eltToListenOn.value; + }) + } forEach(eltsToListenOn, function (eltToListenOn) { var eventListener = function (evt) { if (!bodyContains(elt)) { @@ -1245,7 +1505,7 @@ return (function () { if (explicitCancel || shouldCancel(evt, elt)) { evt.preventDefault(); } - if (maybeFilterEvent(triggerSpec, evt)) { + if (maybeFilterEvent(triggerSpec, elt, evt)) { return; } var eventData = getInternalData(evt); @@ -1253,7 +1513,6 @@ return (function () { if (eventData.handledFor == null) { eventData.handledFor = []; } - var elementData = getInternalData(elt); if (eventData.handledFor.indexOf(elt) < 0) { eventData.handledFor.push(elt); if (triggerSpec.consume) { @@ -1272,11 +1531,11 @@ return (function () { } } if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { + var eltToListenOnData = getInternalData(eltToListenOn) + if (eltToListenOnData.lastValue === eltToListenOn.value) { return; - } else { - elementData.lastValue = elt.value; } + eltToListenOnData.lastValue = eltToListenOn.value } if (elementData.delayed) { clearTimeout(elementData.delayed); @@ -1285,19 +1544,18 @@ return (function () { return; } - if (triggerSpec.throttle) { + if (triggerSpec.throttle > 0) { if (!elementData.throttle) { - issueAjaxRequest(verb, path, elt, evt); + handler(elt, evt); elementData.throttle = setTimeout(function () { elementData.throttle = null; }, triggerSpec.throttle); } - } else if (triggerSpec.delay) { - elementData.delayed = setTimeout(function () { - issueAjaxRequest(verb, path, elt, evt); - }, triggerSpec.delay); + } else if (triggerSpec.delay > 0) { + elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); } else { - issueAjaxRequest(verb, path, elt, evt); + triggerEvent(elt, 'htmx:trigger') + handler(elt, evt); } } }; @@ -1310,7 +1568,7 @@ return (function () { on: eltToListenOn }) eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); - }) + }); } var windowIsScrolling = false // used by initScrollHandler @@ -1336,14 +1594,11 @@ return (function () { if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { elt.setAttribute('data-hx-revealed', 'true'); var nodeData = getInternalData(elt); - if (nodeData.initialized) { - issueAjaxRequest(nodeData.verb, nodeData.path, elt); + if (nodeData.initHash) { + triggerEvent(elt, 'revealed'); } else { // if the node isn't initialized, wait for it before triggering the request - elt.addEventListener("htmx:afterProcessNode", - function () { - issueAjaxRequest(nodeData.verb, nodeData.path, elt); - }, {once: true}); + elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true}); } } } @@ -1502,6 +1757,9 @@ return (function () { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function (event) { if (maybeCloseSSESource(sseSourceElt)) { + return; + } + if (!bodyContains(elt)) { sseEventSource.removeEventListener(sseEventName, sseListener); return; } @@ -1518,7 +1776,7 @@ return (function () { var target = getTarget(elt) var settleInfo = makeSettleInfo(elt); - selectAndSwap(swapSpec.swapStyle, elt, target, response, settleInfo) + selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) settleImmediately(settleInfo.tasks) triggerEvent(elt, "htmx:sseMessage", event) }; @@ -1530,14 +1788,14 @@ return (function () { } } - function processSSETrigger(elt, verb, path, sseEventName) { + function processSSETrigger(elt, handler, sseEventName) { var sseSourceElt = getClosestMatch(elt, hasEventSource); if (sseSourceElt) { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function () { if (!maybeCloseSSESource(sseSourceElt)) { if (bodyContains(elt)) { - issueAjaxRequest(verb, path, elt); + handler(elt); } else { sseEventSource.removeEventListener(sseEventName, sseListener); } @@ -1563,14 +1821,14 @@ return (function () { //==================================================================== - function loadImmediately(elt, verb, path, nodeData, delay) { + function loadImmediately(elt, handler, nodeData, delay) { var load = function(){ if (!nodeData.loaded) { nodeData.loaded = true; - issueAjaxRequest(verb, path, elt); + handler(elt); } } - if (delay) { + if (delay > 0) { setTimeout(load, delay); } else { load(); @@ -1586,46 +1844,59 @@ return (function () { nodeData.path = path; nodeData.verb = verb; triggerSpecs.forEach(function(triggerSpec) { - if (triggerSpec.sseEvent) { - processSSETrigger(elt, verb, path, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - maybeReveal(elt); - } else if (triggerSpec.trigger === "intersect") { - var observerOptions = {}; - if (triggerSpec.root) { - observerOptions.root = querySelectorExt(elt, triggerSpec.root) - } - if (triggerSpec.threshold) { - observerOptions.threshold = parseFloat(triggerSpec.threshold); + addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return } - var observer = new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - if (entry.isIntersecting) { - triggerEvent(elt, "intersect"); - break; - } - } - }, observerOptions); - observer.observe(elt); - addEventListener(elt, verb, path, nodeData, triggerSpec); - } else if (triggerSpec.trigger === "load") { - loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); - } else if (triggerSpec.pollInterval) { - nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec); - } else { - addEventListener(elt, verb, path, nodeData, triggerSpec); - } + issueAjaxRequest(verb, path, elt, evt) + }) }); } }); return explicitAction; } + function addTriggerHandler(elt, triggerSpec, nodeData, handler) { + if (triggerSpec.sseEvent) { + processSSETrigger(elt, handler, triggerSpec.sseEvent); + } else if (triggerSpec.trigger === "revealed") { + initScrollHandler(); + addEventListener(elt, handler, nodeData, triggerSpec); + maybeReveal(elt); + } else if (triggerSpec.trigger === "intersect") { + var observerOptions = {}; + if (triggerSpec.root) { + observerOptions.root = querySelectorExt(elt, triggerSpec.root) + } + if (triggerSpec.threshold) { + observerOptions.threshold = parseFloat(triggerSpec.threshold); + } + var observer = new IntersectionObserver(function (entries) { + for (var i = 0; i < entries.length; i++) { + var entry = entries[i]; + if (entry.isIntersecting) { + triggerEvent(elt, "intersect"); + break; + } + } + }, observerOptions); + observer.observe(elt); + addEventListener(elt, handler, nodeData, triggerSpec); + } else if (triggerSpec.trigger === "load") { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { + loadImmediately(elt, handler, nodeData, triggerSpec.delay); + } + } else if (triggerSpec.pollInterval > 0) { + nodeData.polling = true; + processPolling(elt, handler, triggerSpec); + } else { + addEventListener(elt, handler, nodeData, triggerSpec); + } + } + function evalScript(script) { - if (script.type === "text/javascript" || script.type === "module" || script.type === "") { + if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) { var newScript = getDocument().createElement("script"); forEach(script.attributes, function (attr) { newScript.setAttribute(attr.name, attr.value); @@ -1642,7 +1913,10 @@ return (function () { } catch (e) { logError(e); } finally { - parent.removeChild(script); + // remove old script element, but only if it is still in DOM + if (script.parentElement) { + script.parentElement.removeChild(script); + } } } } @@ -1656,48 +1930,187 @@ return (function () { }); } - function hasChanceOfBeingBoosted() { - return document.querySelector("[hx-boost], [data-hx-boost]"); + function shouldProcessHxOn(elt) { + var attributes = elt.attributes + for (var j = 0; j < attributes.length; j++) { + var attrName = attributes[j].name + if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") || + startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) { + return true + } + } + return false + } + + function findHxOnWildcardElements(elt) { + var node = null + var elements = [] + + if (shouldProcessHxOn(elt)) { + elements.push(elt) + } + + if (document.evaluate) { + var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + + ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt) + while (node = iter.iterateNext()) elements.push(node) + } else { + var allElements = elt.getElementsByTagName("*") + for (var i = 0; i < allElements.length; i++) { + if (shouldProcessHxOn(allElements[i])) { + elements.push(allElements[i]) + } + } + } + + return elements } function findElementsToProcess(elt) { if (elt.querySelectorAll) { - var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; - var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [hx-data-ext]"); + var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; + var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," + + " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]"); return results; } else { return []; } } - function initButtonTracking(form){ - var maybeSetLastButtonClicked = function(evt){ - if (matches(evt.target, "button, input[type='submit']")) { - var internalData = getInternalData(form); - internalData.lastButtonClicked = evt.target; - } - }; - + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + function maybeSetLastButtonClicked(evt) { + var elt = closest(evt.target, "button, input[type='submit']"); + var internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = elt; + } + }; + function maybeUnsetLastButtonClicked(evt){ + var internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = null; + } + } + function getRelatedFormData(evt) { + var elt = closest(evt.target, "button, input[type='submit']"); + if (!elt) { + return; + } + var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form'); + if (!form) { + return; + } + return getInternalData(form); + } + function initButtonTracking(elt) { // need to handle both click and focus in: // focusin - in case someone tabs in to a button and hits the space bar // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + elt.addEventListener('click', maybeSetLastButtonClicked) + elt.addEventListener('focusin', maybeSetLastButtonClicked) + elt.addEventListener('focusout', maybeUnsetLastButtonClicked) + } - form.addEventListener('click', maybeSetLastButtonClicked) - form.addEventListener('focusin', maybeSetLastButtonClicked) - form.addEventListener('focusout', function(evt){ - var internalData = getInternalData(form); - internalData.lastButtonClicked = null; - }) + function countCurlies(line) { + var tokens = tokenizeString(line); + var netCurlies = 0; + for (var i = 0; i < tokens.length; i++) { + const token = tokens[i]; + if (token === "{") { + netCurlies++; + } else if (token === "}") { + netCurlies--; + } + } + return netCurlies; + } + + function addHxOnEventHandler(elt, eventName, code) { + var nodeData = getInternalData(elt); + if (!Array.isArray(nodeData.onHandlers)) { + nodeData.onHandlers = []; + } + var func; + var listener = function (e) { + return maybeEval(elt, function() { + if (!func) { + func = new Function("event", code); + } + func.call(elt, e); + }); + }; + elt.addEventListener(eventName, listener); + nodeData.onHandlers.push({event:eventName, listener:listener}); + } + + function processHxOn(elt) { + var hxOnValue = getAttributeValue(elt, 'hx-on'); + if (hxOnValue) { + var handlers = {} + var lines = hxOnValue.split("\n"); + var currentEvent = null; + var curlyCount = 0; + while (lines.length > 0) { + var line = lines.shift(); + var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/); + if (curlyCount === 0 && match) { + line.split(":") + currentEvent = match[1].slice(0, -1); // strip last colon + handlers[currentEvent] = match[2]; + } else { + handlers[currentEvent] += line; + } + curlyCount += countCurlies(line); + } + + for (var eventName in handlers) { + addHxOnEventHandler(elt, eventName, handlers[eventName]); + } + } + } + + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (var i = 0; i < elt.attributes.length; i++) { + var name = elt.attributes[i].name + var value = elt.attributes[i].value + if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) { + var afterOnPosition = name.indexOf("-on") + 3; + var nextChar = name.slice(afterOnPosition, afterOnPosition + 1); + if (nextChar === "-" || nextChar === ":") { + var eventName = name.slice(afterOnPosition + 1); + // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support + if (startsWith(eventName, ":")) { + eventName = "htmx" + eventName + } else if (startsWith(eventName, "-")) { + eventName = "htmx:" + eventName.slice(1); + } else if (startsWith(eventName, "htmx-")) { + eventName = "htmx:" + eventName.slice(5); + } + + addHxOnEventHandler(elt, eventName, value) + } + } + } } function initNode(elt) { - if (elt.closest && elt.closest(htmx.config.disableSelector)) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) return; } var nodeData = getInternalData(elt); - if (!nodeData.initialized) { - nodeData.initialized = true; + if (nodeData.initHash !== attributeHash(elt)) { + // clean up any previously processed info + deInitNode(elt); + + nodeData.initHash = attributeHash(elt); + + processHxOn(elt); + triggerEvent(elt, "htmx:beforeProcessNode") if (elt.value) { @@ -1705,14 +2118,24 @@ return (function () { } var triggerSpecs = getTriggerSpecs(elt); - var explicitAction = processVerbs(elt, nodeData, triggerSpecs); - - if (!explicitAction && getClosestAttributeValue(elt, "hx-boost") === "true") { - boostElement(elt, nodeData, triggerSpecs); + var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs); + + if (!hasExplicitHttpAction) { + if (getClosestAttributeValue(elt, "hx-boost") === "true") { + boostElement(elt, nodeData, triggerSpecs); + } else if (hasAttribute(elt, 'hx-trigger')) { + triggerSpecs.forEach(function (triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function () { + }) + }) + } } - if (elt.tagName === "FORM") { - initButtonTracking(elt); + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) { + initButtonTracking(elt) } var sseInfo = getAttributeValue(elt, 'hx-sse'); @@ -1730,8 +2153,15 @@ return (function () { function processNode(elt) { elt = resolveTarget(elt); + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return; + } initNode(elt); forEach(findElementsToProcess(elt), function(child) { initNode(child) }); + // Because it happens second, the new way of adding onHandlers superseeds the old one + // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored + forEach(findHxOnWildcardElements(elt), processHxOnWildcard); } //==================================================================== @@ -1809,7 +2239,7 @@ return (function () { eventResult = eventResult && elt.dispatchEvent(kebabedEvent) } withExtensions(elt, function (extension) { - eventResult = eventResult && (extension.onEvent(eventName, event) !== false) + eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) }); return eventResult; } @@ -1825,6 +2255,18 @@ return (function () { } function saveToHistoryCache(url, content, title, scroll) { + if (!canAccessLocalStorage()) { + return; + } + + if (htmx.config.historyCacheSize <= 0) { + // make sure that an eventually already existing cache is purged + localStorage.removeItem("htmx-history-cache"); + return; + } + + url = normalizePath(url); + var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { @@ -1832,7 +2274,9 @@ return (function () { break; } } - historyCache.push({url:url, content: content, title:title, scroll:scroll}) + var newHistoryItem = {url:url, content: content, title:title, scroll:scroll}; + triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache}) + historyCache.push(newHistoryItem) while (historyCache.length > htmx.config.historyCacheSize) { historyCache.shift(); } @@ -1848,6 +2292,12 @@ return (function () { } function getCachedHistory(url) { + if (!canAccessLocalStorage()) { + return null; + } + + url = normalizePath(url); + var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { @@ -1869,13 +2319,43 @@ return (function () { function saveCurrentPageToHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; - triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); - if(htmx.config.historyEnabled) history.replaceState({htmx:true}, getDocument().title, window.location.href); - saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); + + // Allow history snapshot feature to be disabled where hx-history="false" + // is present *anywhere* in the current document we're about to save, + // so we can prevent privileged data entering the cache. + // The page will still be reachable as a history entry, but htmx will fetch it + // live from the server onpopstate rather than look in the localStorage cache + var disableHistoryCache + try { + disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') + } catch (e) { + // IE11: insensitive modifier not supported so fallback to case sensitive selector + disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') + } + if (!disableHistoryCache) { + triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt}); + saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); + } + + if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href); } function pushUrlIntoHistory(path) { - if(htmx.config.historyEnabled) history.pushState({htmx:true}, "", path); + // remove the cache buster parameter, if any + if (htmx.config.getCacheBusterParam) { + path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') + if (endsWith(path, '&') || endsWith(path, "?")) { + path = path.slice(0, -1); + } + } + if(htmx.config.historyEnabled) { + history.pushState({htmx:true}, "", path); + } + currentPathForHistory = path; + } + + function replaceUrlInHistory(path) { + if(htmx.config.historyEnabled) history.replaceState({htmx:true}, "", path); currentPathForHistory = path; } @@ -1890,7 +2370,9 @@ return (function () { var details = {path: path, xhr:request}; triggerEvent(getDocument().body, "htmx:historyCacheMiss", details); request.open('GET', path, true); + request.setRequestHeader("HX-Request", "true"); request.setRequestHeader("HX-History-Restore-Request", "true"); + request.setRequestHeader("HX-Current-URL", getDocument().location.href); request.onload = function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); @@ -1899,11 +2381,20 @@ return (function () { fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; var historyElement = getHistoryElement(); var settleInfo = makeSettleInfo(historyElement); + var title = findTitle(this.response); + if (title) { + var titleElt = find("title"); + if (titleElt) { + titleElt.innerHTML = title; + } else { + window.document.title = title; + } + } // @ts-ignore swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); + triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response}); } else { triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details); } @@ -1922,9 +2413,11 @@ return (function () { swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); document.title = cached.title; - window.scrollTo(0, cached.scroll); + setTimeout(function () { + window.scrollTo(0, cached.scroll); + }, 0); // next 'tick', so browser has time to render layout currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); + triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); } else { if (htmx.config.refreshOnHistoryMiss) { @@ -1936,31 +2429,46 @@ return (function () { } } - function shouldPush(elt) { - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - return (pushUrl && pushUrl !== "false") || - (getInternalData(elt).boosted && getInternalData(elt).pushURL); - } - - function getPushUrl(elt) { - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - return (pushUrl === "true" || pushUrl === "false") ? null : pushUrl; - } - function addRequestIndicatorClasses(elt) { var indicators = findAttributeTargets(elt, 'hx-indicator'); if (indicators == null) { indicators = [elt]; } forEach(indicators, function (ic) { + var internalData = getInternalData(ic); + internalData.requestCount = (internalData.requestCount || 0) + 1; ic.classList["add"].call(ic.classList, htmx.config.requestClass); }); return indicators; } - function removeRequestIndicatorClasses(indicators) { + function disableElements(elt) { + var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt'); + if (disabledElts == null) { + disabledElts = []; + } + forEach(disabledElts, function (disabledElement) { + var internalData = getInternalData(disabledElement); + internalData.requestCount = (internalData.requestCount || 0) + 1; + disabledElement.setAttribute("disabled", ""); + }); + return disabledElts; + } + + function removeRequestIndicators(indicators, disabled) { forEach(indicators, function (ic) { - ic.classList["remove"].call(ic.classList, htmx.config.requestClass); + var internalData = getInternalData(ic); + internalData.requestCount = (internalData.requestCount || 0) - 1; + if (internalData.requestCount === 0) { + ic.classList["remove"].call(ic.classList, htmx.config.requestClass); + } + }); + forEach(disabled, function (disabledElement) { + var internalData = getInternalData(disabledElement); + internalData.requestCount = (internalData.requestCount || 0) - 1; + if (internalData.requestCount === 0) { + disabledElement.removeAttribute('disabled'); + } }); } @@ -1979,7 +2487,7 @@ return (function () { } function shouldInclude(elt) { - if(elt.name === "" || elt.name == null || elt.disabled) { + if(elt.name === "" || elt.name == null || elt.disabled || closest(elt, "fieldset[disabled]")) { return false; } // ignore "submitter" types (see jQuery src/serialize.js) @@ -1992,6 +2500,29 @@ return (function () { return true; } + function addValueToValues(name, value, values) { + // This is a little ugly because both the current value of the named value in the form + // and the new value could be arrays, so we have to handle all four cases :/ + if (name != null && value != null) { + var current = values[name]; + if (current === undefined) { + values[name] = value; + } else if (Array.isArray(current)) { + if (Array.isArray(value)) { + values[name] = current.concat(value); + } else { + current.push(value); + } + } else { + if (Array.isArray(value)) { + values[name] = [current].concat(value); + } else { + values[name] = [current, value]; + } + } + } + } + function processInputValue(processed, values, errors, elt, validate) { if (elt == null || haveSeenNode(processed, elt)) { return; @@ -2001,35 +2532,14 @@ return (function () { if (shouldInclude(elt)) { var name = getRawAttribute(elt,"name"); var value = elt.value; - if (elt.multiple) { + if (elt.multiple && elt.tagName === "SELECT") { value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value }); } // include file inputs if (elt.files) { value = toArray(elt.files); } - // This is a little ugly because both the current value of the named value in the form - // and the new value could be arrays, so we have to handle all four cases :/ - if (name != null && value != null) { - var current = values[name]; - if(current) { - if (Array.isArray(current)) { - if (Array.isArray(value)) { - values[name] = current.concat(value); - } else { - current.push(value); - } - } else { - if (Array.isArray(value)) { - values[name] = [current].concat(value); - } else { - values[name] = [current, value]; - } - } - } else { - values[name] = value; - } - } + addValueToValues(name, value, values); if (validate) { validateElement(elt, errors); } @@ -2062,9 +2572,13 @@ return (function () { var formValues = {}; var errors = []; var internalData = getInternalData(elt); + if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { + internalData.lastButtonClicked = null + } // only validate when form is directly submitted and novalidate or formnovalidate are not set - var validate = matches(elt, 'form') && elt.noValidate !== true; + // or if the element has an explicit hx-validate="true" on it + var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true"; if (internalData.lastButtonClicked) { validate = validate && internalData.lastButtonClicked.formNoValidate !== true; } @@ -2078,11 +2592,11 @@ return (function () { processInputValue(processed, values, errors, elt, validate); // if a button or submit was clicked last, include its value - if (internalData.lastButtonClicked) { - var name = getRawAttribute(internalData.lastButtonClicked,"name"); - if (name) { - values[name] = internalData.lastButtonClicked.value; - } + if (internalData.lastButtonClicked || elt.tagName === "BUTTON" || + (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) { + var button = internalData.lastButtonClicked || elt + var name = getRawAttribute(button, "name") + addValueToValues(name, button.value, formValues) } // include any explicit includes @@ -2228,40 +2742,43 @@ return (function () { "swapDelay" : htmx.config.defaultSwapDelay, "settleDelay" : htmx.config.defaultSettleDelay } - if (getInternalData(elt).boosted && !isAnchorLink(elt)) { + if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { swapSpec["show"] = "top" } 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)); - } - if (modifier.indexOf("scroll:") === 0) { - var scrollSpec = modifier.substr(7); + for (var i = 0; i < split.length; i++) { + var value = split[i]; + if (value.indexOf("swap:") === 0) { + swapSpec["swapDelay"] = parseInterval(value.substr(5)); + } else if (value.indexOf("settle:") === 0) { + swapSpec["settleDelay"] = parseInterval(value.substr(7)); + } else if (value.indexOf("transition:") === 0) { + swapSpec["transition"] = value.substr(11) === "true"; + } else if (value.indexOf("ignoreTitle:") === 0) { + swapSpec["ignoreTitle"] = value.substr(12) === "true"; + } else if (value.indexOf("scroll:") === 0) { + var scrollSpec = value.substr(7); var splitSpec = scrollSpec.split(":"); var scrollVal = splitSpec.pop(); var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; swapSpec["scroll"] = scrollVal; swapSpec["scrollTarget"] = selectorVal; - } - if (modifier.indexOf("show:") === 0) { - var showSpec = modifier.substr(5); + } else if (value.indexOf("show:") === 0) { + var showSpec = value.substr(5); var splitSpec = showSpec.split(":"); var showVal = splitSpec.pop(); var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; swapSpec["show"] = showVal; swapSpec["showTarget"] = selectorVal; - } - if (modifier.indexOf("focus-scroll:") === 0) { - var focusScrollVal = modifier.substr("focus-scroll:".length); + } else if (value.indexOf("focus-scroll:") === 0) { + var focusScrollVal = value.substr("focus-scroll:".length); swapSpec["focusScroll"] = focusScrollVal == "true"; + } else if (i == 0) { + swapSpec["swapStyle"] = value; + } else { + logError('Unknown modifier in hx-swap: ' + value); } } } @@ -2269,6 +2786,11 @@ return (function () { return swapSpec; } + function usesFormData(elt) { + return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || + (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data"); + } + function encodeParamsForBody(xhr, elt, filteredParameters) { var encodedParameters = null; withExtensions(elt, function (extension) { @@ -2279,8 +2801,7 @@ return (function () { if (encodedParameters != null) { return encodedParameters; } else { - if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || - (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) { + if (usesFormData(elt)) { return makeFormData(filteredParameters); } else { return urlEncode(filteredParameters); @@ -2352,6 +2873,9 @@ return (function () { if (attributeValue) { var str = attributeValue.trim(); var evaluateValue = evalAsDefault; + if (str === "unset") { + return null; + } if (str.indexOf("javascript:") === 0) { str = str.substr(11); evaluateValue = true; @@ -2426,7 +2950,7 @@ return (function () { } } - function getResponseURL(xhr) { + function getPathFromResponse(xhr) { // NB: IE11 does not support this stuff if (xhr.responseURL && typeof(URL) !== "undefined") { try { @@ -2439,7 +2963,7 @@ return (function () { } function hasHeader(xhr, regexp) { - return xhr.getAllResponseHeaders().match(regexp); + return regexp.test(xhr.getAllResponseHeaders()) } function ajaxHelper(verb, path, context) { @@ -2458,6 +2982,7 @@ return (function () { values : context.values, targetOverride: resolveTarget(context.target), swapOverride: context.swap, + select: context.select, returnPromise: true }); } @@ -2477,7 +3002,28 @@ return (function () { return arr; } - function issueAjaxRequest(verb, path, elt, event, etc) { + function verifyPath(elt, path, requestConfig) { + var sameHost + var url + if (typeof URL === "function") { + url = new URL(path, document.location.href); + var origin = document.location.origin; + sameHost = origin === url.origin; + } else { + // IE11 doesn't support URL + url = path + sameHost = startsWith(path, document.location.origin) + } + + if (htmx.config.selfRequestsOnly) { + if (!sameHost) { + return false; + } + } + return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig)); + } + + function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { var resolve = null; var reject = null; etc = etc != null ? etc : {}; @@ -2491,18 +3037,52 @@ return (function () { elt = getDocument().body; } var responseHandler = etc.handler || handleAjaxResponse; + var select = etc.select || null; if (!bodyContains(elt)) { - return; // do not issue requests for elements removed from the DOM + // do not issue requests for elements removed from the DOM + maybeCall(resolve); + return promise; } var target = etc.targetOverride || getTarget(elt); if (target == null || target == DUMMY_ELT) { triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); - return; + maybeCall(reject); + return promise; } - var syncElt = elt; var eltData = getInternalData(elt); + var submitter = eltData.lastButtonClicked; + + if (submitter) { + var buttonPath = getRawAttribute(submitter, "formaction"); + if (buttonPath != null) { + path = buttonPath; + } + + var buttonVerb = getRawAttribute(submitter, "formmethod") + if (buttonVerb != null) { + // ignore buttons with formmethod="dialog" + if (buttonVerb.toLowerCase() !== "dialog") { + verb = buttonVerb; + } + } + } + + var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); + // allow event-based confirmation w/ a callback + if (confirmed === undefined) { + var issueRequest = function(skipConfirmation) { + return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation); + } + var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion}; + if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { + maybeCall(resolve); + return promise; + } + } + + var syncElt = elt; var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); var queueStrategy = null; var abortable = false; @@ -2518,10 +3098,12 @@ return (function () { syncStrategy = (syncStrings[1] || 'drop').trim(); eltData = getInternalData(syncElt); if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { - return; + maybeCall(resolve); + return promise; } else if (syncStrategy === "abort") { if (eltData.xhr) { - return; + maybeCall(resolve); + return promise; } else { abortable = true; } @@ -2565,7 +3147,8 @@ return (function () { issueAjaxRequest(verb, path, elt, event, etc) }); } - return; + maybeCall(resolve); + return promise; } } @@ -2593,8 +3176,7 @@ return (function () { } } - var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); - if (confirmQuestion) { + if (confirmQuestion && !confirmed) { if(!confirm(confirmQuestion)) { maybeCall(resolve); endRequestLock() @@ -2604,6 +3186,11 @@ return (function () { var headers = getHeaders(elt, target, promptResponse); + + if (verb !== 'get' && !usesFormData(elt)) { + headers['Content-Type'] = 'application/x-www-form-urlencoded'; + } + if (etc.headers) { headers = mergeObjects(headers, etc.headers); } @@ -2617,8 +3204,8 @@ return (function () { var allParameters = mergeObjects(rawParameters, expressionVars); var filteredParameters = filterValues(allParameters, elt); - if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null) { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; + if (htmx.config.getCacheBusterParam && verb === 'get') { + filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true"; } // behavior of anchors w/ empty href is to use the current URL @@ -2626,9 +3213,16 @@ return (function () { path = getDocument().location.href; } + var requestAttrValues = getValuesForElement(elt, 'hx-request'); + var eltIsBoosted = getInternalData(elt).boosted; + + var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + var requestConfig = { + boosted: eltIsBoosted, + useUrlParams: useUrlParams, parameters: filteredParameters, unfilteredParameters: allParameters, headers:headers, @@ -2653,6 +3247,7 @@ return (function () { headers = requestConfig.headers; filteredParameters = requestConfig.parameters; errors = requestConfig.errors; + useUrlParams = requestConfig.useUrlParams; if(errors && errors.length > 0){ triggerEvent(elt, 'htmx:validation:halted', requestConfig) @@ -2664,25 +3259,31 @@ return (function () { var splitPath = path.split("#"); var pathNoAnchor = splitPath[0]; var anchor = splitPath[1]; - if (verb === 'get') { - var finalPathForGet = pathNoAnchor; + + var finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor; var values = Object.keys(filteredParameters).length !== 0; if (values) { - if (finalPathForGet.indexOf("?") < 0) { - finalPathForGet += "?"; + if (finalPath.indexOf("?") < 0) { + finalPath += "?"; } else { - finalPathForGet += "&"; + finalPath += "&"; } - finalPathForGet += urlEncode(filteredParameters); + finalPath += urlEncode(filteredParameters); if (anchor) { - finalPathForGet += "#" + anchor; + finalPath += "#" + anchor; } } - xhr.open('GET', finalPathForGet, true); - } else { - xhr.open(verb.toUpperCase(), path, true); } + if (!verifyPath(elt, finalPath, requestConfig)) { + triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) + maybeCall(reject); + return promise; + }; + + xhr.open(verb.toUpperCase(), finalPath, true); xhr.overrideMimeType("text/html"); xhr.withCredentials = requestConfig.withCredentials; xhr.timeout = requestConfig.timeout; @@ -2699,19 +3300,24 @@ return (function () { } } - var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, etc:etc, pathInfo:{ - path:path, finalPath:finalPathForGet, anchor:anchor + var responseInfo = { + xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select, + pathInfo: { + requestPath: path, + finalRequestPath: finalPath, + anchor: anchor } }; xhr.onload = function () { try { var hierarchy = hierarchyForElt(elt); + responseInfo.pathInfo.responsePath = getPathFromResponse(xhr); responseHandler(elt, responseInfo); - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerEvent(elt, 'htmx:afterRequest', responseInfo); triggerEvent(elt, 'htmx:afterOnLoad', responseInfo); - // if the body no longer contains the element, trigger the even on the closest parent + // if the body no longer contains the element, trigger the event on the closest parent // remaining in the DOM if (!bodyContains(elt)) { var secondaryTriggerElt = null; @@ -2734,21 +3340,21 @@ return (function () { } } xhr.onerror = function () { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:sendError', responseInfo); maybeCall(reject); endRequestLock(); } xhr.onabort = function() { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo); maybeCall(reject); endRequestLock(); } xhr.ontimeout = function() { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:timeout', responseInfo); maybeCall(reject); @@ -2760,6 +3366,7 @@ return (function () { return promise } var indicators = addRequestIndicatorClasses(elt); + var disableElts = disableElements(elt); forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { forEach([xhr, xhr.upload], function (target) { @@ -2773,14 +3380,99 @@ return (function () { }); }); triggerEvent(elt, 'htmx:beforeSend', responseInfo); - xhr.send(verb === 'get' ? null : encodeParamsForBody(xhr, elt, filteredParameters)); + var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) + xhr.send(params); return promise; } + function determineHistoryUpdates(elt, responseInfo) { + + var xhr = responseInfo.xhr; + + //=========================================== + // First consult response headers + //=========================================== + var pathFromHeaders = null; + var typeFromHeaders = null; + if (hasHeader(xhr,/HX-Push:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Push"); + typeFromHeaders = "push"; + } else if (hasHeader(xhr,/HX-Push-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Push-Url"); + typeFromHeaders = "push"; + } else if (hasHeader(xhr,/HX-Replace-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url"); + typeFromHeaders = "replace"; + } + + // if there was a response header, that has priority + if (pathFromHeaders) { + if (pathFromHeaders === "false") { + return {} + } else { + return { + type: typeFromHeaders, + path : pathFromHeaders + } + } + } + + //=========================================== + // Next resolve via DOM values + //=========================================== + var requestPath = responseInfo.pathInfo.finalRequestPath; + var responsePath = responseInfo.pathInfo.responsePath; + + var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); + var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url"); + var elementIsBoosted = getInternalData(elt).boosted; + + var saveType = null; + var path = null; + + if (pushUrl) { + saveType = "push"; + path = pushUrl; + } else if (replaceUrl) { + saveType = "replace"; + path = replaceUrl; + } else if (elementIsBoosted) { + saveType = "push"; + path = responsePath || requestPath; // if there is no response path, go with the original request path + } + + if (path) { + // false indicates no push, return empty object + if (path === "false") { + return {}; + } + + // true indicates we want to follow wherever the server ended up sending us + if (path === "true") { + path = responsePath || requestPath; // if there is no response path, go with the original request path + } + + // restore any anchor associated with the request + if (responseInfo.pathInfo.anchor && + path.indexOf("#") === -1) { + path = path + "#" + responseInfo.pathInfo.anchor; + } + + return { + type:saveType, + path: path + } + } else { + return {}; + } + } + function handleAjaxResponse(elt, responseInfo) { var xhr = responseInfo.xhr; var target = responseInfo.target; var etc = responseInfo.etc; + var requestConfig = responseInfo.requestConfig; + var select = responseInfo.select; if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; @@ -2788,33 +3480,44 @@ return (function () { handleTrigger(xhr, "HX-Trigger", elt); } - if (hasHeader(xhr,/HX-Push:/i)) { - var pushedUrl = xhr.getResponseHeader("HX-Push"); + if (hasHeader(xhr, /HX-Location:/i)) { + saveCurrentPageToHistory(); + var redirectPath = xhr.getResponseHeader("HX-Location"); + var swapSpec; + if (redirectPath.indexOf("{") === 0) { + swapSpec = parseJSON(redirectPath); + // what's the best way to throw an error if the user didn't include this + redirectPath = swapSpec['path']; + delete swapSpec['path']; + } + ajaxHelper('GET', redirectPath, swapSpec).then(function(){ + pushUrlIntoHistory(redirectPath); + }); + return; } + var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh"); + if (hasHeader(xhr, /HX-Redirect:/i)) { - window.location.href = xhr.getResponseHeader("HX-Redirect"); + location.href = xhr.getResponseHeader("HX-Redirect"); + shouldRefresh && location.reload(); return; } - if (hasHeader(xhr,/HX-Refresh:/i)) { - if ("true" === xhr.getResponseHeader("HX-Refresh")) { - location.reload(); - return; - } + if (shouldRefresh) { + location.reload(); + return; } if (hasHeader(xhr,/HX-Retarget:/i)) { - responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget")); + if (xhr.getResponseHeader("HX-Retarget") === "this") { + responseInfo.target = elt; + } else { + responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget")); + } } - /** @type {boolean} */ - var shouldSaveHistory - if (pushedUrl == "false") { - shouldSaveHistory = false - } else { - shouldSaveHistory = shouldPush(elt) || pushedUrl; - } + var historyUpdate = determineHistoryUpdates(elt, responseInfo); // by default htmx only swaps on 200 return codes and does not swap // on 204 'No Content' @@ -2823,15 +3526,18 @@ return (function () { var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; var serverResponse = xhr.response; var isError = xhr.status >= 400; - var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo); + var ignoreTitle = htmx.config.ignoreTitle + var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo); if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; target = beforeSwapDetails.target; // allow re-targeting serverResponse = beforeSwapDetails.serverResponse; // allow updating content isError = beforeSwapDetails.isError; // allow updating error - + ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title + + responseInfo.target = target; // Make updated target available to response events responseInfo.failed = isError; // Make failed property available to response events - responseInfo.successful = !isError; // Make successful property available to response events + responseInfo.successful = !isError; // Make successful property available to response events if (beforeSwapDetails.shouldSwap) { if (xhr.status === 286) { @@ -2842,18 +3548,29 @@ return (function () { serverResponse = extension.transformResponse(serverResponse, xhr, elt); }); - // Save current page - if (shouldSaveHistory) { + // Save current page if there will be a history update + if (historyUpdate.type) { saveCurrentPageToHistory(); } var swapOverride = etc.swapOverride; + if (hasHeader(xhr,/HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader("HX-Reswap"); + } var swapSpec = getSwapSpecification(elt, swapOverride); + if (swapSpec.hasOwnProperty('ignoreTitle')) { + ignoreTitle = swapSpec.ignoreTitle; + } + target.classList.add(htmx.config.swappingClass); + + // optional transition API promise callbacks + var settleResolve = null; + var settleReject = null; + var doSwap = function () { try { - var activeElt = document.activeElement; var selectionInfo = {}; try { @@ -2868,19 +3585,44 @@ return (function () { // safari issue - see https://github.com/microsoft/playwright/issues/5894 } + var selectOverride; + if (select) { + selectOverride = select; + } + + if (hasHeader(xhr, /HX-Reselect:/i)) { + selectOverride = xhr.getResponseHeader("HX-Reselect"); + } + + // if we need to save history, do so, before swapping so that relative resources have the correct base URL + if (historyUpdate.type) { + triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)); + if (historyUpdate.type === "push") { + pushUrlIntoHistory(historyUpdate.path); + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path}); + } else { + replaceUrlInHistory(historyUpdate.path); + triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path}); + } + } + var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride); if (selectionInfo.elt && !bodyContains(selectionInfo.elt) && - selectionInfo.elt.id) { - var newActiveElt = document.getElementById(selectionInfo.elt.id); + getRawAttribute(selectionInfo.elt, "id")) { + var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id")); var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; if (newActiveElt) { // @ts-ignore if (selectionInfo.start && newActiveElt.setSelectionRange) { // @ts-ignore - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + try { + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + } catch (e) { + // the setSelectionRange method is present on fields that don't support it, so just let this fail + } } newActiveElt.focus(focusOptions); } @@ -2893,9 +3635,6 @@ return (function () { } triggerEvent(elt, 'htmx:afterSwap', responseInfo); }); - if (responseInfo.pathInfo.anchor) { - location.hash = responseInfo.pathInfo.anchor; - } if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { var finalElt = elt; @@ -2915,14 +3654,15 @@ return (function () { } triggerEvent(elt, 'htmx:afterSettle', responseInfo); }); - // push URL and save new page - if (shouldSaveHistory) { - var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; - pushUrlIntoHistory(pathToPush); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: pathToPush}); + + if (responseInfo.pathInfo.anchor) { + var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor); + if(anchorTarget) { + anchorTarget.scrollIntoView({block:'start', behavior: "auto"}); + } } - if(settleInfo.title) { + if(settleInfo.title && !ignoreTitle) { var titleElt = find("title"); if(titleElt) { titleElt.innerHTML = settleInfo.title; @@ -2940,6 +3680,7 @@ return (function () { } handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); } + maybeCall(settleResolve); } if (swapSpec.settleDelay > 0) { @@ -2949,10 +3690,34 @@ return (function () { } } catch (e) { triggerErrorEvent(elt, 'htmx:swapError', responseInfo); + maybeCall(settleReject); throw e; } }; + var shouldTransition = htmx.config.globalViewTransitions + if(swapSpec.hasOwnProperty('transition')){ + shouldTransition = swapSpec.transition; + } + + if(shouldTransition && + triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && + typeof Promise !== "undefined" && document.startViewTransition){ + var settlePromise = new Promise(function (_resolve, _reject) { + settleResolve = _resolve; + settleReject = _reject; + }); + // wrap the original doSwap() in a call to startViewTransition() + var innerDoSwap = doSwap; + doSwap = function() { + document.startViewTransition(function () { + innerDoSwap(); + return settlePromise; + }); + } + } + + if (swapSpec.swapDelay > 0) { setTimeout(doSwap, swapSpec.swapDelay) } else { @@ -2960,7 +3725,7 @@ return (function () { } } if (isError) { - triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.path}, responseInfo)); + triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo)); } } @@ -3048,9 +3813,22 @@ return (function () { //==================================================================== // Initialization //==================================================================== + var isReady = false + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true + }) + /** + * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. + * + * This function uses isReady because there is no realiable way to ask the browswer whether + * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded + * firing and readystate=complete. + */ function ready(fn) { - if (getDocument().readyState !== 'loading') { + // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by + // some means other than the initial page load. + if (isReady || getDocument().readyState === 'complete') { fn(); } else { getDocument().addEventListener('DOMContentLoaded', fn); @@ -3061,9 +3839,9 @@ return (function () { if (htmx.config.includeIndicatorStyles !== false) { getDocument().head.insertAdjacentHTML("beforeend", "<style>\ - ." + htmx.config.indicatorClass + "{opacity:0;transition: opacity 200ms ease-in;}\ - ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1}\ - ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1}\ + ." + htmx.config.indicatorClass + "{opacity:0}\ + ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ + ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ </style>"); } } @@ -3101,6 +3879,9 @@ return (function () { internalData.xhr.abort(); } }); + /** @type {(ev: PopStateEvent) => any} */ + const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null; + /** @type {(ev: PopStateEvent) => any} */ window.onpopstate = function (event) { if (event.state && event.state.htmx) { restoreHistory(); @@ -3110,10 +3891,15 @@ return (function () { 'triggerEvent': triggerEvent }); }); + } else { + if (originalPopstate) { + originalPopstate(event); + } } }; setTimeout(function () { triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event + body = null; // kill reference for gc }, 0); }) diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.min.js b/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.min.js index 998414c..53bbdf6 100644 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.min.js +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.min.js @@ -1 +1,4 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(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 l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=k(e);e.classList.toggle(t)}function T(e,t){e=k(e);W(e.parentElement.children,function(e){q(e,t)});L(e,t)}function H(e,t){e=k(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function N(e,t){if(t.indexOf("closest ")===0){return[H(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[C(e,t.substr(5))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return z().querySelectorAll(t)}}function ee(e,t){if(t){return N(e,t)[0]}else{return N(z().body,e)[0]}}function k(e){if(p(e,"String")){return C(e)}else{return e}}function I(e,t,r){if(m(t)){return{target:z().body,event:e,listener:t}}else{return{target:k(e),event:t,listener:r}}}function M(t,r,n){lr(function(){var e=I(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function D(t,r,n){lr(function(){var e=I(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var te=z().createElement("output");function F(e,t){var r=G(e,t);if(r){if(r==="this"){return[re(e,t)]}else{var n=N(e,r);if(n.length===0){pt('The selector "'+r+'" on '+t+" returned no matches!");return[te]}else{return n}}}}function re(e,t){return h(e,function(e){return V(e,t)!=null})}function ne(e){var t=G(e,"hx-target");if(t){if(t==="this"){return re(e,"hx-target")}else{return ee(e,t)}}else{var r=_(e);if(r.boosted){return z().body}else{return e}}}function P(e){var t=U.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function X(t,r){W(t.attributes,function(e){if(!r.hasAttribute(e.name)&&P(e.name)){t.removeAttribute(e.name)}});W(r.attributes,function(e){if(P(e.name)){t.setAttribute(e.name,e.value)}})}function j(e,t){var r=sr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){pt(e)}}return e==="outerHTML"}function B(e,i,o){var t="#"+i.id;var a="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){a=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{a=e}var r=z().querySelectorAll(t);if(r){W(r,function(e){var t;var r=i.cloneNode(true);t=z().createDocumentFragment();t.appendChild(r);if(!j(a,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ye(a,e,e,t,o)}W(o.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(z().body,"htmx:oobErrorNoTarget",{content:i})}return e}function ie(e,r){W(R(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=V(e,"hx-swap-oob");if(t!=null){B(t,e,r)}})}function oe(e){W(R(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=V(e,"id");var r=z().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function ae(n,e,i){W(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();X(e,t);i.tasks.push(function(){X(e,r)})}}})}function se(e){return function(){q(e,U.config.addedClass);ct(e);at(e);le(e);$(e,"htmx:load")}}function le(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ue(e,t,r,n){ae(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(se(i))}}}function fe(t){var e=_(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){W(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){W(t.children,function(e){fe(e)})}}function ce(e,t,r){if(e.tagName==="BODY"){return me(e,t,r)}else{var n;var i=e.previousSibling;ue(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}_(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}fe(e);u(e).removeChild(e)}}function he(e,t,r){return ue(e,e.firstChild,t,r)}function de(e,t,r){return ue(u(e),e,t,r)}function ve(e,t,r){return ue(e,null,t,r)}function ge(e,t,r){return ue(u(e),e.nextSibling,t,r)}function pe(e,t,r){fe(e);return u(e).removeChild(e)}function me(e,t,r){var n=e.firstChild;ue(e,n,t,r);if(n){while(n.nextSibling){fe(n.nextSibling);e.removeChild(n.nextSibling)}fe(n);e.removeChild(n)}}function xe(e,t){var r=G(e,"hx-select");if(r){var n=z().createDocumentFragment();W(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function ye(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":ce(r,n,i);return;case"afterbegin":he(r,n,i);return;case"beforebegin":de(r,n,i);return;case"beforeend":ve(r,n,i);return;case"afterend":ge(r,n,i);return;case"delete":pe(r,n,i);return;default:var o=sr(t);for(var a=0;a<o.length;a++){var f=o[a];try{var s=f.handleSwap(e,r,n,i);if(s){if(typeof s.length!=="undefined"){for(var l=0;l<s.length;l++){var u=s[l];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){i.tasks.push(se(u))}}}return}}catch(e){pt(e)}}if(e==="innerHTML"){me(r,n,i)}else{ye(U.config.defaultSwapStyle,t,r,n,i)}}}function be(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function we(e,t,r,n,i){i.title=be(n);var o=g(n);if(o){ie(o,i);o=xe(r,o);oe(o);return ye(e,r,t,o,i)}}function Se(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!x(a)){a={value:a}}$(r,o,a)}}}else{$(r,n,[])}}var Ee=/\s/;var Ce=/[\s,]/;var Re=/[_$a-zA-Z]/;var Oe=/[_$a-zA-Z0-9]/;var Le=['"',"'","/"];var qe=/[^\s]/;function Ae(e){var t=[];var r=0;while(r<e.length){if(Re.exec(e.charAt(r))){var n=r;while(Oe.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Le.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function Te(e,t,r){return Re.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function He(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Jt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(z().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(Te(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var Ne="input, textarea, select";function ke(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=Ae(t);do{c(n,qe);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var o={trigger:"every"};c(n,qe);o.pollInterval=v(c(n,/[,\[\s]/));c(n,qe);var a=He(e,n,"event");if(a){o.eventFilter=a}r.push(o)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var a=He(e,n,"event");if(a){s.eventFilter=a}while(n.length>0&&n[0]!==","){c(n,qe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Ce))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Ce);if(u==="closest"||u==="find"){n.shift();u+=" "+c(n,Ce)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Ce)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Ce))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Ce)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Ce)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,qe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,Ne)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ie(e){_(e).cancelled=true}function Me(e,t,r,n){var i=_(e);i.timeout=setTimeout(function(){if(Y(e)&&i.cancelled!==true){if(!je(n,dt("hx:poll:trigger",{triggerSpec:n,target:e}))){Z(t,r,e)}Me(e,t,V(e,"hx-"+t),n)}},n.pollInterval)}function De(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&De(t)&&t.target===""||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href");r.pushURL=true}else{var o=f(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=f(t,"action")}e.forEach(function(e){Be(t,n,i,r,e,true)})}}function Pe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&H(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Xe(e,t){return _(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function je(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(z().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Be(o,a,s,e,l,u){var t;if(l.from){t=N(o,l.from)}else{t=[o]}W(t,function(n){var i=function(e){if(!Y(o)){n.removeEventListener(l.trigger,i);return}if(Xe(o,e)){return}if(u||Pe(e,o)){e.preventDefault()}if(je(l,e)){return}var t=_(e);t.triggerSpec=l;if(t.handledFor==null){t.handledFor=[]}var r=_(o);if(t.handledFor.indexOf(o)<0){t.handledFor.push(o);if(l.consume){e.stopPropagation()}if(l.target&&e.target){if(!d(e.target,l.target)){return}}if(l.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(l.changed){if(r.lastValue===o.value){return}else{r.lastValue=o.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(l.throttle){if(!r.throttle){Z(a,s,o,e);r.throttle=setTimeout(function(){r.throttle=null},l.throttle)}}else if(l.delay){r.delayed=setTimeout(function(){Z(a,s,o,e)},l.delay)}else{Z(a,s,o,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:l.trigger,listener:i,on:n});n.addEventListener(l.trigger,i)})}var Ue=false;var Ve=null;function ze(){if(!Ve){Ve=function(){Ue=true};window.addEventListener("scroll",Ve);setInterval(function(){if(Ue){Ue=false;W(z().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){_e(e)})}},200)}}function _e(e){if(!s(e,"data-hx-revealed")&&b(e)){e.setAttribute("data-hx-revealed","true");var t=_(e);if(t.initialized){Z(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Z(t.verb,t.path,e)},{once:true})}}}function We(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Je(e,o[1],0)}if(o[0]==="send"){Ze(e)}}}function Je(s,r,n){if(!Y(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=U.createWebSocket(r);t.onerror=function(e){J(s,"htmx:wsError",{error:e,socket:t});$e(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=Ge(n);setTimeout(function(){Je(s,r,n+1)},t)}};t.onopen=function(e){n=0};_(s).webSocket=t;t.addEventListener("message",function(e){if($e(s)){return}var t=e.data;gt(s,function(e){t=e.transformResponse(t,null,s)});var r=zt(s);var n=g(t);var i=y(n.children);for(var o=0;o<i.length;o++){var a=i[o];B(V(a,"hx-swap-oob")||"true",a,r)}Ct(r.tasks)})}function $e(e){if(!Y(e)){_(e).webSocket.close();return true}}function Ze(u){var f=h(u,function(e){return _(e).webSocket!=null});if(f){u.addEventListener(ke(u)[0].trigger,function(e){var t=_(f).webSocket;var r=Xt(u,f);var n=Mt(u,"post");var i=n.errors;var o=n.values;var a=Gt(u);var s=Q(o,a);var l=jt(s,u);l["HEADERS"]=r;if(i&&i.length>0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Pe(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ge(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}pt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ke(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Ye(e,o[1])}if(o[0]==="swap"){Qe(e,o[1])}}}function Ye(t,e){var r=U.createEventSource(e);r.onerror=function(e){J(t,"htmx:sseError",{error:e,source:r});tt(t)};_(t).sseEventSource=r}function Qe(o,a){var s=h(o,rt);if(s){var l=_(s).sseEventSource;var u=function(e){if(tt(s)){l.removeEventListener(a,u);return}var t=e.data;gt(o,function(e){t=e.transformResponse(t,null,o)});var r=Ut(o);var n=ne(o);var i=zt(o);we(r.swapStyle,o,n,t,i);Ct(i.tasks);$(o,"htmx:sseMessage",e)};_(o).sseListener=u;l.addEventListener(a,u)}else{J(o,"htmx:noSSESourceError")}}function et(e,t,r,n){var i=h(e,rt);if(i){var o=_(i).sseEventSource;var a=function(){if(!tt(i)){if(Y(e)){Z(t,r,e)}else{o.removeEventListener(n,a)}}};_(e).sseListener=a;o.addEventListener(n,a)}else{J(e,"htmx:noSSESourceError")}}function tt(e){if(!Y(e)){_(e).sseEventSource.close();return true}}function rt(e){return _(e).sseEventSource!=null}function nt(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Z(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function it(o,a,e){var t=false;W(n,function(n){if(s(o,"hx-"+n)){var i=V(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){et(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){ze();_e(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=ee(o,e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){$(o,"intersect");break}}},t);r.observe(o);Be(o,n,i,a,e)}else if(e.trigger==="load"){nt(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Me(o,n,i,e)}else{Be(o,n,i,a,e)}})}});return t}function ot(e){if(e.type==="text/javascript"||e.type==="module"||e.type===""){var t=z().createElement("script");W(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(U.config.inlineScriptNonce){t.nonce=U.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){pt(e)}finally{r.removeChild(e)}}}function at(e){if(d(e,"script")){ot(e)}W(R(e,"script"),function(e){ot(e)})}function st(){return document.querySelector("[hx-boost], [data-hx-boost]")}function lt(e){if(e.querySelectorAll){var t=st()?", a, form":"";var r=e.querySelectorAll(i+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [hx-data-ext]");return r}else{return[]}}function ut(r){var e=function(e){if(d(e.target,"button, input[type='submit']")){var t=_(r);t.lastButtonClicked=e.target}};r.addEventListener("click",e);r.addEventListener("focusin",e);r.addEventListener("focusout",function(e){var t=_(r);t.lastButtonClicked=null})}function ft(e){if(e.closest&&e.closest(U.config.disableSelector)){return}var t=_(e);if(!t.initialized){t.initialized=true;$(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=ke(e);var n=it(e,t,r);if(!n&&G(e,"hx-boost")==="true"){Fe(e,t,r)}if(e.tagName==="FORM"){ut(e)}var i=V(e,"hx-sse");if(i){Ke(e,t,i)}var o=V(e,"hx-ws");if(o){We(e,t,o)}$(e,"htmx:afterProcessNode")}}function ct(e){e=k(e);ft(e);W(lt(e),function(e){ft(e)})}function ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function dt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=z().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function J(e,t,r){$(e,t,Q({error:t},r))}function vt(e){return e==="htmx:afterProcessNode"}function gt(e,t){W(sr(e),function(e){try{t(e)}catch(e){pt(e)}})}function pt(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function $(e,t,r){e=k(e);if(r==null){r={}}r["elt"]=e;var n=dt(t,r);if(U.logger&&!vt(t)){U.logger(e,t,r)}if(r.error){pt(r.error);$(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=ht(t);if(i&&o!==t){var a=dt(o,n.detail);i=i&&e.dispatchEvent(a)}gt(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var mt=location.pathname+location.search;function xt(){var e=z().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||z().body}function yt(e,t,r,n){var i=S(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>U.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(z().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function bt(e){var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function wt(e){var t=U.config.requestClass;var r=e.cloneNode(true);W(R(r,"."+t),function(e){q(e,t)});return r.innerHTML}function St(){var e=xt();var t=mt||location.pathname+location.search;$(z().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(U.config.historyEnabled)history.replaceState({htmx:true},z().title,window.location.href);yt(t,wt(e),z().title,window.scrollY)}function Et(e){if(U.config.historyEnabled)history.pushState({htmx:true},"",e);mt=e}function Ct(e){W(e,function(e){e.call()})}function Rt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};$(z().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){$(z().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=xt();var r=zt(t);me(t,e,r);Ct(r.tasks);mt=n;$(z().body,"htmx:historyRestore",{path:n})}else{J(z().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Ot(e){St();e=e||location.pathname+location.search;var t=bt(e);if(t){var r=g(t.content);var n=xt();var i=zt(n);me(n,r,i);Ct(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);mt=e;$(z().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Rt(e)}}}function Lt(e){var t=G(e,"hx-push-url");return t&&t!=="false"||_(e).boosted&&_(e).pushURL}function qt(e){var t=G(e,"hx-push-url");return t==="true"||t==="false"?null:t}function At(e){var t=F(e,"hx-indicator");if(t==null){t=[e]}W(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Tt(e){W(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function Ht(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Nt(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 kt(t,r,n,e,i){if(e==null||Ht(t,e)){return}else{t.push(e)}if(Nt(e)){var o=f(e,"name");var a=e.value;if(e.multiple){a=y(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=y(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){It(e,n)}}if(d(e,"form")){var l=e.elements;W(l,function(e){kt(t,r,n,e,i)})}}function It(e,t){if(e.willValidate){$(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});$(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Mt(e,t){var r=[];var n={};var i={};var o=[];var a=_(e);var s=d(e,"form")&&e.noValidate!==true;if(a.lastButtonClicked){s=s&&a.lastButtonClicked.formNoValidate!==true}if(t!=="get"){kt(r,i,o,H(e,"form"),s)}kt(r,n,o,e,s);if(a.lastButtonClicked){var l=f(a.lastButtonClicked,"name");if(l){n[l]=a.lastButtonClicked.value}}var u=F(e,"hx-include");W(u,function(e){kt(r,n,o,e,s);if(!d(e,"form")){W(e.querySelectorAll(Ne),function(e){kt(r,n,o,e,s)})}});n=Q(n,i);return{errors:o,values:n}}function Dt(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function Ft(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=Dt(t,r,e)})}else{t=Dt(t,r,n)}}}return t}function Pt(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){W(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Xt(e,t,r){var n={"HX-Request":"true","HX-Trigger":f(e,"id"),"HX-Trigger-Name":f(e,"name"),"HX-Target":V(t,"id"),"HX-Current-URL":z().location.href};Wt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(_(e).boosted){n["HX-Boosted"]="true"}return n}function jt(t,e){var r=G(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){W(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};W(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Bt(e){return f(e,"href")&&f(e,"href").indexOf("#")>=0}function Ut(e,t){var r=t?t:G(e,"hx-swap");var n={swapStyle:_(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(_(e).boosted&&!Bt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var o=1;o<i.length;o++){var a=i[o];if(a.indexOf("swap:")===0){n["swapDelay"]=v(a.substr(5))}if(a.indexOf("settle:")===0){n["settleDelay"]=v(a.substr(7))}if(a.indexOf("scroll:")===0){var s=a.substr(7);var l=s.split(":");var f=l.pop();var u=l.length>0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(a.indexOf("show:")===0){var c=a.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(a.indexOf("focus-scroll:")===0){var d=a.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function Vt(t,r,n){var i=null;gt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(G(r,"hx-encoding")==="multipart/form-data"||d(r,"form")&&f(r,"enctype")==="multipart/form-data"){return Pt(n)}else{return Ft(n)}}}function zt(e){return{tasks:[],elts:[e]}}function _t(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ee(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var o=t.showTarget;if(t.showTarget==="window"){o="body"}i=ee(r,o)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function Wt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}else if(o.indexOf("js:")===0){o=o.substr(3);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Jt(e,function(){return Function("return ("+o+")")()},{})}else{s=S(o)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Wt(u(e),t,r,n)}function Jt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function $t(e,t){return Wt(e,"hx-vars",true,t)}function Zt(e,t){return Wt(e,"hx-vals",false,t)}function Gt(e){return Q($t(e),Zt(e))}function Kt(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Yt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(z().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Qt(e,t){return e.getAllResponseHeaders().match(t)}function er(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return Z(e,t,null,null,{targetOverride:k(r),returnPromise:true})}else{return Z(e,t,k(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:k(r.target),swapOverride:r.swap,returnPromise:true})}}else{return Z(e,t,null,null,{returnPromise:true})}}function tr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Z(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=z().body}var v=r.handler||rr;if(!Y(n)){return}var g=r.targetOverride||ne(n);if(g==null||g==te){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=_(n);var o=G(n,"hx-sync");var m=null;var x=false;if(o){var y=o.split(":");var b=y[0].trim();if(b==="this"){p=re(n,"hx-sync")}else{p=ee(n,b)}o=(y[1]||"drop").trim();i=_(p);if(o==="drop"&&i.xhr&&i.abortable!==true){return}else if(o==="abort"){if(i.xhr){return}else{x=true}}else if(o==="replace"){$(p,"htmx:abort")}else if(o.indexOf("queue")===0){var w=o.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=_(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){Z(e,t,n,f,r)})}return}}var a=new XMLHttpRequest;i.xhr=a;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=G(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){K(c);s();return d}}var R=G(n,"hx-confirm");if(R){if(!confirm(R)){K(c);s();return d}}var O=Xt(n,g,C);if(r.headers){O=Q(O,r.headers)}var L=Mt(n,e);var q=L.errors;var A=L.values;if(r.values){A=Q(A,r.values)}var T=Gt(n);var H=Q(A,T);var N=jt(H,n);if(e!=="get"&&G(n,"hx-encoding")==null){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=z().location.href}var k=Wt(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:q,withCredentials:r.credentials||k.credentials||U.config.withCredentials,timeout:r.timeout||k.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){K(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;q=l.errors;if(q&&q.length>0){$(n,"htmx:validation:halted",l);K(c);s();return d}var I=t.split("#");var M=I[0];var D=I[1];if(e==="get"){var F=M;var P=Object.keys(N).length!==0;if(P){if(F.indexOf("?")<0){F+="?"}else{F+="&"}F+=Ft(N);if(D){F+="#"+D}}a.open("GET",F,true)}else{a.open(e.toUpperCase(),t,true)}a.overrideMimeType("text/html");a.withCredentials=l.withCredentials;a.timeout=l.timeout;if(k.noHeaders){}else{for(var X in O){if(O.hasOwnProperty(X)){var j=O[X];Kt(a,X,j)}}}var u={xhr:a,target:g,requestConfig:l,etc:r,pathInfo:{path:t,finalPath:F,anchor:D}};a.onload=function(){try{var e=tr(n);v(n,u);Tt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!Y(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(Y(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}K(c);s()}catch(e){J(n,"htmx:onLoadError",Q({error:e},u));throw e}};a.onerror=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);K(h);s()};a.onabort=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);K(h);s()};a.ontimeout=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);K(h);s()};if(!$(n,"htmx:beforeRequest",u)){K(c);s();return d}var B=At(n);W(["loadstart","loadend","progress","abort"],function(t){W([a,a.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);a.send(e==="get"?null:Vt(a,n,N));return d}function rr(s,l){var u=l.xhr;var f=l.target;var r=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(Qt(u,/HX-Trigger:/i)){Se(u,"HX-Trigger",s)}if(Qt(u,/HX-Push:/i)){var c=u.getResponseHeader("HX-Push")}if(Qt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Qt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(Qt(u,/HX-Retarget:/i)){l.target=z().querySelector(u.getResponseHeader("HX-Retarget"))}var h;if(c=="false"){h=false}else{h=Lt(s)||c}var n=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var e=u.status>=400;var t=Q({shouldSwap:n,serverResponse:d,isError:e},l);if(!$(f,"htmx:beforeSwap",t))return;f=t.target;d=t.serverResponse;e=t.isError;l.failed=e;l.successful=!e;if(t.shouldSwap){if(u.status===286){Ie(s)}gt(s,function(e){d=e.transformResponse(d,u,s)});if(h){St()}var i=r.swapOverride;var v=Ut(s,i);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=zt(f);we(v.swapStyle,f,s,d,n);if(t.elt&&!Y(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);W(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(l.pathInfo.anchor){location.hash=l.pathInfo.anchor}if(Qt(u,/HX-Trigger-After-Swap:/i)){var o=s;if(!Y(s)){o=z().body}Se(u,"HX-Trigger-After-Swap",o)}var a=function(){W(n.tasks,function(e){e.call()});W(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h){var e=c||qt(s)||Yt(u)||l.pathInfo.finalPath||l.pathInfo.path;Et(e);$(z().body,"htmx:pushedIntoHistory",{path:e})}if(n.title){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}_t(n.elts,v);if(Qt(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!Y(s)){r=z().body}Se(u,"HX-Trigger-After-Settle",r)}};if(v.settleDelay>0){setTimeout(a,v.settleDelay)}else{a()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(v.swapDelay>0){setTimeout(o,v.swapDelay)}else{o()}}if(e){J(s,"htmx:responseError",Q({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var nr={};function ir(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function or(e,t){if(t.init){t.init(r)}nr[e]=Q(ir(),t)}function ar(e){delete nr[e]}function sr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){W(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=nr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return sr(u(e),r,n)}function lr(e){if(z().readyState!=="loading"){e()}else{z().addEventListener("DOMContentLoaded",e)}}function ur(){if(U.config.includeIndicatorStyles!==false){z().head.insertAdjacentHTML("beforeend","<style> ."+U.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+U.config.requestClass+" ."+U.config.indicatorClass+"{opacity:1} ."+U.config.requestClass+"."+U.config.indicatorClass+"{opacity:1} </style>")}}function fr(){var e=z().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function cr(){var e=fr();if(e){U.config=Q(U.config,e)}}lr(function(){cr();ur();var e=z().body;ct(e);var t=z().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=_(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){Ot();W(t,function(e){$(e,"htmx:restored",{document:z(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file +// /////////////////////////////////////////////////////////////////// +// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js +// +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(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 a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/<body/.test(e)}function l(e){var t=!N(e);var r=A(e);var n=e;if(r==="head"){n=n.replace(S,"")}if(Q.config.useTemplateFragments&&t){var i=a("<body><template>"+n+"</template></body>",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a("<table>"+n+"</table>",1);case"col":return a("<table><colgroup>"+n+"</colgroup></table>",2);case"tr":return a("<table><tbody>"+n+"</tbody></table>",2);case"td":case"th":return a("<table><tbody><tr>"+n+"</tr></tbody></table>",3);case"script":case"style":return a("<div>"+n+"</div>",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function oe(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function X(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var Y=function(e,t){var r=re().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function we(t,r){oe(t.attributes,function(e){if(!r.hasAttribute(e.name)&&be(e.name)){t.removeAttribute(e.name)}});oe(r.attributes,function(e){if(be(e.name)){t.setAttribute(e.name,e.value)}})}function Se(e,t){var r=Fr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){b(e)}}return e==="outerHTML"}function Ee(e,i,a){var t="#"+ee(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a<i.length;a++){var o=i[a].split(":",2);var s=o[0].trim();if(s.indexOf("#")===0){s=s.substring(1)}var l=o[1]||"true";var u=t.querySelector("#"+s);if(u){Ee(l,u,r)}}}oe(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=te(e,"hx-swap-oob");if(t!=null){Ee(t,e,r)}})}function Re(e){oe(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=te(e,"id");var r=re().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function Te(o,e,s){oe(e.querySelectorAll("[id]"),function(e){var t=ee(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Le(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=He(n.name,t);t=He(n.value,t)}}}return t}function Ae(e){var t=ae(e);if(t.onHandlers){for(var r=0;r<t.onHandlers.length;r++){const n=t.onHandlers[r];e.removeEventListener(n.event,n.listener)}delete t.onHandlers}}function Ne(e){var t=ae(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){oe(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}Ae(e);oe(Object.keys(t),function(e){delete t[e]})}function p(e){ce(e,"htmx:beforeCleanupElement");Ne(e);if(e.children){oe(e.children,function(e){p(e)})}}function Ie(t,e,r){if(t.tagName==="BODY"){return Ue(t,e,r)}else{var n;var i=t.previousSibling;m(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}p(t);u(t).removeChild(t)}}function ke(e,t,r){return m(e,e.firstChild,t,r)}function Pe(e,t,r){return m(u(e),e,t,r)}function Me(e,t,r){return m(e,null,t,r)}function Xe(e,t,r){return m(u(e),e.nextSibling,t,r)}function De(e,t,r){p(e);return u(e).removeChild(e)}function Ue(e,t,r){var n=e.firstChild;m(e,n,t,r);if(n){while(n.nextSibling){p(n.nextSibling);e.removeChild(n.nextSibling)}p(n);e.removeChild(n)}}function Be(e,t,r){var n=r||ne(e,"hx-select");if(n){var i=re().createDocumentFragment();oe(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function Fe(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Ie(r,n,i);return;case"afterbegin":ke(r,n,i);return;case"beforebegin":Pe(r,n,i);return;case"beforeend":Me(r,n,i);return;case"afterend":Xe(r,n,i);return;case"delete":De(r,n,i);return;default:var a=Fr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Oe(f))}}}return}}catch(e){b(e)}}if(e==="innerHTML"){Ue(r,n,i)}else{Fe(Q.config.defaultSwapStyle,t,r,n,i)}}}function Ve(e){if(e.indexOf("<title")>-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){ce(r,s[l].trim(),[])}}}var ze=/\s/;var x=/[\s,]/;var $e=/[_$a-zA-Z]/;var We=/[_$a-zA-Z0-9]/;var Ge=['"',"'","/"];var Je=/[^\s]/;var Ze=/[{(]/;var Ke=/[})]/;function Ye(e){var t=[];var r=0;while(r<e.length){if($e.exec(e.charAt(r))){var n=r;while(We.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ge.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function Qe(e,t,r){return $e.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function et(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){xt(e,a[1],0)}if(a[0]==="send"){bt(e)}}}function xt(s,r,n){if(!se(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=Q.createWebSocket(r);t.onerror=function(e){fe(s,"htmx:wsError",{error:e,socket:t});yt(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a<i.length;a++){var o=i[a];Ee(te(o,"hx-swap-oob")||"true",o,r)}nr(r.tasks)})}function yt(e){if(!se(e)){ae(e).webSocket.close();return true}}function bt(u){var f=c(u,function(e){return ae(e).webSocket!=null});if(f){u.addEventListener(it(u)[0].trigger,function(e){var t=ae(f).webSocket;var r=xr(u,f);var n=dr(u,"post");var i=n.errors;var a=n.values;var o=Hr(u);var s=le(a,o);var l=yr(s,u);l["HEADERS"]=r;if(i&&i.length>0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){Et(e,a[1])}if(a[0]==="swap"){Ct(e,a[1])}}}function Et(t,e){var r=Q.createEventSource(e);r.onerror=function(e){fe(t,"htmx:sseError",{error:e,source:r});Tt(t)};ae(t).sseEventSource=r}function Ct(a,o){var s=c(a,Ot);if(s){var l=ae(s).sseEventSource;var u=function(e){if(Tt(s)){return}if(!se(a)){l.removeEventListener(o,u);return}var t=e.data;R(a,function(e){t=e.transformResponse(t,null,a)});var r=wr(a);var n=ye(a);var i=T(a);je(r.swapStyle,n,a,t,i);nr(i.tasks);ce(a,"htmx:sseMessage",e)};ae(a).sseListener=u;l.addEventListener(o,u)}else{fe(a,"htmx:noSSESourceError")}}function Rt(e,t,r){var n=c(e,Ot);if(n){var i=ae(n).sseEventSource;var a=function(){if(!Tt(n)){if(se(e)){t(e)}else{i.removeEventListener(r,a)}}};ae(e).sseListener=a;i.addEventListener(r,a)}else{fe(e,"htmx:noSSESourceError")}}function Tt(e){if(!se(e)){ae(e).sseEventSource.close();return true}}function Ot(e){return ae(e).sseEventSource!=null}function qt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n>0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){ce(n,"intersect");break}}},i);a.observe(n);ht(n,r,t,e)}else if(e.trigger==="load"){if(!ct(e,n,Wt("load",{elt:n}))){qt(n,r,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r<t.length;r++){var n=t[r].name;if(s(n,"hx-on:")||s(n,"data-hx-on:")||s(n,"hx-on-")||s(n,"data-hx-on-")){return true}}return false}function kt(e){var t=null;var r=[];if(It(e)){r.push(e)}if(document.evaluate){var n=document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]',e);while(t=n.iterateNext())r.push(t)}else{var i=e.getElementsByTagName("*");for(var a=0;a<i.length;a++){if(It(i[a])){r.push(i[a])}}}return r}function Pt(e){if(e.querySelectorAll){var t=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";var r=e.querySelectorAll(i+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Mt(e){var t=v(e.target,"button, input[type='submit']");var r=Dt(e);if(r){r.lastButtonClicked=t}}function Xt(e){var t=Dt(e);if(t){t.lastButtonClicked=null}}function Dt(e){var t=v(e.target,"button, input[type='submit']");if(!t){return}var r=g("#"+ee(t,"form"))||v(t,"form");if(!r){return}return ae(r)}function Ut(e){e.addEventListener("click",Mt);e.addEventListener("focusin",Mt);e.addEventListener("focusout",Xt)}function Bt(e){var t=Ye(e);var r=0;for(var n=0;n<t.length;n++){const i=t[n];if(i==="{"){r++}else if(i==="}"){r--}}return r}function Ft(t,e,r){var n=ae(t);if(!Array.isArray(n.onHandlers)){n.onHandlers=[]}var i;var a=function(e){return Tr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Vt(e){var t=te(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;t<e.attributes.length;t++){var r=e.attributes[t].name;var n=e.attributes[t].value;if(s(r,"hx-on")||s(r,"data-hx-on")){var i=r.indexOf("-on")+3;var a=r.slice(i,i+1);if(a==="-"||a===":"){var o=r.slice(i+1);if(s(o,":")){o="htmx"+o}else if(s(o,"-")){o="htmx:"+o.slice(1)}else if(s(o,"htmx-")){o="htmx:"+o.slice(5)}Ft(e,o,n)}}}}function _t(t){if(v(t,Q.config.disableSelector)){p(t);return}var r=ae(t);if(r.initHash!==Le(t)){Ne(t);r.initHash=Le(t);Vt(t);ce(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=it(t);var n=Ht(t,r,e);if(!n){if(ne(t,"hx-boost")==="true"){lt(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){Lt(t,e,r,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&o(t,"form")){Ut(t)}var i=te(t,"hx-sse");if(i){St(t,r,i)}var a=te(t,"hx-ws");if(a){pt(t,r,a)}ce(t,"htmx:afterProcessNode")}}function zt(e){e=g(e);if(v(e,Q.config.disableSelector)){p(e);return}_t(e);oe(Pt(e),function(e){_t(e)});oe(kt(e),jt)}function $t(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=re().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function fe(e,t,r){ce(e,t,le({error:t},r))}function Gt(e){return e==="htmx:afterProcessNode"}function R(e,t){oe(Fr(e),function(e){try{t(e)}catch(e){b(e)}})}function b(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ce(e,t,r){e=g(e);if(r==null){r={}}r["elt"]=e;var n=Wt(t,r);if(Q.logger&&!Gt(t)){Q.logger(e,t,r)}if(r.error){b(r.error);ce(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=$t(t);if(i&&a!==t){var o=Wt(a,n.detail);i=i&&e.dispatchEvent(o)}R(e,function(e){i=i&&(e.onEvent(t,n)!==false&&!n.defaultPrevented)});return i}var Jt=location.pathname+location.search;function Zt(){var e=re().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||re().body}function Kt(e,t,r,n){if(!U()){return}if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}e=B(e);var i=E(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};ce(re().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Qt(e){var t=Q.config.requestClass;var r=e.cloneNode(true);oe(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function er(){var e=Zt();var t=Jt||location.pathname+location.search;var r;try{r=re().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){r=re().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!r){ce(re().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Kt(t,Qt(e),re().title,window.scrollY)}if(Q.config.historyEnabled)history.replaceState({htmx:true},re().title,window.location.href)}function tr(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(G(e,"&")||G(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Jt=e}function rr(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Jt=e}function nr(e){oe(e,function(e){e.call()})}function ir(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};ce(re().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",re().location.href);e.onload=function(){if(this.status>=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function fr(e){if(e.name===""||e.name==null||e.disabled||v(e,"fieldset[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 cr(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function hr(t,r,n,e,i){if(e==null||ur(t,e)){return}else{t.push(e)}if(fr(e)){var a=ee(e,"name");var o=e.value;if(e.multiple&&e.tagName==="SELECT"){o=M(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=M(e.files)}cr(a,o,r);if(i){vr(e,n)}}if(h(e,"form")){var s=e.elements;oe(s,function(e){hr(t,r,n,e,i)})}}function vr(e,t){if(e.willValidate){ce(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});ce(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function dr(e,t){var r=[];var n={};var i={};var a=[];var o=ae(e);if(o.lastButtonClicked&&!se(o.lastButtonClicked)){o.lastButtonClicked=null}var s=h(e,"form")&&e.noValidate!==true||te(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){hr(r,i,a,v(e,"form"),s)}hr(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=ee(l,"name");cr(u,l.value,i)}var f=pe(e,"hx-include");oe(f,function(e){hr(r,n,a,e,s);if(!h(e,"form")){oe(e.querySelectorAll(rt),function(e){hr(r,n,a,e,s)})}});n=le(n,i);return{errors:a,values:n}}function gr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function mr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t=gr(t,r,e)})}else{t=gr(t,r,n)}}}return t}function pr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function xr(e,t,r){var n={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":re().location.href};Rr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ae(e).boosted){n["HX-Boosted"]="true"}return n}function yr(t,e){var r=ne(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){oe(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};oe(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function br(e){return ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=d(o.substr(5))}else if(o.indexOf("settle:")===0){n["settleDelay"]=d(o.substr(7))}else if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}else if(o.indexOf("ignoreTitle:")===0){n["ignoreTitle"]=o.substr(12)==="true"}else if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","<style> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file diff --git a/code/starter_video_collector/static/js/htmx.js b/code/starter_video_collector/static/js/htmx.js index 27e57bc..86e7668 100644 --- a/code/starter_video_collector/static/js/htmx.js +++ b/code/starter_video_collector/static/js/htmx.js @@ -1,13 +1,23 @@ -//AMD insanity +// /////////////////////////////////////////////////////////////////// +// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.js +// + +// UMD insanity +// This code sets up support for (in order) AMD, ES6 modules, and globals. (function (root, factory) { //@ts-ignore if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. //@ts-ignore define([], factory); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); } else { // Browser globals - root.htmx = factory(); + root.htmx = root.htmx || factory(); } }(typeof self !== 'undefined' ? self : this, function () { return (function () { @@ -38,6 +48,7 @@ return (function () { defineExtension : defineExtension, removeExtension : removeExtension, logAll : logAll, + logNone : logNone, logger : null, config : { historyEnabled:true, @@ -53,15 +64,24 @@ return (function () { settlingClass:'htmx-settling', swappingClass:'htmx-swapping', allowEval:true, + allowScriptTags:true, inlineScriptNonce:'', attributesToSettle:["class", "style", "width", "height"], withCredentials:false, timeout:0, wsReconnectDelay: 'full-jitter', + wsBinaryType: 'blob', disableSelector: "[hx-disable], [data-hx-disable]", useTemplateFragments: false, scrollBehavior: 'smooth', defaultFocusScroll: false, + getCacheBusterParam: false, + globalViewTransitions: false, + methodsThatUseUrlParams: ["get"], + selfRequestsOnly: false, + ignoreTitle: false, + scrollIntoViewOnBoost: true, + triggerSpecsCache: null, }, parseInterval:parseInterval, _:internalEval, @@ -69,17 +89,23 @@ return (function () { return new EventSource(url, {withCredentials:true}) }, createWebSocket: function(url){ - return new WebSocket(url, []); + var sock = new WebSocket(url, []); + sock.binaryType = htmx.config.wsBinaryType; + return sock; }, - version: "1.7.0" + version: "1.9.10" }; /** @type {import("./htmx").HtmxInternalApi} */ var internalAPI = { + addTriggerHandler: addTriggerHandler, bodyContains: bodyContains, + canAccessLocalStorage: canAccessLocalStorage, + findThisElement: findThisElement, filterValues: filterValues, hasAttribute: hasAttribute, getAttributeValue: getAttributeValue, + getClosestAttributeValue: getClosestAttributeValue, getClosestMatch: getClosestMatch, getExpressionVars: getExpressionVars, getHeaders: getHeaders, @@ -92,6 +118,7 @@ return (function () { mergeObjects: mergeObjects, makeSettleInfo: makeSettleInfo, oobSwap: oobSwap, + querySelectorExt: querySelectorExt, selectAndSwap: selectAndSwap, settleImmediately: settleImmediately, shouldCancel: shouldCancel, @@ -105,21 +132,40 @@ return (function () { return "[hx-" + verb + "], [data-hx-" + verb + "]" }).join(", "); + var HEAD_TAG_REGEX = makeTagRegEx('head'), + TITLE_TAG_REGEX = makeTagRegEx('title'), + SVG_TAGS_REGEX = makeTagRegEx('svg', true); + //==================================================================== // Utilities //==================================================================== + /** + * @param {string} tag + * @param {boolean} global + * @returns {RegExp} + */ + function makeTagRegEx(tag, global = false) { + return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, + global ? 'gim' : 'im'); + } + function parseInterval(str) { if (str == undefined) { - return undefined + return undefined; } + + let interval = NaN; if (str.slice(-2) == "ms") { - return parseFloat(str.slice(0,-2)) || undefined - } - if (str.slice(-1) == "s") { - return (parseFloat(str.slice(0,-1)) * 1000) || undefined + interval = parseFloat(str.slice(0, -2)); + } else if (str.slice(-1) == "s") { + interval = parseFloat(str.slice(0, -1)) * 1000; + } else if (str.slice(-1) == "m") { + interval = parseFloat(str.slice(0, -1)) * 1000 * 60; + } else { + interval = parseFloat(str); } - return parseFloat(str) || undefined + return isNaN(interval) ? undefined : interval; } /** @@ -168,13 +214,11 @@ return (function () { * @returns {HTMLElement | null} */ function getClosestMatch(elt, condition) { - if (condition(elt)) { - return elt; - } else if (parentElt(elt)) { - return getClosestMatch(parentElt(elt), condition); - } else { - return null; + while (elt && !condition(elt)) { + elt = parentElt(elt); } + + return elt ? elt : null; } function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ @@ -208,7 +252,7 @@ return (function () { * @returns {boolean} */ function matches(elt, selector) { - // @ts-ignore: non-standard properties for browser compatability + // @ts-ignore: non-standard properties for browser compatibility // noinspection JSUnresolvedVariable var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; return matchesFunction && matchesFunction.call(elt, selector); @@ -252,38 +296,47 @@ return (function () { return responseNode; } + function aFullPageResponse(resp) { + return /<body/.test(resp) + } + /** * - * @param {string} resp + * @param {string} response * @returns {Element} */ - function makeFragment(resp) { - if (htmx.config.useTemplateFragments) { - var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0); + function makeFragment(response) { + var partialResponse = !aFullPageResponse(response); + var startTag = getStartTag(response); + var content = response; + if (startTag === 'head') { + content = content.replace(HEAD_TAG_REGEX, ''); + } + if (htmx.config.useTemplateFragments && partialResponse) { + var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0); // @ts-ignore type mismatch between DocumentFragment and Element. - // TODO: Are these close enough for htmx to use interchangably? + // TODO: Are these close enough for htmx to use interchangeably? return documentFragment.querySelector('template').content; - } else { - 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); - case "script": - return parseHTML("<div>" + resp + "</div>", 1); - default: - return parseHTML(resp, 0); - } + } + switch (startTag) { + case "thead": + case "tbody": + case "tfoot": + case "colgroup": + case "caption": + return parseHTML("<table>" + content + "</table>", 1); + case "col": + return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2); + case "tr": + return parseHTML("<table><tbody>" + content + "</tbody></table>", 2); + case "td": + case "th": + return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3); + case "script": + case "style": + return parseHTML("<div>" + content + "</div>", 1); + default: + return parseHTML(content, 0); } } @@ -365,13 +418,14 @@ return (function () { return elemTop < window.innerHeight && elemBottom >= 0; } - function bodyContains(elt) { - if (elt.getRootNode() instanceof ShadowRoot) { - return getDocument().body.contains(elt.getRootNode().host); - } else { - return getDocument().body.contains(elt); - } - } + function bodyContains(elt) { + // IE Fix + if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) { + return getDocument().body.contains(elt.getRootNode().host); + } else { + return getDocument().body.contains(elt); + } + } function splitOnWhitespace(trigger) { return trigger.trim().split(/\s+/); @@ -402,6 +456,34 @@ return (function () { } } + function canAccessLocalStorage() { + var test = 'htmx:localStorageTest'; + try { + localStorage.setItem(test, test); + localStorage.removeItem(test); + return true; + } catch(e) { + return false; + } + } + + function normalizePath(path) { + try { + var url = new URL(path); + if (url) { + path = url.pathname + url.search; + } + // remove trailing slash, unless index page + if (!(/^\/$/.test(path))) { + path = path.replace(/\/+$/, ''); + } + return path; + } catch (e) { + // be kind to IE11, which doesn't support URL() + return path; + } + } + //========================================================================================== // public API //========================================================================================== @@ -427,6 +509,10 @@ return (function () { } } + function logNone() { + htmx.logger = null + } + function find(eltOrSelector, selector) { if (selector) { return eltOrSelector.querySelector(selector); @@ -446,7 +532,10 @@ return (function () { function removeElement(elt, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeElement(elt);}, delay) + setTimeout(function(){ + removeElement(elt); + elt = null; + }, delay); } else { elt.parentElement.removeChild(elt); } @@ -455,7 +544,10 @@ return (function () { function addClassToElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){addClassToElement(elt, clazz);}, delay) + setTimeout(function(){ + addClassToElement(elt, clazz); + elt = null; + }, delay); } else { elt.classList && elt.classList.add(clazz); } @@ -464,7 +556,10 @@ return (function () { function removeClassFromElement(elt, clazz, delay) { elt = resolveTarget(elt); if (delay) { - setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) + setTimeout(function(){ + removeClassFromElement(elt, clazz); + elt = null; + }, delay); } else { if (elt.classList) { elt.classList.remove(clazz); @@ -494,26 +589,75 @@ return (function () { if (elt.closest) { return elt.closest(selector); } else { + // TODO remove when IE goes away do{ if (elt == null || matches(elt, selector)){ return elt; } } while (elt = elt && parentElt(elt)); + return null; + } + } + + function startsWith(str, prefix) { + return str.substring(0, prefix.length) === prefix + } + + function endsWith(str, suffix) { + return str.substring(str.length - suffix.length) === suffix + } + + function normalizeSelector(selector) { + var trimmedSelector = selector.trim(); + if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) { + return trimmedSelector.substring(1, trimmedSelector.length - 2); + } else { + return trimmedSelector; } } function querySelectorAllExt(elt, selector) { if (selector.indexOf("closest ") === 0) { - return [closest(elt, selector.substr(8))]; + return [closest(elt, normalizeSelector(selector.substr(8)))]; } else if (selector.indexOf("find ") === 0) { - return [find(elt, selector.substr(5))]; + return [find(elt, normalizeSelector(selector.substr(5)))]; + } else if (selector === "next") { + return [elt.nextElementSibling] + } else if (selector.indexOf("next ") === 0) { + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; + } else if (selector === "previous") { + return [elt.previousElementSibling] + } else if (selector.indexOf("previous ") === 0) { + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; } else if (selector === 'document') { return [document]; } else if (selector === 'window') { return [window]; + } else if (selector === 'body') { + return [document.body]; } else { - return getDocument().querySelectorAll(selector); + return getDocument().querySelectorAll(normalizeSelector(selector)); + } + } + + var scanForwardQuery = function(start, match) { + var results = getDocument().querySelectorAll(match); + for (var i = 0; i < results.length; i++) { + var elt = results[i]; + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { + return elt; + } + } + } + + var scanBackwardsQuery = function(start, match) { + var results = getDocument().querySelectorAll(match); + for (var i = results.length - 1; i >= 0; i--) { + var elt = results[i]; + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { + return elt; + } } } @@ -570,7 +714,7 @@ return (function () { //==================================================================== // Node processing //==================================================================== - + var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors function findAttributeTargets(elt, attrName) { var attrTarget = getClosestAttributeValue(elt, attrName); @@ -659,7 +803,7 @@ return (function () { * @returns */ function oobSwap(oobValue, oobElement, settleInfo) { - var selector = "#" + oobElement.id; + var selector = "#" + getRawAttribute(oobElement, "id"); var swapStyle = "outerHTML"; if (oobValue === "true") { // do nothing @@ -703,7 +847,23 @@ return (function () { return oobValue; } - function handleOutOfBandSwaps(fragment, settleInfo) { + function handleOutOfBandSwaps(elt, fragment, settleInfo) { + var oobSelects = getClosestAttributeValue(elt, "hx-select-oob"); + if (oobSelects) { + var oobSelectValues = oobSelects.split(","); + for (var i = 0; i < oobSelectValues.length; i++) { + var oobSelectValue = oobSelectValues[i].split(":", 2); + var id = oobSelectValue[0].trim(); + if (id.indexOf("#") === 0) { + id = id.substring(1); + } + var oobValue = oobSelectValue[1] || "true"; + var oobElement = fragment.querySelector("#" + id); + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo); + } + } + } forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) { var oobValue = getAttributeValue(oobElement, "hx-swap-oob"); if (oobValue != null) { @@ -724,8 +884,11 @@ return (function () { function handleAttributes(parentNode, fragment, settleInfo) { forEach(fragment.querySelectorAll("[id]"), function (newNode) { - if (newNode.id && newNode.id.length > 0) { - var oldNode = parentNode.querySelector(newNode.tagName + "[id='" + newNode.id + "']"); + var id = getRawAttribute(newNode, "id") + if (id && id.length > 0) { + var normalizedId = id.replace("'", "\\'"); + var normalizedTag = newNode.tagName.replace(':', '\\:'); + var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']"); if (oldNode && oldNode !== parentNode) { var newAttributes = newNode.cloneNode(); cloneAttributes(newNode, oldNode); @@ -767,24 +930,67 @@ return (function () { } } - function cleanUpElement(element) { + // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, + // derived from Java's string hashcode implementation + function stringHash(string, hash) { + var char = 0; + while (char < string.length){ + hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int + } + return hash; + } + + function attributeHash(elt) { + var hash = 0; + // IE fix + if (elt.attributes) { + for (var i = 0; i < elt.attributes.length; i++) { + var attribute = elt.attributes[i]; + if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent) + hash = stringHash(attribute.name, hash); + hash = stringHash(attribute.value, hash); + } + } + } + return hash; + } + + function deInitOnHandlers(elt) { + var internalData = getInternalData(elt); + if (internalData.onHandlers) { + for (var i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i]; + elt.removeEventListener(handlerInfo.event, handlerInfo.listener); + } + delete internalData.onHandlers + } + } + + function deInitNode(element) { var internalData = getInternalData(element); + if (internalData.timeout) { + clearTimeout(internalData.timeout); + } if (internalData.webSocket) { internalData.webSocket.close(); } if (internalData.sseEventSource) { internalData.sseEventSource.close(); } - - triggerEvent(element, "htmx:beforeCleanupElement") - if (internalData.listenerInfos) { - forEach(internalData.listenerInfos, function(info) { - if (element !== info.on) { + forEach(internalData.listenerInfos, function (info) { + if (info.on) { info.on.removeEventListener(info.trigger, info.listener); } }); } + deInitOnHandlers(element); + forEach(Object.keys(internalData), function(key) { delete internalData[key] }); + } + + function cleanUpElement(element) { + triggerEvent(element, "htmx:beforeCleanupElement") + deInitNode(element); if (element.children) { // IE forEach(element.children, function(child) { cleanUpElement(child) }); } @@ -803,8 +1009,7 @@ return (function () { } else { newElt = eltBeforeNewContent.nextSibling; } - getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later - settleInfo.elts = [] // clear existing elements + settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target }); while(newElt && newElt !== target) { if (newElt.nodeType === Node.ELEMENT_NODE) { settleInfo.elts.push(newElt); @@ -849,8 +1054,8 @@ return (function () { } } - function maybeSelectFromResponse(elt, fragment) { - var selector = getClosestAttributeValue(elt, "hx-select"); + function maybeSelectFromResponse(elt, fragment, selectOverride) { + var selector = selectOverride || getClosestAttributeValue(elt, "hx-select"); if (selector) { var newFragment = getDocument().createDocumentFragment(); forEach(fragment.querySelectorAll(selector), function (node) { @@ -915,21 +1120,20 @@ return (function () { function findTitle(content) { if (content.indexOf('<title') > -1) { - var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, ''); - var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im); - + var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, ''); + var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX); if (result) { return result[2]; } } } - function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) { + function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) { settleInfo.title = findTitle(responseText); var fragment = makeFragment(responseText); if (fragment) { - handleOutOfBandSwaps(fragment, settleInfo); - fragment = maybeSelectFromResponse(elt, fragment); + handleOutOfBandSwaps(elt, fragment, settleInfo); + fragment = maybeSelectFromResponse(elt, fragment, selectOverride); handlePreservedElements(fragment); return swap(swapStyle, elt, target, fragment, settleInfo); } @@ -949,7 +1153,10 @@ return (function () { } } } else { - triggerEvent(elt, triggerBody, []); + var eventNames = triggerBody.split(",") + for (var i = 0; i < eventNames.length; i++) { + triggerEvent(elt, eventNames[i].trim(), []); + } } } @@ -959,6 +1166,8 @@ return (function () { var SYMBOL_CONT = /[_$a-zA-Z0-9]/; var STRINGISH_START = ['"', "'", "/"]; var NOT_WHITESPACE = /[^\s]/; + var COMBINED_SELECTOR_START = /[{(]/; + var COMBINED_SELECTOR_END = /[})]/; function tokenizeString(str) { var tokens = []; var position = 0; @@ -1041,101 +1250,137 @@ return (function () { function consumeUntil(tokens, match) { var result = ""; - while (tokens.length > 0 && !tokens[0].match(match)) { + while (tokens.length > 0 && !match.test(tokens[0])) { result += tokens.shift(); } return result; } + function consumeCSSSelector(tokens) { + var result; + if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { + tokens.shift(); + result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim(); + tokens.shift(); + } else { + result = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } + return result; + } + var INPUT_SELECTOR = 'input, textarea, select'; /** * @param {HTMLElement} elt + * @param {string} explicitTrigger + * @param {cache} cache for trigger specs * @returns {import("./htmx").HtmxTriggerSpecification[]} */ - function getTriggerSpecs(elt) { - var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); + function parseAndCacheTrigger(elt, explicitTrigger, cache) { var triggerSpecs = []; - if (explicitTrigger) { - var tokens = tokenizeString(explicitTrigger); - do { - consumeUntil(tokens, NOT_WHITESPACE); - var initialLength = tokens.length; - var trigger = consumeUntil(tokens, /[,\[\s]/); - if (trigger !== "") { - if (trigger === "every") { - var every = {trigger: 'every'}; - consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); - consumeUntil(tokens, NOT_WHITESPACE); - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - every.eventFilter = eventFilter; - } - triggerSpecs.push(every); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); - } else { - var triggerSpec = {trigger: trigger}; - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - triggerSpec.eventFilter = eventFilter; - } - while (tokens.length > 0 && tokens[0] !== ",") { - consumeUntil(tokens, NOT_WHITESPACE) - var token = tokens.shift(); - if (token === "changed") { - triggerSpec.changed = true; - } else if (token === "once") { - triggerSpec.once = true; - } else if (token === "consume") { - triggerSpec.consume = true; - } else if (token === "delay" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "from" && tokens[0] === ":") { - tokens.shift(); + var tokens = tokenizeString(explicitTrigger); + do { + consumeUntil(tokens, NOT_WHITESPACE); + var initialLength = tokens.length; + var trigger = consumeUntil(tokens, /[,\[\s]/); + if (trigger !== "") { + if (trigger === "every") { + var every = {trigger: 'every'}; + consumeUntil(tokens, NOT_WHITESPACE); + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); + consumeUntil(tokens, NOT_WHITESPACE); + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + every.eventFilter = eventFilter; + } + triggerSpecs.push(every); + } else if (trigger.indexOf("sse:") === 0) { + triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); + } else { + var triggerSpec = {trigger: trigger}; + var eventFilter = maybeGenerateConditional(elt, tokens, "event"); + if (eventFilter) { + triggerSpec.eventFilter = eventFilter; + } + while (tokens.length > 0 && tokens[0] !== ",") { + consumeUntil(tokens, NOT_WHITESPACE) + var token = tokens.shift(); + if (token === "changed") { + triggerSpec.changed = true; + } else if (token === "once") { + triggerSpec.once = true; + } else if (token === "consume") { + triggerSpec.consume = true; + } else if (token === "delay" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); + } else if (token === "from" && tokens[0] === ":") { + tokens.shift(); + if (COMBINED_SELECTOR_START.test(tokens[0])) { + var from_arg = consumeCSSSelector(tokens); + } else { var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); - if (from_arg === "closest" || from_arg === "find") { + if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") { tokens.shift(); - from_arg += - " " + - consumeUntil( - tokens, - WHITESPACE_OR_COMMA - ); + var selector = consumeCSSSelector(tokens); + // `next` and `previous` allow a selector-less syntax + if (selector.length > 0) { + from_arg += " " + selector; + } } - triggerSpec.from = from_arg; - } else if (token === "target" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if (token === "throttle" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "queue" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if ((token === "root" || token === "threshold") && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); } + triggerSpec.from = from_arg; + } else if (token === "target" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.target = consumeCSSSelector(tokens); + } else if (token === "throttle" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); + } else if (token === "queue" && tokens[0] === ":") { + tokens.shift(); + triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } else if (token === "root" && tokens[0] === ":") { + tokens.shift(); + triggerSpec[token] = consumeCSSSelector(tokens); + } else if (token === "threshold" && tokens[0] === ":") { + tokens.shift(); + triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); + } else { + triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); } - triggerSpecs.push(triggerSpec); } + triggerSpecs.push(triggerSpec); } - if (tokens.length === initialLength) { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - consumeUntil(tokens, NOT_WHITESPACE); - } while (tokens[0] === "," && tokens.shift()) + } + if (tokens.length === initialLength) { + triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); + } + consumeUntil(tokens, NOT_WHITESPACE); + } while (tokens[0] === "," && tokens.shift()) + if (cache) { + cache[explicitTrigger] = triggerSpecs + } + return triggerSpecs + } + + /** + * @param {HTMLElement} elt + * @returns {import("./htmx").HtmxTriggerSpecification[]} + */ + function getTriggerSpecs(elt) { + var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); + var triggerSpecs = []; + if (explicitTrigger) { + var cache = htmx.config.triggerSpecsCache + triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) } if (triggerSpecs.length > 0) { return triggerSpecs; } else if (matches(elt, 'form')) { return [{trigger: 'submit'}]; + } else if (matches(elt, 'input[type="button"], input[type="submit"]')){ + return [{trigger: 'click'}]; } else if (matches(elt, INPUT_SELECTOR)) { return [{trigger: 'change'}]; } else { @@ -1147,14 +1392,17 @@ return (function () { getInternalData(elt).cancelled = true; } - function processPolling(elt, verb, path, spec) { + function processPolling(elt, handler, spec) { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { - issueAjaxRequest(verb, path, elt); + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { + handler(elt); } - processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), spec); + processPolling(elt, handler, spec); } }, spec.pollInterval); } @@ -1166,23 +1414,27 @@ return (function () { } function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt) && elt.target === "") || elt.tagName === "FORM") { + if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || elt.tagName === "FORM") { nodeData.boosted = true; var verb, path; if (elt.tagName === "A") { verb = "get"; - path = getRawAttribute(elt, 'href'); - nodeData.pushURL = true; + path = getRawAttribute(elt, 'href') } else { var rawAttribute = getRawAttribute(elt, "method"); verb = rawAttribute ? rawAttribute.toLowerCase() : "get"; if (verb === "get") { - nodeData.pushURL = true; } path = getRawAttribute(elt, 'action'); } triggerSpecs.forEach(function(triggerSpec) { - addEventListener(elt, verb, path, nodeData, triggerSpec, true); + addEventListener(elt, function(elt, evt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + issueAjaxRequest(verb, path, elt, evt) + }, nodeData, triggerSpec, true); }); } } @@ -1213,11 +1465,11 @@ return (function () { return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); } - function maybeFilterEvent(triggerSpec, evt) { + function maybeFilterEvent(triggerSpec, elt, evt) { var eventFilter = triggerSpec.eventFilter; if(eventFilter){ try { - return eventFilter(evt) !== true; + return eventFilter.call(elt, evt) !== true; } catch(e) { triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); return true; @@ -1226,13 +1478,21 @@ return (function () { return false; } - function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { + function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { + var elementData = getInternalData(elt); var eltsToListenOn; if (triggerSpec.from) { eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); } else { eltsToListenOn = [elt]; } + // store the initial values of the elements, so we can tell if they change + if (triggerSpec.changed) { + eltsToListenOn.forEach(function (eltToListenOn) { + var eltToListenOnData = getInternalData(eltToListenOn); + eltToListenOnData.lastValue = eltToListenOn.value; + }) + } forEach(eltsToListenOn, function (eltToListenOn) { var eventListener = function (evt) { if (!bodyContains(elt)) { @@ -1245,7 +1505,7 @@ return (function () { if (explicitCancel || shouldCancel(evt, elt)) { evt.preventDefault(); } - if (maybeFilterEvent(triggerSpec, evt)) { + if (maybeFilterEvent(triggerSpec, elt, evt)) { return; } var eventData = getInternalData(evt); @@ -1253,7 +1513,6 @@ return (function () { if (eventData.handledFor == null) { eventData.handledFor = []; } - var elementData = getInternalData(elt); if (eventData.handledFor.indexOf(elt) < 0) { eventData.handledFor.push(elt); if (triggerSpec.consume) { @@ -1272,11 +1531,11 @@ return (function () { } } if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { + var eltToListenOnData = getInternalData(eltToListenOn) + if (eltToListenOnData.lastValue === eltToListenOn.value) { return; - } else { - elementData.lastValue = elt.value; } + eltToListenOnData.lastValue = eltToListenOn.value } if (elementData.delayed) { clearTimeout(elementData.delayed); @@ -1285,19 +1544,18 @@ return (function () { return; } - if (triggerSpec.throttle) { + if (triggerSpec.throttle > 0) { if (!elementData.throttle) { - issueAjaxRequest(verb, path, elt, evt); + handler(elt, evt); elementData.throttle = setTimeout(function () { elementData.throttle = null; }, triggerSpec.throttle); } - } else if (triggerSpec.delay) { - elementData.delayed = setTimeout(function () { - issueAjaxRequest(verb, path, elt, evt); - }, triggerSpec.delay); + } else if (triggerSpec.delay > 0) { + elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); } else { - issueAjaxRequest(verb, path, elt, evt); + triggerEvent(elt, 'htmx:trigger') + handler(elt, evt); } } }; @@ -1310,7 +1568,7 @@ return (function () { on: eltToListenOn }) eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); - }) + }); } var windowIsScrolling = false // used by initScrollHandler @@ -1336,14 +1594,11 @@ return (function () { if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { elt.setAttribute('data-hx-revealed', 'true'); var nodeData = getInternalData(elt); - if (nodeData.initialized) { - issueAjaxRequest(nodeData.verb, nodeData.path, elt); + if (nodeData.initHash) { + triggerEvent(elt, 'revealed'); } else { // if the node isn't initialized, wait for it before triggering the request - elt.addEventListener("htmx:afterProcessNode", - function () { - issueAjaxRequest(nodeData.verb, nodeData.path, elt); - }, {once: true}); + elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true}); } } } @@ -1502,6 +1757,9 @@ return (function () { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function (event) { if (maybeCloseSSESource(sseSourceElt)) { + return; + } + if (!bodyContains(elt)) { sseEventSource.removeEventListener(sseEventName, sseListener); return; } @@ -1518,7 +1776,7 @@ return (function () { var target = getTarget(elt) var settleInfo = makeSettleInfo(elt); - selectAndSwap(swapSpec.swapStyle, elt, target, response, settleInfo) + selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) settleImmediately(settleInfo.tasks) triggerEvent(elt, "htmx:sseMessage", event) }; @@ -1530,14 +1788,14 @@ return (function () { } } - function processSSETrigger(elt, verb, path, sseEventName) { + function processSSETrigger(elt, handler, sseEventName) { var sseSourceElt = getClosestMatch(elt, hasEventSource); if (sseSourceElt) { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function () { if (!maybeCloseSSESource(sseSourceElt)) { if (bodyContains(elt)) { - issueAjaxRequest(verb, path, elt); + handler(elt); } else { sseEventSource.removeEventListener(sseEventName, sseListener); } @@ -1563,14 +1821,14 @@ return (function () { //==================================================================== - function loadImmediately(elt, verb, path, nodeData, delay) { + function loadImmediately(elt, handler, nodeData, delay) { var load = function(){ if (!nodeData.loaded) { nodeData.loaded = true; - issueAjaxRequest(verb, path, elt); + handler(elt); } } - if (delay) { + if (delay > 0) { setTimeout(load, delay); } else { load(); @@ -1586,46 +1844,59 @@ return (function () { nodeData.path = path; nodeData.verb = verb; triggerSpecs.forEach(function(triggerSpec) { - if (triggerSpec.sseEvent) { - processSSETrigger(elt, verb, path, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - maybeReveal(elt); - } else if (triggerSpec.trigger === "intersect") { - var observerOptions = {}; - if (triggerSpec.root) { - observerOptions.root = querySelectorExt(elt, triggerSpec.root) - } - if (triggerSpec.threshold) { - observerOptions.threshold = parseFloat(triggerSpec.threshold); + addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return } - var observer = new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - if (entry.isIntersecting) { - triggerEvent(elt, "intersect"); - break; - } - } - }, observerOptions); - observer.observe(elt); - addEventListener(elt, verb, path, nodeData, triggerSpec); - } else if (triggerSpec.trigger === "load") { - loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); - } else if (triggerSpec.pollInterval) { - nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec); - } else { - addEventListener(elt, verb, path, nodeData, triggerSpec); - } + issueAjaxRequest(verb, path, elt, evt) + }) }); } }); return explicitAction; } + function addTriggerHandler(elt, triggerSpec, nodeData, handler) { + if (triggerSpec.sseEvent) { + processSSETrigger(elt, handler, triggerSpec.sseEvent); + } else if (triggerSpec.trigger === "revealed") { + initScrollHandler(); + addEventListener(elt, handler, nodeData, triggerSpec); + maybeReveal(elt); + } else if (triggerSpec.trigger === "intersect") { + var observerOptions = {}; + if (triggerSpec.root) { + observerOptions.root = querySelectorExt(elt, triggerSpec.root) + } + if (triggerSpec.threshold) { + observerOptions.threshold = parseFloat(triggerSpec.threshold); + } + var observer = new IntersectionObserver(function (entries) { + for (var i = 0; i < entries.length; i++) { + var entry = entries[i]; + if (entry.isIntersecting) { + triggerEvent(elt, "intersect"); + break; + } + } + }, observerOptions); + observer.observe(elt); + addEventListener(elt, handler, nodeData, triggerSpec); + } else if (triggerSpec.trigger === "load") { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { + loadImmediately(elt, handler, nodeData, triggerSpec.delay); + } + } else if (triggerSpec.pollInterval > 0) { + nodeData.polling = true; + processPolling(elt, handler, triggerSpec); + } else { + addEventListener(elt, handler, nodeData, triggerSpec); + } + } + function evalScript(script) { - if (script.type === "text/javascript" || script.type === "module" || script.type === "") { + if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) { var newScript = getDocument().createElement("script"); forEach(script.attributes, function (attr) { newScript.setAttribute(attr.name, attr.value); @@ -1642,7 +1913,10 @@ return (function () { } catch (e) { logError(e); } finally { - parent.removeChild(script); + // remove old script element, but only if it is still in DOM + if (script.parentElement) { + script.parentElement.removeChild(script); + } } } } @@ -1656,48 +1930,187 @@ return (function () { }); } - function hasChanceOfBeingBoosted() { - return document.querySelector("[hx-boost], [data-hx-boost]"); + function shouldProcessHxOn(elt) { + var attributes = elt.attributes + for (var j = 0; j < attributes.length; j++) { + var attrName = attributes[j].name + if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") || + startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) { + return true + } + } + return false + } + + function findHxOnWildcardElements(elt) { + var node = null + var elements = [] + + if (shouldProcessHxOn(elt)) { + elements.push(elt) + } + + if (document.evaluate) { + var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + + ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt) + while (node = iter.iterateNext()) elements.push(node) + } else { + var allElements = elt.getElementsByTagName("*") + for (var i = 0; i < allElements.length; i++) { + if (shouldProcessHxOn(allElements[i])) { + elements.push(allElements[i]) + } + } + } + + return elements } function findElementsToProcess(elt) { if (elt.querySelectorAll) { - var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; - var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [hx-data-ext]"); + var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; + var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," + + " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]"); return results; } else { return []; } } - function initButtonTracking(form){ - var maybeSetLastButtonClicked = function(evt){ - if (matches(evt.target, "button, input[type='submit']")) { - var internalData = getInternalData(form); - internalData.lastButtonClicked = evt.target; - } - }; - + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + function maybeSetLastButtonClicked(evt) { + var elt = closest(evt.target, "button, input[type='submit']"); + var internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = elt; + } + }; + function maybeUnsetLastButtonClicked(evt){ + var internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = null; + } + } + function getRelatedFormData(evt) { + var elt = closest(evt.target, "button, input[type='submit']"); + if (!elt) { + return; + } + var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form'); + if (!form) { + return; + } + return getInternalData(form); + } + function initButtonTracking(elt) { // need to handle both click and focus in: // focusin - in case someone tabs in to a button and hits the space bar // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + elt.addEventListener('click', maybeSetLastButtonClicked) + elt.addEventListener('focusin', maybeSetLastButtonClicked) + elt.addEventListener('focusout', maybeUnsetLastButtonClicked) + } - form.addEventListener('click', maybeSetLastButtonClicked) - form.addEventListener('focusin', maybeSetLastButtonClicked) - form.addEventListener('focusout', function(evt){ - var internalData = getInternalData(form); - internalData.lastButtonClicked = null; - }) + function countCurlies(line) { + var tokens = tokenizeString(line); + var netCurlies = 0; + for (var i = 0; i < tokens.length; i++) { + const token = tokens[i]; + if (token === "{") { + netCurlies++; + } else if (token === "}") { + netCurlies--; + } + } + return netCurlies; + } + + function addHxOnEventHandler(elt, eventName, code) { + var nodeData = getInternalData(elt); + if (!Array.isArray(nodeData.onHandlers)) { + nodeData.onHandlers = []; + } + var func; + var listener = function (e) { + return maybeEval(elt, function() { + if (!func) { + func = new Function("event", code); + } + func.call(elt, e); + }); + }; + elt.addEventListener(eventName, listener); + nodeData.onHandlers.push({event:eventName, listener:listener}); + } + + function processHxOn(elt) { + var hxOnValue = getAttributeValue(elt, 'hx-on'); + if (hxOnValue) { + var handlers = {} + var lines = hxOnValue.split("\n"); + var currentEvent = null; + var curlyCount = 0; + while (lines.length > 0) { + var line = lines.shift(); + var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/); + if (curlyCount === 0 && match) { + line.split(":") + currentEvent = match[1].slice(0, -1); // strip last colon + handlers[currentEvent] = match[2]; + } else { + handlers[currentEvent] += line; + } + curlyCount += countCurlies(line); + } + + for (var eventName in handlers) { + addHxOnEventHandler(elt, eventName, handlers[eventName]); + } + } + } + + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (var i = 0; i < elt.attributes.length; i++) { + var name = elt.attributes[i].name + var value = elt.attributes[i].value + if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) { + var afterOnPosition = name.indexOf("-on") + 3; + var nextChar = name.slice(afterOnPosition, afterOnPosition + 1); + if (nextChar === "-" || nextChar === ":") { + var eventName = name.slice(afterOnPosition + 1); + // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support + if (startsWith(eventName, ":")) { + eventName = "htmx" + eventName + } else if (startsWith(eventName, "-")) { + eventName = "htmx:" + eventName.slice(1); + } else if (startsWith(eventName, "htmx-")) { + eventName = "htmx:" + eventName.slice(5); + } + + addHxOnEventHandler(elt, eventName, value) + } + } + } } function initNode(elt) { - if (elt.closest && elt.closest(htmx.config.disableSelector)) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) return; } var nodeData = getInternalData(elt); - if (!nodeData.initialized) { - nodeData.initialized = true; + if (nodeData.initHash !== attributeHash(elt)) { + // clean up any previously processed info + deInitNode(elt); + + nodeData.initHash = attributeHash(elt); + + processHxOn(elt); + triggerEvent(elt, "htmx:beforeProcessNode") if (elt.value) { @@ -1705,14 +2118,24 @@ return (function () { } var triggerSpecs = getTriggerSpecs(elt); - var explicitAction = processVerbs(elt, nodeData, triggerSpecs); - - if (!explicitAction && getClosestAttributeValue(elt, "hx-boost") === "true") { - boostElement(elt, nodeData, triggerSpecs); + var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs); + + if (!hasExplicitHttpAction) { + if (getClosestAttributeValue(elt, "hx-boost") === "true") { + boostElement(elt, nodeData, triggerSpecs); + } else if (hasAttribute(elt, 'hx-trigger')) { + triggerSpecs.forEach(function (triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function () { + }) + }) + } } - if (elt.tagName === "FORM") { - initButtonTracking(elt); + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) { + initButtonTracking(elt) } var sseInfo = getAttributeValue(elt, 'hx-sse'); @@ -1730,8 +2153,15 @@ return (function () { function processNode(elt) { elt = resolveTarget(elt); + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return; + } initNode(elt); forEach(findElementsToProcess(elt), function(child) { initNode(child) }); + // Because it happens second, the new way of adding onHandlers superseeds the old one + // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored + forEach(findHxOnWildcardElements(elt), processHxOnWildcard); } //==================================================================== @@ -1809,7 +2239,7 @@ return (function () { eventResult = eventResult && elt.dispatchEvent(kebabedEvent) } withExtensions(elt, function (extension) { - eventResult = eventResult && (extension.onEvent(eventName, event) !== false) + eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) }); return eventResult; } @@ -1825,6 +2255,18 @@ return (function () { } function saveToHistoryCache(url, content, title, scroll) { + if (!canAccessLocalStorage()) { + return; + } + + if (htmx.config.historyCacheSize <= 0) { + // make sure that an eventually already existing cache is purged + localStorage.removeItem("htmx-history-cache"); + return; + } + + url = normalizePath(url); + var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { @@ -1832,7 +2274,9 @@ return (function () { break; } } - historyCache.push({url:url, content: content, title:title, scroll:scroll}) + var newHistoryItem = {url:url, content: content, title:title, scroll:scroll}; + triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache}) + historyCache.push(newHistoryItem) while (historyCache.length > htmx.config.historyCacheSize) { historyCache.shift(); } @@ -1848,6 +2292,12 @@ return (function () { } function getCachedHistory(url) { + if (!canAccessLocalStorage()) { + return null; + } + + url = normalizePath(url); + var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { @@ -1869,13 +2319,43 @@ return (function () { function saveCurrentPageToHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; - triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); - if(htmx.config.historyEnabled) history.replaceState({htmx:true}, getDocument().title, window.location.href); - saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); + + // Allow history snapshot feature to be disabled where hx-history="false" + // is present *anywhere* in the current document we're about to save, + // so we can prevent privileged data entering the cache. + // The page will still be reachable as a history entry, but htmx will fetch it + // live from the server onpopstate rather than look in the localStorage cache + var disableHistoryCache + try { + disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') + } catch (e) { + // IE11: insensitive modifier not supported so fallback to case sensitive selector + disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') + } + if (!disableHistoryCache) { + triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt}); + saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); + } + + if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href); } function pushUrlIntoHistory(path) { - if(htmx.config.historyEnabled) history.pushState({htmx:true}, "", path); + // remove the cache buster parameter, if any + if (htmx.config.getCacheBusterParam) { + path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') + if (endsWith(path, '&') || endsWith(path, "?")) { + path = path.slice(0, -1); + } + } + if(htmx.config.historyEnabled) { + history.pushState({htmx:true}, "", path); + } + currentPathForHistory = path; + } + + function replaceUrlInHistory(path) { + if(htmx.config.historyEnabled) history.replaceState({htmx:true}, "", path); currentPathForHistory = path; } @@ -1890,7 +2370,9 @@ return (function () { var details = {path: path, xhr:request}; triggerEvent(getDocument().body, "htmx:historyCacheMiss", details); request.open('GET', path, true); + request.setRequestHeader("HX-Request", "true"); request.setRequestHeader("HX-History-Restore-Request", "true"); + request.setRequestHeader("HX-Current-URL", getDocument().location.href); request.onload = function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); @@ -1899,11 +2381,20 @@ return (function () { fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; var historyElement = getHistoryElement(); var settleInfo = makeSettleInfo(historyElement); + var title = findTitle(this.response); + if (title) { + var titleElt = find("title"); + if (titleElt) { + titleElt.innerHTML = title; + } else { + window.document.title = title; + } + } // @ts-ignore swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); + triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response}); } else { triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details); } @@ -1922,9 +2413,11 @@ return (function () { swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); document.title = cached.title; - window.scrollTo(0, cached.scroll); + setTimeout(function () { + window.scrollTo(0, cached.scroll); + }, 0); // next 'tick', so browser has time to render layout currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); + triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); } else { if (htmx.config.refreshOnHistoryMiss) { @@ -1936,31 +2429,46 @@ return (function () { } } - function shouldPush(elt) { - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - return (pushUrl && pushUrl !== "false") || - (getInternalData(elt).boosted && getInternalData(elt).pushURL); - } - - function getPushUrl(elt) { - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - return (pushUrl === "true" || pushUrl === "false") ? null : pushUrl; - } - function addRequestIndicatorClasses(elt) { var indicators = findAttributeTargets(elt, 'hx-indicator'); if (indicators == null) { indicators = [elt]; } forEach(indicators, function (ic) { + var internalData = getInternalData(ic); + internalData.requestCount = (internalData.requestCount || 0) + 1; ic.classList["add"].call(ic.classList, htmx.config.requestClass); }); return indicators; } - function removeRequestIndicatorClasses(indicators) { + function disableElements(elt) { + var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt'); + if (disabledElts == null) { + disabledElts = []; + } + forEach(disabledElts, function (disabledElement) { + var internalData = getInternalData(disabledElement); + internalData.requestCount = (internalData.requestCount || 0) + 1; + disabledElement.setAttribute("disabled", ""); + }); + return disabledElts; + } + + function removeRequestIndicators(indicators, disabled) { forEach(indicators, function (ic) { - ic.classList["remove"].call(ic.classList, htmx.config.requestClass); + var internalData = getInternalData(ic); + internalData.requestCount = (internalData.requestCount || 0) - 1; + if (internalData.requestCount === 0) { + ic.classList["remove"].call(ic.classList, htmx.config.requestClass); + } + }); + forEach(disabled, function (disabledElement) { + var internalData = getInternalData(disabledElement); + internalData.requestCount = (internalData.requestCount || 0) - 1; + if (internalData.requestCount === 0) { + disabledElement.removeAttribute('disabled'); + } }); } @@ -1979,7 +2487,7 @@ return (function () { } function shouldInclude(elt) { - if(elt.name === "" || elt.name == null || elt.disabled) { + if(elt.name === "" || elt.name == null || elt.disabled || closest(elt, "fieldset[disabled]")) { return false; } // ignore "submitter" types (see jQuery src/serialize.js) @@ -1992,6 +2500,29 @@ return (function () { return true; } + function addValueToValues(name, value, values) { + // This is a little ugly because both the current value of the named value in the form + // and the new value could be arrays, so we have to handle all four cases :/ + if (name != null && value != null) { + var current = values[name]; + if (current === undefined) { + values[name] = value; + } else if (Array.isArray(current)) { + if (Array.isArray(value)) { + values[name] = current.concat(value); + } else { + current.push(value); + } + } else { + if (Array.isArray(value)) { + values[name] = [current].concat(value); + } else { + values[name] = [current, value]; + } + } + } + } + function processInputValue(processed, values, errors, elt, validate) { if (elt == null || haveSeenNode(processed, elt)) { return; @@ -2001,35 +2532,14 @@ return (function () { if (shouldInclude(elt)) { var name = getRawAttribute(elt,"name"); var value = elt.value; - if (elt.multiple) { + if (elt.multiple && elt.tagName === "SELECT") { value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value }); } // include file inputs if (elt.files) { value = toArray(elt.files); } - // This is a little ugly because both the current value of the named value in the form - // and the new value could be arrays, so we have to handle all four cases :/ - if (name != null && value != null) { - var current = values[name]; - if(current) { - if (Array.isArray(current)) { - if (Array.isArray(value)) { - values[name] = current.concat(value); - } else { - current.push(value); - } - } else { - if (Array.isArray(value)) { - values[name] = [current].concat(value); - } else { - values[name] = [current, value]; - } - } - } else { - values[name] = value; - } - } + addValueToValues(name, value, values); if (validate) { validateElement(elt, errors); } @@ -2062,9 +2572,13 @@ return (function () { var formValues = {}; var errors = []; var internalData = getInternalData(elt); + if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { + internalData.lastButtonClicked = null + } // only validate when form is directly submitted and novalidate or formnovalidate are not set - var validate = matches(elt, 'form') && elt.noValidate !== true; + // or if the element has an explicit hx-validate="true" on it + var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true"; if (internalData.lastButtonClicked) { validate = validate && internalData.lastButtonClicked.formNoValidate !== true; } @@ -2078,11 +2592,11 @@ return (function () { processInputValue(processed, values, errors, elt, validate); // if a button or submit was clicked last, include its value - if (internalData.lastButtonClicked) { - var name = getRawAttribute(internalData.lastButtonClicked,"name"); - if (name) { - values[name] = internalData.lastButtonClicked.value; - } + if (internalData.lastButtonClicked || elt.tagName === "BUTTON" || + (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) { + var button = internalData.lastButtonClicked || elt + var name = getRawAttribute(button, "name") + addValueToValues(name, button.value, formValues) } // include any explicit includes @@ -2228,40 +2742,43 @@ return (function () { "swapDelay" : htmx.config.defaultSwapDelay, "settleDelay" : htmx.config.defaultSettleDelay } - if (getInternalData(elt).boosted && !isAnchorLink(elt)) { + if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { swapSpec["show"] = "top" } 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)); - } - if (modifier.indexOf("scroll:") === 0) { - var scrollSpec = modifier.substr(7); + for (var i = 0; i < split.length; i++) { + var value = split[i]; + if (value.indexOf("swap:") === 0) { + swapSpec["swapDelay"] = parseInterval(value.substr(5)); + } else if (value.indexOf("settle:") === 0) { + swapSpec["settleDelay"] = parseInterval(value.substr(7)); + } else if (value.indexOf("transition:") === 0) { + swapSpec["transition"] = value.substr(11) === "true"; + } else if (value.indexOf("ignoreTitle:") === 0) { + swapSpec["ignoreTitle"] = value.substr(12) === "true"; + } else if (value.indexOf("scroll:") === 0) { + var scrollSpec = value.substr(7); var splitSpec = scrollSpec.split(":"); var scrollVal = splitSpec.pop(); var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; swapSpec["scroll"] = scrollVal; swapSpec["scrollTarget"] = selectorVal; - } - if (modifier.indexOf("show:") === 0) { - var showSpec = modifier.substr(5); + } else if (value.indexOf("show:") === 0) { + var showSpec = value.substr(5); var splitSpec = showSpec.split(":"); var showVal = splitSpec.pop(); var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; swapSpec["show"] = showVal; swapSpec["showTarget"] = selectorVal; - } - if (modifier.indexOf("focus-scroll:") === 0) { - var focusScrollVal = modifier.substr("focus-scroll:".length); + } else if (value.indexOf("focus-scroll:") === 0) { + var focusScrollVal = value.substr("focus-scroll:".length); swapSpec["focusScroll"] = focusScrollVal == "true"; + } else if (i == 0) { + swapSpec["swapStyle"] = value; + } else { + logError('Unknown modifier in hx-swap: ' + value); } } } @@ -2269,6 +2786,11 @@ return (function () { return swapSpec; } + function usesFormData(elt) { + return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || + (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data"); + } + function encodeParamsForBody(xhr, elt, filteredParameters) { var encodedParameters = null; withExtensions(elt, function (extension) { @@ -2279,8 +2801,7 @@ return (function () { if (encodedParameters != null) { return encodedParameters; } else { - if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || - (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) { + if (usesFormData(elt)) { return makeFormData(filteredParameters); } else { return urlEncode(filteredParameters); @@ -2352,6 +2873,9 @@ return (function () { if (attributeValue) { var str = attributeValue.trim(); var evaluateValue = evalAsDefault; + if (str === "unset") { + return null; + } if (str.indexOf("javascript:") === 0) { str = str.substr(11); evaluateValue = true; @@ -2426,7 +2950,7 @@ return (function () { } } - function getResponseURL(xhr) { + function getPathFromResponse(xhr) { // NB: IE11 does not support this stuff if (xhr.responseURL && typeof(URL) !== "undefined") { try { @@ -2439,7 +2963,7 @@ return (function () { } function hasHeader(xhr, regexp) { - return xhr.getAllResponseHeaders().match(regexp); + return regexp.test(xhr.getAllResponseHeaders()) } function ajaxHelper(verb, path, context) { @@ -2458,6 +2982,7 @@ return (function () { values : context.values, targetOverride: resolveTarget(context.target), swapOverride: context.swap, + select: context.select, returnPromise: true }); } @@ -2477,7 +3002,28 @@ return (function () { return arr; } - function issueAjaxRequest(verb, path, elt, event, etc) { + function verifyPath(elt, path, requestConfig) { + var sameHost + var url + if (typeof URL === "function") { + url = new URL(path, document.location.href); + var origin = document.location.origin; + sameHost = origin === url.origin; + } else { + // IE11 doesn't support URL + url = path + sameHost = startsWith(path, document.location.origin) + } + + if (htmx.config.selfRequestsOnly) { + if (!sameHost) { + return false; + } + } + return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig)); + } + + function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { var resolve = null; var reject = null; etc = etc != null ? etc : {}; @@ -2491,18 +3037,52 @@ return (function () { elt = getDocument().body; } var responseHandler = etc.handler || handleAjaxResponse; + var select = etc.select || null; if (!bodyContains(elt)) { - return; // do not issue requests for elements removed from the DOM + // do not issue requests for elements removed from the DOM + maybeCall(resolve); + return promise; } var target = etc.targetOverride || getTarget(elt); if (target == null || target == DUMMY_ELT) { triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); - return; + maybeCall(reject); + return promise; } - var syncElt = elt; var eltData = getInternalData(elt); + var submitter = eltData.lastButtonClicked; + + if (submitter) { + var buttonPath = getRawAttribute(submitter, "formaction"); + if (buttonPath != null) { + path = buttonPath; + } + + var buttonVerb = getRawAttribute(submitter, "formmethod") + if (buttonVerb != null) { + // ignore buttons with formmethod="dialog" + if (buttonVerb.toLowerCase() !== "dialog") { + verb = buttonVerb; + } + } + } + + var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); + // allow event-based confirmation w/ a callback + if (confirmed === undefined) { + var issueRequest = function(skipConfirmation) { + return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation); + } + var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion}; + if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { + maybeCall(resolve); + return promise; + } + } + + var syncElt = elt; var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); var queueStrategy = null; var abortable = false; @@ -2518,10 +3098,12 @@ return (function () { syncStrategy = (syncStrings[1] || 'drop').trim(); eltData = getInternalData(syncElt); if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { - return; + maybeCall(resolve); + return promise; } else if (syncStrategy === "abort") { if (eltData.xhr) { - return; + maybeCall(resolve); + return promise; } else { abortable = true; } @@ -2565,7 +3147,8 @@ return (function () { issueAjaxRequest(verb, path, elt, event, etc) }); } - return; + maybeCall(resolve); + return promise; } } @@ -2593,8 +3176,7 @@ return (function () { } } - var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); - if (confirmQuestion) { + if (confirmQuestion && !confirmed) { if(!confirm(confirmQuestion)) { maybeCall(resolve); endRequestLock() @@ -2604,6 +3186,11 @@ return (function () { var headers = getHeaders(elt, target, promptResponse); + + if (verb !== 'get' && !usesFormData(elt)) { + headers['Content-Type'] = 'application/x-www-form-urlencoded'; + } + if (etc.headers) { headers = mergeObjects(headers, etc.headers); } @@ -2617,8 +3204,8 @@ return (function () { var allParameters = mergeObjects(rawParameters, expressionVars); var filteredParameters = filterValues(allParameters, elt); - if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null) { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; + if (htmx.config.getCacheBusterParam && verb === 'get') { + filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true"; } // behavior of anchors w/ empty href is to use the current URL @@ -2626,9 +3213,16 @@ return (function () { path = getDocument().location.href; } + var requestAttrValues = getValuesForElement(elt, 'hx-request'); + var eltIsBoosted = getInternalData(elt).boosted; + + var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + var requestConfig = { + boosted: eltIsBoosted, + useUrlParams: useUrlParams, parameters: filteredParameters, unfilteredParameters: allParameters, headers:headers, @@ -2653,6 +3247,7 @@ return (function () { headers = requestConfig.headers; filteredParameters = requestConfig.parameters; errors = requestConfig.errors; + useUrlParams = requestConfig.useUrlParams; if(errors && errors.length > 0){ triggerEvent(elt, 'htmx:validation:halted', requestConfig) @@ -2664,25 +3259,31 @@ return (function () { var splitPath = path.split("#"); var pathNoAnchor = splitPath[0]; var anchor = splitPath[1]; - if (verb === 'get') { - var finalPathForGet = pathNoAnchor; + + var finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor; var values = Object.keys(filteredParameters).length !== 0; if (values) { - if (finalPathForGet.indexOf("?") < 0) { - finalPathForGet += "?"; + if (finalPath.indexOf("?") < 0) { + finalPath += "?"; } else { - finalPathForGet += "&"; + finalPath += "&"; } - finalPathForGet += urlEncode(filteredParameters); + finalPath += urlEncode(filteredParameters); if (anchor) { - finalPathForGet += "#" + anchor; + finalPath += "#" + anchor; } } - xhr.open('GET', finalPathForGet, true); - } else { - xhr.open(verb.toUpperCase(), path, true); } + if (!verifyPath(elt, finalPath, requestConfig)) { + triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) + maybeCall(reject); + return promise; + }; + + xhr.open(verb.toUpperCase(), finalPath, true); xhr.overrideMimeType("text/html"); xhr.withCredentials = requestConfig.withCredentials; xhr.timeout = requestConfig.timeout; @@ -2699,19 +3300,24 @@ return (function () { } } - var responseInfo = {xhr: xhr, target: target, requestConfig: requestConfig, etc:etc, pathInfo:{ - path:path, finalPath:finalPathForGet, anchor:anchor + var responseInfo = { + xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select, + pathInfo: { + requestPath: path, + finalRequestPath: finalPath, + anchor: anchor } }; xhr.onload = function () { try { var hierarchy = hierarchyForElt(elt); + responseInfo.pathInfo.responsePath = getPathFromResponse(xhr); responseHandler(elt, responseInfo); - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerEvent(elt, 'htmx:afterRequest', responseInfo); triggerEvent(elt, 'htmx:afterOnLoad', responseInfo); - // if the body no longer contains the element, trigger the even on the closest parent + // if the body no longer contains the element, trigger the event on the closest parent // remaining in the DOM if (!bodyContains(elt)) { var secondaryTriggerElt = null; @@ -2734,21 +3340,21 @@ return (function () { } } xhr.onerror = function () { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:sendError', responseInfo); maybeCall(reject); endRequestLock(); } xhr.onabort = function() { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo); maybeCall(reject); endRequestLock(); } xhr.ontimeout = function() { - removeRequestIndicatorClasses(indicators); + removeRequestIndicators(indicators, disableElts); triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); triggerErrorEvent(elt, 'htmx:timeout', responseInfo); maybeCall(reject); @@ -2760,6 +3366,7 @@ return (function () { return promise } var indicators = addRequestIndicatorClasses(elt); + var disableElts = disableElements(elt); forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { forEach([xhr, xhr.upload], function (target) { @@ -2773,14 +3380,99 @@ return (function () { }); }); triggerEvent(elt, 'htmx:beforeSend', responseInfo); - xhr.send(verb === 'get' ? null : encodeParamsForBody(xhr, elt, filteredParameters)); + var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) + xhr.send(params); return promise; } + function determineHistoryUpdates(elt, responseInfo) { + + var xhr = responseInfo.xhr; + + //=========================================== + // First consult response headers + //=========================================== + var pathFromHeaders = null; + var typeFromHeaders = null; + if (hasHeader(xhr,/HX-Push:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Push"); + typeFromHeaders = "push"; + } else if (hasHeader(xhr,/HX-Push-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Push-Url"); + typeFromHeaders = "push"; + } else if (hasHeader(xhr,/HX-Replace-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url"); + typeFromHeaders = "replace"; + } + + // if there was a response header, that has priority + if (pathFromHeaders) { + if (pathFromHeaders === "false") { + return {} + } else { + return { + type: typeFromHeaders, + path : pathFromHeaders + } + } + } + + //=========================================== + // Next resolve via DOM values + //=========================================== + var requestPath = responseInfo.pathInfo.finalRequestPath; + var responsePath = responseInfo.pathInfo.responsePath; + + var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); + var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url"); + var elementIsBoosted = getInternalData(elt).boosted; + + var saveType = null; + var path = null; + + if (pushUrl) { + saveType = "push"; + path = pushUrl; + } else if (replaceUrl) { + saveType = "replace"; + path = replaceUrl; + } else if (elementIsBoosted) { + saveType = "push"; + path = responsePath || requestPath; // if there is no response path, go with the original request path + } + + if (path) { + // false indicates no push, return empty object + if (path === "false") { + return {}; + } + + // true indicates we want to follow wherever the server ended up sending us + if (path === "true") { + path = responsePath || requestPath; // if there is no response path, go with the original request path + } + + // restore any anchor associated with the request + if (responseInfo.pathInfo.anchor && + path.indexOf("#") === -1) { + path = path + "#" + responseInfo.pathInfo.anchor; + } + + return { + type:saveType, + path: path + } + } else { + return {}; + } + } + function handleAjaxResponse(elt, responseInfo) { var xhr = responseInfo.xhr; var target = responseInfo.target; var etc = responseInfo.etc; + var requestConfig = responseInfo.requestConfig; + var select = responseInfo.select; if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; @@ -2788,33 +3480,44 @@ return (function () { handleTrigger(xhr, "HX-Trigger", elt); } - if (hasHeader(xhr,/HX-Push:/i)) { - var pushedUrl = xhr.getResponseHeader("HX-Push"); + if (hasHeader(xhr, /HX-Location:/i)) { + saveCurrentPageToHistory(); + var redirectPath = xhr.getResponseHeader("HX-Location"); + var swapSpec; + if (redirectPath.indexOf("{") === 0) { + swapSpec = parseJSON(redirectPath); + // what's the best way to throw an error if the user didn't include this + redirectPath = swapSpec['path']; + delete swapSpec['path']; + } + ajaxHelper('GET', redirectPath, swapSpec).then(function(){ + pushUrlIntoHistory(redirectPath); + }); + return; } + var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh"); + if (hasHeader(xhr, /HX-Redirect:/i)) { - window.location.href = xhr.getResponseHeader("HX-Redirect"); + location.href = xhr.getResponseHeader("HX-Redirect"); + shouldRefresh && location.reload(); return; } - if (hasHeader(xhr,/HX-Refresh:/i)) { - if ("true" === xhr.getResponseHeader("HX-Refresh")) { - location.reload(); - return; - } + if (shouldRefresh) { + location.reload(); + return; } if (hasHeader(xhr,/HX-Retarget:/i)) { - responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget")); + if (xhr.getResponseHeader("HX-Retarget") === "this") { + responseInfo.target = elt; + } else { + responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget")); + } } - /** @type {boolean} */ - var shouldSaveHistory - if (pushedUrl == "false") { - shouldSaveHistory = false - } else { - shouldSaveHistory = shouldPush(elt) || pushedUrl; - } + var historyUpdate = determineHistoryUpdates(elt, responseInfo); // by default htmx only swaps on 200 return codes and does not swap // on 204 'No Content' @@ -2823,15 +3526,18 @@ return (function () { var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; var serverResponse = xhr.response; var isError = xhr.status >= 400; - var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo); + var ignoreTitle = htmx.config.ignoreTitle + var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo); if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; target = beforeSwapDetails.target; // allow re-targeting serverResponse = beforeSwapDetails.serverResponse; // allow updating content isError = beforeSwapDetails.isError; // allow updating error - + ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title + + responseInfo.target = target; // Make updated target available to response events responseInfo.failed = isError; // Make failed property available to response events - responseInfo.successful = !isError; // Make successful property available to response events + responseInfo.successful = !isError; // Make successful property available to response events if (beforeSwapDetails.shouldSwap) { if (xhr.status === 286) { @@ -2842,18 +3548,29 @@ return (function () { serverResponse = extension.transformResponse(serverResponse, xhr, elt); }); - // Save current page - if (shouldSaveHistory) { + // Save current page if there will be a history update + if (historyUpdate.type) { saveCurrentPageToHistory(); } var swapOverride = etc.swapOverride; + if (hasHeader(xhr,/HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader("HX-Reswap"); + } var swapSpec = getSwapSpecification(elt, swapOverride); + if (swapSpec.hasOwnProperty('ignoreTitle')) { + ignoreTitle = swapSpec.ignoreTitle; + } + target.classList.add(htmx.config.swappingClass); + + // optional transition API promise callbacks + var settleResolve = null; + var settleReject = null; + var doSwap = function () { try { - var activeElt = document.activeElement; var selectionInfo = {}; try { @@ -2868,19 +3585,44 @@ return (function () { // safari issue - see https://github.com/microsoft/playwright/issues/5894 } + var selectOverride; + if (select) { + selectOverride = select; + } + + if (hasHeader(xhr, /HX-Reselect:/i)) { + selectOverride = xhr.getResponseHeader("HX-Reselect"); + } + + // if we need to save history, do so, before swapping so that relative resources have the correct base URL + if (historyUpdate.type) { + triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)); + if (historyUpdate.type === "push") { + pushUrlIntoHistory(historyUpdate.path); + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path}); + } else { + replaceUrlInHistory(historyUpdate.path); + triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path}); + } + } + var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo); + selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride); if (selectionInfo.elt && !bodyContains(selectionInfo.elt) && - selectionInfo.elt.id) { - var newActiveElt = document.getElementById(selectionInfo.elt.id); + getRawAttribute(selectionInfo.elt, "id")) { + var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id")); var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; if (newActiveElt) { // @ts-ignore if (selectionInfo.start && newActiveElt.setSelectionRange) { // @ts-ignore - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + try { + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); + } catch (e) { + // the setSelectionRange method is present on fields that don't support it, so just let this fail + } } newActiveElt.focus(focusOptions); } @@ -2893,9 +3635,6 @@ return (function () { } triggerEvent(elt, 'htmx:afterSwap', responseInfo); }); - if (responseInfo.pathInfo.anchor) { - location.hash = responseInfo.pathInfo.anchor; - } if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { var finalElt = elt; @@ -2915,14 +3654,15 @@ return (function () { } triggerEvent(elt, 'htmx:afterSettle', responseInfo); }); - // push URL and save new page - if (shouldSaveHistory) { - var pathToPush = pushedUrl || getPushUrl(elt) || getResponseURL(xhr) || responseInfo.pathInfo.finalPath || responseInfo.pathInfo.path; - pushUrlIntoHistory(pathToPush); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: pathToPush}); + + if (responseInfo.pathInfo.anchor) { + var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor); + if(anchorTarget) { + anchorTarget.scrollIntoView({block:'start', behavior: "auto"}); + } } - if(settleInfo.title) { + if(settleInfo.title && !ignoreTitle) { var titleElt = find("title"); if(titleElt) { titleElt.innerHTML = settleInfo.title; @@ -2940,6 +3680,7 @@ return (function () { } handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); } + maybeCall(settleResolve); } if (swapSpec.settleDelay > 0) { @@ -2949,10 +3690,34 @@ return (function () { } } catch (e) { triggerErrorEvent(elt, 'htmx:swapError', responseInfo); + maybeCall(settleReject); throw e; } }; + var shouldTransition = htmx.config.globalViewTransitions + if(swapSpec.hasOwnProperty('transition')){ + shouldTransition = swapSpec.transition; + } + + if(shouldTransition && + triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && + typeof Promise !== "undefined" && document.startViewTransition){ + var settlePromise = new Promise(function (_resolve, _reject) { + settleResolve = _resolve; + settleReject = _reject; + }); + // wrap the original doSwap() in a call to startViewTransition() + var innerDoSwap = doSwap; + doSwap = function() { + document.startViewTransition(function () { + innerDoSwap(); + return settlePromise; + }); + } + } + + if (swapSpec.swapDelay > 0) { setTimeout(doSwap, swapSpec.swapDelay) } else { @@ -2960,7 +3725,7 @@ return (function () { } } if (isError) { - triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.path}, responseInfo)); + triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo)); } } @@ -3048,9 +3813,22 @@ return (function () { //==================================================================== // Initialization //==================================================================== + var isReady = false + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true + }) + /** + * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. + * + * This function uses isReady because there is no realiable way to ask the browswer whether + * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded + * firing and readystate=complete. + */ function ready(fn) { - if (getDocument().readyState !== 'loading') { + // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by + // some means other than the initial page load. + if (isReady || getDocument().readyState === 'complete') { fn(); } else { getDocument().addEventListener('DOMContentLoaded', fn); @@ -3061,9 +3839,9 @@ return (function () { if (htmx.config.includeIndicatorStyles !== false) { getDocument().head.insertAdjacentHTML("beforeend", "<style>\ - ." + htmx.config.indicatorClass + "{opacity:0;transition: opacity 200ms ease-in;}\ - ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1}\ - ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1}\ + ." + htmx.config.indicatorClass + "{opacity:0}\ + ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ + ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ </style>"); } } @@ -3101,6 +3879,9 @@ return (function () { internalData.xhr.abort(); } }); + /** @type {(ev: PopStateEvent) => any} */ + const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null; + /** @type {(ev: PopStateEvent) => any} */ window.onpopstate = function (event) { if (event.state && event.state.htmx) { restoreHistory(); @@ -3110,10 +3891,15 @@ return (function () { 'triggerEvent': triggerEvent }); }); + } else { + if (originalPopstate) { + originalPopstate(event); + } } }; setTimeout(function () { triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event + body = null; // kill reference for gc }, 0); }) diff --git a/code/starter_video_collector/static/js/htmx.min.js b/code/starter_video_collector/static/js/htmx.min.js index 998414c..53bbdf6 100644 --- a/code/starter_video_collector/static/js/htmx.min.js +++ b/code/starter_video_collector/static/js/htmx.min.js @@ -1 +1,4 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(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 l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=k(e);e.classList.toggle(t)}function T(e,t){e=k(e);W(e.parentElement.children,function(e){q(e,t)});L(e,t)}function H(e,t){e=k(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function N(e,t){if(t.indexOf("closest ")===0){return[H(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[C(e,t.substr(5))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return z().querySelectorAll(t)}}function ee(e,t){if(t){return N(e,t)[0]}else{return N(z().body,e)[0]}}function k(e){if(p(e,"String")){return C(e)}else{return e}}function I(e,t,r){if(m(t)){return{target:z().body,event:e,listener:t}}else{return{target:k(e),event:t,listener:r}}}function M(t,r,n){lr(function(){var e=I(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function D(t,r,n){lr(function(){var e=I(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var te=z().createElement("output");function F(e,t){var r=G(e,t);if(r){if(r==="this"){return[re(e,t)]}else{var n=N(e,r);if(n.length===0){pt('The selector "'+r+'" on '+t+" returned no matches!");return[te]}else{return n}}}}function re(e,t){return h(e,function(e){return V(e,t)!=null})}function ne(e){var t=G(e,"hx-target");if(t){if(t==="this"){return re(e,"hx-target")}else{return ee(e,t)}}else{var r=_(e);if(r.boosted){return z().body}else{return e}}}function P(e){var t=U.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function X(t,r){W(t.attributes,function(e){if(!r.hasAttribute(e.name)&&P(e.name)){t.removeAttribute(e.name)}});W(r.attributes,function(e){if(P(e.name)){t.setAttribute(e.name,e.value)}})}function j(e,t){var r=sr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){pt(e)}}return e==="outerHTML"}function B(e,i,o){var t="#"+i.id;var a="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){a=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{a=e}var r=z().querySelectorAll(t);if(r){W(r,function(e){var t;var r=i.cloneNode(true);t=z().createDocumentFragment();t.appendChild(r);if(!j(a,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ye(a,e,e,t,o)}W(o.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(z().body,"htmx:oobErrorNoTarget",{content:i})}return e}function ie(e,r){W(R(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=V(e,"hx-swap-oob");if(t!=null){B(t,e,r)}})}function oe(e){W(R(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=V(e,"id");var r=z().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function ae(n,e,i){W(e.querySelectorAll("[id]"),function(e){if(e.id&&e.id.length>0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();X(e,t);i.tasks.push(function(){X(e,r)})}}})}function se(e){return function(){q(e,U.config.addedClass);ct(e);at(e);le(e);$(e,"htmx:load")}}function le(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ue(e,t,r,n){ae(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(se(i))}}}function fe(t){var e=_(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){W(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){W(t.children,function(e){fe(e)})}}function ce(e,t,r){if(e.tagName==="BODY"){return me(e,t,r)}else{var n;var i=e.previousSibling;ue(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}_(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}fe(e);u(e).removeChild(e)}}function he(e,t,r){return ue(e,e.firstChild,t,r)}function de(e,t,r){return ue(u(e),e,t,r)}function ve(e,t,r){return ue(e,null,t,r)}function ge(e,t,r){return ue(u(e),e.nextSibling,t,r)}function pe(e,t,r){fe(e);return u(e).removeChild(e)}function me(e,t,r){var n=e.firstChild;ue(e,n,t,r);if(n){while(n.nextSibling){fe(n.nextSibling);e.removeChild(n.nextSibling)}fe(n);e.removeChild(n)}}function xe(e,t){var r=G(e,"hx-select");if(r){var n=z().createDocumentFragment();W(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function ye(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":ce(r,n,i);return;case"afterbegin":he(r,n,i);return;case"beforebegin":de(r,n,i);return;case"beforeend":ve(r,n,i);return;case"afterend":ge(r,n,i);return;case"delete":pe(r,n,i);return;default:var o=sr(t);for(var a=0;a<o.length;a++){var f=o[a];try{var s=f.handleSwap(e,r,n,i);if(s){if(typeof s.length!=="undefined"){for(var l=0;l<s.length;l++){var u=s[l];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){i.tasks.push(se(u))}}}return}}catch(e){pt(e)}}if(e==="innerHTML"){me(r,n,i)}else{ye(U.config.defaultSwapStyle,t,r,n,i)}}}function be(e){if(e.indexOf("<title")>-1){var t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function we(e,t,r,n,i){i.title=be(n);var o=g(n);if(o){ie(o,i);o=xe(r,o);oe(o);return ye(e,r,t,o,i)}}function Se(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var o in i){if(i.hasOwnProperty(o)){var a=i[o];if(!x(a)){a={value:a}}$(r,o,a)}}}else{$(r,n,[])}}var Ee=/\s/;var Ce=/[\s,]/;var Re=/[_$a-zA-Z]/;var Oe=/[_$a-zA-Z0-9]/;var Le=['"',"'","/"];var qe=/[^\s]/;function Ae(e){var t=[];var r=0;while(r<e.length){if(Re.exec(e.charAt(r))){var n=r;while(Oe.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Le.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var o=e.charAt(r);t.push(o)}r++}return t}function Te(e,t,r){return Re.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function He(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var o=null;while(t.length>0){var a=t[0];if(a==="]"){n--;if(n===0){if(o===null){i=i+"true"}t.shift();i+=")})";try{var s=Jt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(z().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(a==="["){n++}if(Te(a,o,r)){i+="(("+r+"."+a+") ? ("+r+"."+a+") : (window."+a+"))"}else{i=i+a}o=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var Ne="input, textarea, select";function ke(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=Ae(t);do{c(n,qe);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var o={trigger:"every"};c(n,qe);o.pollInterval=v(c(n,/[,\[\s]/));c(n,qe);var a=He(e,n,"event");if(a){o.eventFilter=a}r.push(o)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var a=He(e,n,"event");if(a){s.eventFilter=a}while(n.length>0&&n[0]!==","){c(n,qe);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Ce))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Ce);if(u==="closest"||u==="find"){n.shift();u+=" "+c(n,Ce)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Ce)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Ce))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Ce)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Ce)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,qe)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,Ne)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function Ie(e){_(e).cancelled=true}function Me(e,t,r,n){var i=_(e);i.timeout=setTimeout(function(){if(Y(e)&&i.cancelled!==true){if(!je(n,dt("hx:poll:trigger",{triggerSpec:n,target:e}))){Z(t,r,e)}Me(e,t,V(e,"hx-"+t),n)}},n.pollInterval)}function De(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&De(t)&&t.target===""||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href");r.pushURL=true}else{var o=f(t,"method");n=o?o.toLowerCase():"get";if(n==="get"){r.pushURL=true}i=f(t,"action")}e.forEach(function(e){Be(t,n,i,r,e,true)})}}function Pe(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&H(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Xe(e,t){return _(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function je(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(z().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Be(o,a,s,e,l,u){var t;if(l.from){t=N(o,l.from)}else{t=[o]}W(t,function(n){var i=function(e){if(!Y(o)){n.removeEventListener(l.trigger,i);return}if(Xe(o,e)){return}if(u||Pe(e,o)){e.preventDefault()}if(je(l,e)){return}var t=_(e);t.triggerSpec=l;if(t.handledFor==null){t.handledFor=[]}var r=_(o);if(t.handledFor.indexOf(o)<0){t.handledFor.push(o);if(l.consume){e.stopPropagation()}if(l.target&&e.target){if(!d(e.target,l.target)){return}}if(l.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(l.changed){if(r.lastValue===o.value){return}else{r.lastValue=o.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(l.throttle){if(!r.throttle){Z(a,s,o,e);r.throttle=setTimeout(function(){r.throttle=null},l.throttle)}}else if(l.delay){r.delayed=setTimeout(function(){Z(a,s,o,e)},l.delay)}else{Z(a,s,o,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:l.trigger,listener:i,on:n});n.addEventListener(l.trigger,i)})}var Ue=false;var Ve=null;function ze(){if(!Ve){Ve=function(){Ue=true};window.addEventListener("scroll",Ve);setInterval(function(){if(Ue){Ue=false;W(z().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){_e(e)})}},200)}}function _e(e){if(!s(e,"data-hx-revealed")&&b(e)){e.setAttribute("data-hx-revealed","true");var t=_(e);if(t.initialized){Z(t.verb,t.path,e)}else{e.addEventListener("htmx:afterProcessNode",function(){Z(t.verb,t.path,e)},{once:true})}}}function We(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Je(e,o[1],0)}if(o[0]==="send"){Ze(e)}}}function Je(s,r,n){if(!Y(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=U.createWebSocket(r);t.onerror=function(e){J(s,"htmx:wsError",{error:e,socket:t});$e(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=Ge(n);setTimeout(function(){Je(s,r,n+1)},t)}};t.onopen=function(e){n=0};_(s).webSocket=t;t.addEventListener("message",function(e){if($e(s)){return}var t=e.data;gt(s,function(e){t=e.transformResponse(t,null,s)});var r=zt(s);var n=g(t);var i=y(n.children);for(var o=0;o<i.length;o++){var a=i[o];B(V(a,"hx-swap-oob")||"true",a,r)}Ct(r.tasks)})}function $e(e){if(!Y(e)){_(e).webSocket.close();return true}}function Ze(u){var f=h(u,function(e){return _(e).webSocket!=null});if(f){u.addEventListener(ke(u)[0].trigger,function(e){var t=_(f).webSocket;var r=Xt(u,f);var n=Mt(u,"post");var i=n.errors;var o=n.values;var a=Gt(u);var s=Q(o,a);var l=jt(s,u);l["HEADERS"]=r;if(i&&i.length>0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Pe(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ge(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}pt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Ke(e,t,r){var n=w(r);for(var i=0;i<n.length;i++){var o=n[i].split(/:(.+)/);if(o[0]==="connect"){Ye(e,o[1])}if(o[0]==="swap"){Qe(e,o[1])}}}function Ye(t,e){var r=U.createEventSource(e);r.onerror=function(e){J(t,"htmx:sseError",{error:e,source:r});tt(t)};_(t).sseEventSource=r}function Qe(o,a){var s=h(o,rt);if(s){var l=_(s).sseEventSource;var u=function(e){if(tt(s)){l.removeEventListener(a,u);return}var t=e.data;gt(o,function(e){t=e.transformResponse(t,null,o)});var r=Ut(o);var n=ne(o);var i=zt(o);we(r.swapStyle,o,n,t,i);Ct(i.tasks);$(o,"htmx:sseMessage",e)};_(o).sseListener=u;l.addEventListener(a,u)}else{J(o,"htmx:noSSESourceError")}}function et(e,t,r,n){var i=h(e,rt);if(i){var o=_(i).sseEventSource;var a=function(){if(!tt(i)){if(Y(e)){Z(t,r,e)}else{o.removeEventListener(n,a)}}};_(e).sseListener=a;o.addEventListener(n,a)}else{J(e,"htmx:noSSESourceError")}}function tt(e){if(!Y(e)){_(e).sseEventSource.close();return true}}function rt(e){return _(e).sseEventSource!=null}function nt(e,t,r,n,i){var o=function(){if(!n.loaded){n.loaded=true;Z(t,r,e)}};if(i){setTimeout(o,i)}else{o()}}function it(o,a,e){var t=false;W(n,function(n){if(s(o,"hx-"+n)){var i=V(o,"hx-"+n);t=true;a.path=i;a.verb=n;e.forEach(function(e){if(e.sseEvent){et(o,n,i,e.sseEvent)}else if(e.trigger==="revealed"){ze();_e(o)}else if(e.trigger==="intersect"){var t={};if(e.root){t.root=ee(o,e.root)}if(e.threshold){t.threshold=parseFloat(e.threshold)}var r=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){$(o,"intersect");break}}},t);r.observe(o);Be(o,n,i,a,e)}else if(e.trigger==="load"){nt(o,n,i,a,e.delay)}else if(e.pollInterval){a.polling=true;Me(o,n,i,e)}else{Be(o,n,i,a,e)}})}});return t}function ot(e){if(e.type==="text/javascript"||e.type==="module"||e.type===""){var t=z().createElement("script");W(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(U.config.inlineScriptNonce){t.nonce=U.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){pt(e)}finally{r.removeChild(e)}}}function at(e){if(d(e,"script")){ot(e)}W(R(e,"script"),function(e){ot(e)})}function st(){return document.querySelector("[hx-boost], [data-hx-boost]")}function lt(e){if(e.querySelectorAll){var t=st()?", a, form":"";var r=e.querySelectorAll(i+t+", [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [hx-data-ext]");return r}else{return[]}}function ut(r){var e=function(e){if(d(e.target,"button, input[type='submit']")){var t=_(r);t.lastButtonClicked=e.target}};r.addEventListener("click",e);r.addEventListener("focusin",e);r.addEventListener("focusout",function(e){var t=_(r);t.lastButtonClicked=null})}function ft(e){if(e.closest&&e.closest(U.config.disableSelector)){return}var t=_(e);if(!t.initialized){t.initialized=true;$(e,"htmx:beforeProcessNode");if(e.value){t.lastValue=e.value}var r=ke(e);var n=it(e,t,r);if(!n&&G(e,"hx-boost")==="true"){Fe(e,t,r)}if(e.tagName==="FORM"){ut(e)}var i=V(e,"hx-sse");if(i){Ke(e,t,i)}var o=V(e,"hx-ws");if(o){We(e,t,o)}$(e,"htmx:afterProcessNode")}}function ct(e){e=k(e);ft(e);W(lt(e),function(e){ft(e)})}function ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function dt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=z().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function J(e,t,r){$(e,t,Q({error:t},r))}function vt(e){return e==="htmx:afterProcessNode"}function gt(e,t){W(sr(e),function(e){try{t(e)}catch(e){pt(e)}})}function pt(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function $(e,t,r){e=k(e);if(r==null){r={}}r["elt"]=e;var n=dt(t,r);if(U.logger&&!vt(t)){U.logger(e,t,r)}if(r.error){pt(r.error);$(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var o=ht(t);if(i&&o!==t){var a=dt(o,n.detail);i=i&&e.dispatchEvent(a)}gt(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var mt=location.pathname+location.search;function xt(){var e=z().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||z().body}function yt(e,t,r,n){var i=S(localStorage.getItem("htmx-history-cache"))||[];for(var o=0;o<i.length;o++){if(i[o].url===e){i.splice(o,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>U.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(z().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function bt(e){var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function wt(e){var t=U.config.requestClass;var r=e.cloneNode(true);W(R(r,"."+t),function(e){q(e,t)});return r.innerHTML}function St(){var e=xt();var t=mt||location.pathname+location.search;$(z().body,"htmx:beforeHistorySave",{path:t,historyElt:e});if(U.config.historyEnabled)history.replaceState({htmx:true},z().title,window.location.href);yt(t,wt(e),z().title,window.scrollY)}function Et(e){if(U.config.historyEnabled)history.pushState({htmx:true},"",e);mt=e}function Ct(e){W(e,function(e){e.call()})}function Rt(n){var e=new XMLHttpRequest;var i={path:n,xhr:e};$(z().body,"htmx:historyCacheMiss",i);e.open("GET",n,true);e.setRequestHeader("HX-History-Restore-Request","true");e.onload=function(){if(this.status>=200&&this.status<400){$(z().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=xt();var r=zt(t);me(t,e,r);Ct(r.tasks);mt=n;$(z().body,"htmx:historyRestore",{path:n})}else{J(z().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Ot(e){St();e=e||location.pathname+location.search;var t=bt(e);if(t){var r=g(t.content);var n=xt();var i=zt(n);me(n,r,i);Ct(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);mt=e;$(z().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Rt(e)}}}function Lt(e){var t=G(e,"hx-push-url");return t&&t!=="false"||_(e).boosted&&_(e).pushURL}function qt(e){var t=G(e,"hx-push-url");return t==="true"||t==="false"?null:t}function At(e){var t=F(e,"hx-indicator");if(t==null){t=[e]}W(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Tt(e){W(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function Ht(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function Nt(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 kt(t,r,n,e,i){if(e==null||Ht(t,e)){return}else{t.push(e)}if(Nt(e)){var o=f(e,"name");var a=e.value;if(e.multiple){a=y(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){a=y(e.files)}if(o!=null&&a!=null){var s=r[o];if(s){if(Array.isArray(s)){if(Array.isArray(a)){r[o]=s.concat(a)}else{s.push(a)}}else{if(Array.isArray(a)){r[o]=[s].concat(a)}else{r[o]=[s,a]}}}else{r[o]=a}}if(i){It(e,n)}}if(d(e,"form")){var l=e.elements;W(l,function(e){kt(t,r,n,e,i)})}}function It(e,t){if(e.willValidate){$(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});$(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function Mt(e,t){var r=[];var n={};var i={};var o=[];var a=_(e);var s=d(e,"form")&&e.noValidate!==true;if(a.lastButtonClicked){s=s&&a.lastButtonClicked.formNoValidate!==true}if(t!=="get"){kt(r,i,o,H(e,"form"),s)}kt(r,n,o,e,s);if(a.lastButtonClicked){var l=f(a.lastButtonClicked,"name");if(l){n[l]=a.lastButtonClicked.value}}var u=F(e,"hx-include");W(u,function(e){kt(r,n,o,e,s);if(!d(e,"form")){W(e.querySelectorAll(Ne),function(e){kt(r,n,o,e,s)})}});n=Q(n,i);return{errors:o,values:n}}function Dt(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function Ft(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=Dt(t,r,e)})}else{t=Dt(t,r,n)}}}return t}function Pt(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){W(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function Xt(e,t,r){var n={"HX-Request":"true","HX-Trigger":f(e,"id"),"HX-Trigger-Name":f(e,"name"),"HX-Target":V(t,"id"),"HX-Current-URL":z().location.href};Wt(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(_(e).boosted){n["HX-Boosted"]="true"}return n}function jt(t,e){var r=G(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){W(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};W(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function Bt(e){return f(e,"href")&&f(e,"href").indexOf("#")>=0}function Ut(e,t){var r=t?t:G(e,"hx-swap");var n={swapStyle:_(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(_(e).boosted&&!Bt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var o=1;o<i.length;o++){var a=i[o];if(a.indexOf("swap:")===0){n["swapDelay"]=v(a.substr(5))}if(a.indexOf("settle:")===0){n["settleDelay"]=v(a.substr(7))}if(a.indexOf("scroll:")===0){var s=a.substr(7);var l=s.split(":");var f=l.pop();var u=l.length>0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(a.indexOf("show:")===0){var c=a.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(a.indexOf("focus-scroll:")===0){var d=a.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function Vt(t,r,n){var i=null;gt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(G(r,"hx-encoding")==="multipart/form-data"||d(r,"form")&&f(r,"enctype")==="multipart/form-data"){return Pt(n)}else{return Ft(n)}}}function zt(e){return{tasks:[],elts:[e]}}function _t(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ee(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var o=t.showTarget;if(t.showTarget==="window"){o="body"}i=ee(r,o)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function Wt(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var o=i.trim();var a=r;if(o.indexOf("javascript:")===0){o=o.substr(11);a=true}else if(o.indexOf("js:")===0){o=o.substr(3);a=true}if(o.indexOf("{")!==0){o="{"+o+"}"}var s;if(a){s=Jt(e,function(){return Function("return ("+o+")")()},{})}else{s=S(o)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Wt(u(e),t,r,n)}function Jt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function $t(e,t){return Wt(e,"hx-vars",true,t)}function Zt(e,t){return Wt(e,"hx-vals",false,t)}function Gt(e){return Q($t(e),Zt(e))}function Kt(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Yt(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(z().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function Qt(e,t){return e.getAllResponseHeaders().match(t)}function er(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return Z(e,t,null,null,{targetOverride:k(r),returnPromise:true})}else{return Z(e,t,k(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:k(r.target),swapOverride:r.swap,returnPromise:true})}}else{return Z(e,t,null,null,{returnPromise:true})}}function tr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function Z(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=z().body}var v=r.handler||rr;if(!Y(n)){return}var g=r.targetOverride||ne(n);if(g==null||g==te){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=_(n);var o=G(n,"hx-sync");var m=null;var x=false;if(o){var y=o.split(":");var b=y[0].trim();if(b==="this"){p=re(n,"hx-sync")}else{p=ee(n,b)}o=(y[1]||"drop").trim();i=_(p);if(o==="drop"&&i.xhr&&i.abortable!==true){return}else if(o==="abort"){if(i.xhr){return}else{x=true}}else if(o==="replace"){$(p,"htmx:abort")}else if(o.indexOf("queue")===0){var w=o.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=_(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){Z(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){Z(e,t,n,f,r)})}return}}var a=new XMLHttpRequest;i.xhr=a;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=G(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){K(c);s();return d}}var R=G(n,"hx-confirm");if(R){if(!confirm(R)){K(c);s();return d}}var O=Xt(n,g,C);if(r.headers){O=Q(O,r.headers)}var L=Mt(n,e);var q=L.errors;var A=L.values;if(r.values){A=Q(A,r.values)}var T=Gt(n);var H=Q(A,T);var N=jt(H,n);if(e!=="get"&&G(n,"hx-encoding")==null){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=z().location.href}var k=Wt(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:q,withCredentials:r.credentials||k.credentials||U.config.withCredentials,timeout:r.timeout||k.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){K(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;q=l.errors;if(q&&q.length>0){$(n,"htmx:validation:halted",l);K(c);s();return d}var I=t.split("#");var M=I[0];var D=I[1];if(e==="get"){var F=M;var P=Object.keys(N).length!==0;if(P){if(F.indexOf("?")<0){F+="?"}else{F+="&"}F+=Ft(N);if(D){F+="#"+D}}a.open("GET",F,true)}else{a.open(e.toUpperCase(),t,true)}a.overrideMimeType("text/html");a.withCredentials=l.withCredentials;a.timeout=l.timeout;if(k.noHeaders){}else{for(var X in O){if(O.hasOwnProperty(X)){var j=O[X];Kt(a,X,j)}}}var u={xhr:a,target:g,requestConfig:l,etc:r,pathInfo:{path:t,finalPath:F,anchor:D}};a.onload=function(){try{var e=tr(n);v(n,u);Tt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!Y(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(Y(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}K(c);s()}catch(e){J(n,"htmx:onLoadError",Q({error:e},u));throw e}};a.onerror=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);K(h);s()};a.onabort=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);K(h);s()};a.ontimeout=function(){Tt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);K(h);s()};if(!$(n,"htmx:beforeRequest",u)){K(c);s();return d}var B=At(n);W(["loadstart","loadend","progress","abort"],function(t){W([a,a.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);a.send(e==="get"?null:Vt(a,n,N));return d}function rr(s,l){var u=l.xhr;var f=l.target;var r=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(Qt(u,/HX-Trigger:/i)){Se(u,"HX-Trigger",s)}if(Qt(u,/HX-Push:/i)){var c=u.getResponseHeader("HX-Push")}if(Qt(u,/HX-Redirect:/i)){window.location.href=u.getResponseHeader("HX-Redirect");return}if(Qt(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(Qt(u,/HX-Retarget:/i)){l.target=z().querySelector(u.getResponseHeader("HX-Retarget"))}var h;if(c=="false"){h=false}else{h=Lt(s)||c}var n=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var e=u.status>=400;var t=Q({shouldSwap:n,serverResponse:d,isError:e},l);if(!$(f,"htmx:beforeSwap",t))return;f=t.target;d=t.serverResponse;e=t.isError;l.failed=e;l.successful=!e;if(t.shouldSwap){if(u.status===286){Ie(s)}gt(s,function(e){d=e.transformResponse(d,u,s)});if(h){St()}var i=r.swapOverride;var v=Ut(s,i);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=zt(f);we(v.swapStyle,f,s,d,n);if(t.elt&&!Y(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);W(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(l.pathInfo.anchor){location.hash=l.pathInfo.anchor}if(Qt(u,/HX-Trigger-After-Swap:/i)){var o=s;if(!Y(s)){o=z().body}Se(u,"HX-Trigger-After-Swap",o)}var a=function(){W(n.tasks,function(e){e.call()});W(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h){var e=c||qt(s)||Yt(u)||l.pathInfo.finalPath||l.pathInfo.path;Et(e);$(z().body,"htmx:pushedIntoHistory",{path:e})}if(n.title){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}_t(n.elts,v);if(Qt(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!Y(s)){r=z().body}Se(u,"HX-Trigger-After-Settle",r)}};if(v.settleDelay>0){setTimeout(a,v.settleDelay)}else{a()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(v.swapDelay>0){setTimeout(o,v.swapDelay)}else{o()}}if(e){J(s,"htmx:responseError",Q({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var nr={};function ir(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function or(e,t){if(t.init){t.init(r)}nr[e]=Q(ir(),t)}function ar(e){delete nr[e]}function sr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){W(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=nr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return sr(u(e),r,n)}function lr(e){if(z().readyState!=="loading"){e()}else{z().addEventListener("DOMContentLoaded",e)}}function ur(){if(U.config.includeIndicatorStyles!==false){z().head.insertAdjacentHTML("beforeend","<style> ."+U.config.indicatorClass+"{opacity:0;transition: opacity 200ms ease-in;} ."+U.config.requestClass+" ."+U.config.indicatorClass+"{opacity:1} ."+U.config.requestClass+"."+U.config.indicatorClass+"{opacity:1} </style>")}}function fr(){var e=z().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function cr(){var e=fr();if(e){U.config=Q(U.config,e)}}lr(function(){cr();ur();var e=z().body;ct(e);var t=z().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=_(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){Ot();W(t,function(e){$(e,"htmx:restored",{document:z(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file +// /////////////////////////////////////////////////////////////////// +// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js +// +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(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 a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/<body/.test(e)}function l(e){var t=!N(e);var r=A(e);var n=e;if(r==="head"){n=n.replace(S,"")}if(Q.config.useTemplateFragments&&t){var i=a("<body><template>"+n+"</template></body>",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a("<table>"+n+"</table>",1);case"col":return a("<table><colgroup>"+n+"</colgroup></table>",2);case"tr":return a("<table><tbody>"+n+"</tbody></table>",2);case"td":case"th":return a("<table><tbody><tr>"+n+"</tr></tbody></table>",3);case"script":case"style":return a("<div>"+n+"</div>",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function oe(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function X(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var Y=function(e,t){var r=re().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function we(t,r){oe(t.attributes,function(e){if(!r.hasAttribute(e.name)&&be(e.name)){t.removeAttribute(e.name)}});oe(r.attributes,function(e){if(be(e.name)){t.setAttribute(e.name,e.value)}})}function Se(e,t){var r=Fr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){b(e)}}return e==="outerHTML"}function Ee(e,i,a){var t="#"+ee(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a<i.length;a++){var o=i[a].split(":",2);var s=o[0].trim();if(s.indexOf("#")===0){s=s.substring(1)}var l=o[1]||"true";var u=t.querySelector("#"+s);if(u){Ee(l,u,r)}}}oe(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=te(e,"hx-swap-oob");if(t!=null){Ee(t,e,r)}})}function Re(e){oe(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=te(e,"id");var r=re().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function Te(o,e,s){oe(e.querySelectorAll("[id]"),function(e){var t=ee(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Le(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=He(n.name,t);t=He(n.value,t)}}}return t}function Ae(e){var t=ae(e);if(t.onHandlers){for(var r=0;r<t.onHandlers.length;r++){const n=t.onHandlers[r];e.removeEventListener(n.event,n.listener)}delete t.onHandlers}}function Ne(e){var t=ae(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){oe(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}Ae(e);oe(Object.keys(t),function(e){delete t[e]})}function p(e){ce(e,"htmx:beforeCleanupElement");Ne(e);if(e.children){oe(e.children,function(e){p(e)})}}function Ie(t,e,r){if(t.tagName==="BODY"){return Ue(t,e,r)}else{var n;var i=t.previousSibling;m(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}p(t);u(t).removeChild(t)}}function ke(e,t,r){return m(e,e.firstChild,t,r)}function Pe(e,t,r){return m(u(e),e,t,r)}function Me(e,t,r){return m(e,null,t,r)}function Xe(e,t,r){return m(u(e),e.nextSibling,t,r)}function De(e,t,r){p(e);return u(e).removeChild(e)}function Ue(e,t,r){var n=e.firstChild;m(e,n,t,r);if(n){while(n.nextSibling){p(n.nextSibling);e.removeChild(n.nextSibling)}p(n);e.removeChild(n)}}function Be(e,t,r){var n=r||ne(e,"hx-select");if(n){var i=re().createDocumentFragment();oe(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function Fe(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Ie(r,n,i);return;case"afterbegin":ke(r,n,i);return;case"beforebegin":Pe(r,n,i);return;case"beforeend":Me(r,n,i);return;case"afterend":Xe(r,n,i);return;case"delete":De(r,n,i);return;default:var a=Fr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Oe(f))}}}return}}catch(e){b(e)}}if(e==="innerHTML"){Ue(r,n,i)}else{Fe(Q.config.defaultSwapStyle,t,r,n,i)}}}function Ve(e){if(e.indexOf("<title")>-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){ce(r,s[l].trim(),[])}}}var ze=/\s/;var x=/[\s,]/;var $e=/[_$a-zA-Z]/;var We=/[_$a-zA-Z0-9]/;var Ge=['"',"'","/"];var Je=/[^\s]/;var Ze=/[{(]/;var Ke=/[})]/;function Ye(e){var t=[];var r=0;while(r<e.length){if($e.exec(e.charAt(r))){var n=r;while(We.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ge.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function Qe(e,t,r){return $e.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function et(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){xt(e,a[1],0)}if(a[0]==="send"){bt(e)}}}function xt(s,r,n){if(!se(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=Q.createWebSocket(r);t.onerror=function(e){fe(s,"htmx:wsError",{error:e,socket:t});yt(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a<i.length;a++){var o=i[a];Ee(te(o,"hx-swap-oob")||"true",o,r)}nr(r.tasks)})}function yt(e){if(!se(e)){ae(e).webSocket.close();return true}}function bt(u){var f=c(u,function(e){return ae(e).webSocket!=null});if(f){u.addEventListener(it(u)[0].trigger,function(e){var t=ae(f).webSocket;var r=xr(u,f);var n=dr(u,"post");var i=n.errors;var a=n.values;var o=Hr(u);var s=le(a,o);var l=yr(s,u);l["HEADERS"]=r;if(i&&i.length>0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){Et(e,a[1])}if(a[0]==="swap"){Ct(e,a[1])}}}function Et(t,e){var r=Q.createEventSource(e);r.onerror=function(e){fe(t,"htmx:sseError",{error:e,source:r});Tt(t)};ae(t).sseEventSource=r}function Ct(a,o){var s=c(a,Ot);if(s){var l=ae(s).sseEventSource;var u=function(e){if(Tt(s)){return}if(!se(a)){l.removeEventListener(o,u);return}var t=e.data;R(a,function(e){t=e.transformResponse(t,null,a)});var r=wr(a);var n=ye(a);var i=T(a);je(r.swapStyle,n,a,t,i);nr(i.tasks);ce(a,"htmx:sseMessage",e)};ae(a).sseListener=u;l.addEventListener(o,u)}else{fe(a,"htmx:noSSESourceError")}}function Rt(e,t,r){var n=c(e,Ot);if(n){var i=ae(n).sseEventSource;var a=function(){if(!Tt(n)){if(se(e)){t(e)}else{i.removeEventListener(r,a)}}};ae(e).sseListener=a;i.addEventListener(r,a)}else{fe(e,"htmx:noSSESourceError")}}function Tt(e){if(!se(e)){ae(e).sseEventSource.close();return true}}function Ot(e){return ae(e).sseEventSource!=null}function qt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n>0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){ce(n,"intersect");break}}},i);a.observe(n);ht(n,r,t,e)}else if(e.trigger==="load"){if(!ct(e,n,Wt("load",{elt:n}))){qt(n,r,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r<t.length;r++){var n=t[r].name;if(s(n,"hx-on:")||s(n,"data-hx-on:")||s(n,"hx-on-")||s(n,"data-hx-on-")){return true}}return false}function kt(e){var t=null;var r=[];if(It(e)){r.push(e)}if(document.evaluate){var n=document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]',e);while(t=n.iterateNext())r.push(t)}else{var i=e.getElementsByTagName("*");for(var a=0;a<i.length;a++){if(It(i[a])){r.push(i[a])}}}return r}function Pt(e){if(e.querySelectorAll){var t=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";var r=e.querySelectorAll(i+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Mt(e){var t=v(e.target,"button, input[type='submit']");var r=Dt(e);if(r){r.lastButtonClicked=t}}function Xt(e){var t=Dt(e);if(t){t.lastButtonClicked=null}}function Dt(e){var t=v(e.target,"button, input[type='submit']");if(!t){return}var r=g("#"+ee(t,"form"))||v(t,"form");if(!r){return}return ae(r)}function Ut(e){e.addEventListener("click",Mt);e.addEventListener("focusin",Mt);e.addEventListener("focusout",Xt)}function Bt(e){var t=Ye(e);var r=0;for(var n=0;n<t.length;n++){const i=t[n];if(i==="{"){r++}else if(i==="}"){r--}}return r}function Ft(t,e,r){var n=ae(t);if(!Array.isArray(n.onHandlers)){n.onHandlers=[]}var i;var a=function(e){return Tr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Vt(e){var t=te(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;t<e.attributes.length;t++){var r=e.attributes[t].name;var n=e.attributes[t].value;if(s(r,"hx-on")||s(r,"data-hx-on")){var i=r.indexOf("-on")+3;var a=r.slice(i,i+1);if(a==="-"||a===":"){var o=r.slice(i+1);if(s(o,":")){o="htmx"+o}else if(s(o,"-")){o="htmx:"+o.slice(1)}else if(s(o,"htmx-")){o="htmx:"+o.slice(5)}Ft(e,o,n)}}}}function _t(t){if(v(t,Q.config.disableSelector)){p(t);return}var r=ae(t);if(r.initHash!==Le(t)){Ne(t);r.initHash=Le(t);Vt(t);ce(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=it(t);var n=Ht(t,r,e);if(!n){if(ne(t,"hx-boost")==="true"){lt(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){Lt(t,e,r,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&o(t,"form")){Ut(t)}var i=te(t,"hx-sse");if(i){St(t,r,i)}var a=te(t,"hx-ws");if(a){pt(t,r,a)}ce(t,"htmx:afterProcessNode")}}function zt(e){e=g(e);if(v(e,Q.config.disableSelector)){p(e);return}_t(e);oe(Pt(e),function(e){_t(e)});oe(kt(e),jt)}function $t(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=re().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function fe(e,t,r){ce(e,t,le({error:t},r))}function Gt(e){return e==="htmx:afterProcessNode"}function R(e,t){oe(Fr(e),function(e){try{t(e)}catch(e){b(e)}})}function b(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ce(e,t,r){e=g(e);if(r==null){r={}}r["elt"]=e;var n=Wt(t,r);if(Q.logger&&!Gt(t)){Q.logger(e,t,r)}if(r.error){b(r.error);ce(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=$t(t);if(i&&a!==t){var o=Wt(a,n.detail);i=i&&e.dispatchEvent(o)}R(e,function(e){i=i&&(e.onEvent(t,n)!==false&&!n.defaultPrevented)});return i}var Jt=location.pathname+location.search;function Zt(){var e=re().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||re().body}function Kt(e,t,r,n){if(!U()){return}if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}e=B(e);var i=E(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};ce(re().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Qt(e){var t=Q.config.requestClass;var r=e.cloneNode(true);oe(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function er(){var e=Zt();var t=Jt||location.pathname+location.search;var r;try{r=re().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){r=re().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!r){ce(re().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Kt(t,Qt(e),re().title,window.scrollY)}if(Q.config.historyEnabled)history.replaceState({htmx:true},re().title,window.location.href)}function tr(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(G(e,"&")||G(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Jt=e}function rr(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Jt=e}function nr(e){oe(e,function(e){e.call()})}function ir(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};ce(re().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",re().location.href);e.onload=function(){if(this.status>=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function fr(e){if(e.name===""||e.name==null||e.disabled||v(e,"fieldset[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 cr(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function hr(t,r,n,e,i){if(e==null||ur(t,e)){return}else{t.push(e)}if(fr(e)){var a=ee(e,"name");var o=e.value;if(e.multiple&&e.tagName==="SELECT"){o=M(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=M(e.files)}cr(a,o,r);if(i){vr(e,n)}}if(h(e,"form")){var s=e.elements;oe(s,function(e){hr(t,r,n,e,i)})}}function vr(e,t){if(e.willValidate){ce(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});ce(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function dr(e,t){var r=[];var n={};var i={};var a=[];var o=ae(e);if(o.lastButtonClicked&&!se(o.lastButtonClicked)){o.lastButtonClicked=null}var s=h(e,"form")&&e.noValidate!==true||te(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){hr(r,i,a,v(e,"form"),s)}hr(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=ee(l,"name");cr(u,l.value,i)}var f=pe(e,"hx-include");oe(f,function(e){hr(r,n,a,e,s);if(!h(e,"form")){oe(e.querySelectorAll(rt),function(e){hr(r,n,a,e,s)})}});n=le(n,i);return{errors:a,values:n}}function gr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function mr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t=gr(t,r,e)})}else{t=gr(t,r,n)}}}return t}function pr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function xr(e,t,r){var n={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":re().location.href};Rr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ae(e).boosted){n["HX-Boosted"]="true"}return n}function yr(t,e){var r=ne(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){oe(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};oe(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function br(e){return ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=d(o.substr(5))}else if(o.indexOf("settle:")===0){n["settleDelay"]=d(o.substr(7))}else if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}else if(o.indexOf("ignoreTitle:")===0){n["ignoreTitle"]=o.substr(12)==="true"}else if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","<style> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file From 825a201b1883ba70c1a3a1fcda08d83545fe9a17 Mon Sep 17 00:00:00 2001 From: Michael Kennedy <michael@talkpython.fm> Date: Wed, 13 Mar 2024 10:10:57 -0700 Subject: [PATCH 17/21] Fixes sys.gettrace() is not being used anymore, closes #8 --- code/ch4_app/ch4_final_video_collector/app.py | 5 +++++ code/ch4_app/ch4_starter_video_collector/app.py | 5 +++++ code/ch5_partials/ch5_final_video_collector/app.py | 5 +++++ code/ch5_partials/ch5_starter_video_collector/app.py | 5 +++++ code/ch6_active_search/ch6_final_video_collector/app.py | 5 +++++ code/ch6_active_search/ch6_starter_video_collector/app.py | 5 +++++ code/ch7_infinite_scroll/ch7_final_video_collector/app.py | 6 ++++++ code/ch7_infinite_scroll/ch7_starter_video_collector/app.py | 5 +++++ code/starter_video_collector/app.py | 5 +++++ 9 files changed, 46 insertions(+) diff --git a/code/ch4_app/ch4_final_video_collector/app.py b/code/ch4_app/ch4_final_video_collector/app.py index dced78d..71fa232 100644 --- a/code/ch4_app/ch4_final_video_collector/app.py +++ b/code/ch4_app/ch4_final_video_collector/app.py @@ -47,7 +47,12 @@ def setup_db(): if __name__ == '__main__': configure() + + # Python 3.12 has a new way to determine this, + # see https://github.com/talkpython/htmx-python-course/issues/8#issuecomment-1990894657 being_debugged = sys.gettrace() is not None + being_debugged = being_debugged or sys.monitoring.get_tool(sys.monitoring.DEBUGGER_ID) is not None + app.run(debug=being_debugged) else: configure() diff --git a/code/ch4_app/ch4_starter_video_collector/app.py b/code/ch4_app/ch4_starter_video_collector/app.py index dced78d..71fa232 100644 --- a/code/ch4_app/ch4_starter_video_collector/app.py +++ b/code/ch4_app/ch4_starter_video_collector/app.py @@ -47,7 +47,12 @@ def setup_db(): if __name__ == '__main__': configure() + + # Python 3.12 has a new way to determine this, + # see https://github.com/talkpython/htmx-python-course/issues/8#issuecomment-1990894657 being_debugged = sys.gettrace() is not None + being_debugged = being_debugged or sys.monitoring.get_tool(sys.monitoring.DEBUGGER_ID) is not None + app.run(debug=being_debugged) else: configure() diff --git a/code/ch5_partials/ch5_final_video_collector/app.py b/code/ch5_partials/ch5_final_video_collector/app.py index 4dd198b..c4963a5 100644 --- a/code/ch5_partials/ch5_final_video_collector/app.py +++ b/code/ch5_partials/ch5_final_video_collector/app.py @@ -49,7 +49,12 @@ def setup_db(): if __name__ == '__main__': configure() + + # Python 3.12 has a new way to determine this, + # see https://github.com/talkpython/htmx-python-course/issues/8#issuecomment-1990894657 being_debugged = sys.gettrace() is not None + being_debugged = being_debugged or sys.monitoring.get_tool(sys.monitoring.DEBUGGER_ID) is not None + app.run(debug=being_debugged) else: configure() diff --git a/code/ch5_partials/ch5_starter_video_collector/app.py b/code/ch5_partials/ch5_starter_video_collector/app.py index dced78d..71fa232 100644 --- a/code/ch5_partials/ch5_starter_video_collector/app.py +++ b/code/ch5_partials/ch5_starter_video_collector/app.py @@ -47,7 +47,12 @@ def setup_db(): if __name__ == '__main__': configure() + + # Python 3.12 has a new way to determine this, + # see https://github.com/talkpython/htmx-python-course/issues/8#issuecomment-1990894657 being_debugged = sys.gettrace() is not None + being_debugged = being_debugged or sys.monitoring.get_tool(sys.monitoring.DEBUGGER_ID) is not None + app.run(debug=being_debugged) else: configure() diff --git a/code/ch6_active_search/ch6_final_video_collector/app.py b/code/ch6_active_search/ch6_final_video_collector/app.py index 4dd198b..c4963a5 100644 --- a/code/ch6_active_search/ch6_final_video_collector/app.py +++ b/code/ch6_active_search/ch6_final_video_collector/app.py @@ -49,7 +49,12 @@ def setup_db(): if __name__ == '__main__': configure() + + # Python 3.12 has a new way to determine this, + # see https://github.com/talkpython/htmx-python-course/issues/8#issuecomment-1990894657 being_debugged = sys.gettrace() is not None + being_debugged = being_debugged or sys.monitoring.get_tool(sys.monitoring.DEBUGGER_ID) is not None + app.run(debug=being_debugged) else: configure() diff --git a/code/ch6_active_search/ch6_starter_video_collector/app.py b/code/ch6_active_search/ch6_starter_video_collector/app.py index 4dd198b..c4963a5 100644 --- a/code/ch6_active_search/ch6_starter_video_collector/app.py +++ b/code/ch6_active_search/ch6_starter_video_collector/app.py @@ -49,7 +49,12 @@ def setup_db(): if __name__ == '__main__': configure() + + # Python 3.12 has a new way to determine this, + # see https://github.com/talkpython/htmx-python-course/issues/8#issuecomment-1990894657 being_debugged = sys.gettrace() is not None + being_debugged = being_debugged or sys.monitoring.get_tool(sys.monitoring.DEBUGGER_ID) is not None + app.run(debug=being_debugged) else: configure() diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/app.py b/code/ch7_infinite_scroll/ch7_final_video_collector/app.py index 4dd198b..1a92d31 100644 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/app.py +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/app.py @@ -49,7 +49,13 @@ def setup_db(): if __name__ == '__main__': configure() + + # Python 3.12 has a new way to determine this, + # see https://github.com/talkpython/htmx-python-course/issues/8#issuecomment-1990894657 being_debugged = sys.gettrace() is not None + being_debugged = being_debugged or sys.monitoring.get_tool(sys.monitoring.DEBUGGER_ID) is not None + + print(f'{being_debugged=}') app.run(debug=being_debugged) else: configure() diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/app.py b/code/ch7_infinite_scroll/ch7_starter_video_collector/app.py index 4dd198b..c4963a5 100644 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/app.py +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/app.py @@ -49,7 +49,12 @@ def setup_db(): if __name__ == '__main__': configure() + + # Python 3.12 has a new way to determine this, + # see https://github.com/talkpython/htmx-python-course/issues/8#issuecomment-1990894657 being_debugged = sys.gettrace() is not None + being_debugged = being_debugged or sys.monitoring.get_tool(sys.monitoring.DEBUGGER_ID) is not None + app.run(debug=being_debugged) else: configure() diff --git a/code/starter_video_collector/app.py b/code/starter_video_collector/app.py index dced78d..71fa232 100644 --- a/code/starter_video_collector/app.py +++ b/code/starter_video_collector/app.py @@ -47,7 +47,12 @@ def setup_db(): if __name__ == '__main__': configure() + + # Python 3.12 has a new way to determine this, + # see https://github.com/talkpython/htmx-python-course/issues/8#issuecomment-1990894657 being_debugged = sys.gettrace() is not None + being_debugged = being_debugged or sys.monitoring.get_tool(sys.monitoring.DEBUGGER_ID) is not None + app.run(debug=being_debugged) else: configure() From 5363b79926fa84ac944960e2f2b842e445f60800 Mon Sep 17 00:00:00 2001 From: Michael Kennedy <michael@talkpython.fm> Date: Mon, 1 Jul 2024 11:46:53 -0700 Subject: [PATCH 18/21] Update to the latest dependencies. --- requirements.txt | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/requirements.txt b/requirements.txt index 959604b..7c7d2f7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,30 +1,38 @@ # This file was autogenerated by uv via the following command: # uv pip compile requirements.piptools --output-file requirements.txt -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -blinker==1.7.0 +blinker==1.8.2 # via flask click==8.1.7 # via flask -flask==3.0.2 -itsdangerous==2.1.2 +flask==3.0.3 + # via -r requirements.piptools +itsdangerous==2.2.0 # via flask -jinja-partials==0.2.0 -jinja2==3.1.3 +jinja-partials==0.2.1 + # via -r requirements.piptools +jinja2==3.1.4 # via + # -r requirements.piptools # flask # jinja-partials markupsafe==2.1.5 # via + # -r requirements.piptools # jinja2 # werkzeug -more-itertools==10.2.0 -pydantic==2.6.3 -pydantic-core==2.16.3 +more-itertools==10.3.0 + # via -r requirements.piptools +pydantic==2.8.0 + # via -r requirements.piptools +pydantic-core==2.20.0 # via pydantic -typing-extensions==4.10.0 +typing-extensions==4.12.2 # via # pydantic # pydantic-core -werkzeug==3.0.1 - # via flask +werkzeug==3.0.3 + # via + # -r requirements.piptools + # flask From ba5d8ae63c3160ddec42c4d3d471d7b96621b61a Mon Sep 17 00:00:00 2001 From: Michael Kennedy <michael@talkpython.fm> Date: Mon, 1 Jul 2024 11:53:28 -0700 Subject: [PATCH 19/21] Upgrade to the 2.0 release of HTMX (no code changes needed) --- .../static/js/htmx.d.ts | 195 + .../static/js/htmx.js | 8890 ++++++++++------- .../static/js/htmx.min.js | 6 +- .../templates/shared/_layout.html | 2 +- .../static/js/htmx.d.ts | 195 + .../static/js/htmx.js | 8890 ++++++++++------- .../static/js/htmx.min.js | 6 +- .../static/js/htmx.d.ts | 195 + .../static/js/htmx.js | 8890 ++++++++++------- .../static/js/htmx.min.js | 6 +- .../templates/shared/_layout.html | 2 +- .../static/js/htmx.d.ts | 195 + .../static/js/htmx.js | 8890 ++++++++++------- .../static/js/htmx.min.js | 6 +- .../templates/shared/_layout.html | 2 +- .../static/js/htmx.d.ts | 195 + .../static/js/htmx.js | 8890 ++++++++++------- .../static/js/htmx.min.js | 6 +- .../templates/shared/_layout.html | 2 +- .../static/js/htmx.d.ts | 195 + .../static/js/htmx.js | 8890 ++++++++++------- .../static/js/htmx.min.js | 6 +- .../templates/shared/_layout.html | 2 +- .../static/js/htmx.d.ts | 195 + .../static/js/htmx.js | 8890 ++++++++++------- .../static/js/htmx.min.js | 6 +- .../templates/shared/_layout.html | 2 +- .../static/js/htmx.d.ts | 195 + .../static/js/htmx.js | 8890 ++++++++++------- .../static/js/htmx.min.js | 6 +- .../templates/shared/_layout.html | 2 +- .../static/js/htmx.d.ts | 195 + .../starter_video_collector/static/js/htmx.js | 8890 ++++++++++------- .../static/js/htmx.min.js | 6 +- 34 files changed, 47284 insertions(+), 34549 deletions(-) create mode 100644 code/ch4_app/ch4_final_video_collector/static/js/htmx.d.ts create mode 100644 code/ch4_app/ch4_starter_video_collector/static/js/htmx.d.ts create mode 100644 code/ch5_partials/ch5_final_video_collector/static/js/htmx.d.ts create mode 100644 code/ch5_partials/ch5_starter_video_collector/static/js/htmx.d.ts create mode 100644 code/ch6_active_search/ch6_final_video_collector/static/js/htmx.d.ts create mode 100644 code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.d.ts create mode 100644 code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.d.ts create mode 100644 code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.d.ts create mode 100644 code/starter_video_collector/static/js/htmx.d.ts diff --git a/code/ch4_app/ch4_final_video_collector/static/js/htmx.d.ts b/code/ch4_app/ch4_final_video_collector/static/js/htmx.d.ts new file mode 100644 index 0000000..3775459 --- /dev/null +++ b/code/ch4_app/ch4_final_video_collector/static/js/htmx.d.ts @@ -0,0 +1,195 @@ +declare namespace htmx { + const onLoad: (callback: (elt: Node) => void) => EventListener; + const process: (elt: string | Element) => void; + const on: (arg1: string | EventTarget, arg2: string | EventListener, arg3?: EventListener) => EventListener; + const off: (arg1: string | EventTarget, arg2: string | EventListener, arg3?: EventListener) => EventListener; + const trigger: (elt: string | EventTarget, eventName: string, detail?: any) => boolean; + const ajax: (verb: HttpVerb, path: string, context: string | Element | HtmxAjaxHelperContext) => Promise<void>; + const find: (eltOrSelector: string | ParentNode, selector?: string) => Element; + const findAll: (eltOrSelector: string | ParentNode, selector?: string) => NodeListOf<Element>; + const closest: (elt: string | Element, selector: string) => Element; + function values(elt: Element, type: HttpVerb): any; + const remove: (elt: Node, delay?: number) => void; + const addClass: (elt: string | Element, clazz: string, delay?: number) => void; + const removeClass: (node: string | Node, clazz: string, delay?: number) => void; + const toggleClass: (elt: string | Element, clazz: string) => void; + const takeClass: (elt: string | Node, clazz: string) => void; + const swap: (target: string | Element, content: string, swapSpec: HtmxSwapSpecification, swapOptions?: SwapOptions) => void; + const defineExtension: (name: string, extension: any) => void; + const removeExtension: (name: string) => void; + const logAll: () => void; + const logNone: () => void; + const logger: any; + namespace config { + const historyEnabled: boolean; + const historyCacheSize: number; + const refreshOnHistoryMiss: boolean; + const defaultSwapStyle: HtmxSwapStyle; + const defaultSwapDelay: number; + const defaultSettleDelay: number; + const includeIndicatorStyles: boolean; + const indicatorClass: string; + const requestClass: string; + const addedClass: string; + const settlingClass: string; + const swappingClass: string; + const allowEval: boolean; + const allowScriptTags: boolean; + const inlineScriptNonce: string; + const inlineStyleNonce: string; + const attributesToSettle: string[]; + const withCredentials: boolean; + const timeout: number; + const wsReconnectDelay: "full-jitter" | ((retryCount: number) => number); + const wsBinaryType: BinaryType; + const disableSelector: string; + const scrollBehavior: 'auto' | 'instant' | 'smooth'; + const defaultFocusScroll: boolean; + const getCacheBusterParam: boolean; + const globalViewTransitions: boolean; + const methodsThatUseUrlParams: (HttpVerb)[]; + const selfRequestsOnly: boolean; + const ignoreTitle: boolean; + const scrollIntoViewOnBoost: boolean; + const triggerSpecsCache: any | null; + const disableInheritance: boolean; + const responseHandling: HtmxResponseHandlingConfig[]; + const allowNestedOobSwaps: boolean; + } + const parseInterval: (str: string) => number; + const _: (str: string) => any; + const version: string; +} +type HttpVerb = 'get' | 'head' | 'post' | 'put' | 'delete' | 'connect' | 'options' | 'trace' | 'patch'; +type SwapOptions = { + select?: string; + selectOOB?: string; + eventInfo?: any; + anchor?: string; + contextElement?: Element; + afterSwapCallback?: swapCallback; + afterSettleCallback?: swapCallback; +}; +type swapCallback = () => any; +type HtmxSwapStyle = 'innerHTML' | 'outerHTML' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'delete' | 'none' | string; +type HtmxSwapSpecification = { + swapStyle: HtmxSwapStyle; + swapDelay: number; + settleDelay: number; + transition?: boolean; + ignoreTitle?: boolean; + head?: string; + scroll?: 'top' | 'bottom'; + scrollTarget?: string; + show?: string; + showTarget?: string; + focusScroll?: boolean; +}; +type ConditionalFunction = ((this: Node, evt: Event) => boolean) & { + source: string; +}; +type HtmxTriggerSpecification = { + trigger: string; + pollInterval?: number; + eventFilter?: ConditionalFunction; + changed?: boolean; + once?: boolean; + consume?: boolean; + delay?: number; + from?: string; + target?: string; + throttle?: number; + queue?: string; + root?: string; + threshold?: string; +}; +type HtmxElementValidationError = { + elt: Element; + message: string; + validity: ValidityState; +}; +type HtmxHeaderSpecification = Record<string, string>; +type HtmxAjaxHelperContext = { + source?: Element | string; + event?: Event; + handler?: HtmxAjaxHandler; + target: Element | string; + swap?: HtmxSwapStyle; + values?: any | FormData; + headers?: Record<string, string>; + select?: string; +}; +type HtmxRequestConfig = { + boosted: boolean; + useUrlParams: boolean; + formData: FormData; + /** + * formData proxy + */ + parameters: any; + unfilteredFormData: FormData; + /** + * unfilteredFormData proxy + */ + unfilteredParameters: any; + headers: HtmxHeaderSpecification; + target: Element; + verb: HttpVerb; + errors: HtmxElementValidationError[]; + withCredentials: boolean; + timeout: number; + path: string; + triggeringEvent: Event; +}; +type HtmxResponseInfo = { + xhr: XMLHttpRequest; + target: Element; + requestConfig: HtmxRequestConfig; + etc: HtmxAjaxEtc; + boosted: boolean; + select: string; + pathInfo: { + requestPath: string; + finalRequestPath: string; + responsePath: string | null; + anchor: string; + }; + failed?: boolean; + successful?: boolean; +}; +type HtmxAjaxEtc = { + returnPromise?: boolean; + handler?: HtmxAjaxHandler; + select?: string; + targetOverride?: Element; + swapOverride?: HtmxSwapStyle; + headers?: Record<string, string>; + values?: any | FormData; + credentials?: boolean; + timeout?: number; +}; +type HtmxResponseHandlingConfig = { + code?: string; + swap: boolean; + error?: boolean; + ignoreTitle?: boolean; + select?: string; + target?: string; + swapOverride?: string; + event?: string; +}; +type HtmxBeforeSwapDetails = HtmxResponseInfo & { + shouldSwap: boolean; + serverResponse: any; + isError: boolean; + ignoreTitle: boolean; + selectOverride: string; +}; +type HtmxAjaxHandler = (elt: Element, responseInfo: HtmxResponseInfo) => any; +type HtmxSettleTask = (() => void); +type HtmxSettleInfo = { + tasks: HtmxSettleTask[]; + elts: Element[]; + title?: string; +}; +type HtmxExtension = any; diff --git a/code/ch4_app/ch4_final_video_collector/static/js/htmx.js b/code/ch4_app/ch4_final_video_collector/static/js/htmx.js index 86e7668..c57bcd7 100644 --- a/code/ch4_app/ch4_final_video_collector/static/js/htmx.js +++ b/code/ch4_app/ch4_final_video_collector/static/js/htmx.js @@ -1,3909 +1,5131 @@ -// /////////////////////////////////////////////////////////////////// -// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.js -// - -// UMD insanity -// This code sets up support for (in order) AMD, ES6 modules, and globals. -(function (root, factory) { - //@ts-ignore - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - //@ts-ignore - define([], factory); - } else if (typeof module === 'object' && module.exports) { - // Node. Does not work with strict CommonJS, but - // only CommonJS-like environments that support module.exports, - // like Node. - module.exports = factory(); - } else { - // Browser globals - root.htmx = root.htmx || factory(); - } -}(typeof self !== 'undefined' ? self : this, function () { -return (function () { - 'use strict'; - - // Public API - //** @type {import("./htmx").HtmxApi} */ - // TODO: list all methods in public API - var htmx = { - onLoad: onLoadHelper, - process: processNode, - on: addEventListenerImpl, - off: removeEventListenerImpl, - trigger : triggerEvent, - ajax : ajaxHelper, - find : find, - findAll : findAll, - closest : closest, - values : function(elt, type){ - var inputValues = getInputValues(elt, type || "post"); - return inputValues.values; - }, - remove : removeElement, - addClass : addClassToElement, - removeClass : removeClassFromElement, - toggleClass : toggleClassOnElement, - takeClass : takeClassForElement, - defineExtension : defineExtension, - removeExtension : removeExtension, - logAll : logAll, - logNone : logNone, - logger : null, - config : { - historyEnabled:true, - historyCacheSize:10, - refreshOnHistoryMiss:false, - defaultSwapStyle:'innerHTML', - defaultSwapDelay:0, - defaultSettleDelay:20, - includeIndicatorStyles:true, - indicatorClass:'htmx-indicator', - requestClass:'htmx-request', - addedClass:'htmx-added', - settlingClass:'htmx-settling', - swappingClass:'htmx-swapping', - allowEval:true, - allowScriptTags:true, - inlineScriptNonce:'', - attributesToSettle:["class", "style", "width", "height"], - withCredentials:false, - timeout:0, - wsReconnectDelay: 'full-jitter', - wsBinaryType: 'blob', - disableSelector: "[hx-disable], [data-hx-disable]", - useTemplateFragments: false, - scrollBehavior: 'smooth', - defaultFocusScroll: false, - getCacheBusterParam: false, - globalViewTransitions: false, - methodsThatUseUrlParams: ["get"], - selfRequestsOnly: false, - ignoreTitle: false, - scrollIntoViewOnBoost: true, - triggerSpecsCache: null, - }, - parseInterval:parseInterval, - _:internalEval, - createEventSource: function(url){ - return new EventSource(url, {withCredentials:true}) - }, - createWebSocket: function(url){ - var sock = new WebSocket(url, []); - sock.binaryType = htmx.config.wsBinaryType; - return sock; - }, - version: "1.9.10" - }; - - /** @type {import("./htmx").HtmxInternalApi} */ - var internalAPI = { - addTriggerHandler: addTriggerHandler, - bodyContains: bodyContains, - canAccessLocalStorage: canAccessLocalStorage, - findThisElement: findThisElement, - filterValues: filterValues, - hasAttribute: hasAttribute, - getAttributeValue: getAttributeValue, - getClosestAttributeValue: getClosestAttributeValue, - getClosestMatch: getClosestMatch, - getExpressionVars: getExpressionVars, - getHeaders: getHeaders, - getInputValues: getInputValues, - getInternalData: getInternalData, - getSwapSpecification: getSwapSpecification, - getTriggerSpecs: getTriggerSpecs, - getTarget: getTarget, - makeFragment: makeFragment, - mergeObjects: mergeObjects, - makeSettleInfo: makeSettleInfo, - oobSwap: oobSwap, - querySelectorExt: querySelectorExt, - selectAndSwap: selectAndSwap, - settleImmediately: settleImmediately, - shouldCancel: shouldCancel, - triggerEvent: triggerEvent, - triggerErrorEvent: triggerErrorEvent, - withExtensions: withExtensions, - } - - var VERBS = ['get', 'post', 'put', 'delete', 'patch']; - var VERB_SELECTOR = VERBS.map(function(verb){ - return "[hx-" + verb + "], [data-hx-" + verb + "]" - }).join(", "); - - var HEAD_TAG_REGEX = makeTagRegEx('head'), - TITLE_TAG_REGEX = makeTagRegEx('title'), - SVG_TAGS_REGEX = makeTagRegEx('svg', true); - - //==================================================================== - // Utilities - //==================================================================== - - /** - * @param {string} tag - * @param {boolean} global - * @returns {RegExp} - */ - function makeTagRegEx(tag, global = false) { - return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, - global ? 'gim' : 'im'); - } - - function parseInterval(str) { - if (str == undefined) { - return undefined; - } - - let interval = NaN; - if (str.slice(-2) == "ms") { - interval = parseFloat(str.slice(0, -2)); - } else if (str.slice(-1) == "s") { - interval = parseFloat(str.slice(0, -1)) * 1000; - } else if (str.slice(-1) == "m") { - interval = parseFloat(str.slice(0, -1)) * 1000 * 60; - } else { - interval = parseFloat(str); - } - return isNaN(interval) ? undefined : interval; - } - - /** - * @param {HTMLElement} elt - * @param {string} name - * @returns {(string | null)} - */ - function getRawAttribute(elt, name) { - return elt.getAttribute && elt.getAttribute(name); - } - - // resolve with both hx and data-hx prefixes - function hasAttribute(elt, qualifiedName) { - return elt.hasAttribute && (elt.hasAttribute(qualifiedName) || - elt.hasAttribute("data-" + qualifiedName)); - } - - /** - * - * @param {HTMLElement} elt - * @param {string} qualifiedName - * @returns {(string | null)} - */ - function getAttributeValue(elt, qualifiedName) { - return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); - } - - /** - * @param {HTMLElement} elt - * @returns {HTMLElement | null} - */ - function parentElt(elt) { - return elt.parentElement; - } - - /** - * @returns {Document} - */ - function getDocument() { - return document; - } - - /** - * @param {HTMLElement} elt - * @param {(e:HTMLElement) => boolean} condition - * @returns {HTMLElement | null} - */ - function getClosestMatch(elt, condition) { - while (elt && !condition(elt)) { - elt = parentElt(elt); - } - - return elt ? elt : null; - } - - function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ - var attributeValue = getAttributeValue(ancestor, attributeName); - var disinherit = getAttributeValue(ancestor, "hx-disinherit"); - if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) { - return "unset"; - } else { - return attributeValue - } - } - - /** - * @param {HTMLElement} elt - * @param {string} attributeName - * @returns {string | null} - */ - function getClosestAttributeValue(elt, attributeName) { - var closestAttr = null; - getClosestMatch(elt, function (e) { - return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName); - }); - if (closestAttr !== "unset") { - return closestAttr; - } - } - - /** - * @param {HTMLElement} elt - * @param {string} selector - * @returns {boolean} - */ - function matches(elt, selector) { - // @ts-ignore: non-standard properties for browser compatibility - // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; - return matchesFunction && matchesFunction.call(elt, selector); - } - - /** - * @param {string} str - * @returns {string} - */ - 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 ""; - } - } - - /** - * - * @param {string} resp - * @param {number} depth - * @returns {Element} - */ - function parseHTML(resp, depth) { - var parser = new DOMParser(); - var responseDoc = parser.parseFromString(resp, "text/html"); - - /** @type {Element} */ - var responseNode = responseDoc.body; - while (depth > 0) { - depth--; - // @ts-ignore - responseNode = responseNode.firstChild; - } - if (responseNode == null) { - // @ts-ignore - responseNode = getDocument().createDocumentFragment(); - } - return responseNode; - } - - function aFullPageResponse(resp) { - return /<body/.test(resp) - } +// v2.0.0 from https://github.com/bigskysoftware/htmx/releases + +var htmx = (function() { + 'use strict' + + // Public API + const htmx = { + // Tsc madness here, assigning the functions directly results in an invalid TypeScript output, but reassigning is fine + /* Event processing */ + /** @type {typeof onLoadHelper} */ + onLoad: null, + /** @type {typeof processNode} */ + process: null, + /** @type {typeof addEventListenerImpl} */ + on: null, + /** @type {typeof removeEventListenerImpl} */ + off: null, + /** @type {typeof triggerEvent} */ + trigger: null, + /** @type {typeof ajaxHelper} */ + ajax: null, + /* DOM querying helpers */ + /** @type {typeof find} */ + find: null, + /** @type {typeof findAll} */ + findAll: null, + /** @type {typeof closest} */ + closest: null, + /** + * Returns the input values that would resolve for a given element via the htmx value resolution mechanism + * + * @see https://htmx.org/api/#values + * + * @param {Element} elt the element to resolve values on + * @param {HttpVerb} type the request type (e.g. **get** or **post**) non-GET's will include the enclosing form of the element. Defaults to **post** + * @returns {Object} + */ + values: function(elt, type) { + const inputValues = getInputValues(elt, type || 'post') + return inputValues.values + }, + /* DOM manipulation helpers */ + /** @type {typeof removeElement} */ + remove: null, + /** @type {typeof addClassToElement} */ + addClass: null, + /** @type {typeof removeClassFromElement} */ + removeClass: null, + /** @type {typeof toggleClassOnElement} */ + toggleClass: null, + /** @type {typeof takeClassForElement} */ + takeClass: null, + /** @type {typeof swap} */ + swap: null, + /* Extension entrypoints */ + /** @type {typeof defineExtension} */ + defineExtension: null, + /** @type {typeof removeExtension} */ + removeExtension: null, + /* Debugging */ + /** @type {typeof logAll} */ + logAll: null, + /** @type {typeof logNone} */ + logNone: null, + /* Debugging */ + /** + * The logger htmx uses to log with + * + * @see https://htmx.org/api/#logger + */ + logger: null, + /** + * A property holding the configuration htmx uses at runtime. + * + * Note that using a [meta tag](https://htmx.org/docs/#config) is the preferred mechanism for setting these properties. + * + * @see https://htmx.org/api/#config + */ + config: { + /** + * Whether to use history. + * @type boolean + * @default true + */ + historyEnabled: true, + /** + * The number of pages to keep in **localStorage** for history support. + * @type number + * @default 10 + */ + historyCacheSize: 10, + /** + * @type boolean + * @default false + */ + refreshOnHistoryMiss: false, + /** + * The default swap style to use if **[hx-swap](https://htmx.org/attributes/hx-swap)** is omitted. + * @type HtmxSwapStyle + * @default 'innerHTML' + */ + defaultSwapStyle: 'innerHTML', + /** + * The default delay between receiving a response from the server and doing the swap. + * @type number + * @default 0 + */ + defaultSwapDelay: 0, + /** + * The default delay between completing the content swap and settling attributes. + * @type number + * @default 20 + */ + defaultSettleDelay: 20, + /** + * If true, htmx will inject a small amount of CSS into the page to make indicators invisible unless the **htmx-indicator** class is present. + * @type boolean + * @default true + */ + includeIndicatorStyles: true, + /** + * The class to place on indicators when a request is in flight. + * @type string + * @default 'htmx-indicator' + */ + indicatorClass: 'htmx-indicator', + /** + * The class to place on triggering elements when a request is in flight. + * @type string + * @default 'htmx-request' + */ + requestClass: 'htmx-request', + /** + * The class to temporarily place on elements that htmx has added to the DOM. + * @type string + * @default 'htmx-added' + */ + addedClass: 'htmx-added', + /** + * The class to place on target elements when htmx is in the settling phase. + * @type string + * @default 'htmx-settling' + */ + settlingClass: 'htmx-settling', + /** + * The class to place on target elements when htmx is in the swapping phase. + * @type string + * @default 'htmx-swapping' + */ + swappingClass: 'htmx-swapping', + /** + * Allows the use of eval-like functionality in htmx, to enable **hx-vars**, trigger conditions & script tag evaluation. Can be set to **false** for CSP compatibility. + * @type boolean + * @default true + */ + allowEval: true, + /** + * If set to false, disables the interpretation of script tags. + * @type boolean + * @default true + */ + allowScriptTags: true, + /** + * If set, the nonce will be added to inline scripts. + * @type string + * @default '' + */ + inlineScriptNonce: '', + /** + * If set, the nonce will be added to inline styles. + * @type string + * @default '' + */ + inlineStyleNonce: '', + /** + * The attributes to settle during the settling phase. + * @type string[] + * @default ['class', 'style', 'width', 'height'] + */ + attributesToSettle: ['class', 'style', 'width', 'height'], + /** + * Allow cross-site Access-Control requests using credentials such as cookies, authorization headers or TLS client certificates. + * @type boolean + * @default false + */ + withCredentials: false, + /** + * @type number + * @default 0 + */ + timeout: 0, + /** + * The default implementation of **getWebSocketReconnectDelay** for reconnecting after unexpected connection loss by the event code **Abnormal Closure**, **Service Restart** or **Try Again Later**. + * @type {'full-jitter' | ((retryCount:number) => number)} + * @default "full-jitter" + */ + wsReconnectDelay: 'full-jitter', + /** + * The type of binary data being received over the WebSocket connection + * @type BinaryType + * @default 'blob' + */ + wsBinaryType: 'blob', + /** + * @type string + * @default '[hx-disable], [data-hx-disable]' + */ + disableSelector: '[hx-disable], [data-hx-disable]', + /** + * @type {'auto' | 'instant' | 'smooth'} + * @default 'smooth' + */ + scrollBehavior: 'instant', + /** + * If the focused element should be scrolled into view. + * @type boolean + * @default false + */ + defaultFocusScroll: false, + /** + * If set to true htmx will include a cache-busting parameter in GET requests to avoid caching partial responses by the browser + * @type boolean + * @default false + */ + getCacheBusterParam: false, + /** + * If set to true, htmx will use the View Transition API when swapping in new content. + * @type boolean + * @default false + */ + globalViewTransitions: false, + /** + * htmx will format requests with these methods by encoding their parameters in the URL, not the request body + * @type {(HttpVerb)[]} + * @default ['get', 'delete'] + */ + methodsThatUseUrlParams: ['get', 'delete'], + /** + * If set to true, disables htmx-based requests to non-origin hosts. + * @type boolean + * @default false + */ + selfRequestsOnly: true, + /** + * If set to true htmx will not update the title of the document when a title tag is found in new content + * @type boolean + * @default false + */ + ignoreTitle: false, + /** + * Whether the target of a boosted element is scrolled into the viewport. + * @type boolean + * @default true + */ + scrollIntoViewOnBoost: true, + /** + * The cache to store evaluated trigger specifications into. + * You may define a simple object to use a never-clearing cache, or implement your own system using a [proxy object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Proxy) + * @type {Object|null} + * @default null + */ + triggerSpecsCache: null, + /** @type boolean */ + disableInheritance: false, + /** @type HtmxResponseHandlingConfig[] */ + responseHandling: [ + { code: '204', swap: false }, + { code: '[23]..', swap: true }, + { code: '[45]..', swap: false, error: true } + ], + /** + * Whether to process OOB swaps on elements that are nested within the main response element. + * @type boolean + * @default true + */ + allowNestedOobSwaps: true + }, + /** @type {typeof parseInterval} */ + parseInterval: null, + /** @type {typeof internalEval} */ + _: null, + version: '2.0.0' + } + // Tsc madness part 2 + htmx.onLoad = onLoadHelper + htmx.process = processNode + htmx.on = addEventListenerImpl + htmx.off = removeEventListenerImpl + htmx.trigger = triggerEvent + htmx.ajax = ajaxHelper + htmx.find = find + htmx.findAll = findAll + htmx.closest = closest + htmx.remove = removeElement + htmx.addClass = addClassToElement + htmx.removeClass = removeClassFromElement + htmx.toggleClass = toggleClassOnElement + htmx.takeClass = takeClassForElement + htmx.swap = swap + htmx.defineExtension = defineExtension + htmx.removeExtension = removeExtension + htmx.logAll = logAll + htmx.logNone = logNone + htmx.parseInterval = parseInterval + htmx._ = internalEval + + const internalAPI = { + addTriggerHandler, + bodyContains, + canAccessLocalStorage, + findThisElement, + filterValues, + swap, + hasAttribute, + getAttributeValue, + getClosestAttributeValue, + getClosestMatch, + getExpressionVars, + getHeaders, + getInputValues, + getInternalData, + getSwapSpecification, + getTriggerSpecs, + getTarget, + makeFragment, + mergeObjects, + makeSettleInfo, + oobSwap, + querySelectorExt, + settleImmediately, + shouldCancel, + triggerEvent, + triggerErrorEvent, + withExtensions + } + + const VERBS = ['get', 'post', 'put', 'delete', 'patch'] + const VERB_SELECTOR = VERBS.map(function(verb) { + return '[hx-' + verb + '], [data-hx-' + verb + ']' + }).join(', ') + + const HEAD_TAG_REGEX = makeTagRegEx('head') + + //= =================================================================== + // Utilities + //= =================================================================== + + /** + * @param {string} tag + * @param {boolean} global + * @returns {RegExp} + */ + function makeTagRegEx(tag, global = false) { + return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, + global ? 'gim' : 'im') + } + + /** + * Parses an interval string consistent with the way htmx does. Useful for plugins that have timing-related attributes. + * + * Caution: Accepts an int followed by either **s** or **ms**. All other values use **parseFloat** + * + * @see https://htmx.org/api/#parseInterval + * + * @param {string} str timing string + * @returns {number|undefined} + */ + function parseInterval(str) { + if (str == undefined) { + return undefined + } - /** - * - * @param {string} response - * @returns {Element} - */ - function makeFragment(response) { - var partialResponse = !aFullPageResponse(response); - var startTag = getStartTag(response); - var content = response; - if (startTag === 'head') { - content = content.replace(HEAD_TAG_REGEX, ''); - } - if (htmx.config.useTemplateFragments && partialResponse) { - var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0); - // @ts-ignore type mismatch between DocumentFragment and Element. - // TODO: Are these close enough for htmx to use interchangeably? - return documentFragment.querySelector('template').content; - } - switch (startTag) { - case "thead": - case "tbody": - case "tfoot": - case "colgroup": - case "caption": - return parseHTML("<table>" + content + "</table>", 1); - case "col": - return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2); - case "tr": - return parseHTML("<table><tbody>" + content + "</tbody></table>", 2); - case "td": - case "th": - return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3); - case "script": - case "style": - return parseHTML("<div>" + content + "</div>", 1); - default: - return parseHTML(content, 0); - } - } + let interval = NaN + if (str.slice(-2) == 'ms') { + interval = parseFloat(str.slice(0, -2)) + } else if (str.slice(-1) == 's') { + interval = parseFloat(str.slice(0, -1)) * 1000 + } else if (str.slice(-1) == 'm') { + interval = parseFloat(str.slice(0, -1)) * 1000 * 60 + } else { + interval = parseFloat(str) + } + return isNaN(interval) ? undefined : interval + } + + /** + * @param {Node} elt + * @param {string} name + * @returns {(string | null)} + */ + function getRawAttribute(elt, name) { + return elt instanceof Element && elt.getAttribute(name) + } + + /** + * @param {Element} elt + * @param {string} qualifiedName + * @returns {boolean} + */ + // resolve with both hx and data-hx prefixes + function hasAttribute(elt, qualifiedName) { + return !!elt.hasAttribute && (elt.hasAttribute(qualifiedName) || + elt.hasAttribute('data-' + qualifiedName)) + } + + /** + * + * @param {Node} elt + * @param {string} qualifiedName + * @returns {(string | null)} + */ + function getAttributeValue(elt, qualifiedName) { + return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, 'data-' + qualifiedName) + } + + /** + * @param {Node} elt + * @returns {Node | null} + */ + function parentElt(elt) { + const parent = elt.parentElement + if (!parent && elt.parentNode instanceof ShadowRoot) return elt.parentNode + return parent + } + + /** + * @returns {Document} + */ + function getDocument() { + return document + } + + /** + * @param {Node} elt + * @param {boolean} global + * @returns {Node|Document} + */ + function getRootNode(elt, global) { + return elt.getRootNode ? elt.getRootNode({ composed: global }) : getDocument() + } + + /** + * @param {Node} elt + * @param {(e:Node) => boolean} condition + * @returns {Node | null} + */ + function getClosestMatch(elt, condition) { + while (elt && !condition(elt)) { + elt = parentElt(elt) + } - /** - * @param {Function} func - */ - function maybeCall(func){ - if(func) { - func(); - } + return elt || null + } + + /** + * @param {Element} initialElement + * @param {Element} ancestor + * @param {string} attributeName + * @returns {string|null} + */ + function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName) { + const attributeValue = getAttributeValue(ancestor, attributeName) + const disinherit = getAttributeValue(ancestor, 'hx-disinherit') + var inherit = getAttributeValue(ancestor, 'hx-inherit') + if (initialElement !== ancestor) { + if (htmx.config.disableInheritance) { + if (inherit && (inherit === '*' || inherit.split(' ').indexOf(attributeName) >= 0)) { + return attributeValue + } else { + return null + } + } + if (disinherit && (disinherit === '*' || disinherit.split(' ').indexOf(attributeName) >= 0)) { + return 'unset' + } + } + return attributeValue + } + + /** + * @param {Element} elt + * @param {string} attributeName + * @returns {string | null} + */ + function getClosestAttributeValue(elt, attributeName) { + let closestAttr = null + getClosestMatch(elt, function(e) { + return !!(closestAttr = getAttributeValueWithDisinheritance(elt, asElement(e), attributeName)) + }) + if (closestAttr !== 'unset') { + return closestAttr + } + } + + /** + * @param {Node} elt + * @param {string} selector + * @returns {boolean} + */ + function matches(elt, selector) { + // @ts-ignore: non-standard properties for browser compatibility + // noinspection JSUnresolvedVariable + const matchesFunction = elt instanceof Element && (elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector) + return !!matchesFunction && matchesFunction.call(elt, selector) + } + + /** + * @param {string} str + * @returns {string} + */ + function getStartTag(str) { + const tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i + const match = tagMatcher.exec(str) + if (match) { + return match[1].toLowerCase() + } else { + return '' + } + } + + /** + * @param {string} resp + * @returns {Document} + */ + function parseHTML(resp) { + const parser = new DOMParser() + return parser.parseFromString(resp, 'text/html') + } + + /** + * @param {DocumentFragment} fragment + * @param {Node} elt + */ + function takeChildrenFor(fragment, elt) { + while (elt.childNodes.length > 0) { + fragment.append(elt.childNodes[0]) + } + } + + /** + * @param {HTMLScriptElement} script + * @returns {HTMLScriptElement} + */ + function duplicateScript(script) { + const newScript = getDocument().createElement('script') + forEach(script.attributes, function(attr) { + newScript.setAttribute(attr.name, attr.value) + }) + newScript.textContent = script.textContent + newScript.async = false + if (htmx.config.inlineScriptNonce) { + newScript.nonce = htmx.config.inlineScriptNonce + } + return newScript + } + + /** + * @param {HTMLScriptElement} script + * @returns {boolean} + */ + function isJavaScriptScriptNode(script) { + return script.matches('script') && (script.type === 'text/javascript' || script.type === 'module' || script.type === '') + } + + /** + * we have to make new copies of script tags that we are going to insert because + * SOME browsers (not saying who, but it involves an element and an animal) don't + * execute scripts created in <template> tags when they are inserted into the DOM + * and all the others do lmao + * @param {DocumentFragment} fragment + */ + function normalizeScriptTags(fragment) { + Array.from(fragment.querySelectorAll('script')).forEach(/** @param {HTMLScriptElement} script */ (script) => { + if (isJavaScriptScriptNode(script)) { + const newScript = duplicateScript(script) + const parent = script.parentNode + try { + parent.insertBefore(newScript, script) + } catch (e) { + logError(e) + } finally { + script.remove() + } + } + }) + } + + /** + * @typedef {DocumentFragment & {title?: string}} DocumentFragmentWithTitle + * @description a document fragment representing the response HTML, including + * a `title` property for any title information found + */ + + /** + * @param {string} response HTML + * @returns {DocumentFragmentWithTitle} + */ + function makeFragment(response) { + // strip head tag to determine shape of response we are dealing with + const responseWithNoHead = response.replace(HEAD_TAG_REGEX, '') + const startTag = getStartTag(responseWithNoHead) + /** @type DocumentFragmentWithTitle */ + let fragment + if (startTag === 'html') { + // if it is a full document, parse it and return the body + fragment = /** @type DocumentFragmentWithTitle */ (new DocumentFragment()) + const doc = parseHTML(response) + takeChildrenFor(fragment, doc.body) + fragment.title = doc.title + } else if (startTag === 'body') { + // parse body w/o wrapping in template + fragment = /** @type DocumentFragmentWithTitle */ (new DocumentFragment()) + const doc = parseHTML(responseWithNoHead) + takeChildrenFor(fragment, doc.body) + fragment.title = doc.title + } else { + // otherwise we have non-body partial HTML content, so wrap it in a template to maximize parsing flexibility + const doc = parseHTML('<body><template class="internal-htmx-wrapper">' + responseWithNoHead + '</template></body>') + fragment = /** @type DocumentFragmentWithTitle */ (doc.querySelector('template').content) + // extract title into fragment for later processing + fragment.title = doc.title + + // for legacy reasons we support a title tag at the root level of non-body responses, so we need to handle it + var titleElement = fragment.querySelector('title') + if (titleElement && titleElement.parentNode === fragment) { + titleElement.remove() + fragment.title = titleElement.innerText + } + } + if (fragment) { + if (htmx.config.allowScriptTags) { + normalizeScriptTags(fragment) + } else { + // remove all script tags if scripts are disabled + fragment.querySelectorAll('script').forEach((script) => script.remove()) + } + } + return fragment + } + + /** + * @param {Function} func + */ + function maybeCall(func) { + if (func) { + func() + } + } + + /** + * @param {any} o + * @param {string} type + * @returns + */ + function isType(o, type) { + return Object.prototype.toString.call(o) === '[object ' + type + ']' + } + + /** + * @param {*} o + * @returns {o is Function} + */ + function isFunction(o) { + return typeof o === 'function' + } + + /** + * @param {*} o + * @returns {o is Object} + */ + function isRawObject(o) { + return isType(o, 'Object') + } + + /** + * @typedef {Object} OnHandler + * @property {(keyof HTMLElementEventMap)|string} event + * @property {EventListener} listener + */ + + /** + * @typedef {Object} ListenerInfo + * @property {string} trigger + * @property {EventListener} listener + * @property {EventTarget} on + */ + + /** + * @typedef {Object} HtmxNodeInternalData + * Element data + * @property {number} [initHash] + * @property {boolean} [boosted] + * @property {OnHandler[]} [onHandlers] + * @property {number} [timeout] + * @property {ListenerInfo[]} [listenerInfos] + * @property {boolean} [cancelled] + * @property {boolean} [triggeredOnce] + * @property {number} [delayed] + * @property {number|null} [throttle] + * @property {string} [lastValue] + * @property {boolean} [loaded] + * @property {string} [path] + * @property {string} [verb] + * @property {boolean} [polling] + * @property {HTMLButtonElement|HTMLInputElement|null} [lastButtonClicked] + * @property {number} [requestCount] + * @property {XMLHttpRequest} [xhr] + * @property {(() => void)[]} [queuedRequests] + * @property {boolean} [abortable] + * + * Event data + * @property {HtmxTriggerSpecification} [triggerSpec] + * @property {EventTarget[]} [handledFor] + */ + + /** + * getInternalData retrieves "private" data stored by htmx within an element + * @param {EventTarget|Event} elt + * @returns {HtmxNodeInternalData} + */ + function getInternalData(elt) { + const dataProp = 'htmx-internal-data' + let data = elt[dataProp] + if (!data) { + data = elt[dataProp] = {} + } + return data + } + + /** + * toArray converts an ArrayLike object into a real array. + * @template T + * @param {ArrayLike<T>} arr + * @returns {T[]} + */ + function toArray(arr) { + const returnArr = [] + if (arr) { + for (let i = 0; i < arr.length; i++) { + returnArr.push(arr[i]) + } + } + return returnArr + } + + /** + * @template T + * @param {T[]|NamedNodeMap|HTMLCollection|HTMLFormControlsCollection|ArrayLike<T>} arr + * @param {(T) => void} func + */ + function forEach(arr, func) { + if (arr) { + for (let i = 0; i < arr.length; i++) { + func(arr[i]) + } + } + } + + /** + * @param {Element} el + * @returns {boolean} + */ + function isScrolledIntoView(el) { + const rect = el.getBoundingClientRect() + const elemTop = rect.top + const elemBottom = rect.bottom + return elemTop < window.innerHeight && elemBottom >= 0 + } + + /** + * @param {Node} elt + * @returns {boolean} + */ + function bodyContains(elt) { + // IE Fix + const rootNode = elt.getRootNode && elt.getRootNode() + if (rootNode && rootNode instanceof window.ShadowRoot) { + return getDocument().body.contains(rootNode.host) + } else { + return getDocument().body.contains(elt) + } + } + + /** + * @param {string} trigger + * @returns {string[]} + */ + function splitOnWhitespace(trigger) { + return trigger.trim().split(/\s+/) + } + + /** + * mergeObjects takes all the keys from + * obj2 and duplicates them into obj1 + * @template T1 + * @template T2 + * @param {T1} obj1 + * @param {T2} obj2 + * @returns {T1 & T2} + */ + function mergeObjects(obj1, obj2) { + for (const key in obj2) { + if (obj2.hasOwnProperty(key)) { + // @ts-ignore tsc doesn't seem to properly handle types merging + obj1[key] = obj2[key] + } + } + // @ts-ignore tsc doesn't seem to properly handle types merging + return obj1 + } + + /** + * @param {string} jString + * @returns {any|null} + */ + function parseJSON(jString) { + try { + return JSON.parse(jString) + } catch (error) { + logError(error) + return null + } + } + + /** + * @returns {boolean} + */ + function canAccessLocalStorage() { + const test = 'htmx:localStorageTest' + try { + localStorage.setItem(test, test) + localStorage.removeItem(test) + return true + } catch (e) { + return false + } + } + + /** + * @param {string} path + * @returns {string} + */ + function normalizePath(path) { + try { + const url = new URL(path) + if (url) { + path = url.pathname + url.search + } + // remove trailing slash, unless index page + if (!(/^\/$/.test(path))) { + path = path.replace(/\/+$/, '') + } + return path + } catch (e) { + // be kind to IE11, which doesn't support URL() + return path + } + } + + //= ========================================================================================= + // public API + //= ========================================================================================= + + /** + * @param {string} str + * @returns {any} + */ + function internalEval(str) { + return maybeEval(getDocument().body, function() { + return eval(str) + }) + } + + /** + * Adds a callback for the **htmx:load** event. This can be used to process new content, for example initializing the content with a javascript library + * + * @see https://htmx.org/api/#onLoad + * + * @param {(elt: Node) => void} callback the callback to call on newly loaded content + * @returns {EventListener} + */ + function onLoadHelper(callback) { + const value = htmx.on('htmx:load', /** @param {CustomEvent} evt */ function(evt) { + callback(evt.detail.elt) + }) + return value + } + + /** + * Log all htmx events, useful for debugging. + * + * @see https://htmx.org/api/#logAll + */ + function logAll() { + htmx.logger = function(elt, event, data) { + if (console) { + console.log(event, elt, data) + } + } + } + + function logNone() { + htmx.logger = null + } + + /** + * Finds an element matching the selector + * + * @see https://htmx.org/api/#find + * + * @param {ParentNode|string} eltOrSelector the root element to find the matching element in, inclusive | the selector to match + * @param {string} [selector] the selector to match + * @returns {Element|null} + */ + function find(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return eltOrSelector.querySelector(selector) + } else { + return find(getDocument(), eltOrSelector) + } + } + + /** + * Finds all elements matching the selector + * + * @see https://htmx.org/api/#findAll + * + * @param {ParentNode|string} eltOrSelector the root element to find the matching elements in, inclusive | the selector to match + * @param {string} [selector] the selector to match + * @returns {NodeListOf<Element>} + */ + function findAll(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return eltOrSelector.querySelectorAll(selector) + } else { + return findAll(getDocument(), eltOrSelector) + } + } + + /** + * @returns Window + */ + function getWindow() { + return window + } + + /** + * Removes an element from the DOM + * + * @see https://htmx.org/api/#remove + * + * @param {Node} elt + * @param {number} [delay] + */ + function removeElement(elt, delay) { + elt = resolveTarget(elt) + if (delay) { + getWindow().setTimeout(function() { + removeElement(elt) + elt = null + }, delay) + } else { + parentElt(elt).removeChild(elt) + } + } + + /** + * @param {any} elt + * @return {Element|null} + */ + function asElement(elt) { + return elt instanceof Element ? elt : null + } + + /** + * @param {any} elt + * @return {HTMLElement|null} + */ + function asHtmlElement(elt) { + return elt instanceof HTMLElement ? elt : null + } + + /** + * @param {any} value + * @return {string|null} + */ + function asString(value) { + return typeof value === 'string' ? value : null + } + + /** + * @param {EventTarget} elt + * @return {ParentNode|null} + */ + function asParentNode(elt) { + return elt instanceof Element || elt instanceof Document || elt instanceof DocumentFragment ? elt : null + } + + /** + * This method adds a class to the given element. + * + * @see https://htmx.org/api/#addClass + * + * @param {Element|string} elt the element to add the class to + * @param {string} clazz the class to add + * @param {number} [delay] the delay (in milliseconds) before class is added + */ + function addClassToElement(elt, clazz, delay) { + elt = asElement(resolveTarget(elt)) + if (!elt) { + return + } + if (delay) { + getWindow().setTimeout(function() { + addClassToElement(elt, clazz) + elt = null + }, delay) + } else { + elt.classList && elt.classList.add(clazz) + } + } + + /** + * Removes a class from the given element + * + * @see https://htmx.org/api/#removeClass + * + * @param {Node|string} node element to remove the class from + * @param {string} clazz the class to remove + * @param {number} [delay] the delay (in milliseconds before class is removed) + */ + function removeClassFromElement(node, clazz, delay) { + let elt = asElement(resolveTarget(node)) + if (!elt) { + return + } + if (delay) { + getWindow().setTimeout(function() { + removeClassFromElement(elt, clazz) + elt = null + }, delay) + } else { + if (elt.classList) { + elt.classList.remove(clazz) + // if there are no classes left, remove the class attribute + if (elt.classList.length === 0) { + elt.removeAttribute('class') } + } + } + } + + /** + * Toggles the given class on an element + * + * @see https://htmx.org/api/#toggleClass + * + * @param {Element|string} elt the element to toggle the class on + * @param {string} clazz the class to toggle + */ + function toggleClassOnElement(elt, clazz) { + elt = resolveTarget(elt) + elt.classList.toggle(clazz) + } + + /** + * Takes the given class from its siblings, so that among its siblings, only the given element will have the class. + * + * @see https://htmx.org/api/#takeClass + * + * @param {Node|string} elt the element that will take the class + * @param {string} clazz the class to take + */ + function takeClassForElement(elt, clazz) { + elt = resolveTarget(elt) + forEach(elt.parentElement.children, function(child) { + removeClassFromElement(child, clazz) + }) + addClassToElement(asElement(elt), clazz) + } + + /** + * Finds the closest matching element in the given elements parentage, inclusive of the element + * + * @see https://htmx.org/api/#closest + * + * @param {Element|string} elt the element to find the selector from + * @param {string} selector the selector to find + * @returns {Element|null} + */ + function closest(elt, selector) { + elt = asElement(resolveTarget(elt)) + if (elt && elt.closest) { + return elt.closest(selector) + } else { + // TODO remove when IE goes away + do { + if (elt == null || matches(elt, selector)) { + return elt + } + } + while (elt = elt && asElement(parentElt(elt))) + return null + } + } + + /** + * @param {string} str + * @param {string} prefix + * @returns {boolean} + */ + function startsWith(str, prefix) { + return str.substring(0, prefix.length) === prefix + } + + /** + * @param {string} str + * @param {string} suffix + * @returns {boolean} + */ + function endsWith(str, suffix) { + return str.substring(str.length - suffix.length) === suffix + } + + /** + * @param {string} selector + * @returns {string} + */ + function normalizeSelector(selector) { + const trimmedSelector = selector.trim() + if (startsWith(trimmedSelector, '<') && endsWith(trimmedSelector, '/>')) { + return trimmedSelector.substring(1, trimmedSelector.length - 2) + } else { + return trimmedSelector + } + } + + /** + * @param {Node|Element|Document|string} elt + * @param {string} selector + * @param {boolean=} global + * @returns {(Node|Window)[]} + */ + function querySelectorAllExt(elt, selector, global) { + elt = resolveTarget(elt) + if (selector.indexOf('closest ') === 0) { + return [closest(asElement(elt), normalizeSelector(selector.substr(8)))] + } else if (selector.indexOf('find ') === 0) { + return [find(asParentNode(elt), normalizeSelector(selector.substr(5)))] + } else if (selector === 'next') { + return [asElement(elt).nextElementSibling] + } else if (selector.indexOf('next ') === 0) { + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)), !!global)] + } else if (selector === 'previous') { + return [asElement(elt).previousElementSibling] + } else if (selector.indexOf('previous ') === 0) { + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)), !!global)] + } else if (selector === 'document') { + return [document] + } else if (selector === 'window') { + return [window] + } else if (selector === 'body') { + return [document.body] + } else if (selector === 'root') { + return [getRootNode(elt, !!global)] + } else if (selector.indexOf('global ') === 0) { + return querySelectorAllExt(elt, selector.slice(7), true) + } else { + return toArray(asParentNode(getRootNode(elt, !!global)).querySelectorAll(normalizeSelector(selector))) + } + } + + /** + * @param {Node} start + * @param {string} match + * @param {boolean} global + * @returns {Element} + */ + var scanForwardQuery = function(start, match, global) { + const results = asParentNode(getRootNode(start, global)).querySelectorAll(match) + for (let i = 0; i < results.length; i++) { + const elt = results[i] + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { + return elt + } + } + } + + /** + * @param {Node} start + * @param {string} match + * @param {boolean} global + * @returns {Element} + */ + var scanBackwardsQuery = function(start, match, global) { + const results = asParentNode(getRootNode(start, global)).querySelectorAll(match) + for (let i = results.length - 1; i >= 0; i--) { + const elt = results[i] + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { + return elt + } + } + } + + /** + * @param {Node|string} eltOrSelector + * @param {string=} selector + * @returns {Node|Window} + */ + function querySelectorExt(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return querySelectorAllExt(eltOrSelector, selector)[0] + } else { + return querySelectorAllExt(getDocument().body, eltOrSelector)[0] + } + } + + /** + * @template {EventTarget} T + * @param {T|string} eltOrSelector + * @param {T} [context] + * @returns {Element|T|null} + */ + function resolveTarget(eltOrSelector, context) { + if (typeof eltOrSelector === 'string') { + return find(asParentNode(context) || document, eltOrSelector) + } else { + return eltOrSelector + } + } + + /** + * @typedef {keyof HTMLElementEventMap|string} AnyEventName + */ + + /** + * @typedef {Object} EventArgs + * @property {EventTarget} target + * @property {AnyEventName} event + * @property {EventListener} listener + */ + + /** + * @param {EventTarget|AnyEventName} arg1 + * @param {AnyEventName|EventListener} arg2 + * @param {EventListener} [arg3] + * @returns {EventArgs} + */ + function processEventArgs(arg1, arg2, arg3) { + if (isFunction(arg2)) { + return { + target: getDocument().body, + event: asString(arg1), + listener: arg2 + } + } else { + return { + target: resolveTarget(arg1), + event: asString(arg2), + listener: arg3 + } + } + } + + /** + * Adds an event listener to an element + * + * @see https://htmx.org/api/#on + * + * @param {EventTarget|string} arg1 the element to add the listener to | the event name to add the listener for + * @param {string|EventListener} arg2 the event name to add the listener for | the listener to add + * @param {EventListener} [arg3] the listener to add + * @returns {EventListener} + */ + function addEventListenerImpl(arg1, arg2, arg3) { + ready(function() { + const eventArgs = processEventArgs(arg1, arg2, arg3) + eventArgs.target.addEventListener(eventArgs.event, eventArgs.listener) + }) + const b = isFunction(arg2) + return b ? arg2 : arg3 + } + + /** + * Removes an event listener from an element + * + * @see https://htmx.org/api/#off + * + * @param {EventTarget|string} arg1 the element to remove the listener from | the event name to remove the listener from + * @param {string|EventListener} arg2 the event name to remove the listener from | the listener to remove + * @param {EventListener} [arg3] the listener to remove + * @returns {EventListener} + */ + function removeEventListenerImpl(arg1, arg2, arg3) { + ready(function() { + const eventArgs = processEventArgs(arg1, arg2, arg3) + eventArgs.target.removeEventListener(eventArgs.event, eventArgs.listener) + }) + return isFunction(arg2) ? arg2 : arg3 + } + + //= =================================================================== + // Node processing + //= =================================================================== + + const DUMMY_ELT = getDocument().createElement('output') // dummy element for bad selectors + /** + * @param {Element} elt + * @param {string} attrName + * @returns {(Node|Window)[]} + */ + function findAttributeTargets(elt, attrName) { + const attrTarget = getClosestAttributeValue(elt, attrName) + if (attrTarget) { + if (attrTarget === 'this') { + return [findThisElement(elt, attrName)] + } else { + const result = querySelectorAllExt(elt, attrTarget) + if (result.length === 0) { + logError('The selector "' + attrTarget + '" on ' + attrName + ' returned no matches!') + return [DUMMY_ELT] + } else { + return result + } + } + } + } + + /** + * @param {Element} elt + * @param {string} attribute + * @returns {Element|null} + */ + function findThisElement(elt, attribute) { + return asElement(getClosestMatch(elt, function(elt) { + return getAttributeValue(asElement(elt), attribute) != null + })) + } + + /** + * @param {Element} elt + * @returns {Node|Window|null} + */ + function getTarget(elt) { + const targetStr = getClosestAttributeValue(elt, 'hx-target') + if (targetStr) { + if (targetStr === 'this') { + return findThisElement(elt, 'hx-target') + } else { + return querySelectorExt(elt, targetStr) + } + } else { + const data = getInternalData(elt) + if (data.boosted) { + return getDocument().body + } else { + return elt + } + } + } + + /** + * @param {string} name + * @returns {boolean} + */ + function shouldSettleAttribute(name) { + const attributesToSettle = htmx.config.attributesToSettle + for (let i = 0; i < attributesToSettle.length; i++) { + if (name === attributesToSettle[i]) { + return true + } + } + return false + } + + /** + * @param {Element} mergeTo + * @param {Element} mergeFrom + */ + function cloneAttributes(mergeTo, mergeFrom) { + forEach(mergeTo.attributes, function(attr) { + if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) { + mergeTo.removeAttribute(attr.name) + } + }) + forEach(mergeFrom.attributes, function(attr) { + if (shouldSettleAttribute(attr.name)) { + mergeTo.setAttribute(attr.name, attr.value) + } + }) + } + + /** + * @param {HtmxSwapStyle} swapStyle + * @param {Element} target + * @returns {boolean} + */ + function isInlineSwap(swapStyle, target) { + const extensions = getExtensions(target) + for (let i = 0; i < extensions.length; i++) { + const extension = extensions[i] + try { + if (extension.isInlineSwap(swapStyle)) { + return true + } + } catch (e) { + logError(e) + } + } + return swapStyle === 'outerHTML' + } + + /** + * @param {string} oobValue + * @param {Element} oobElement + * @param {HtmxSettleInfo} settleInfo + * @returns + */ + function oobSwap(oobValue, oobElement, settleInfo) { + let selector = '#' + getRawAttribute(oobElement, 'id') + /** @type HtmxSwapStyle */ + let swapStyle = 'outerHTML' + if (oobValue === 'true') { + // do nothing + } else if (oobValue.indexOf(':') > 0) { + swapStyle = oobValue.substr(0, oobValue.indexOf(':')) + selector = oobValue.substr(oobValue.indexOf(':') + 1, oobValue.length) + } else { + swapStyle = oobValue + } - /** - * @param {any} o - * @param {string} type - * @returns - */ - function isType(o, type) { - return Object.prototype.toString.call(o) === "[object " + type + "]"; - } - - /** - * @param {*} o - * @returns {o is Function} - */ - function isFunction(o) { - return isType(o, "Function"); - } - - /** - * @param {*} o - * @returns {o is Object} - */ - function isRawObject(o) { - return isType(o, "Object"); - } - - /** - * getInternalData retrieves "private" data stored by htmx within an element - * @param {HTMLElement} elt - * @returns {*} - */ - function getInternalData(elt) { - var dataProp = 'htmx-internal-data'; - var data = elt[dataProp]; - if (!data) { - data = elt[dataProp] = {}; - } - return data; - } - - /** - * toArray converts an ArrayLike object into a real array. - * @param {ArrayLike} arr - * @returns {any[]} - */ - function toArray(arr) { - var returnArr = []; - if (arr) { - for (var i = 0; i < arr.length; i++) { - returnArr.push(arr[i]); - } - } - return returnArr + const targets = getDocument().querySelectorAll(selector) + if (targets) { + forEach( + targets, + function(target) { + let fragment + const oobElementClone = oobElement.cloneNode(true) + fragment = getDocument().createDocumentFragment() + fragment.appendChild(oobElementClone) + if (!isInlineSwap(swapStyle, target)) { + fragment = asParentNode(oobElementClone) // if this is not an inline swap, we use the content of the node, not the node itself + } + + const beforeSwapDetails = { shouldSwap: true, target, fragment } + if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return + + target = beforeSwapDetails.target // allow re-targeting + if (beforeSwapDetails.shouldSwap) { + swapWithStyle(swapStyle, target, target, fragment, settleInfo) + } + forEach(settleInfo.elts, function(elt) { + triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails) + }) + } + ) + oobElement.parentNode.removeChild(oobElement) + } else { + oobElement.parentNode.removeChild(oobElement) + triggerErrorEvent(getDocument().body, 'htmx:oobErrorNoTarget', { content: oobElement }) + } + return oobValue + } + + /** + * @param {DocumentFragment} fragment + */ + function handlePreservedElements(fragment) { + forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function(preservedElt) { + const id = getAttributeValue(preservedElt, 'id') + const oldElt = getDocument().getElementById(id) + if (oldElt != null) { + preservedElt.parentNode.replaceChild(oldElt, preservedElt) + } + }) + } + + /** + * @param {Node} parentNode + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function handleAttributes(parentNode, fragment, settleInfo) { + forEach(fragment.querySelectorAll('[id]'), function(newNode) { + const id = getRawAttribute(newNode, 'id') + if (id && id.length > 0) { + const normalizedId = id.replace("'", "\\'") + const normalizedTag = newNode.tagName.replace(':', '\\:') + const parentElt = asParentNode(parentNode) + const oldNode = parentElt && parentElt.querySelector(normalizedTag + "[id='" + normalizedId + "']") + if (oldNode && oldNode !== parentElt) { + const newAttributes = newNode.cloneNode() + cloneAttributes(newNode, oldNode) + settleInfo.tasks.push(function() { + cloneAttributes(newNode, newAttributes) + }) + } + } + }) + } + + /** + * @param {Node} child + * @returns {HtmxSettleTask} + */ + function makeAjaxLoadTask(child) { + return function() { + removeClassFromElement(child, htmx.config.addedClass) + processNode(asElement(child)) + processFocus(asParentNode(child)) + triggerEvent(child, 'htmx:load') + } + } + + /** + * @param {ParentNode} child + */ + function processFocus(child) { + const autofocus = '[autofocus]' + const autoFocusedElt = asHtmlElement(matches(child, autofocus) ? child : child.querySelector(autofocus)) + if (autoFocusedElt != null) { + autoFocusedElt.focus() + } + } + + /** + * @param {Node} parentNode + * @param {Node} insertBefore + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) { + handleAttributes(parentNode, fragment, settleInfo) + while (fragment.childNodes.length > 0) { + const child = fragment.firstChild + addClassToElement(asElement(child), htmx.config.addedClass) + parentNode.insertBefore(child, insertBefore) + if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { + settleInfo.tasks.push(makeAjaxLoadTask(child)) + } + } + } + + /** + * based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, + * derived from Java's string hashcode implementation + * @param {string} string + * @param {number} hash + * @returns {number} + */ + function stringHash(string, hash) { + let char = 0 + while (char < string.length) { + hash = (hash << 5) - hash + string.charCodeAt(char++) | 0 // bitwise or ensures we have a 32-bit int + } + return hash + } + + /** + * @param {Element} elt + * @returns {number} + */ + function attributeHash(elt) { + let hash = 0 + // IE fix + if (elt.attributes) { + for (let i = 0; i < elt.attributes.length; i++) { + const attribute = elt.attributes[i] + if (attribute.value) { // only include attributes w/ actual values (empty is same as non-existent) + hash = stringHash(attribute.name, hash) + hash = stringHash(attribute.value, hash) + } + } + } + return hash + } + + /** + * @param {EventTarget} elt + */ + function deInitOnHandlers(elt) { + const internalData = getInternalData(elt) + if (internalData.onHandlers) { + for (let i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i] + removeEventListenerImpl(elt, handlerInfo.event, handlerInfo.listener) + } + delete internalData.onHandlers + } + } + + /** + * @param {Node} element + */ + function deInitNode(element) { + const internalData = getInternalData(element) + if (internalData.timeout) { + clearTimeout(internalData.timeout) + } + if (internalData.listenerInfos) { + forEach(internalData.listenerInfos, function(info) { + if (info.on) { + removeEventListenerImpl(info.on, info.trigger, info.listener) } - - function forEach(arr, func) { - if (arr) { - for (var i = 0; i < arr.length; i++) { - func(arr[i]); - } - } + }) + } + deInitOnHandlers(element) + forEach(Object.keys(internalData), function(key) { delete internalData[key] }) + } + + /** + * @param {Node} element + */ + function cleanUpElement(element) { + triggerEvent(element, 'htmx:beforeCleanupElement') + deInitNode(element) + // @ts-ignore IE11 code + // noinspection JSUnresolvedReference + if (element.children) { // IE + // @ts-ignore + forEach(element.children, function(child) { cleanUpElement(child) }) + } + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapOuterHTML(target, fragment, settleInfo) { + /** @type {Node} */ + let newElt + const eltBeforeNewContent = target.previousSibling + insertNodesBefore(parentElt(target), target, fragment, settleInfo) + if (eltBeforeNewContent == null) { + newElt = parentElt(target).firstChild + } else { + newElt = eltBeforeNewContent.nextSibling + } + settleInfo.elts = settleInfo.elts.filter(function(e) { return e !== target }) + while (newElt && newElt !== target) { + if (newElt instanceof Element) { + settleInfo.elts.push(newElt) + newElt = newElt.nextElementSibling + } else { + newElt = null + } + } + cleanUpElement(target) + if (target instanceof Element) { + target.remove() + } else { + target.parentNode.removeChild(target) + } + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapAfterBegin(target, fragment, settleInfo) { + return insertNodesBefore(target, target.firstChild, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapBeforeBegin(target, fragment, settleInfo) { + return insertNodesBefore(parentElt(target), target, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapBeforeEnd(target, fragment, settleInfo) { + return insertNodesBefore(target, null, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapAfterEnd(target, fragment, settleInfo) { + return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo) + } + + /** + * @param {Node} target + */ + function swapDelete(target) { + cleanUpElement(target) + return parentElt(target).removeChild(target) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapInnerHTML(target, fragment, settleInfo) { + const firstChild = target.firstChild + insertNodesBefore(target, firstChild, fragment, settleInfo) + if (firstChild) { + while (firstChild.nextSibling) { + cleanUpElement(firstChild.nextSibling) + target.removeChild(firstChild.nextSibling) + } + cleanUpElement(firstChild) + target.removeChild(firstChild) + } + } + + /** + * @param {HtmxSwapStyle} swapStyle + * @param {Element} elt + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapWithStyle(swapStyle, elt, target, fragment, settleInfo) { + switch (swapStyle) { + case 'none': + return + case 'outerHTML': + swapOuterHTML(target, fragment, settleInfo) + return + case 'afterbegin': + swapAfterBegin(target, fragment, settleInfo) + return + case 'beforebegin': + swapBeforeBegin(target, fragment, settleInfo) + return + case 'beforeend': + swapBeforeEnd(target, fragment, settleInfo) + return + case 'afterend': + swapAfterEnd(target, fragment, settleInfo) + return + case 'delete': + swapDelete(target) + return + default: + var extensions = getExtensions(elt) + for (let i = 0; i < extensions.length; i++) { + const ext = extensions[i] + try { + const newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo) + if (newElements) { + if (typeof newElements.length !== 'undefined') { + // if handleSwap returns an array (like) of elements, we handle them + for (let j = 0; j < newElements.length; j++) { + const child = newElements[j] + if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { + settleInfo.tasks.push(makeAjaxLoadTask(child)) + } + } + } + return + } + } catch (e) { + logError(e) + } + } + if (swapStyle === 'innerHTML') { + swapInnerHTML(target, fragment, settleInfo) + } else { + swapWithStyle(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo) } + } + } + + /** + * @param {DocumentFragment} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function findAndSwapOobElements(fragment, settleInfo) { + forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function(oobElement) { + if (htmx.config.allowNestedOobSwaps || oobElement.parentElement === null) { + const oobValue = getAttributeValue(oobElement, 'hx-swap-oob') + if (oobValue != null) { + oobSwap(oobValue, oobElement, settleInfo) + } + } else { + oobElement.removeAttribute('hx-swap-oob') + oobElement.removeAttribute('data-hx-swap-oob') + } + }) + } + + /** + * Implements complete swapping pipeline, including: focus and selection preservation, + * title updates, scroll, OOB swapping, normal swapping and settling + * @param {string|Element} target + * @param {string} content + * @param {HtmxSwapSpecification} swapSpec + * @param {SwapOptions} [swapOptions] + */ + function swap(target, content, swapSpec, swapOptions) { + if (!swapOptions) { + swapOptions = {} + } - function isScrolledIntoView(el) { - var rect = el.getBoundingClientRect(); - var elemTop = rect.top; - var elemBottom = rect.bottom; - return elemTop < window.innerHeight && elemBottom >= 0; - } + target = resolveTarget(target) + + // preserve focus and selection + const activeElt = document.activeElement + let selectionInfo = {} + try { + selectionInfo = { + elt: activeElt, + // @ts-ignore + start: activeElt ? activeElt.selectionStart : null, + // @ts-ignore + end: activeElt ? activeElt.selectionEnd : null + } + } catch (e) { + // safari issue - see https://github.com/microsoft/playwright/issues/5894 + } + const settleInfo = makeSettleInfo(target) - function bodyContains(elt) { - // IE Fix - if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) { - return getDocument().body.contains(elt.getRootNode().host); - } else { - return getDocument().body.contains(elt); - } - } + // For text content swaps, don't parse the response as HTML, just insert it + if (swapSpec.swapStyle === 'textContent') { + target.textContent = content + // Otherwise, make the fragment and process it + } else { + let fragment = makeFragment(content) + + settleInfo.title = fragment.title + + // select-oob swaps + if (swapOptions.selectOOB) { + const oobSelectValues = swapOptions.selectOOB.split(',') + for (let i = 0; i < oobSelectValues.length; i++) { + const oobSelectValue = oobSelectValues[i].split(':', 2) + let id = oobSelectValue[0].trim() + if (id.indexOf('#') === 0) { + id = id.substring(1) + } + const oobValue = oobSelectValue[1] || 'true' + const oobElement = fragment.querySelector('#' + id) + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo) + } + } + } + // oob swaps + findAndSwapOobElements(fragment, settleInfo) + forEach(findAll(fragment, 'template'), /** @param {HTMLTemplateElement} template */function(template) { + findAndSwapOobElements(template.content, settleInfo) + if (template.content.childElementCount === 0) { + // Avoid polluting the DOM with empty templates that were only used to encapsulate oob swap + template.remove() + } + }) + + // normal swap + if (swapOptions.select) { + const newFragment = getDocument().createDocumentFragment() + forEach(fragment.querySelectorAll(swapOptions.select), function(node) { + newFragment.appendChild(node) + }) + fragment = newFragment + } + handlePreservedElements(fragment) + swapWithStyle(swapSpec.swapStyle, swapOptions.contextElement, target, fragment, settleInfo) + } - function splitOnWhitespace(trigger) { - return trigger.trim().split(/\s+/); - } + // apply saved focus and selection information to swapped content + if (selectionInfo.elt && + !bodyContains(selectionInfo.elt) && + getRawAttribute(selectionInfo.elt, 'id')) { + const newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, 'id')) + const focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll } + if (newActiveElt) { + // @ts-ignore + if (selectionInfo.start && newActiveElt.setSelectionRange) { + try { + // @ts-ignore + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end) + } catch (e) { + // the setSelectionRange method is present on fields that don't support it, so just let this fail + } + } + newActiveElt.focus(focusOptions) + } + } - /** - * mergeObjects takes all of the keys from - * obj2 and duplicates them into obj1 - * @param {Object} obj1 - * @param {Object} obj2 - * @returns {Object} - */ - function mergeObjects(obj1, obj2) { - for (var key in obj2) { - if (obj2.hasOwnProperty(key)) { - obj1[key] = obj2[key]; - } - } - return obj1; - } + target.classList.remove(htmx.config.swappingClass) + forEach(settleInfo.elts, function(elt) { + if (elt.classList) { + elt.classList.add(htmx.config.settlingClass) + } + triggerEvent(elt, 'htmx:afterSwap', swapOptions.eventInfo) + }) + if (swapOptions.afterSwapCallback) { + swapOptions.afterSwapCallback() + } - function parseJSON(jString) { - try { - return JSON.parse(jString); - } catch(error) { - logError(error); - return null; - } - } + // merge in new title after swap but before settle + if (!swapSpec.ignoreTitle) { + handleTitle(settleInfo.title) + } - function canAccessLocalStorage() { - var test = 'htmx:localStorageTest'; - try { - localStorage.setItem(test, test); - localStorage.removeItem(test); - return true; - } catch(e) { - return false; - } - } + // settle + const doSettle = function() { + forEach(settleInfo.tasks, function(task) { + task.call() + }) + forEach(settleInfo.elts, function(elt) { + if (elt.classList) { + elt.classList.remove(htmx.config.settlingClass) + } + triggerEvent(elt, 'htmx:afterSettle', swapOptions.eventInfo) + }) + + if (swapOptions.anchor) { + const anchorTarget = asElement(resolveTarget('#' + swapOptions.anchor)) + if (anchorTarget) { + anchorTarget.scrollIntoView({ block: 'start', behavior: 'auto' }) + } + } + + updateScrollState(settleInfo.elts, swapSpec) + if (swapOptions.afterSettleCallback) { + swapOptions.afterSettleCallback() + } + } - function normalizePath(path) { + if (swapSpec.settleDelay > 0) { + getWindow().setTimeout(doSettle, swapSpec.settleDelay) + } else { + doSettle() + } + } + + /** + * @param {XMLHttpRequest} xhr + * @param {string} header + * @param {EventTarget} elt + */ + function handleTriggerHeader(xhr, header, elt) { + const triggerBody = xhr.getResponseHeader(header) + if (triggerBody.indexOf('{') === 0) { + const triggers = parseJSON(triggerBody) + for (const eventName in triggers) { + if (triggers.hasOwnProperty(eventName)) { + let detail = triggers[eventName] + if (!isRawObject(detail)) { + detail = { value: detail } + } + triggerEvent(elt, eventName, detail) + } + } + } else { + const eventNames = triggerBody.split(',') + for (let i = 0; i < eventNames.length; i++) { + triggerEvent(elt, eventNames[i].trim(), []) + } + } + } + + const WHITESPACE = /\s/ + const WHITESPACE_OR_COMMA = /[\s,]/ + const SYMBOL_START = /[_$a-zA-Z]/ + const SYMBOL_CONT = /[_$a-zA-Z0-9]/ + const STRINGISH_START = ['"', "'", '/'] + const NOT_WHITESPACE = /[^\s]/ + const COMBINED_SELECTOR_START = /[{(]/ + const COMBINED_SELECTOR_END = /[})]/ + + /** + * @param {string} str + * @returns {string[]} + */ + function tokenizeString(str) { + /** @type string[] */ + const tokens = [] + let position = 0 + while (position < str.length) { + if (SYMBOL_START.exec(str.charAt(position))) { + var startPosition = position + while (SYMBOL_CONT.exec(str.charAt(position + 1))) { + position++ + } + tokens.push(str.substr(startPosition, position - startPosition + 1)) + } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) { + const startChar = str.charAt(position) + var startPosition = position + position++ + while (position < str.length && str.charAt(position) !== startChar) { + if (str.charAt(position) === '\\') { + position++ + } + position++ + } + tokens.push(str.substr(startPosition, position - startPosition + 1)) + } else { + const symbol = str.charAt(position) + tokens.push(symbol) + } + position++ + } + return tokens + } + + /** + * @param {string} token + * @param {string|null} last + * @param {string} paramName + * @returns {boolean} + */ + function isPossibleRelativeReference(token, last, paramName) { + return SYMBOL_START.exec(token.charAt(0)) && + token !== 'true' && + token !== 'false' && + token !== 'this' && + token !== paramName && + last !== '.' + } + + /** + * @param {EventTarget|string} elt + * @param {string[]} tokens + * @param {string} paramName + * @returns {ConditionalFunction|null} + */ + function maybeGenerateConditional(elt, tokens, paramName) { + if (tokens[0] === '[') { + tokens.shift() + let bracketCount = 1 + let conditionalSource = ' return (function(' + paramName + '){ return (' + let last = null + while (tokens.length > 0) { + const token = tokens[0] + // @ts-ignore For some reason tsc doesn't understand the shift call, and thinks we're comparing the same value here, i.e. '[' vs ']' + if (token === ']') { + bracketCount-- + if (bracketCount === 0) { + if (last === null) { + conditionalSource = conditionalSource + 'true' + } + tokens.shift() + conditionalSource += ')})' try { - var url = new URL(path); - if (url) { - path = url.pathname + url.search; - } - // remove trailing slash, unless index page - if (!(/^\/$/.test(path))) { - path = path.replace(/\/+$/, ''); - } - return path; + const conditionFunction = maybeEval(elt, function() { + return Function(conditionalSource)() + }, + function() { return true }) + conditionFunction.source = conditionalSource + return conditionFunction } catch (e) { - // be kind to IE11, which doesn't support URL() - return path; - } - } - - //========================================================================================== - // public API - //========================================================================================== - - function internalEval(str){ - return maybeEval(getDocument().body, function () { - return eval(str); - }); - } - - function onLoadHelper(callback) { - var value = htmx.on("htmx:load", function(evt) { - callback(evt.detail.elt); - }); - return value; - } - - function logAll(){ - htmx.logger = function(elt, event, data) { - if(console) { - console.log(event, elt, data); - } - } - } - - function logNone() { - htmx.logger = null - } - - function find(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelector(selector); - } else { - return find(getDocument(), eltOrSelector); - } - } - - function findAll(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelectorAll(selector); - } else { - return findAll(getDocument(), eltOrSelector); - } - } - - function removeElement(elt, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - removeElement(elt); - elt = null; - }, delay); - } else { - elt.parentElement.removeChild(elt); - } - } - - function addClassToElement(elt, clazz, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - addClassToElement(elt, clazz); - elt = null; - }, delay); - } else { - elt.classList && elt.classList.add(clazz); - } - } - - function removeClassFromElement(elt, clazz, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - removeClassFromElement(elt, clazz); - elt = null; - }, delay); - } else { - if (elt.classList) { - elt.classList.remove(clazz); - // if there are no classes left, remove the class attribute - if (elt.classList.length === 0) { - elt.removeAttribute("class"); - } - } - } - } - - function toggleClassOnElement(elt, clazz) { - elt = resolveTarget(elt); - elt.classList.toggle(clazz); - } - - function takeClassForElement(elt, clazz) { - elt = resolveTarget(elt); - forEach(elt.parentElement.children, function(child){ - removeClassFromElement(child, clazz); - }) - addClassToElement(elt, clazz); - } - - function closest(elt, selector) { - elt = resolveTarget(elt); - if (elt.closest) { - return elt.closest(selector); - } else { - // TODO remove when IE goes away - do{ - if (elt == null || matches(elt, selector)){ - return elt; - } - } - while (elt = elt && parentElt(elt)); - return null; - } - } - - function startsWith(str, prefix) { - return str.substring(0, prefix.length) === prefix - } - - function endsWith(str, suffix) { - return str.substring(str.length - suffix.length) === suffix - } - - function normalizeSelector(selector) { - var trimmedSelector = selector.trim(); - if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) { - return trimmedSelector.substring(1, trimmedSelector.length - 2); - } else { - return trimmedSelector; - } - } - - function querySelectorAllExt(elt, selector) { - if (selector.indexOf("closest ") === 0) { - return [closest(elt, normalizeSelector(selector.substr(8)))]; - } else if (selector.indexOf("find ") === 0) { - return [find(elt, normalizeSelector(selector.substr(5)))]; - } else if (selector === "next") { - return [elt.nextElementSibling] - } else if (selector.indexOf("next ") === 0) { - return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; - } else if (selector === "previous") { - return [elt.previousElementSibling] - } else if (selector.indexOf("previous ") === 0) { - return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; - } else if (selector === 'document') { - return [document]; - } else if (selector === 'window') { - return [window]; - } else if (selector === 'body') { - return [document.body]; - } else { - return getDocument().querySelectorAll(normalizeSelector(selector)); - } - } - - var scanForwardQuery = function(start, match) { - var results = getDocument().querySelectorAll(match); - for (var i = 0; i < results.length; i++) { - var elt = results[i]; - if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { - return elt; - } - } - } - - var scanBackwardsQuery = function(start, match) { - var results = getDocument().querySelectorAll(match); - for (var i = results.length - 1; i >= 0; i--) { - var elt = results[i]; - if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { - return elt; - } - } - } - - function querySelectorExt(eltOrSelector, selector) { - if (selector) { - return querySelectorAllExt(eltOrSelector, selector)[0]; - } else { - return querySelectorAllExt(getDocument().body, eltOrSelector)[0]; - } - } - - function resolveTarget(arg2) { - if (isType(arg2, 'String')) { - return find(arg2); - } else { - return arg2; - } - } - - function processEventArgs(arg1, arg2, arg3) { - if (isFunction(arg2)) { - return { - target: getDocument().body, - event: arg1, - listener: arg2 - } - } else { - return { - target: resolveTarget(arg1), - event: arg2, - listener: arg3 - } - } - - } - - function addEventListenerImpl(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 removeEventListenerImpl(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 - //==================================================================== - - var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors - function findAttributeTargets(elt, attrName) { - var attrTarget = getClosestAttributeValue(elt, attrName); - if (attrTarget) { - if (attrTarget === "this") { - return [findThisElement(elt, attrName)]; - } else { - var result = querySelectorAllExt(elt, attrTarget); - if (result.length === 0) { - logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!"); - return [DUMMY_ELT] - } else { - return result; - } - } - } - } - - function findThisElement(elt, attribute){ - return getClosestMatch(elt, function (elt) { - return getAttributeValue(elt, attribute) != null; - }) - } - - function getTarget(elt) { - var targetStr = getClosestAttributeValue(elt, "hx-target"); - if (targetStr) { - if (targetStr === "this") { - return findThisElement(elt,'hx-target'); - } else { - return querySelectorExt(elt, targetStr) - } - } else { - var data = getInternalData(elt); - if (data.boosted) { - return getDocument().body; - } else { - return elt; - } - } - } - - function shouldSettleAttribute(name) { - var attributesToSettle = htmx.config.attributesToSettle; - for (var i = 0; i < attributesToSettle.length; i++) { - if (name === attributesToSettle[i]) { - return true; - } - } - return false; - } - - function cloneAttributes(mergeTo, mergeFrom) { - forEach(mergeTo.attributes, function (attr) { - if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) { - mergeTo.removeAttribute(attr.name) - } - }); - forEach(mergeFrom.attributes, function (attr) { - if (shouldSettleAttribute(attr.name)) { - mergeTo.setAttribute(attr.name, attr.value); - } - }); - } - - function isInlineSwap(swapStyle, target) { - var extensions = getExtensions(target); - for (var i = 0; i < extensions.length; i++) { - var extension = extensions[i]; - try { - if (extension.isInlineSwap(swapStyle)) { - return true; - } - } catch(e) { - logError(e); - } - } - return swapStyle === "outerHTML"; - } - - /** - * - * @param {string} oobValue - * @param {HTMLElement} oobElement - * @param {*} settleInfo - * @returns - */ - function oobSwap(oobValue, oobElement, settleInfo) { - var selector = "#" + getRawAttribute(oobElement, "id"); - var swapStyle = "outerHTML"; - if (oobValue === "true") { - // do nothing - } else if (oobValue.indexOf(":") > 0) { - swapStyle = oobValue.substr(0, oobValue.indexOf(":")); - selector = oobValue.substr(oobValue.indexOf(":") + 1, oobValue.length); - } else { - swapStyle = oobValue; - } - - var targets = getDocument().querySelectorAll(selector); - if (targets) { - forEach( - targets, - function (target) { - var fragment; - var oobElementClone = oobElement.cloneNode(true); - fragment = getDocument().createDocumentFragment(); - fragment.appendChild(oobElementClone); - if (!isInlineSwap(swapStyle, target)) { - fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself - } - - var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment }; - if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return; - - target = beforeSwapDetails.target; // allow re-targeting - if (beforeSwapDetails['shouldSwap']){ - swap(swapStyle, target, target, fragment, settleInfo); - } - forEach(settleInfo.elts, function (elt) { - triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails); - }); - } - ); - oobElement.parentNode.removeChild(oobElement); - } else { - oobElement.parentNode.removeChild(oobElement); - triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}); - } - return oobValue; - } - - function handleOutOfBandSwaps(elt, fragment, settleInfo) { - var oobSelects = getClosestAttributeValue(elt, "hx-select-oob"); - if (oobSelects) { - var oobSelectValues = oobSelects.split(","); - for (var i = 0; i < oobSelectValues.length; i++) { - var oobSelectValue = oobSelectValues[i].split(":", 2); - var id = oobSelectValue[0].trim(); - if (id.indexOf("#") === 0) { - id = id.substring(1); - } - var oobValue = oobSelectValue[1] || "true"; - var oobElement = fragment.querySelector("#" + id); - if (oobElement) { - oobSwap(oobValue, oobElement, settleInfo); - } - } - } - forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) { - var oobValue = getAttributeValue(oobElement, "hx-swap-oob"); - if (oobValue != null) { - oobSwap(oobValue, oobElement, settleInfo); - } - }); - } - - function handlePreservedElements(fragment) { - forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function (preservedElt) { - var id = getAttributeValue(preservedElt, "id"); - var oldElt = getDocument().getElementById(id); - if (oldElt != null) { - preservedElt.parentNode.replaceChild(oldElt, preservedElt); - } - }); - } - - function handleAttributes(parentNode, fragment, settleInfo) { - forEach(fragment.querySelectorAll("[id]"), function (newNode) { - var id = getRawAttribute(newNode, "id") - if (id && id.length > 0) { - var normalizedId = id.replace("'", "\\'"); - var normalizedTag = newNode.tagName.replace(':', '\\:'); - var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']"); - if (oldNode && oldNode !== parentNode) { - var newAttributes = newNode.cloneNode(); - cloneAttributes(newNode, oldNode); - settleInfo.tasks.push(function () { - cloneAttributes(newNode, newAttributes); - }); - } - } - }); - } - - function makeAjaxLoadTask(child) { - return function () { - removeClassFromElement(child, htmx.config.addedClass); - processNode(child); - processScripts(child); - processFocus(child) - triggerEvent(child, 'htmx:load'); - }; - } - - function processFocus(child) { - var autofocus = "[autofocus]"; - var autoFocusedElt = matches(child, autofocus) ? child : child.querySelector(autofocus) - if (autoFocusedElt != null) { - autoFocusedElt.focus(); - } - } - - function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) { - handleAttributes(parentNode, fragment, settleInfo); - while(fragment.childNodes.length > 0){ - var child = fragment.firstChild; - addClassToElement(child, htmx.config.addedClass); - parentNode.insertBefore(child, insertBefore); - if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { - settleInfo.tasks.push(makeAjaxLoadTask(child)); - } - } - } - - // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, - // derived from Java's string hashcode implementation - function stringHash(string, hash) { - var char = 0; - while (char < string.length){ - hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int - } - return hash; - } - - function attributeHash(elt) { - var hash = 0; - // IE fix - if (elt.attributes) { - for (var i = 0; i < elt.attributes.length; i++) { - var attribute = elt.attributes[i]; - if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent) - hash = stringHash(attribute.name, hash); - hash = stringHash(attribute.value, hash); - } - } - } - return hash; - } - - function deInitOnHandlers(elt) { - var internalData = getInternalData(elt); - if (internalData.onHandlers) { - for (var i = 0; i < internalData.onHandlers.length; i++) { - const handlerInfo = internalData.onHandlers[i]; - elt.removeEventListener(handlerInfo.event, handlerInfo.listener); - } - delete internalData.onHandlers - } - } - - function deInitNode(element) { - var internalData = getInternalData(element); - if (internalData.timeout) { - clearTimeout(internalData.timeout); - } - if (internalData.webSocket) { - internalData.webSocket.close(); - } - if (internalData.sseEventSource) { - internalData.sseEventSource.close(); - } - if (internalData.listenerInfos) { - forEach(internalData.listenerInfos, function (info) { - if (info.on) { - info.on.removeEventListener(info.trigger, info.listener); - } - }); - } - deInitOnHandlers(element); - forEach(Object.keys(internalData), function(key) { delete internalData[key] }); - } - - function cleanUpElement(element) { - triggerEvent(element, "htmx:beforeCleanupElement") - deInitNode(element); - if (element.children) { // IE - forEach(element.children, function(child) { cleanUpElement(child) }); - } - } - - function swapOuterHTML(target, fragment, settleInfo) { - if (target.tagName === "BODY") { - return swapInnerHTML(target, fragment, settleInfo); - } else { - // @type {HTMLElement} - var newElt - var eltBeforeNewContent = target.previousSibling; - insertNodesBefore(parentElt(target), target, fragment, settleInfo); - if (eltBeforeNewContent == null) { - newElt = parentElt(target).firstChild; - } else { - newElt = eltBeforeNewContent.nextSibling; - } - settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target }); - while(newElt && newElt !== target) { - if (newElt.nodeType === Node.ELEMENT_NODE) { - settleInfo.elts.push(newElt); - } - newElt = newElt.nextElementSibling; - } - cleanUpElement(target); - parentElt(target).removeChild(target); - } - } - - function swapAfterBegin(target, fragment, settleInfo) { - return insertNodesBefore(target, target.firstChild, fragment, settleInfo); - } - - function swapBeforeBegin(target, fragment, settleInfo) { - return insertNodesBefore(parentElt(target), target, fragment, settleInfo); - } - - function swapBeforeEnd(target, fragment, settleInfo) { - return insertNodesBefore(target, null, fragment, settleInfo); - } - - function swapAfterEnd(target, fragment, settleInfo) { - return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo); - } - function swapDelete(target, fragment, settleInfo) { - cleanUpElement(target); - return parentElt(target).removeChild(target); - } - - function swapInnerHTML(target, fragment, settleInfo) { - var firstChild = target.firstChild; - insertNodesBefore(target, firstChild, fragment, settleInfo); - if (firstChild) { - while (firstChild.nextSibling) { - cleanUpElement(firstChild.nextSibling) - target.removeChild(firstChild.nextSibling); - } - cleanUpElement(firstChild) - target.removeChild(firstChild); - } - } - - function maybeSelectFromResponse(elt, fragment, selectOverride) { - var selector = selectOverride || getClosestAttributeValue(elt, "hx-select"); - if (selector) { - var newFragment = getDocument().createDocumentFragment(); - forEach(fragment.querySelectorAll(selector), function (node) { - newFragment.appendChild(node); - }); - fragment = newFragment; - } - return fragment; - } - - function swap(swapStyle, elt, target, fragment, settleInfo) { - switch (swapStyle) { - case "none": - return; - case "outerHTML": - swapOuterHTML(target, fragment, settleInfo); - return; - case "afterbegin": - swapAfterBegin(target, fragment, settleInfo); - return; - case "beforebegin": - swapBeforeBegin(target, fragment, settleInfo); - return; - case "beforeend": - swapBeforeEnd(target, fragment, settleInfo); - return; - case "afterend": - swapAfterEnd(target, fragment, settleInfo); - return; - case "delete": - swapDelete(target, fragment, settleInfo); - return; - default: - var extensions = getExtensions(elt); - for (var i = 0; i < extensions.length; i++) { - var ext = extensions[i]; - try { - var newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo); - if (newElements) { - if (typeof newElements.length !== 'undefined') { - // if handleSwap returns an array (like) of elements, we handle them - for (var j = 0; j < newElements.length; j++) { - var child = newElements[j]; - if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { - settleInfo.tasks.push(makeAjaxLoadTask(child)); - } - } - } - return; - } - } catch (e) { - logError(e); - } - } - if (swapStyle === "innerHTML") { - swapInnerHTML(target, fragment, settleInfo); - } else { - swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo); - } - } - } - - function findTitle(content) { - if (content.indexOf('<title') > -1) { - var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, ''); - var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX); - if (result) { - return result[2]; - } - } - } - - function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) { - settleInfo.title = findTitle(responseText); - var fragment = makeFragment(responseText); - if (fragment) { - handleOutOfBandSwaps(elt, fragment, settleInfo); - fragment = maybeSelectFromResponse(elt, fragment, selectOverride); - handlePreservedElements(fragment); - return swap(swapStyle, elt, target, fragment, settleInfo); - } - } - - function handleTrigger(xhr, header, elt) { - var triggerBody = xhr.getResponseHeader(header); - if (triggerBody.indexOf("{") === 0) { - var triggers = parseJSON(triggerBody); - for (var eventName in triggers) { - if (triggers.hasOwnProperty(eventName)) { - var detail = triggers[eventName]; - if (!isRawObject(detail)) { - detail = {"value": detail} - } - triggerEvent(elt, eventName, detail); - } - } - } else { - var eventNames = triggerBody.split(",") - for (var i = 0; i < eventNames.length; i++) { - triggerEvent(elt, eventNames[i].trim(), []); - } - } - } - - var WHITESPACE = /\s/; - var WHITESPACE_OR_COMMA = /[\s,]/; - var SYMBOL_START = /[_$a-zA-Z]/; - var SYMBOL_CONT = /[_$a-zA-Z0-9]/; - var STRINGISH_START = ['"', "'", "/"]; - var NOT_WHITESPACE = /[^\s]/; - var COMBINED_SELECTOR_START = /[{(]/; - var COMBINED_SELECTOR_END = /[})]/; - function tokenizeString(str) { - var tokens = []; - var position = 0; - while (position < str.length) { - if(SYMBOL_START.exec(str.charAt(position))) { - var startPosition = position; - while (SYMBOL_CONT.exec(str.charAt(position + 1))) { - position++; - } - tokens.push(str.substr(startPosition, position - startPosition + 1)); - } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) { - var startChar = str.charAt(position); - var startPosition = position; - position++; - while (position < str.length && str.charAt(position) !== startChar ) { - if (str.charAt(position) === "\\") { - position++; - } - position++; - } - tokens.push(str.substr(startPosition, position - startPosition + 1)); - } else { - var symbol = str.charAt(position); - tokens.push(symbol); - } - position++; - } - return tokens; - } - - function isPossibleRelativeReference(token, last, paramName) { - return SYMBOL_START.exec(token.charAt(0)) && - token !== "true" && - token !== "false" && - token !== "this" && - token !== paramName && - last !== "."; - } - - function maybeGenerateConditional(elt, tokens, paramName) { - if (tokens[0] === '[') { - tokens.shift(); - var bracketCount = 1; - var conditionalSource = " return (function(" + paramName + "){ return ("; - var last = null; - while (tokens.length > 0) { - var token = tokens[0]; - if (token === "]") { - bracketCount--; - if (bracketCount === 0) { - if (last === null) { - conditionalSource = conditionalSource + "true"; - } - tokens.shift(); - conditionalSource += ")})"; - try { - var conditionFunction = maybeEval(elt,function () { - return Function(conditionalSource)(); - }, - function(){return true}) - conditionFunction.source = conditionalSource; - return conditionFunction; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:syntax:error", {error:e, source:conditionalSource}) - return null; - } - } - } else if (token === "[") { - bracketCount++; - } - if (isPossibleRelativeReference(token, last, paramName)) { - conditionalSource += "((" + paramName + "." + token + ") ? (" + paramName + "." + token + ") : (window." + token + "))"; - } else { - conditionalSource = conditionalSource + token; - } - last = tokens.shift(); - } - } - } - - function consumeUntil(tokens, match) { - var result = ""; - while (tokens.length > 0 && !match.test(tokens[0])) { - result += tokens.shift(); - } - return result; - } - - function consumeCSSSelector(tokens) { - var result; - if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { - tokens.shift(); - result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim(); - tokens.shift(); - } else { - result = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } - return result; - } - - var INPUT_SELECTOR = 'input, textarea, select'; - - /** - * @param {HTMLElement} elt - * @param {string} explicitTrigger - * @param {cache} cache for trigger specs - * @returns {import("./htmx").HtmxTriggerSpecification[]} - */ - function parseAndCacheTrigger(elt, explicitTrigger, cache) { - var triggerSpecs = []; - var tokens = tokenizeString(explicitTrigger); - do { - consumeUntil(tokens, NOT_WHITESPACE); - var initialLength = tokens.length; - var trigger = consumeUntil(tokens, /[,\[\s]/); - if (trigger !== "") { - if (trigger === "every") { - var every = {trigger: 'every'}; - consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); - consumeUntil(tokens, NOT_WHITESPACE); - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - every.eventFilter = eventFilter; - } - triggerSpecs.push(every); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); - } else { - var triggerSpec = {trigger: trigger}; - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - triggerSpec.eventFilter = eventFilter; - } - while (tokens.length > 0 && tokens[0] !== ",") { - consumeUntil(tokens, NOT_WHITESPACE) - var token = tokens.shift(); - if (token === "changed") { - triggerSpec.changed = true; - } else if (token === "once") { - triggerSpec.once = true; - } else if (token === "consume") { - triggerSpec.consume = true; - } else if (token === "delay" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "from" && tokens[0] === ":") { - tokens.shift(); - if (COMBINED_SELECTOR_START.test(tokens[0])) { - var from_arg = consumeCSSSelector(tokens); - } else { - var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); - if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") { - tokens.shift(); - var selector = consumeCSSSelector(tokens); - // `next` and `previous` allow a selector-less syntax - if (selector.length > 0) { - from_arg += " " + selector; - } - } - } - triggerSpec.from = from_arg; - } else if (token === "target" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.target = consumeCSSSelector(tokens); - } else if (token === "throttle" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "queue" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if (token === "root" && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeCSSSelector(tokens); - } else if (token === "threshold" && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - } - triggerSpecs.push(triggerSpec); - } - } - if (tokens.length === initialLength) { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - consumeUntil(tokens, NOT_WHITESPACE); - } while (tokens[0] === "," && tokens.shift()) - if (cache) { - cache[explicitTrigger] = triggerSpecs - } - return triggerSpecs - } - - /** - * @param {HTMLElement} elt - * @returns {import("./htmx").HtmxTriggerSpecification[]} - */ - function getTriggerSpecs(elt) { - var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); - var triggerSpecs = []; - if (explicitTrigger) { - var cache = htmx.config.triggerSpecsCache - triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) - } - - if (triggerSpecs.length > 0) { - return triggerSpecs; - } else if (matches(elt, 'form')) { - return [{trigger: 'submit'}]; - } else if (matches(elt, 'input[type="button"], input[type="submit"]')){ - return [{trigger: 'click'}]; - } else if (matches(elt, INPUT_SELECTOR)) { - return [{trigger: 'change'}]; - } else { - return [{trigger: 'click'}]; - } - } - - function cancelPolling(elt) { - getInternalData(elt).cancelled = true; - } - - function processPolling(elt, handler, spec) { - var nodeData = getInternalData(elt); - nodeData.timeout = setTimeout(function () { - if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { - triggerSpec: spec, - target: elt - }))) { - handler(elt); - } - processPolling(elt, handler, spec); - } - }, spec.pollInterval); - } - - function isLocalLink(elt) { - return location.hostname === elt.hostname && - getRawAttribute(elt,'href') && - getRawAttribute(elt,'href').indexOf("#") !== 0; - } - - function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || 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"; - if (verb === "get") { - } - path = getRawAttribute(elt, 'action'); - } - triggerSpecs.forEach(function(triggerSpec) { - addEventListener(elt, function(elt, evt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return - } - issueAjaxRequest(verb, path, elt, evt) - }, nodeData, triggerSpec, true); - }); - } - } - - /** - * - * @param {Event} evt - * @param {HTMLElement} elt - * @returns - */ - function shouldCancel(evt, elt) { - if (evt.type === "submit" || evt.type === "click") { - if (elt.tagName === "FORM") { - return true; - } - if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { - return true; - } - if (elt.tagName === "A" && elt.href && - (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) { - return true; - } - } - return false; - } - - function ignoreBoostedAnchorCtrlClick(elt, evt) { - return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); - } - - function maybeFilterEvent(triggerSpec, elt, evt) { - var eventFilter = triggerSpec.eventFilter; - if(eventFilter){ - try { - return eventFilter.call(elt, evt) !== true; - } catch(e) { - triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); - return true; - } - } - return false; - } - - function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { - var elementData = getInternalData(elt); - var eltsToListenOn; - if (triggerSpec.from) { - eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); - } else { - eltsToListenOn = [elt]; - } - // store the initial values of the elements, so we can tell if they change - if (triggerSpec.changed) { - eltsToListenOn.forEach(function (eltToListenOn) { - var eltToListenOnData = getInternalData(eltToListenOn); - eltToListenOnData.lastValue = eltToListenOn.value; - }) - } - forEach(eltsToListenOn, function (eltToListenOn) { - var eventListener = function (evt) { - if (!bodyContains(elt)) { - eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); - return; - } - if (ignoreBoostedAnchorCtrlClick(elt, evt)) { - return; - } - if (explicitCancel || shouldCancel(evt, elt)) { - evt.preventDefault(); - } - if (maybeFilterEvent(triggerSpec, elt, evt)) { - return; - } - var eventData = getInternalData(evt); - eventData.triggerSpec = triggerSpec; - if (eventData.handledFor == null) { - eventData.handledFor = []; - } - if (eventData.handledFor.indexOf(elt) < 0) { - eventData.handledFor.push(elt); - if (triggerSpec.consume) { - evt.stopPropagation(); - } - if (triggerSpec.target && evt.target) { - if (!matches(evt.target, triggerSpec.target)) { - return; - } - } - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } - } - if (triggerSpec.changed) { - var eltToListenOnData = getInternalData(eltToListenOn) - if (eltToListenOnData.lastValue === eltToListenOn.value) { - return; - } - eltToListenOnData.lastValue = eltToListenOn.value - } - if (elementData.delayed) { - clearTimeout(elementData.delayed); - } - if (elementData.throttle) { - return; - } - - if (triggerSpec.throttle > 0) { - if (!elementData.throttle) { - handler(elt, evt); - elementData.throttle = setTimeout(function () { - elementData.throttle = null; - }, triggerSpec.throttle); - } - } else if (triggerSpec.delay > 0) { - elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); - } else { - triggerEvent(elt, 'htmx:trigger') - handler(elt, evt); - } - } - }; - if (nodeData.listenerInfos == null) { - nodeData.listenerInfos = []; - } - nodeData.listenerInfos.push({ - trigger: triggerSpec.trigger, - listener: eventListener, - on: eltToListenOn - }) - eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); - }); - } - - var windowIsScrolling = false // used by initScrollHandler - var scrollHandler = null; - function initScrollHandler() { - if (!scrollHandler) { - scrollHandler = function() { - windowIsScrolling = true - }; - window.addEventListener("scroll", scrollHandler) - setInterval(function() { - if (windowIsScrolling) { - windowIsScrolling = false; - forEach(getDocument().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"), function (elt) { - maybeReveal(elt); - }) - } - }, 200); - } - } - - function maybeReveal(elt) { - if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { - elt.setAttribute('data-hx-revealed', 'true'); - var nodeData = getInternalData(elt); - if (nodeData.initHash) { - triggerEvent(elt, 'revealed'); - } else { - // if the node isn't initialized, wait for it before triggering the request - elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true}); - } - } - } - - //==================================================================== - // Web Sockets - //==================================================================== - - function processWebSocketInfo(elt, nodeData, info) { - var values = splitOnWhitespace(info); - for (var i = 0; i < values.length; i++) { - var value = values[i].split(/:(.+)/); - if (value[0] === "connect") { - ensureWebSocket(elt, value[1], 0); - } - if (value[0] === "send") { - processWebSocketSend(elt); - } - } - } - - function ensureWebSocket(elt, wssSource, retryCount) { - if (!bodyContains(elt)) { - return; // stop ensuring websocket connection when socket bearing element ceases to exist - } - - if (wssSource.indexOf("/") == 0) { // complete absolute paths only - var base_part = location.hostname + (location.port ? ':'+location.port: ''); - if (location.protocol == 'https:') { - wssSource = "wss://" + base_part + wssSource; - } else if (location.protocol == 'http:') { - wssSource = "ws://" + base_part + wssSource; - } - } - var socket = htmx.createWebSocket(wssSource); - socket.onerror = function (e) { - triggerErrorEvent(elt, "htmx:wsError", {error:e, socket:socket}); - maybeCloseWebSocketSource(elt); - }; - - socket.onclose = function (e) { - if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later - var delay = getWebSocketReconnectDelay(retryCount); - setTimeout(function() { - ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout - }, delay); - } - }; - socket.onopen = function (e) { - retryCount = 0; - } - - getInternalData(elt).webSocket = socket; - socket.addEventListener('message', function (event) { - if (maybeCloseWebSocketSource(elt)) { - return; - } - - var response = event.data; - withExtensions(elt, function(extension){ - response = extension.transformResponse(response, null, elt); - }); - - var settleInfo = makeSettleInfo(elt); - var fragment = makeFragment(response); - var children = toArray(fragment.children); - for (var i = 0; i < children.length; i++) { - var child = children[i]; - oobSwap(getAttributeValue(child, "hx-swap-oob") || "true", child, settleInfo); - } - - settleImmediately(settleInfo.tasks); - }); - } - - function maybeCloseWebSocketSource(elt) { - if (!bodyContains(elt)) { - getInternalData(elt).webSocket.close(); - return true; - } - } - - function processWebSocketSend(elt) { - var webSocketSourceElt = getClosestMatch(elt, function (parent) { - return getInternalData(parent).webSocket != null; - }); - if (webSocketSourceElt) { - elt.addEventListener(getTriggerSpecs(elt)[0].trigger, function (evt) { - var webSocket = getInternalData(webSocketSourceElt).webSocket; - var headers = getHeaders(elt, webSocketSourceElt); - var results = getInputValues(elt, 'post'); - var errors = results.errors; - var rawParameters = results.values; - var expressionVars = getExpressionVars(elt); - var allParameters = mergeObjects(rawParameters, expressionVars); - var filteredParameters = filterValues(allParameters, elt); - filteredParameters['HEADERS'] = headers; - if (errors && errors.length > 0) { - triggerEvent(elt, 'htmx:validation:halted', errors); - return; - } - webSocket.send(JSON.stringify(filteredParameters)); - if(shouldCancel(evt, elt)){ - evt.preventDefault(); - } - }); - } else { - triggerErrorEvent(elt, "htmx:noWebSocketSourceError"); - } - } - - function getWebSocketReconnectDelay(retryCount) { - var delay = htmx.config.wsReconnectDelay; - if (typeof delay === 'function') { - // @ts-ignore - return delay(retryCount); - } - if (delay === 'full-jitter') { - var exp = Math.min(retryCount, 6); - var maxDelay = 1000 * Math.pow(2, exp); - return maxDelay * Math.random(); - } - logError('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"'); - } - - //==================================================================== - // Server Sent Events - //==================================================================== - - function processSSEInfo(elt, nodeData, info) { - var values = splitOnWhitespace(info); - for (var i = 0; i < values.length; i++) { - var value = values[i].split(/:(.+)/); - if (value[0] === "connect") { - processSSESource(elt, value[1]); - } - - if ((value[0] === "swap")) { - processSSESwap(elt, value[1]) - } - } - } - - function processSSESource(elt, sseSrc) { - var source = htmx.createEventSource(sseSrc); - source.onerror = function (e) { - triggerErrorEvent(elt, "htmx:sseError", {error:e, source:source}); - maybeCloseSSESource(elt); - }; - getInternalData(elt).sseEventSource = source; - } - - function processSSESwap(elt, sseEventName) { - var sseSourceElt = getClosestMatch(elt, hasEventSource); - if (sseSourceElt) { - var sseEventSource = getInternalData(sseSourceElt).sseEventSource; - var sseListener = function (event) { - if (maybeCloseSSESource(sseSourceElt)) { - return; - } - if (!bodyContains(elt)) { - sseEventSource.removeEventListener(sseEventName, sseListener); - return; - } - - /////////////////////////// - // TODO: merge this code with AJAX and WebSockets code in the future. - - var response = event.data; - withExtensions(elt, function(extension){ - response = extension.transformResponse(response, null, elt); - }); - - var swapSpec = getSwapSpecification(elt) - var target = getTarget(elt) - var settleInfo = makeSettleInfo(elt); - - selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) - settleImmediately(settleInfo.tasks) - triggerEvent(elt, "htmx:sseMessage", event) - }; - - getInternalData(elt).sseListener = sseListener; - sseEventSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "htmx:noSSESourceError"); - } - } - - function processSSETrigger(elt, handler, sseEventName) { - var sseSourceElt = getClosestMatch(elt, hasEventSource); - if (sseSourceElt) { - var sseEventSource = getInternalData(sseSourceElt).sseEventSource; - var sseListener = function () { - if (!maybeCloseSSESource(sseSourceElt)) { - if (bodyContains(elt)) { - handler(elt); - } else { - sseEventSource.removeEventListener(sseEventName, sseListener); - } - } - }; - getInternalData(elt).sseListener = sseListener; - sseEventSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "htmx:noSSESourceError"); - } - } - - function maybeCloseSSESource(elt) { - if (!bodyContains(elt)) { - getInternalData(elt).sseEventSource.close(); - return true; - } - } - - function hasEventSource(node) { - return getInternalData(node).sseEventSource != null; - } - - //==================================================================== - - function loadImmediately(elt, handler, nodeData, delay) { - var load = function(){ - if (!nodeData.loaded) { - nodeData.loaded = true; - handler(elt); - } - } - if (delay > 0) { - setTimeout(load, delay); - } else { - load(); - } - } - - function processVerbs(elt, nodeData, triggerSpecs) { - var explicitAction = false; - forEach(VERBS, function (verb) { - if (hasAttribute(elt,'hx-' + verb)) { - var path = getAttributeValue(elt, 'hx-' + verb); - explicitAction = true; - nodeData.path = path; - nodeData.verb = verb; - triggerSpecs.forEach(function(triggerSpec) { - addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return - } - issueAjaxRequest(verb, path, elt, evt) - }) - }); - } - }); - return explicitAction; - } - - function addTriggerHandler(elt, triggerSpec, nodeData, handler) { - if (triggerSpec.sseEvent) { - processSSETrigger(elt, handler, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - addEventListener(elt, handler, nodeData, triggerSpec); - maybeReveal(elt); - } else if (triggerSpec.trigger === "intersect") { - var observerOptions = {}; - if (triggerSpec.root) { - observerOptions.root = querySelectorExt(elt, triggerSpec.root) - } - if (triggerSpec.threshold) { - observerOptions.threshold = parseFloat(triggerSpec.threshold); - } - var observer = new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - if (entry.isIntersecting) { - triggerEvent(elt, "intersect"); - break; - } - } - }, observerOptions); - observer.observe(elt); - addEventListener(elt, handler, nodeData, triggerSpec); - } else if (triggerSpec.trigger === "load") { - if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { - loadImmediately(elt, handler, nodeData, triggerSpec.delay); - } - } else if (triggerSpec.pollInterval > 0) { - nodeData.polling = true; - processPolling(elt, handler, triggerSpec); - } else { - addEventListener(elt, handler, nodeData, triggerSpec); - } - } - - function evalScript(script) { - if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) { - var newScript = getDocument().createElement("script"); - forEach(script.attributes, function (attr) { - newScript.setAttribute(attr.name, attr.value); - }); - newScript.textContent = script.textContent; - newScript.async = false; - if (htmx.config.inlineScriptNonce) { - newScript.nonce = htmx.config.inlineScriptNonce; - } - var parent = script.parentElement; - - try { - parent.insertBefore(newScript, script); - } catch (e) { - logError(e); - } finally { - // remove old script element, but only if it is still in DOM - if (script.parentElement) { - script.parentElement.removeChild(script); - } - } - } - } - - function processScripts(elt) { - if (matches(elt, "script")) { - evalScript(elt); - } - forEach(findAll(elt, "script"), function (script) { - evalScript(script); - }); - } - - function shouldProcessHxOn(elt) { - var attributes = elt.attributes - for (var j = 0; j < attributes.length; j++) { - var attrName = attributes[j].name - if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") || - startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) { - return true - } - } - return false - } - - function findHxOnWildcardElements(elt) { - var node = null - var elements = [] - - if (shouldProcessHxOn(elt)) { - elements.push(elt) - } - - if (document.evaluate) { - var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + - ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt) - while (node = iter.iterateNext()) elements.push(node) - } else { - var allElements = elt.getElementsByTagName("*") - for (var i = 0; i < allElements.length; i++) { - if (shouldProcessHxOn(allElements[i])) { - elements.push(allElements[i]) - } - } - } - - return elements - } - - function findElementsToProcess(elt) { - if (elt.querySelectorAll) { - var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; - var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]"); - return results; - } else { - return []; - } - } - - // Handle submit buttons/inputs that have the form attribute set - // see https://developer.mozilla.org/docs/Web/HTML/Element/button - function maybeSetLastButtonClicked(evt) { - var elt = closest(evt.target, "button, input[type='submit']"); - var internalData = getRelatedFormData(evt) - if (internalData) { - internalData.lastButtonClicked = elt; - } - }; - function maybeUnsetLastButtonClicked(evt){ - var internalData = getRelatedFormData(evt) - if (internalData) { - internalData.lastButtonClicked = null; - } - } - function getRelatedFormData(evt) { - var elt = closest(evt.target, "button, input[type='submit']"); - if (!elt) { - return; - } - var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form'); - if (!form) { - return; - } - return getInternalData(form); - } - function initButtonTracking(elt) { - // need to handle both click and focus in: - // focusin - in case someone tabs in to a button and hits the space bar - // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 - elt.addEventListener('click', maybeSetLastButtonClicked) - elt.addEventListener('focusin', maybeSetLastButtonClicked) - elt.addEventListener('focusout', maybeUnsetLastButtonClicked) - } - - function countCurlies(line) { - var tokens = tokenizeString(line); - var netCurlies = 0; - for (var i = 0; i < tokens.length; i++) { - const token = tokens[i]; - if (token === "{") { - netCurlies++; - } else if (token === "}") { - netCurlies--; - } - } - return netCurlies; - } - - function addHxOnEventHandler(elt, eventName, code) { - var nodeData = getInternalData(elt); - if (!Array.isArray(nodeData.onHandlers)) { - nodeData.onHandlers = []; - } - var func; - var listener = function (e) { - return maybeEval(elt, function() { - if (!func) { - func = new Function("event", code); - } - func.call(elt, e); - }); - }; - elt.addEventListener(eventName, listener); - nodeData.onHandlers.push({event:eventName, listener:listener}); - } - - function processHxOn(elt) { - var hxOnValue = getAttributeValue(elt, 'hx-on'); - if (hxOnValue) { - var handlers = {} - var lines = hxOnValue.split("\n"); - var currentEvent = null; - var curlyCount = 0; - while (lines.length > 0) { - var line = lines.shift(); - var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/); - if (curlyCount === 0 && match) { - line.split(":") - currentEvent = match[1].slice(0, -1); // strip last colon - handlers[currentEvent] = match[2]; - } else { - handlers[currentEvent] += line; - } - curlyCount += countCurlies(line); - } - - for (var eventName in handlers) { - addHxOnEventHandler(elt, eventName, handlers[eventName]); - } - } - } - - function processHxOnWildcard(elt) { - // wipe any previous on handlers so that this function takes precedence - deInitOnHandlers(elt) - - for (var i = 0; i < elt.attributes.length; i++) { - var name = elt.attributes[i].name - var value = elt.attributes[i].value - if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) { - var afterOnPosition = name.indexOf("-on") + 3; - var nextChar = name.slice(afterOnPosition, afterOnPosition + 1); - if (nextChar === "-" || nextChar === ":") { - var eventName = name.slice(afterOnPosition + 1); - // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support - if (startsWith(eventName, ":")) { - eventName = "htmx" + eventName - } else if (startsWith(eventName, "-")) { - eventName = "htmx:" + eventName.slice(1); - } else if (startsWith(eventName, "htmx-")) { - eventName = "htmx:" + eventName.slice(5); - } - - addHxOnEventHandler(elt, eventName, value) - } - } - } - } - - function initNode(elt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return; - } - var nodeData = getInternalData(elt); - if (nodeData.initHash !== attributeHash(elt)) { - // clean up any previously processed info - deInitNode(elt); - - nodeData.initHash = attributeHash(elt); - - processHxOn(elt); - - triggerEvent(elt, "htmx:beforeProcessNode") - - if (elt.value) { - nodeData.lastValue = elt.value; - } - - var triggerSpecs = getTriggerSpecs(elt); - var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs); - - if (!hasExplicitHttpAction) { - if (getClosestAttributeValue(elt, "hx-boost") === "true") { - boostElement(elt, nodeData, triggerSpecs); - } else if (hasAttribute(elt, 'hx-trigger')) { - triggerSpecs.forEach(function (triggerSpec) { - // For "naked" triggers, don't do anything at all - addTriggerHandler(elt, triggerSpec, nodeData, function () { - }) - }) - } - } - - // Handle submit buttons/inputs that have the form attribute set - // see https://developer.mozilla.org/docs/Web/HTML/Element/button - if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) { - initButtonTracking(elt) - } - - var sseInfo = getAttributeValue(elt, 'hx-sse'); - if (sseInfo) { - processSSEInfo(elt, nodeData, sseInfo); - } - - var wsInfo = getAttributeValue(elt, 'hx-ws'); - if (wsInfo) { - processWebSocketInfo(elt, nodeData, wsInfo); - } - triggerEvent(elt, "htmx:afterProcessNode"); - } - } - - function processNode(elt) { - elt = resolveTarget(elt); - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return; - } - initNode(elt); - forEach(findElementsToProcess(elt), function(child) { initNode(child) }); - // Because it happens second, the new way of adding onHandlers superseeds the old one - // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored - forEach(findHxOnWildcardElements(elt), processHxOnWildcard); - } - - //==================================================================== - // Event/Log Support - //==================================================================== - - function kebabEventName(str) { - return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase(); - } - - 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({error:eventName}, detail)); - } - - function ignoreEventForLogging(eventName) { - return eventName === "htmx:afterProcessNode" - } - - /** - * `withExtensions` locates all active extensions for a provided element, then - * executes the provided function using each of the active extensions. It should - * be called internally at every extendable execution point in htmx. - * - * @param {HTMLElement} elt - * @param {(extension:import("./htmx").HtmxExtension) => void} toDo - * @returns void - */ - function withExtensions(elt, toDo) { - forEach(getExtensions(elt), function(extension){ - try { - toDo(extension); - } catch (e) { - logError(e); - } - }); - } - - function logError(msg) { - if(console.error) { - console.error(msg); - } else if (console.log) { - console.log("ERROR: ", msg); - } - } - - function triggerEvent(elt, eventName, detail) { - elt = resolveTarget(elt); - if (detail == null) { - detail = {}; - } - detail["elt"] = elt; - var event = makeEvent(eventName, detail); - if (htmx.logger && !ignoreEventForLogging(eventName)) { - htmx.logger(elt, eventName, detail); - } - if (detail.error) { - logError(detail.error); - triggerEvent(elt, "htmx:error", {errorInfo:detail}) - } - var eventResult = elt.dispatchEvent(event); - var kebabName = kebabEventName(eventName); - if (eventResult && kebabName !== eventName) { - var kebabedEvent = makeEvent(kebabName, event.detail); - eventResult = eventResult && elt.dispatchEvent(kebabedEvent) - } - withExtensions(elt, function (extension) { - eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) - }); - return eventResult; - } - - //==================================================================== - // History Support - //==================================================================== - var currentPathForHistory = location.pathname+location.search; - - function getHistoryElement() { - var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]'); - return historyElt || getDocument().body; - } - - function saveToHistoryCache(url, content, title, scroll) { - if (!canAccessLocalStorage()) { - return; - } - - if (htmx.config.historyCacheSize <= 0) { - // make sure that an eventually already existing cache is purged - localStorage.removeItem("htmx-history-cache"); - return; - } - - url = normalizePath(url); - - var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - historyCache.splice(i, 1); - break; - } - } - var newHistoryItem = {url:url, content: content, title:title, scroll:scroll}; - triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache}) - historyCache.push(newHistoryItem) - while (historyCache.length > htmx.config.historyCacheSize) { - historyCache.shift(); - } - while(historyCache.length > 0){ - try { - localStorage.setItem("htmx-history-cache", JSON.stringify(historyCache)); - break; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:historyCacheError", {cause:e, cache: historyCache}) - historyCache.shift(); // shrink the cache and retry - } - } - } - - function getCachedHistory(url) { - if (!canAccessLocalStorage()) { - return null; - } - - url = normalizePath(url); - - var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - return historyCache[i]; - } - } - return null; - } - - function cleanInnerHtmlForHistory(elt) { - var className = htmx.config.requestClass; - var clone = elt.cloneNode(true); - forEach(findAll(clone, "." + className), function(child){ - removeClassFromElement(child, className); - }); - return clone.innerHTML; - } - - function saveCurrentPageToHistory() { - var elt = getHistoryElement(); - var path = currentPathForHistory || location.pathname+location.search; - - // Allow history snapshot feature to be disabled where hx-history="false" - // is present *anywhere* in the current document we're about to save, - // so we can prevent privileged data entering the cache. - // The page will still be reachable as a history entry, but htmx will fetch it - // live from the server onpopstate rather than look in the localStorage cache - var disableHistoryCache - try { - disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') - } catch (e) { - // IE11: insensitive modifier not supported so fallback to case sensitive selector - disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') - } - if (!disableHistoryCache) { - triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt}); - saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); - } - - if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href); - } - - function pushUrlIntoHistory(path) { - // remove the cache buster parameter, if any - if (htmx.config.getCacheBusterParam) { - path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') - if (endsWith(path, '&') || endsWith(path, "?")) { - path = path.slice(0, -1); - } - } - if(htmx.config.historyEnabled) { - history.pushState({htmx:true}, "", path); - } - currentPathForHistory = path; - } - - function replaceUrlInHistory(path) { - if(htmx.config.historyEnabled) history.replaceState({htmx:true}, "", path); - currentPathForHistory = path; - } - - function settleImmediately(tasks) { - forEach(tasks, function (task) { - task.call(); - }); - } - - function loadHistoryFromServer(path) { - var request = new XMLHttpRequest(); - var details = {path: path, xhr:request}; - triggerEvent(getDocument().body, "htmx:historyCacheMiss", details); - request.open('GET', path, true); - request.setRequestHeader("HX-Request", "true"); - request.setRequestHeader("HX-History-Restore-Request", "true"); - request.setRequestHeader("HX-Current-URL", getDocument().location.href); - request.onload = function () { - if (this.status >= 200 && this.status < 400) { - triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); - var fragment = makeFragment(this.response); - // @ts-ignore - fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; - var historyElement = getHistoryElement(); - var settleInfo = makeSettleInfo(historyElement); - var title = findTitle(this.response); - if (title) { - var titleElt = find("title"); - if (titleElt) { - titleElt.innerHTML = title; - } else { - window.document.title = title; - } - } - // @ts-ignore - swapInnerHTML(historyElement, fragment, settleInfo) - settleImmediately(settleInfo.tasks); - currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response}); - } else { - triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details); - } - }; - request.send(); - } - - function restoreHistory(path) { - saveCurrentPageToHistory(); - path = path || location.pathname+location.search; - var cached = getCachedHistory(path); - if (cached) { - var fragment = makeFragment(cached.content); - var historyElement = getHistoryElement(); - var settleInfo = makeSettleInfo(historyElement); - swapInnerHTML(historyElement, fragment, settleInfo) - settleImmediately(settleInfo.tasks); - document.title = cached.title; - setTimeout(function () { - window.scrollTo(0, cached.scroll); - }, 0); // next 'tick', so browser has time to render layout - currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); - } else { - if (htmx.config.refreshOnHistoryMiss) { - - // @ts-ignore: optional parameter in reload() function throws error - window.location.reload(true); - } else { - loadHistoryFromServer(path); - } - } - } - - function addRequestIndicatorClasses(elt) { - var indicators = findAttributeTargets(elt, 'hx-indicator'); - if (indicators == null) { - indicators = [elt]; - } - forEach(indicators, function (ic) { - var internalData = getInternalData(ic); - internalData.requestCount = (internalData.requestCount || 0) + 1; - ic.classList["add"].call(ic.classList, htmx.config.requestClass); - }); - return indicators; - } - - function disableElements(elt) { - var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt'); - if (disabledElts == null) { - disabledElts = []; - } - forEach(disabledElts, function (disabledElement) { - var internalData = getInternalData(disabledElement); - internalData.requestCount = (internalData.requestCount || 0) + 1; - disabledElement.setAttribute("disabled", ""); - }); - return disabledElts; - } - - function removeRequestIndicators(indicators, disabled) { - forEach(indicators, function (ic) { - var internalData = getInternalData(ic); - internalData.requestCount = (internalData.requestCount || 0) - 1; - if (internalData.requestCount === 0) { - ic.classList["remove"].call(ic.classList, htmx.config.requestClass); - } - }); - forEach(disabled, function (disabledElement) { - var internalData = getInternalData(disabledElement); - internalData.requestCount = (internalData.requestCount || 0) - 1; - if (internalData.requestCount === 0) { - disabledElement.removeAttribute('disabled'); - } - }); - } - - //==================================================================== - // 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 || closest(elt, "fieldset[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 addValueToValues(name, value, values) { - // This is a little ugly because both the current value of the named value in the form - // and the new value could be arrays, so we have to handle all four cases :/ - if (name != null && value != null) { - var current = values[name]; - if (current === undefined) { - values[name] = value; - } else if (Array.isArray(current)) { - if (Array.isArray(value)) { - values[name] = current.concat(value); - } else { - current.push(value); - } - } else { - if (Array.isArray(value)) { - values[name] = [current].concat(value); - } else { - values[name] = [current, value]; - } - } - } - } - - function processInputValue(processed, values, errors, elt, validate) { - if (elt == null || haveSeenNode(processed, elt)) { - return; - } else { - processed.push(elt); - } - if (shouldInclude(elt)) { - var name = getRawAttribute(elt,"name"); - var value = elt.value; - if (elt.multiple && elt.tagName === "SELECT") { - value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value }); - } - // include file inputs - if (elt.files) { - value = toArray(elt.files); - } - addValueToValues(name, value, values); - if (validate) { - validateElement(elt, errors); - } - } - if (matches(elt, 'form')) { - var inputs = elt.elements; - forEach(inputs, function(input) { - processInputValue(processed, values, errors, input, validate); - }); - } - } - - function validateElement(element, errors) { - if (element.willValidate) { - triggerEvent(element, "htmx:validation:validate") - if (!element.checkValidity()) { - errors.push({elt: element, message:element.validationMessage, validity:element.validity}); - triggerEvent(element, "htmx:validation:failed", {message:element.validationMessage, validity:element.validity}) - } - } - } - - /** - * @param {HTMLElement} elt - * @param {string} verb - */ - function getInputValues(elt, verb) { - var processed = []; - var values = {}; - var formValues = {}; - var errors = []; - var internalData = getInternalData(elt); - if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { - internalData.lastButtonClicked = null - } - - // only validate when form is directly submitted and novalidate or formnovalidate are not set - // or if the element has an explicit hx-validate="true" on it - var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true"; - if (internalData.lastButtonClicked) { - validate = validate && internalData.lastButtonClicked.formNoValidate !== true; - } - - // for a non-GET include the closest form - if (verb !== 'get') { - processInputValue(processed, formValues, errors, closest(elt, 'form'), validate); - } - - // include the element itself - processInputValue(processed, values, errors, elt, validate); - - // if a button or submit was clicked last, include its value - if (internalData.lastButtonClicked || elt.tagName === "BUTTON" || - (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) { - var button = internalData.lastButtonClicked || elt - var name = getRawAttribute(button, "name") - addValueToValues(name, button.value, formValues) - } - - // include any explicit includes - var includes = findAttributeTargets(elt, "hx-include"); - forEach(includes, function(node) { - processInputValue(processed, values, errors, node, validate); - // if a non-form is included, include any input values within it - if (!matches(node, 'form')) { - forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { - processInputValue(processed, values, errors, descendant, validate); - }) - } - }); - - // form values take precedence, overriding the regular values - values = mergeObjects(values, formValues); - - return {errors:errors, values:values}; - } - - function appendParam(returnStr, name, realValue) { - if (returnStr !== "") { - returnStr += "&"; - } - if (String(realValue) === "[object Object]") { - realValue = JSON.stringify(realValue); - } - var s = encodeURIComponent(realValue); - returnStr += encodeURIComponent(name) + "=" + s; - 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; - } - - function makeFormData(values) { - var formData = new FormData(); - for (var name in values) { - if (values.hasOwnProperty(name)) { - var value = values[name]; - if (Array.isArray(value)) { - forEach(value, function(v) { - formData.append(name, v); - }); - } else { - formData.append(name, value); - } - } - } - return formData; - } - - //==================================================================== - // Ajax - //==================================================================== - - /** - * @param {HTMLElement} elt - * @param {HTMLElement} target - * @param {string} prompt - * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification - */ - function getHeaders(elt, target, prompt) { - var headers = { - "HX-Request" : "true", - "HX-Trigger" : getRawAttribute(elt, "id"), - "HX-Trigger-Name" : getRawAttribute(elt, "name"), - "HX-Target" : getAttributeValue(target, "id"), - "HX-Current-URL" : getDocument().location.href, - } - getValuesForElement(elt, "hx-headers", false, headers) - if (prompt !== undefined) { - headers["HX-Prompt"] = prompt; - } - if (getInternalData(elt).boosted) { - headers["HX-Boosted"] = "true"; - } - return headers; - } - - /** - * filterValues takes an object containing form input values - * and returns a new object that only contains keys that are - * specified by the closest "hx-params" attribute - * @param {Object} inputValues - * @param {HTMLElement} elt - * @returns {Object} - */ - function filterValues(inputValues, elt) { - var paramsValue = getClosestAttributeValue(elt, "hx-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 isAnchorLink(elt) { - return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0 - } - - /** - * - * @param {HTMLElement} elt - * @param {string} swapInfoOverride - * @returns {import("./htmx").HtmxSwapSpecification} - */ - function getSwapSpecification(elt, swapInfoOverride) { - var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap"); - var swapSpec = { - "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, - "swapDelay" : htmx.config.defaultSwapDelay, - "settleDelay" : htmx.config.defaultSettleDelay - } - if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { - swapSpec["show"] = "top" - } - if (swapInfo) { - var split = splitOnWhitespace(swapInfo); - if (split.length > 0) { - for (var i = 0; i < split.length; i++) { - var value = split[i]; - if (value.indexOf("swap:") === 0) { - swapSpec["swapDelay"] = parseInterval(value.substr(5)); - } else if (value.indexOf("settle:") === 0) { - swapSpec["settleDelay"] = parseInterval(value.substr(7)); - } else if (value.indexOf("transition:") === 0) { - swapSpec["transition"] = value.substr(11) === "true"; - } else if (value.indexOf("ignoreTitle:") === 0) { - swapSpec["ignoreTitle"] = value.substr(12) === "true"; - } else if (value.indexOf("scroll:") === 0) { - var scrollSpec = value.substr(7); - var splitSpec = scrollSpec.split(":"); - var scrollVal = splitSpec.pop(); - var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; - swapSpec["scroll"] = scrollVal; - swapSpec["scrollTarget"] = selectorVal; - } else if (value.indexOf("show:") === 0) { - var showSpec = value.substr(5); - var splitSpec = showSpec.split(":"); - var showVal = splitSpec.pop(); - var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; - swapSpec["show"] = showVal; - swapSpec["showTarget"] = selectorVal; - } else if (value.indexOf("focus-scroll:") === 0) { - var focusScrollVal = value.substr("focus-scroll:".length); - swapSpec["focusScroll"] = focusScrollVal == "true"; - } else if (i == 0) { - swapSpec["swapStyle"] = value; - } else { - logError('Unknown modifier in hx-swap: ' + value); - } - } - } - } - return swapSpec; - } - - function usesFormData(elt) { - return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || - (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data"); - } - - function encodeParamsForBody(xhr, elt, filteredParameters) { - var encodedParameters = null; - withExtensions(elt, function (extension) { - if (encodedParameters == null) { - encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt); - } - }); - if (encodedParameters != null) { - return encodedParameters; - } else { - if (usesFormData(elt)) { - return makeFormData(filteredParameters); - } else { - return urlEncode(filteredParameters); - } - } - } - - /** - * - * @param {Element} target - * @returns {import("./htmx").HtmxSettleInfo} - */ - function makeSettleInfo(target) { - return {tasks: [], elts: [target]}; - } - - function updateScrollState(content, swapSpec) { - var first = content[0]; - var last = content[content.length - 1]; - if (swapSpec.scroll) { - var target = null; - if (swapSpec.scrollTarget) { - target = querySelectorExt(first, swapSpec.scrollTarget); - } - if (swapSpec.scroll === "top" && (first || target)) { - target = target || first; - target.scrollTop = 0; - } - if (swapSpec.scroll === "bottom" && (last || target)) { - target = target || last; - target.scrollTop = target.scrollHeight; - } - } - if (swapSpec.show) { - var target = null; - if (swapSpec.showTarget) { - var targetStr = swapSpec.showTarget; - if (swapSpec.showTarget === "window") { - targetStr = "body"; - } - target = querySelectorExt(first, targetStr); - } - if (swapSpec.show === "top" && (first || target)) { - target = target || first; - target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior}); - } - if (swapSpec.show === "bottom" && (last || target)) { - target = target || last; - target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior}); - } - } - } - - /** - * @param {HTMLElement} elt - * @param {string} attr - * @param {boolean=} evalAsDefault - * @param {Object=} values - * @returns {Object} - */ - function getValuesForElement(elt, attr, evalAsDefault, values) { - if (values == null) { - values = {}; - } - if (elt == null) { - return values; - } - var attributeValue = getAttributeValue(elt, attr); - if (attributeValue) { - var str = attributeValue.trim(); - var evaluateValue = evalAsDefault; - if (str === "unset") { - return null; - } - if (str.indexOf("javascript:") === 0) { - str = str.substr(11); - evaluateValue = true; - } else if (str.indexOf("js:") === 0) { - str = str.substr(3); - evaluateValue = true; - } - if (str.indexOf('{') !== 0) { - str = "{" + str + "}"; - } - var varsValues; - if (evaluateValue) { - varsValues = maybeEval(elt,function () {return Function("return (" + str + ")")();}, {}); - } else { - varsValues = parseJSON(str); - } - for (var key in varsValues) { - if (varsValues.hasOwnProperty(key)) { - if (values[key] == null) { - values[key] = varsValues[key]; - } - } - } - } - return getValuesForElement(parentElt(elt), attr, evalAsDefault, values); - } - - function maybeEval(elt, toEval, defaultVal) { - if (htmx.config.allowEval) { - return toEval(); - } else { - triggerErrorEvent(elt, 'htmx:evalDisallowedError'); - return defaultVal; - } - } - - /** - * @param {HTMLElement} elt - * @param {*} expressionVars - * @returns - */ - function getHXVarsForElement(elt, expressionVars) { - return getValuesForElement(elt, "hx-vars", true, expressionVars); - } - - /** - * @param {HTMLElement} elt - * @param {*} expressionVars - * @returns - */ - function getHXValsForElement(elt, expressionVars) { - return getValuesForElement(elt, "hx-vals", false, expressionVars); - } - - /** - * @param {HTMLElement} elt - * @returns {Object} - */ - function getExpressionVars(elt) { - return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)); - } - - function safelySetHeaderValue(xhr, header, headerValue) { - if (headerValue !== null) { - try { - xhr.setRequestHeader(header, headerValue); - } catch (e) { - // On an exception, try to set the header URI encoded instead - xhr.setRequestHeader(header, encodeURIComponent(headerValue)); - xhr.setRequestHeader(header + "-URI-AutoEncoded", "true"); - } - } - } - - function getPathFromResponse(xhr) { - // NB: IE11 does not support this stuff - if (xhr.responseURL && typeof(URL) !== "undefined") { - try { - var url = new URL(xhr.responseURL); - return url.pathname + url.search; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:badResponseUrl", {url: xhr.responseURL}); - } - } - } - - function hasHeader(xhr, regexp) { - return regexp.test(xhr.getAllResponseHeaders()) - } - - function ajaxHelper(verb, path, context) { - verb = verb.toLowerCase(); - if (context) { - if (context instanceof Element || isType(context, 'String')) { - return issueAjaxRequest(verb, path, null, null, { - targetOverride: resolveTarget(context), - returnPromise: true - }); - } else { - return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, - { - handler : context.handler, - headers : context.headers, - values : context.values, - targetOverride: resolveTarget(context.target), - swapOverride: context.swap, - select: context.select, - returnPromise: true - }); - } - } else { - return issueAjaxRequest(verb, path, null, null, { - returnPromise: true - }); - } - } - - function hierarchyForElt(elt) { - var arr = []; - while (elt) { - arr.push(elt); - elt = elt.parentElement; - } - return arr; - } - - function verifyPath(elt, path, requestConfig) { - var sameHost - var url - if (typeof URL === "function") { - url = new URL(path, document.location.href); - var origin = document.location.origin; - sameHost = origin === url.origin; - } else { - // IE11 doesn't support URL - url = path - sameHost = startsWith(path, document.location.origin) - } - - if (htmx.config.selfRequestsOnly) { - if (!sameHost) { - return false; - } - } - return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig)); - } - - function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { - var resolve = null; - var reject = null; - etc = etc != null ? etc : {}; - if(etc.returnPromise && typeof Promise !== "undefined"){ - var promise = new Promise(function (_resolve, _reject) { - resolve = _resolve; - reject = _reject; - }); - } - if(elt == null) { - elt = getDocument().body; - } - var responseHandler = etc.handler || handleAjaxResponse; - var select = etc.select || null; - - if (!bodyContains(elt)) { - // do not issue requests for elements removed from the DOM - maybeCall(resolve); - return promise; - } - var target = etc.targetOverride || getTarget(elt); - if (target == null || target == DUMMY_ELT) { - triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); - maybeCall(reject); - return promise; - } - - var eltData = getInternalData(elt); - var submitter = eltData.lastButtonClicked; - - if (submitter) { - var buttonPath = getRawAttribute(submitter, "formaction"); - if (buttonPath != null) { - path = buttonPath; - } - - var buttonVerb = getRawAttribute(submitter, "formmethod") - if (buttonVerb != null) { - // ignore buttons with formmethod="dialog" - if (buttonVerb.toLowerCase() !== "dialog") { - verb = buttonVerb; - } - } - } - - var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); - // allow event-based confirmation w/ a callback - if (confirmed === undefined) { - var issueRequest = function(skipConfirmation) { - return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation); - } - var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion}; - if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { - maybeCall(resolve); - return promise; - } - } - - var syncElt = elt; - var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); - var queueStrategy = null; - var abortable = false; - if (syncStrategy) { - var syncStrings = syncStrategy.split(":"); - var selector = syncStrings[0].trim(); - if (selector === "this") { - syncElt = findThisElement(elt, 'hx-sync'); - } else { - syncElt = querySelectorExt(elt, selector); - } - // default to the drop strategy - syncStrategy = (syncStrings[1] || 'drop').trim(); - eltData = getInternalData(syncElt); - if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { - maybeCall(resolve); - return promise; - } else if (syncStrategy === "abort") { - if (eltData.xhr) { - maybeCall(resolve); - return promise; - } else { - abortable = true; - } - } else if (syncStrategy === "replace") { - triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue - } else if (syncStrategy.indexOf("queue") === 0) { - var queueStrArray = syncStrategy.split(" "); - queueStrategy = (queueStrArray[1] || "last").trim(); - } - } - - if (eltData.xhr) { - if (eltData.abortable) { - triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue - } else { - if(queueStrategy == null){ - if (event) { - var eventData = getInternalData(event); - if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { - queueStrategy = eventData.triggerSpec.queue; - } - } - if (queueStrategy == null) { - queueStrategy = "last"; - } - } - if (eltData.queuedRequests == null) { - eltData.queuedRequests = []; - } - if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } else if (queueStrategy === "all") { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } else if (queueStrategy === "last") { - eltData.queuedRequests = []; // dump existing queue - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } - maybeCall(resolve); - return promise; - } - } - - var xhr = new XMLHttpRequest(); - eltData.xhr = xhr; - eltData.abortable = abortable; - var endRequestLock = function(){ - eltData.xhr = null; - eltData.abortable = false; - if (eltData.queuedRequests != null && - eltData.queuedRequests.length > 0) { - var queuedRequest = eltData.queuedRequests.shift(); - queuedRequest(); - } - } - var promptQuestion = getClosestAttributeValue(elt, "hx-prompt"); - if (promptQuestion) { - var promptResponse = prompt(promptQuestion); - // prompt returns null if cancelled and empty string if accepted with no entry - if (promptResponse === null || - !triggerEvent(elt, 'htmx:prompt', {prompt: promptResponse, target:target})) { - maybeCall(resolve); - endRequestLock(); - return promise; - } + triggerErrorEvent(getDocument().body, 'htmx:syntax:error', { error: e, source: conditionalSource }) + return null } + } + } else if (token === '[') { + bracketCount++ + } + if (isPossibleRelativeReference(token, last, paramName)) { + conditionalSource += '((' + paramName + '.' + token + ') ? (' + paramName + '.' + token + ') : (window.' + token + '))' + } else { + conditionalSource = conditionalSource + token + } + last = tokens.shift() + } + } + } + + /** + * @param {string[]} tokens + * @param {RegExp} match + * @returns {string} + */ + function consumeUntil(tokens, match) { + let result = '' + while (tokens.length > 0 && !match.test(tokens[0])) { + result += tokens.shift() + } + return result + } + + /** + * @param {string[]} tokens + * @returns {string} + */ + function consumeCSSSelector(tokens) { + let result + if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { + tokens.shift() + result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim() + tokens.shift() + } else { + result = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } + return result + } + + const INPUT_SELECTOR = 'input, textarea, select' + + /** + * @param {Element} elt + * @param {string} explicitTrigger + * @param {Object} cache for trigger specs + * @returns {HtmxTriggerSpecification[]} + */ + function parseAndCacheTrigger(elt, explicitTrigger, cache) { + /** @type HtmxTriggerSpecification[] */ + const triggerSpecs = [] + const tokens = tokenizeString(explicitTrigger) + do { + consumeUntil(tokens, NOT_WHITESPACE) + const initialLength = tokens.length + const trigger = consumeUntil(tokens, /[,\[\s]/) + if (trigger !== '') { + if (trigger === 'every') { + /** @type HtmxTriggerSpecification */ + const every = { trigger: 'every' } + consumeUntil(tokens, NOT_WHITESPACE) + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)) + consumeUntil(tokens, NOT_WHITESPACE) + var eventFilter = maybeGenerateConditional(elt, tokens, 'event') + if (eventFilter) { + every.eventFilter = eventFilter + } + triggerSpecs.push(every) + } else { + /** @type HtmxTriggerSpecification */ + const triggerSpec = { trigger } + var eventFilter = maybeGenerateConditional(elt, tokens, 'event') + if (eventFilter) { + triggerSpec.eventFilter = eventFilter + } + while (tokens.length > 0 && tokens[0] !== ',') { + consumeUntil(tokens, NOT_WHITESPACE) + const token = tokens.shift() + if (token === 'changed') { + triggerSpec.changed = true + } else if (token === 'once') { + triggerSpec.once = true + } else if (token === 'consume') { + triggerSpec.consume = true + } else if (token === 'delay' && tokens[0] === ':') { + tokens.shift() + triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)) + } else if (token === 'from' && tokens[0] === ':') { + tokens.shift() + if (COMBINED_SELECTOR_START.test(tokens[0])) { + var from_arg = consumeCSSSelector(tokens) + } else { + var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA) + if (from_arg === 'closest' || from_arg === 'find' || from_arg === 'next' || from_arg === 'previous') { + tokens.shift() + const selector = consumeCSSSelector(tokens) + // `next` and `previous` allow a selector-less syntax + if (selector.length > 0) { + from_arg += ' ' + selector + } + } + } + triggerSpec.from = from_arg + } else if (token === 'target' && tokens[0] === ':') { + tokens.shift() + triggerSpec.target = consumeCSSSelector(tokens) + } else if (token === 'throttle' && tokens[0] === ':') { + tokens.shift() + triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)) + } else if (token === 'queue' && tokens[0] === ':') { + tokens.shift() + triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } else if (token === 'root' && tokens[0] === ':') { + tokens.shift() + triggerSpec[token] = consumeCSSSelector(tokens) + } else if (token === 'threshold' && tokens[0] === ':') { + tokens.shift() + triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } else { + triggerErrorEvent(elt, 'htmx:syntax:error', { token: tokens.shift() }) + } + } + triggerSpecs.push(triggerSpec) + } + } + if (tokens.length === initialLength) { + triggerErrorEvent(elt, 'htmx:syntax:error', { token: tokens.shift() }) + } + consumeUntil(tokens, NOT_WHITESPACE) + } while (tokens[0] === ',' && tokens.shift()) + if (cache) { + cache[explicitTrigger] = triggerSpecs + } + return triggerSpecs + } + + /** + * @param {Element} elt + * @returns {HtmxTriggerSpecification[]} + */ + function getTriggerSpecs(elt) { + const explicitTrigger = getAttributeValue(elt, 'hx-trigger') + let triggerSpecs = [] + if (explicitTrigger) { + const cache = htmx.config.triggerSpecsCache + triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) + } - if (confirmQuestion && !confirmed) { - if(!confirm(confirmQuestion)) { - maybeCall(resolve); - endRequestLock() - return promise; - } + if (triggerSpecs.length > 0) { + return triggerSpecs + } else if (matches(elt, 'form')) { + return [{ trigger: 'submit' }] + } else if (matches(elt, 'input[type="button"], input[type="submit"]')) { + return [{ trigger: 'click' }] + } else if (matches(elt, INPUT_SELECTOR)) { + return [{ trigger: 'change' }] + } else { + return [{ trigger: 'click' }] + } + } + + /** + * @param {Element} elt + */ + function cancelPolling(elt) { + getInternalData(elt).cancelled = true + } + + /** + * @param {Element} elt + * @param {TriggerHandler} handler + * @param {HtmxTriggerSpecification} spec + */ + function processPolling(elt, handler, spec) { + const nodeData = getInternalData(elt) + nodeData.timeout = getWindow().setTimeout(function() { + if (bodyContains(elt) && nodeData.cancelled !== true) { + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { + handler(elt) + } + processPolling(elt, handler, spec) + } + }, spec.pollInterval) + } + + /** + * @param {HTMLAnchorElement} elt + * @returns {boolean} + */ + function isLocalLink(elt) { + return location.hostname === elt.hostname && + getRawAttribute(elt, 'href') && + getRawAttribute(elt, 'href').indexOf('#') !== 0 + } + + /** + * @param {Element} elt + */ + function eltIsDisabled(elt) { + return closest(elt, htmx.config.disableSelector) + } + + /** + * @param {Element} elt + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification[]} triggerSpecs + */ + function boostElement(elt, nodeData, triggerSpecs) { + if ((elt instanceof HTMLAnchorElement && isLocalLink(elt) && (elt.target === '' || elt.target === '_self')) || elt.tagName === 'FORM') { + nodeData.boosted = true + let verb, path + if (elt.tagName === 'A') { + verb = 'get' + path = getRawAttribute(elt, 'href') + } else { + const rawAttribute = getRawAttribute(elt, 'method') + verb = rawAttribute ? rawAttribute.toLowerCase() : 'get' + if (verb === 'get') { + } + path = getRawAttribute(elt, 'action') + } + triggerSpecs.forEach(function(triggerSpec) { + addEventListener(elt, function(node, evt) { + const elt = asElement(node) + if (eltIsDisabled(elt)) { + cleanUpElement(elt) + return + } + issueAjaxRequest(verb, path, elt, evt) + }, nodeData, triggerSpec, true) + }) + } + } + + /** + * @param {Event} evt + * @param {Node} node + * @returns {boolean} + */ + function shouldCancel(evt, node) { + const elt = asElement(node) + if (!elt) { + return false + } + if (evt.type === 'submit' || evt.type === 'click') { + if (elt.tagName === 'FORM') { + return true + } + if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { + return true + } + if (elt instanceof HTMLAnchorElement && elt.href && + (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf('#') !== 0)) { + return true + } + } + return false + } + + /** + * @param {Node} elt + * @param {Event|MouseEvent|KeyboardEvent|TouchEvent} evt + * @returns {boolean} + */ + function ignoreBoostedAnchorCtrlClick(elt, evt) { + return getInternalData(elt).boosted && elt instanceof HTMLAnchorElement && evt.type === 'click' && + // @ts-ignore this will resolve to undefined for events that don't define those properties, which is fine + (evt.ctrlKey || evt.metaKey) + } + + /** + * @param {HtmxTriggerSpecification} triggerSpec + * @param {Node} elt + * @param {Event} evt + * @returns {boolean} + */ + function maybeFilterEvent(triggerSpec, elt, evt) { + const eventFilter = triggerSpec.eventFilter + if (eventFilter) { + try { + return eventFilter.call(elt, evt) !== true + } catch (e) { + const source = eventFilter.source + triggerErrorEvent(getDocument().body, 'htmx:eventFilter:error', { error: e, source }) + return true + } + } + return false + } + + /** + * @param {Node} elt + * @param {TriggerHandler} handler + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification} triggerSpec + * @param {boolean} [explicitCancel] + */ + function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { + const elementData = getInternalData(elt) + /** @type {(Node|Window)[]} */ + let eltsToListenOn + if (triggerSpec.from) { + eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from) + } else { + eltsToListenOn = [elt] + } + // store the initial values of the elements, so we can tell if they change + if (triggerSpec.changed) { + eltsToListenOn.forEach(function(eltToListenOn) { + const eltToListenOnData = getInternalData(eltToListenOn) + // @ts-ignore value will be undefined for non-input elements, which is fine + eltToListenOnData.lastValue = eltToListenOn.value + }) + } + forEach(eltsToListenOn, function(eltToListenOn) { + /** @type EventListener */ + const eventListener = function(evt) { + if (!bodyContains(elt)) { + eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener) + return + } + if (ignoreBoostedAnchorCtrlClick(elt, evt)) { + return + } + if (explicitCancel || shouldCancel(evt, elt)) { + evt.preventDefault() + } + if (maybeFilterEvent(triggerSpec, elt, evt)) { + return + } + const eventData = getInternalData(evt) + eventData.triggerSpec = triggerSpec + if (eventData.handledFor == null) { + eventData.handledFor = [] + } + if (eventData.handledFor.indexOf(elt) < 0) { + eventData.handledFor.push(elt) + if (triggerSpec.consume) { + evt.stopPropagation() + } + if (triggerSpec.target && evt.target) { + if (!matches(asElement(evt.target), triggerSpec.target)) { + return + } + } + if (triggerSpec.once) { + if (elementData.triggeredOnce) { + return + } else { + elementData.triggeredOnce = true + } + } + if (triggerSpec.changed) { + const eltToListenOnData = getInternalData(eltToListenOn) + // @ts-ignore value will be undefined for non-input elements, which is fine + const value = eltToListenOn.value + if (eltToListenOnData.lastValue === value) { + return + } + eltToListenOnData.lastValue = value + } + if (elementData.delayed) { + clearTimeout(elementData.delayed) + } + if (elementData.throttle) { + return + } + + if (triggerSpec.throttle > 0) { + if (!elementData.throttle) { + handler(elt, evt) + elementData.throttle = getWindow().setTimeout(function() { + elementData.throttle = null + }, triggerSpec.throttle) + } + } else if (triggerSpec.delay > 0) { + elementData.delayed = getWindow().setTimeout(function() { handler(elt, evt) }, triggerSpec.delay) + } else { + triggerEvent(elt, 'htmx:trigger') + handler(elt, evt) + } + } + } + if (nodeData.listenerInfos == null) { + nodeData.listenerInfos = [] + } + nodeData.listenerInfos.push({ + trigger: triggerSpec.trigger, + listener: eventListener, + on: eltToListenOn + }) + eltToListenOn.addEventListener(triggerSpec.trigger, eventListener) + }) + } + + let windowIsScrolling = false // used by initScrollHandler + let scrollHandler = null + function initScrollHandler() { + if (!scrollHandler) { + scrollHandler = function() { + windowIsScrolling = true + } + window.addEventListener('scroll', scrollHandler) + setInterval(function() { + if (windowIsScrolling) { + windowIsScrolling = false + forEach(getDocument().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"), function(elt) { + maybeReveal(elt) + }) + } + }, 200) + } + } + + /** + * @param {Element} elt + */ + function maybeReveal(elt) { + if (!hasAttribute(elt, 'data-hx-revealed') && isScrolledIntoView(elt)) { + elt.setAttribute('data-hx-revealed', 'true') + const nodeData = getInternalData(elt) + if (nodeData.initHash) { + triggerEvent(elt, 'revealed') + } else { + // if the node isn't initialized, wait for it before triggering the request + elt.addEventListener('htmx:afterProcessNode', function() { triggerEvent(elt, 'revealed') }, { once: true }) + } + } + } + + //= =================================================================== + + /** + * @param {Element} elt + * @param {TriggerHandler} handler + * @param {HtmxNodeInternalData} nodeData + * @param {number} delay + */ + function loadImmediately(elt, handler, nodeData, delay) { + const load = function() { + if (!nodeData.loaded) { + nodeData.loaded = true + handler(elt) + } + } + if (delay > 0) { + getWindow().setTimeout(load, delay) + } else { + load() + } + } + + /** + * @param {Element} elt + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification[]} triggerSpecs + * @returns {boolean} + */ + function processVerbs(elt, nodeData, triggerSpecs) { + let explicitAction = false + forEach(VERBS, function(verb) { + if (hasAttribute(elt, 'hx-' + verb)) { + const path = getAttributeValue(elt, 'hx-' + verb) + explicitAction = true + nodeData.path = path + nodeData.verb = verb + triggerSpecs.forEach(function(triggerSpec) { + addTriggerHandler(elt, triggerSpec, nodeData, function(node, evt) { + const elt = asElement(node) + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return } + issueAjaxRequest(verb, path, elt, evt) + }) + }) + } + }) + return explicitAction + } + + /** + * @callback TriggerHandler + * @param {Node} elt + * @param {Event} [evt] + */ + + /** + * @param {Node} elt + * @param {HtmxTriggerSpecification} triggerSpec + * @param {HtmxNodeInternalData} nodeData + * @param {TriggerHandler} handler + */ + function addTriggerHandler(elt, triggerSpec, nodeData, handler) { + if (triggerSpec.trigger === 'revealed') { + initScrollHandler() + addEventListener(elt, handler, nodeData, triggerSpec) + maybeReveal(asElement(elt)) + } else if (triggerSpec.trigger === 'intersect') { + const observerOptions = {} + if (triggerSpec.root) { + observerOptions.root = querySelectorExt(elt, triggerSpec.root) + } + if (triggerSpec.threshold) { + observerOptions.threshold = parseFloat(triggerSpec.threshold) + } + const observer = new IntersectionObserver(function(entries) { + for (let i = 0; i < entries.length; i++) { + const entry = entries[i] + if (entry.isIntersecting) { + triggerEvent(elt, 'intersect') + break + } + } + }, observerOptions) + observer.observe(asElement(elt)) + addEventListener(asElement(elt), handler, nodeData, triggerSpec) + } else if (triggerSpec.trigger === 'load') { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent('load', { elt }))) { + loadImmediately(asElement(elt), handler, nodeData, triggerSpec.delay) + } + } else if (triggerSpec.pollInterval > 0) { + nodeData.polling = true + processPolling(asElement(elt), handler, triggerSpec) + } else { + addEventListener(elt, handler, nodeData, triggerSpec) + } + } + + /** + * @param {Node} node + * @returns {boolean} + */ + function shouldProcessHxOn(node) { + const elt = asElement(node) + if (!elt) { + return false + } + const attributes = elt.attributes + for (let j = 0; j < attributes.length; j++) { + const attrName = attributes[j].name + if (startsWith(attrName, 'hx-on:') || startsWith(attrName, 'data-hx-on:') || + startsWith(attrName, 'hx-on-') || startsWith(attrName, 'data-hx-on-')) { + return true + } + } + return false + } + + /** + * @param {Node} elt + * @returns {Element[]} + */ + const HX_ON_QUERY = new XPathEvaluator() + .createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + + ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]') + + function processHXOnRoot(elt, elements) { + if (shouldProcessHxOn(elt)) { + elements.push(asElement(elt)) + } + const iter = HX_ON_QUERY.evaluate(elt) + let node = null + while (node = iter.iterateNext()) elements.push(asElement(node)) + } + + function findHxOnWildcardElements(elt) { + /** @type {Element[]} */ + const elements = [] + if (elt instanceof DocumentFragment) { + for (const child of elt.childNodes) { + processHXOnRoot(child, elements) + } + } else { + processHXOnRoot(elt, elements) + } + return elements + } + + /** + * @param {Element} elt + * @returns {NodeListOf<Element>|[]} + */ + function findElementsToProcess(elt) { + if (elt.querySelectorAll) { + const boostedSelector = ', [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]' + + const extensionSelectors = [] + for (const e in extensions) { + const extension = extensions[e] + if (extension.getSelectors) { + var selectors = extension.getSelectors() + if (selectors) { + extensionSelectors.push(selectors) + } + } + } + + const results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit']," + + ' [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]' + extensionSelectors.flat().map(s => ', ' + s).join('')) + + return results + } else { + return [] + } + } + + /** + * Handle submit buttons/inputs that have the form attribute set + * see https://developer.mozilla.org/docs/Web/HTML/Element/button + * @param {Event} evt + */ + function maybeSetLastButtonClicked(evt) { + const elt = /** @type {HTMLButtonElement|HTMLInputElement} */ (closest(asElement(evt.target), "button, input[type='submit']")) + const internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = elt + } + } + + /** + * @param {Event} evt + */ + function maybeUnsetLastButtonClicked(evt) { + const internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = null + } + } + + /** + * @param {Event} evt + * @returns {HtmxNodeInternalData|undefined} + */ + function getRelatedFormData(evt) { + const elt = closest(asElement(evt.target), "button, input[type='submit']") + if (!elt) { + return + } + const form = resolveTarget('#' + getRawAttribute(elt, 'form'), elt.getRootNode()) || closest(elt, 'form') + if (!form) { + return + } + return getInternalData(form) + } + + /** + * @param {EventTarget} elt + */ + function initButtonTracking(elt) { + // need to handle both click and focus in: + // focusin - in case someone tabs in to a button and hits the space bar + // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + elt.addEventListener('click', maybeSetLastButtonClicked) + elt.addEventListener('focusin', maybeSetLastButtonClicked) + elt.addEventListener('focusout', maybeUnsetLastButtonClicked) + } + + /** + * @param {Element} elt + * @param {string} eventName + * @param {string} code + */ + function addHxOnEventHandler(elt, eventName, code) { + const nodeData = getInternalData(elt) + if (!Array.isArray(nodeData.onHandlers)) { + nodeData.onHandlers = [] + } + let func + /** @type EventListener */ + const listener = function(e) { + maybeEval(elt, function() { + if (eltIsDisabled(elt)) { + return + } + if (!func) { + func = new Function('event', code) + } + func.call(elt, e) + }) + } + elt.addEventListener(eventName, listener) + nodeData.onHandlers.push({ event: eventName, listener }) + } + + /** + * @param {Element} elt + */ + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (let i = 0; i < elt.attributes.length; i++) { + const name = elt.attributes[i].name + const value = elt.attributes[i].value + if (startsWith(name, 'hx-on') || startsWith(name, 'data-hx-on')) { + const afterOnPosition = name.indexOf('-on') + 3 + const nextChar = name.slice(afterOnPosition, afterOnPosition + 1) + if (nextChar === '-' || nextChar === ':') { + let eventName = name.slice(afterOnPosition + 1) + // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support + if (startsWith(eventName, ':')) { + eventName = 'htmx' + eventName + } else if (startsWith(eventName, '-')) { + eventName = 'htmx:' + eventName.slice(1) + } else if (startsWith(eventName, 'htmx-')) { + eventName = 'htmx:' + eventName.slice(5) + } + + addHxOnEventHandler(elt, eventName, value) + } + } + } + } + + /** + * @param {Element|HTMLInputElement} elt + */ + function initNode(elt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + const nodeData = getInternalData(elt) + if (nodeData.initHash !== attributeHash(elt)) { + // clean up any previously processed info + deInitNode(elt) + + nodeData.initHash = attributeHash(elt) + + triggerEvent(elt, 'htmx:beforeProcessNode') + + // @ts-ignore value will be undefined for non-input elements, which is fine + if (elt.value) { + // @ts-ignore + nodeData.lastValue = elt.value + } + + const triggerSpecs = getTriggerSpecs(elt) + const hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs) + + if (!hasExplicitHttpAction) { + if (getClosestAttributeValue(elt, 'hx-boost') === 'true') { + boostElement(elt, nodeData, triggerSpecs) + } else if (hasAttribute(elt, 'hx-trigger')) { + triggerSpecs.forEach(function(triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function() { + }) + }) + } + } + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + if (elt.tagName === 'FORM' || (getRawAttribute(elt, 'type') === 'submit' && hasAttribute(elt, 'form'))) { + initButtonTracking(elt) + } - var headers = getHeaders(elt, target, promptResponse); - - if (verb !== 'get' && !usesFormData(elt)) { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; - } + triggerEvent(elt, 'htmx:afterProcessNode') + } + } + + /** + * Processes new content, enabling htmx behavior. This can be useful if you have content that is added to the DOM outside of the normal htmx request cycle but still want htmx attributes to work. + * + * @see https://htmx.org/api/#process + * + * @param {Element|string} elt element to process + */ + function processNode(elt) { + elt = resolveTarget(elt) + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + initNode(elt) + forEach(findElementsToProcess(elt), function(child) { initNode(child) }) + forEach(findHxOnWildcardElements(elt), processHxOnWildcard) + } + + //= =================================================================== + // Event/Log Support + //= =================================================================== + + /** + * @param {string} str + * @returns {string} + */ + function kebabEventName(str) { + return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase() + } + + /** + * @param {string} eventName + * @param {any} detail + * @returns {CustomEvent} + */ + function makeEvent(eventName, detail) { + let evt + if (window.CustomEvent && typeof window.CustomEvent === 'function') { + // TODO: `composed: true` here is a hack to make global event handlers work with events in shadow DOM + // This breaks expected encapsulation but needs to be here until decided otherwise by core devs + evt = new CustomEvent(eventName, { bubbles: true, cancelable: true, composed: true, detail }) + } else { + evt = getDocument().createEvent('CustomEvent') + evt.initCustomEvent(eventName, true, true, detail) + } + return evt + } + + /** + * @param {EventTarget|string} elt + * @param {string} eventName + * @param {any=} detail + */ + function triggerErrorEvent(elt, eventName, detail) { + triggerEvent(elt, eventName, mergeObjects({ error: eventName }, detail)) + } + + /** + * @param {string} eventName + * @returns {boolean} + */ + function ignoreEventForLogging(eventName) { + return eventName === 'htmx:afterProcessNode' + } + + /** + * `withExtensions` locates all active extensions for a provided element, then + * executes the provided function using each of the active extensions. It should + * be called internally at every extendable execution point in htmx. + * + * @param {Element} elt + * @param {(extension:HtmxExtension) => void} toDo + * @returns void + */ + function withExtensions(elt, toDo) { + forEach(getExtensions(elt), function(extension) { + try { + toDo(extension) + } catch (e) { + logError(e) + } + }) + } + + function logError(msg) { + if (console.error) { + console.error(msg) + } else if (console.log) { + console.log('ERROR: ', msg) + } + } + + /** + * Triggers a given event on an element + * + * @see https://htmx.org/api/#trigger + * + * @param {EventTarget|string} elt the element to trigger the event on + * @param {string} eventName the name of the event to trigger + * @param {any=} detail details for the event + * @returns {boolean} + */ + function triggerEvent(elt, eventName, detail) { + elt = resolveTarget(elt) + if (detail == null) { + detail = {} + } + detail.elt = elt + const event = makeEvent(eventName, detail) + if (htmx.logger && !ignoreEventForLogging(eventName)) { + htmx.logger(elt, eventName, detail) + } + if (detail.error) { + logError(detail.error) + triggerEvent(elt, 'htmx:error', { errorInfo: detail }) + } + let eventResult = elt.dispatchEvent(event) + const kebabName = kebabEventName(eventName) + if (eventResult && kebabName !== eventName) { + const kebabedEvent = makeEvent(kebabName, event.detail) + eventResult = eventResult && elt.dispatchEvent(kebabedEvent) + } + withExtensions(asElement(elt), function(extension) { + eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) + }) + return eventResult + } + + //= =================================================================== + // History Support + //= =================================================================== + let currentPathForHistory = location.pathname + location.search + + /** + * @returns {Element} + */ + function getHistoryElement() { + const historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]') + return historyElt || getDocument().body + } + + /** + * @param {string} url + * @param {Element} rootElt + */ + function saveToHistoryCache(url, rootElt) { + if (!canAccessLocalStorage()) { + return + } - if (etc.headers) { - headers = mergeObjects(headers, etc.headers); - } - var results = getInputValues(elt, verb); - var errors = results.errors; - var rawParameters = results.values; - if (etc.values) { - rawParameters = mergeObjects(rawParameters, etc.values); - } - var expressionVars = getExpressionVars(elt); - var allParameters = mergeObjects(rawParameters, expressionVars); - var filteredParameters = filterValues(allParameters, elt); + // get state to save + const innerHTML = cleanInnerHtmlForHistory(rootElt) + const title = getDocument().title + const scroll = window.scrollY - if (htmx.config.getCacheBusterParam && verb === 'get') { - filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true"; - } + if (htmx.config.historyCacheSize <= 0) { + // make sure that an eventually already existing cache is purged + localStorage.removeItem('htmx-history-cache') + return + } - // behavior of anchors w/ empty href is to use the current URL - if (path == null || path === "") { - path = getDocument().location.href; - } + url = normalizePath(url) + const historyCache = parseJSON(localStorage.getItem('htmx-history-cache')) || [] + for (let i = 0; i < historyCache.length; i++) { + if (historyCache[i].url === url) { + historyCache.splice(i, 1) + break + } + } - var requestAttrValues = getValuesForElement(elt, 'hx-request'); + /** @type HtmxHistoryItem */ + const newHistoryItem = { url, content: innerHTML, title, scroll } - var eltIsBoosted = getInternalData(elt).boosted; + triggerEvent(getDocument().body, 'htmx:historyItemCreated', { item: newHistoryItem, cache: historyCache }) - var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + historyCache.push(newHistoryItem) + while (historyCache.length > htmx.config.historyCacheSize) { + historyCache.shift() + } - var requestConfig = { - boosted: eltIsBoosted, - useUrlParams: useUrlParams, - parameters: filteredParameters, - unfilteredParameters: allParameters, - headers:headers, - target:target, - verb:verb, - errors:errors, - withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, - timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, - path:path, - triggeringEvent:event - }; + // keep trying to save the cache until it succeeds or is empty + while (historyCache.length > 0) { + try { + localStorage.setItem('htmx-history-cache', JSON.stringify(historyCache)) + break + } catch (e) { + triggerErrorEvent(getDocument().body, 'htmx:historyCacheError', { cause: e, cache: historyCache }) + historyCache.shift() // shrink the cache and retry + } + } + } + + /** + * @typedef {Object} HtmxHistoryItem + * @property {string} url + * @property {string} content + * @property {string} title + * @property {number} scroll + */ + + /** + * @param {string} url + * @returns {HtmxHistoryItem|null} + */ + function getCachedHistory(url) { + if (!canAccessLocalStorage()) { + return null + } - if(!triggerEvent(elt, 'htmx:configRequest', requestConfig)){ - maybeCall(resolve); - endRequestLock(); - return promise; - } + url = normalizePath(url) - // copy out in case the object was overwritten - path = requestConfig.path; - verb = requestConfig.verb; - headers = requestConfig.headers; - filteredParameters = requestConfig.parameters; - errors = requestConfig.errors; - useUrlParams = requestConfig.useUrlParams; - - if(errors && errors.length > 0){ - triggerEvent(elt, 'htmx:validation:halted', requestConfig) - maybeCall(resolve); - endRequestLock(); - return promise; - } + const historyCache = parseJSON(localStorage.getItem('htmx-history-cache')) || [] + for (let i = 0; i < historyCache.length; i++) { + if (historyCache[i].url === url) { + return historyCache[i] + } + } + return null + } + + /** + * @param {Element} elt + * @returns {string} + */ + function cleanInnerHtmlForHistory(elt) { + const className = htmx.config.requestClass + const clone = /** @type Element */ (elt.cloneNode(true)) + forEach(findAll(clone, '.' + className), function(child) { + removeClassFromElement(child, className) + }) + return clone.innerHTML + } + + function saveCurrentPageToHistory() { + const elt = getHistoryElement() + const path = currentPathForHistory || location.pathname + location.search + + // Allow history snapshot feature to be disabled where hx-history="false" + // is present *anywhere* in the current document we're about to save, + // so we can prevent privileged data entering the cache. + // The page will still be reachable as a history entry, but htmx will fetch it + // live from the server onpopstate rather than look in the localStorage cache + let disableHistoryCache + try { + disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') + } catch (e) { + // IE11: insensitive modifier not supported so fallback to case sensitive selector + disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') + } + if (!disableHistoryCache) { + triggerEvent(getDocument().body, 'htmx:beforeHistorySave', { path, historyElt: elt }) + saveToHistoryCache(path, elt) + } - var splitPath = path.split("#"); - var pathNoAnchor = splitPath[0]; - var anchor = splitPath[1]; - - var finalPath = path - if (useUrlParams) { - finalPath = pathNoAnchor; - var values = Object.keys(filteredParameters).length !== 0; - if (values) { - if (finalPath.indexOf("?") < 0) { - finalPath += "?"; - } else { - finalPath += "&"; - } - finalPath += urlEncode(filteredParameters); - if (anchor) { - finalPath += "#" + anchor; - } - } - } + if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, getDocument().title, window.location.href) + } + + /** + * @param {string} path + */ + function pushUrlIntoHistory(path) { + // remove the cache buster parameter, if any + if (htmx.config.getCacheBusterParam) { + path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') + if (endsWith(path, '&') || endsWith(path, '?')) { + path = path.slice(0, -1) + } + } + if (htmx.config.historyEnabled) { + history.pushState({ htmx: true }, '', path) + } + currentPathForHistory = path + } + + /** + * @param {string} path + */ + function replaceUrlInHistory(path) { + if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, '', path) + currentPathForHistory = path + } + + /** + * @param {HtmxSettleTask[]} tasks + */ + function settleImmediately(tasks) { + forEach(tasks, function(task) { + task.call(undefined) + }) + } + + /** + * @param {string} path + */ + function loadHistoryFromServer(path) { + const request = new XMLHttpRequest() + const details = { path, xhr: request } + triggerEvent(getDocument().body, 'htmx:historyCacheMiss', details) + request.open('GET', path, true) + request.setRequestHeader('HX-Request', 'true') + request.setRequestHeader('HX-History-Restore-Request', 'true') + request.setRequestHeader('HX-Current-URL', getDocument().location.href) + request.onload = function() { + if (this.status >= 200 && this.status < 400) { + triggerEvent(getDocument().body, 'htmx:historyCacheMissLoad', details) + const fragment = makeFragment(this.response) + /** @type ParentNode */ + const content = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment + const historyElement = getHistoryElement() + const settleInfo = makeSettleInfo(historyElement) + handleTitle(fragment.title) + + swapInnerHTML(historyElement, content, settleInfo) + settleImmediately(settleInfo.tasks) + currentPathForHistory = path + triggerEvent(getDocument().body, 'htmx:historyRestore', { path, cacheMiss: true, serverResponse: this.response }) + } else { + triggerErrorEvent(getDocument().body, 'htmx:historyCacheMissLoadError', details) + } + } + request.send() + } + + /** + * @param {string} [path] + */ + function restoreHistory(path) { + saveCurrentPageToHistory() + path = path || location.pathname + location.search + const cached = getCachedHistory(path) + if (cached) { + const fragment = makeFragment(cached.content) + const historyElement = getHistoryElement() + const settleInfo = makeSettleInfo(historyElement) + handleTitle(fragment.title) + swapInnerHTML(historyElement, fragment, settleInfo) + settleImmediately(settleInfo.tasks) + getWindow().setTimeout(function() { + window.scrollTo(0, cached.scroll) + }, 0) // next 'tick', so browser has time to render layout + currentPathForHistory = path + triggerEvent(getDocument().body, 'htmx:historyRestore', { path, item: cached }) + } else { + if (htmx.config.refreshOnHistoryMiss) { + // @ts-ignore: optional parameter in reload() function throws error + // noinspection JSUnresolvedReference + window.location.reload(true) + } else { + loadHistoryFromServer(path) + } + } + } + + /** + * @param {Element} elt + * @returns {Element[]} + */ + function addRequestIndicatorClasses(elt) { + let indicators = /** @type Element[] */ (findAttributeTargets(elt, 'hx-indicator')) + if (indicators == null) { + indicators = [elt] + } + forEach(indicators, function(ic) { + const internalData = getInternalData(ic) + internalData.requestCount = (internalData.requestCount || 0) + 1 + ic.classList.add.call(ic.classList, htmx.config.requestClass) + }) + return indicators + } + + /** + * @param {Element} elt + * @returns {Element[]} + */ + function disableElements(elt) { + let disabledElts = /** @type Element[] */ (findAttributeTargets(elt, 'hx-disabled-elt')) + if (disabledElts == null) { + disabledElts = [] + } + forEach(disabledElts, function(disabledElement) { + const internalData = getInternalData(disabledElement) + internalData.requestCount = (internalData.requestCount || 0) + 1 + disabledElement.setAttribute('disabled', '') + }) + return disabledElts + } + + /** + * @param {Element[]} indicators + * @param {Element[]} disabled + */ + function removeRequestIndicators(indicators, disabled) { + forEach(indicators, function(ic) { + const internalData = getInternalData(ic) + internalData.requestCount = (internalData.requestCount || 0) - 1 + if (internalData.requestCount === 0) { + ic.classList.remove.call(ic.classList, htmx.config.requestClass) + } + }) + forEach(disabled, function(disabledElement) { + const internalData = getInternalData(disabledElement) + internalData.requestCount = (internalData.requestCount || 0) - 1 + if (internalData.requestCount === 0) { + disabledElement.removeAttribute('disabled') + } + }) + } + + //= =================================================================== + // Input Value Processing + //= =================================================================== + + /** + * @param {Element[]} processed + * @param {Element} elt + * @returns {boolean} + */ + function haveSeenNode(processed, elt) { + for (let i = 0; i < processed.length; i++) { + const node = processed[i] + if (node.isSameNode(elt)) { + return true + } + } + return false + } + + /** + * @param {Element} element + * @return {boolean} + */ + function shouldInclude(element) { + // Cast to trick tsc, undefined values will work fine here + const elt = /** @type {HTMLInputElement} */ (element) + if (elt.name === '' || elt.name == null || elt.disabled || closest(elt, 'fieldset[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 + } + + /** @param {string} name + * @param {string|Array|FormDataEntryValue} value + * @param {FormData} formData */ + function addValueToFormData(name, value, formData) { + if (name != null && value != null) { + if (Array.isArray(value)) { + value.forEach(function(v) { formData.append(name, v) }) + } else { + formData.append(name, value) + } + } + } + + /** @param {string} name + * @param {string|Array} value + * @param {FormData} formData */ + function removeValueFromFormData(name, value, formData) { + if (name != null && value != null) { + let values = formData.getAll(name) + if (Array.isArray(value)) { + values = values.filter(v => value.indexOf(v) < 0) + } else { + values = values.filter(v => v !== value) + } + formData.delete(name) + forEach(values, v => formData.append(name, v)) + } + } + + /** + * @param {Element[]} processed + * @param {FormData} formData + * @param {HtmxElementValidationError[]} errors + * @param {Element|HTMLInputElement|HTMLSelectElement|HTMLFormElement} elt + * @param {boolean} validate + */ + function processInputValue(processed, formData, errors, elt, validate) { + if (elt == null || haveSeenNode(processed, elt)) { + return + } else { + processed.push(elt) + } + if (shouldInclude(elt)) { + const name = getRawAttribute(elt, 'name') + // @ts-ignore value will be undefined for non-input elements, which is fine + let value = elt.value + if (elt instanceof HTMLSelectElement && elt.multiple) { + value = toArray(elt.querySelectorAll('option:checked')).map(function(e) { return (/** @type HTMLOptionElement */(e)).value }) + } + // include file inputs + if (elt instanceof HTMLInputElement && elt.files) { + value = toArray(elt.files) + } + addValueToFormData(name, value, formData) + if (validate) { + validateElement(elt, errors) + } + } + if (elt instanceof HTMLFormElement) { + forEach(elt.elements, function(input) { + if (processed.indexOf(input) >= 0) { + // The input has already been processed and added to the values, but the FormData that will be + // constructed right after on the form, will include it once again. So remove that input's value + // now to avoid duplicates + removeValueFromFormData(input.name, input.value, formData) + } else { + processed.push(input) + } + if (validate) { + validateElement(input, errors) + } + }) + new FormData(elt).forEach(function(value, name) { + if (value instanceof File && value.name === '') { + return // ignore no-name files + } + addValueToFormData(name, value, formData) + }) + } + } + + /** + * + * @param {Element} elt + * @param {HtmxElementValidationError[]} errors + */ + function validateElement(elt, errors) { + const element = /** @type {HTMLElement & ElementInternals} */ (elt) + if (element.willValidate) { + triggerEvent(element, 'htmx:validation:validate') + if (!element.checkValidity()) { + errors.push({ elt: element, message: element.validationMessage, validity: element.validity }) + triggerEvent(element, 'htmx:validation:failed', { message: element.validationMessage, validity: element.validity }) + } + } + } + + /** + * Override values in the one FormData with those from another. + * @param {FormData} receiver the formdata that will be mutated + * @param {FormData} donor the formdata that will provide the overriding values + * @returns {FormData} the {@linkcode receiver} + */ + function overrideFormData(receiver, donor) { + for (const key of donor.keys()) { + receiver.delete(key) + donor.getAll(key).forEach(function(value) { + receiver.append(key, value) + }) + } + return receiver + } + + /** + * @param {Element|HTMLFormElement} elt + * @param {HttpVerb} verb + * @returns {{errors: HtmxElementValidationError[], formData: FormData, values: Object}} + */ + function getInputValues(elt, verb) { + /** @type Element[] */ + const processed = [] + const formData = new FormData() + const priorityFormData = new FormData() + /** @type HtmxElementValidationError[] */ + const errors = [] + const internalData = getInternalData(elt) + if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { + internalData.lastButtonClicked = null + } - if (!verifyPath(elt, finalPath, requestConfig)) { - triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) - maybeCall(reject); - return promise; - }; + // only validate when form is directly submitted and novalidate or formnovalidate are not set + // or if the element has an explicit hx-validate="true" on it + let validate = (elt instanceof HTMLFormElement && elt.noValidate !== true) || getAttributeValue(elt, 'hx-validate') === 'true' + if (internalData.lastButtonClicked) { + validate = validate && internalData.lastButtonClicked.formNoValidate !== true + } - xhr.open(verb.toUpperCase(), finalPath, true); - xhr.overrideMimeType("text/html"); - xhr.withCredentials = requestConfig.withCredentials; - xhr.timeout = requestConfig.timeout; + // for a non-GET include the closest form + if (verb !== 'get') { + processInputValue(processed, priorityFormData, errors, closest(elt, 'form'), validate) + } - // request headers - if (requestAttrValues.noHeaders) { - // ignore all headers - } else { - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - var headerValue = headers[header]; - safelySetHeaderValue(xhr, header, headerValue); - } - } - } + // include the element itself + processInputValue(processed, formData, errors, elt, validate) - var responseInfo = { - xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select, - pathInfo: { - requestPath: path, - finalRequestPath: finalPath, - anchor: anchor - } - }; - - xhr.onload = function () { - try { - var hierarchy = hierarchyForElt(elt); - responseInfo.pathInfo.responsePath = getPathFromResponse(xhr); - responseHandler(elt, responseInfo); - removeRequestIndicators(indicators, disableElts); - triggerEvent(elt, 'htmx:afterRequest', responseInfo); - triggerEvent(elt, 'htmx:afterOnLoad', responseInfo); - // if the body no longer contains the element, trigger the event on the closest parent - // remaining in the DOM - if (!bodyContains(elt)) { - var secondaryTriggerElt = null; - while (hierarchy.length > 0 && secondaryTriggerElt == null) { - var parentEltInHierarchy = hierarchy.shift(); - if (bodyContains(parentEltInHierarchy)) { - secondaryTriggerElt = parentEltInHierarchy; - } - } - if (secondaryTriggerElt) { - triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo); - triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo); - } - } - maybeCall(resolve); - endRequestLock(); - } catch (e) { - triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({error:e}, responseInfo)); - throw e; - } - } - xhr.onerror = function () { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:sendError', responseInfo); - maybeCall(reject); - endRequestLock(); - } - xhr.onabort = function() { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo); - maybeCall(reject); - endRequestLock(); - } - xhr.ontimeout = function() { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:timeout', responseInfo); - maybeCall(reject); - endRequestLock(); - } - if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){ - maybeCall(resolve); - endRequestLock() - return promise - } - var indicators = addRequestIndicatorClasses(elt); - var disableElts = disableElements(elt); - - forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { - forEach([xhr, xhr.upload], function (target) { - target.addEventListener(eventName, function(event){ - triggerEvent(elt, "htmx:xhr:" + eventName, { - lengthComputable:event.lengthComputable, - loaded:event.loaded, - total:event.total - }); - }) - }); - }); - triggerEvent(elt, 'htmx:beforeSend', responseInfo); - var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) - xhr.send(params); - return promise; - } - - function determineHistoryUpdates(elt, responseInfo) { - - var xhr = responseInfo.xhr; - - //=========================================== - // First consult response headers - //=========================================== - var pathFromHeaders = null; - var typeFromHeaders = null; - if (hasHeader(xhr,/HX-Push:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Push"); - typeFromHeaders = "push"; - } else if (hasHeader(xhr,/HX-Push-Url:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Push-Url"); - typeFromHeaders = "push"; - } else if (hasHeader(xhr,/HX-Replace-Url:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url"); - typeFromHeaders = "replace"; - } + // if a button or submit was clicked last, include its value + if (internalData.lastButtonClicked || elt.tagName === 'BUTTON' || + (elt.tagName === 'INPUT' && getRawAttribute(elt, 'type') === 'submit')) { + const button = internalData.lastButtonClicked || (/** @type HTMLInputElement|HTMLButtonElement */(elt)) + const name = getRawAttribute(button, 'name') + addValueToFormData(name, button.value, priorityFormData) + } - // if there was a response header, that has priority - if (pathFromHeaders) { - if (pathFromHeaders === "false") { - return {} - } else { - return { - type: typeFromHeaders, - path : pathFromHeaders - } - } - } + // include any explicit includes + const includes = findAttributeTargets(elt, 'hx-include') + forEach(includes, function(node) { + processInputValue(processed, formData, errors, asElement(node), validate) + // if a non-form is included, include any input values within it + if (!matches(node, 'form')) { + forEach(asParentNode(node).querySelectorAll(INPUT_SELECTOR), function(descendant) { + processInputValue(processed, formData, errors, descendant, validate) + }) + } + }) + + // values from a <form> take precedence, overriding the regular values + overrideFormData(formData, priorityFormData) + + return { errors, formData, values: formDataProxy(formData) } + } + + /** + * @param {string} returnStr + * @param {string} name + * @param {any} realValue + * @returns {string} + */ + function appendParam(returnStr, name, realValue) { + if (returnStr !== '') { + returnStr += '&' + } + if (String(realValue) === '[object Object]') { + realValue = JSON.stringify(realValue) + } + const s = encodeURIComponent(realValue) + returnStr += encodeURIComponent(name) + '=' + s + return returnStr + } + + /** + * @param {FormData|Object} values + * @returns string + */ + function urlEncode(values) { + values = formDataFromObject(values) + let returnStr = '' + values.forEach(function(value, key) { + returnStr = appendParam(returnStr, key, value) + }) + return returnStr + } + + //= =================================================================== + // Ajax + //= =================================================================== + + /** + * @param {Element} elt + * @param {Element} target + * @param {string} prompt + * @returns {HtmxHeaderSpecification} + */ + function getHeaders(elt, target, prompt) { + /** @type HtmxHeaderSpecification */ + const headers = { + 'HX-Request': 'true', + 'HX-Trigger': getRawAttribute(elt, 'id'), + 'HX-Trigger-Name': getRawAttribute(elt, 'name'), + 'HX-Target': getAttributeValue(target, 'id'), + 'HX-Current-URL': getDocument().location.href + } + getValuesForElement(elt, 'hx-headers', false, headers) + if (prompt !== undefined) { + headers['HX-Prompt'] = prompt + } + if (getInternalData(elt).boosted) { + headers['HX-Boosted'] = 'true' + } + return headers + } + + /** + * filterValues takes an object containing form input values + * and returns a new object that only contains keys that are + * specified by the closest "hx-params" attribute + * @param {FormData} inputValues + * @param {Element} elt + * @returns {FormData} + */ + function filterValues(inputValues, elt) { + const paramsValue = getClosestAttributeValue(elt, 'hx-params') + if (paramsValue) { + if (paramsValue === 'none') { + return new FormData() + } else if (paramsValue === '*') { + return inputValues + } else if (paramsValue.indexOf('not ') === 0) { + forEach(paramsValue.substr(4).split(','), function(name) { + name = name.trim() + inputValues.delete(name) + }) + return inputValues + } else { + const newValues = new FormData() + forEach(paramsValue.split(','), function(name) { + name = name.trim() + if (inputValues.has(name)) { + inputValues.getAll(name).forEach(function(value) { newValues.append(name, value) }) + } + }) + return newValues + } + } else { + return inputValues + } + } + + /** + * @param {Element} elt + * @return {boolean} + */ + function isAnchorLink(elt) { + return !!getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf('#') >= 0 + } + + /** + * @param {Element} elt + * @param {HtmxSwapStyle} [swapInfoOverride] + * @returns {HtmxSwapSpecification} + */ + function getSwapSpecification(elt, swapInfoOverride) { + const swapInfo = swapInfoOverride || getClosestAttributeValue(elt, 'hx-swap') + /** @type HtmxSwapSpecification */ + const swapSpec = { + swapStyle: getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, + swapDelay: htmx.config.defaultSwapDelay, + settleDelay: htmx.config.defaultSettleDelay + } + if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { + swapSpec.show = 'top' + } + if (swapInfo) { + const split = splitOnWhitespace(swapInfo) + if (split.length > 0) { + for (let i = 0; i < split.length; i++) { + const value = split[i] + if (value.indexOf('swap:') === 0) { + swapSpec.swapDelay = parseInterval(value.substr(5)) + } else if (value.indexOf('settle:') === 0) { + swapSpec.settleDelay = parseInterval(value.substr(7)) + } else if (value.indexOf('transition:') === 0) { + swapSpec.transition = value.substr(11) === 'true' + } else if (value.indexOf('ignoreTitle:') === 0) { + swapSpec.ignoreTitle = value.substr(12) === 'true' + } else if (value.indexOf('scroll:') === 0) { + const scrollSpec = value.substr(7) + var splitSpec = scrollSpec.split(':') + const scrollVal = splitSpec.pop() + var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null + // @ts-ignore + swapSpec.scroll = scrollVal + swapSpec.scrollTarget = selectorVal + } else if (value.indexOf('show:') === 0) { + const showSpec = value.substr(5) + var splitSpec = showSpec.split(':') + const showVal = splitSpec.pop() + var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null + swapSpec.show = showVal + swapSpec.showTarget = selectorVal + } else if (value.indexOf('focus-scroll:') === 0) { + const focusScrollVal = value.substr('focus-scroll:'.length) + swapSpec.focusScroll = focusScrollVal == 'true' + } else if (i == 0) { + swapSpec.swapStyle = value + } else { + logError('Unknown modifier in hx-swap: ' + value) + } + } + } + } + return swapSpec + } + + /** + * @param {Element} elt + * @return {boolean} + */ + function usesFormData(elt) { + return getClosestAttributeValue(elt, 'hx-encoding') === 'multipart/form-data' || + (matches(elt, 'form') && getRawAttribute(elt, 'enctype') === 'multipart/form-data') + } + + /** + * @param {XMLHttpRequest} xhr + * @param {Element} elt + * @param {FormData} filteredParameters + * @returns {*|string|null} + */ + function encodeParamsForBody(xhr, elt, filteredParameters) { + let encodedParameters = null + withExtensions(elt, function(extension) { + if (encodedParameters == null) { + encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt) + } + }) + if (encodedParameters != null) { + return encodedParameters + } else { + if (usesFormData(elt)) { + // Force conversion to an actual FormData object in case filteredParameters is a formDataProxy + // See https://github.com/bigskysoftware/htmx/issues/2317 + return overrideFormData(new FormData(), formDataFromObject(filteredParameters)) + } else { + return urlEncode(filteredParameters) + } + } + } + + /** + * + * @param {Element} target + * @returns {HtmxSettleInfo} + */ + function makeSettleInfo(target) { + return { tasks: [], elts: [target] } + } + + /** + * @param {Element[]} content + * @param {HtmxSwapSpecification} swapSpec + */ + function updateScrollState(content, swapSpec) { + const first = content[0] + const last = content[content.length - 1] + if (swapSpec.scroll) { + var target = null + if (swapSpec.scrollTarget) { + target = asElement(querySelectorExt(first, swapSpec.scrollTarget)) + } + if (swapSpec.scroll === 'top' && (first || target)) { + target = target || first + target.scrollTop = 0 + } + if (swapSpec.scroll === 'bottom' && (last || target)) { + target = target || last + target.scrollTop = target.scrollHeight + } + } + if (swapSpec.show) { + var target = null + if (swapSpec.showTarget) { + let targetStr = swapSpec.showTarget + if (swapSpec.showTarget === 'window') { + targetStr = 'body' + } + target = asElement(querySelectorExt(first, targetStr)) + } + if (swapSpec.show === 'top' && (first || target)) { + target = target || first + // @ts-ignore For some reason tsc doesn't recognize "instant" as a valid option for now + target.scrollIntoView({ block: 'start', behavior: htmx.config.scrollBehavior }) + } + if (swapSpec.show === 'bottom' && (last || target)) { + target = target || last + // @ts-ignore For some reason tsc doesn't recognize "instant" as a valid option for now + target.scrollIntoView({ block: 'end', behavior: htmx.config.scrollBehavior }) + } + } + } + + /** + * @param {Element} elt + * @param {string} attr + * @param {boolean=} evalAsDefault + * @param {Object=} values + * @returns {Object} + */ + function getValuesForElement(elt, attr, evalAsDefault, values) { + if (values == null) { + values = {} + } + if (elt == null) { + return values + } + const attributeValue = getAttributeValue(elt, attr) + if (attributeValue) { + let str = attributeValue.trim() + let evaluateValue = evalAsDefault + if (str === 'unset') { + return null + } + if (str.indexOf('javascript:') === 0) { + str = str.substr(11) + evaluateValue = true + } else if (str.indexOf('js:') === 0) { + str = str.substr(3) + evaluateValue = true + } + if (str.indexOf('{') !== 0) { + str = '{' + str + '}' + } + let varsValues + if (evaluateValue) { + varsValues = maybeEval(elt, function() { return Function('return (' + str + ')')() }, {}) + } else { + varsValues = parseJSON(str) + } + for (const key in varsValues) { + if (varsValues.hasOwnProperty(key)) { + if (values[key] == null) { + values[key] = varsValues[key] + } + } + } + } + return getValuesForElement(asElement(parentElt(elt)), attr, evalAsDefault, values) + } + + /** + * @param {EventTarget|string} elt + * @param {() => any} toEval + * @param {any=} defaultVal + * @returns {any} + */ + function maybeEval(elt, toEval, defaultVal) { + if (htmx.config.allowEval) { + return toEval() + } else { + triggerErrorEvent(elt, 'htmx:evalDisallowedError') + return defaultVal + } + } + + /** + * @param {Element} elt + * @param {*?} expressionVars + * @returns + */ + function getHXVarsForElement(elt, expressionVars) { + return getValuesForElement(elt, 'hx-vars', true, expressionVars) + } + + /** + * @param {Element} elt + * @param {*?} expressionVars + * @returns + */ + function getHXValsForElement(elt, expressionVars) { + return getValuesForElement(elt, 'hx-vals', false, expressionVars) + } + + /** + * @param {Element} elt + * @returns {FormData} + */ + function getExpressionVars(elt) { + return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)) + } + + /** + * @param {XMLHttpRequest} xhr + * @param {string} header + * @param {string|null} headerValue + */ + function safelySetHeaderValue(xhr, header, headerValue) { + if (headerValue !== null) { + try { + xhr.setRequestHeader(header, headerValue) + } catch (e) { + // On an exception, try to set the header URI encoded instead + xhr.setRequestHeader(header, encodeURIComponent(headerValue)) + xhr.setRequestHeader(header + '-URI-AutoEncoded', 'true') + } + } + } + + /** + * @param {XMLHttpRequest} xhr + * @return {string} + */ + function getPathFromResponse(xhr) { + // NB: IE11 does not support this stuff + if (xhr.responseURL && typeof (URL) !== 'undefined') { + try { + const url = new URL(xhr.responseURL) + return url.pathname + url.search + } catch (e) { + triggerErrorEvent(getDocument().body, 'htmx:badResponseUrl', { url: xhr.responseURL }) + } + } + } + + /** + * @param {XMLHttpRequest} xhr + * @param {RegExp} regexp + * @return {boolean} + */ + function hasHeader(xhr, regexp) { + return regexp.test(xhr.getAllResponseHeaders()) + } + + /** + * Issues an htmx-style AJAX request + * + * @see https://htmx.org/api/#ajax + * + * @param {HttpVerb} verb + * @param {string} path the URL path to make the AJAX + * @param {Element|string|HtmxAjaxHelperContext} context the element to target (defaults to the **body**) | a selector for the target | a context object that contains any of the following + * @return {Promise<void>} Promise that resolves immediately if no request is sent, or when the request is complete + */ + function ajaxHelper(verb, path, context) { + verb = (/** @type HttpVerb */(verb.toLowerCase())) + if (context) { + if (context instanceof Element || typeof context === 'string') { + return issueAjaxRequest(verb, path, null, null, { + targetOverride: resolveTarget(context), + returnPromise: true + }) + } else { + return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, + { + handler: context.handler, + headers: context.headers, + values: context.values, + targetOverride: resolveTarget(context.target), + swapOverride: context.swap, + select: context.select, + returnPromise: true + }) + } + } else { + return issueAjaxRequest(verb, path, null, null, { + returnPromise: true + }) + } + } + + /** + * @param {Element} elt + * @return {Element[]} + */ + function hierarchyForElt(elt) { + const arr = [] + while (elt) { + arr.push(elt) + elt = elt.parentElement + } + return arr + } + + /** + * @param {Element} elt + * @param {string} path + * @param {HtmxRequestConfig} requestConfig + * @return {boolean} + */ + function verifyPath(elt, path, requestConfig) { + let sameHost + let url + if (typeof URL === 'function') { + url = new URL(path, document.location.href) + const origin = document.location.origin + sameHost = origin === url.origin + } else { + // IE11 doesn't support URL + url = path + sameHost = startsWith(path, document.location.origin) + } - //=========================================== - // Next resolve via DOM values - //=========================================== - var requestPath = responseInfo.pathInfo.finalRequestPath; - var responsePath = responseInfo.pathInfo.responsePath; - - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url"); - var elementIsBoosted = getInternalData(elt).boosted; - - var saveType = null; - var path = null; - - if (pushUrl) { - saveType = "push"; - path = pushUrl; - } else if (replaceUrl) { - saveType = "replace"; - path = replaceUrl; - } else if (elementIsBoosted) { - saveType = "push"; - path = responsePath || requestPath; // if there is no response path, go with the original request path - } + if (htmx.config.selfRequestsOnly) { + if (!sameHost) { + return false + } + } + return triggerEvent(elt, 'htmx:validateUrl', mergeObjects({ url, sameHost }, requestConfig)) + } + + /** + * @param {Object|FormData} obj + * @return {FormData} + */ + function formDataFromObject(obj) { + if (obj instanceof FormData) return obj + const formData = new FormData() + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + if (typeof obj[key].forEach === 'function') { + obj[key].forEach(function(v) { formData.append(key, v) }) + } else if (typeof obj[key] === 'object') { + formData.append(key, JSON.stringify(obj[key])) + } else { + formData.append(key, obj[key]) + } + } + } + return formData + } + + /** + * @param {FormData} formData + * @param {string} name + * @param {Array} array + * @returns {Array} + */ + function formDataArrayProxy(formData, name, array) { + // mutating the array should mutate the underlying form data + return new Proxy(array, { + get: function(target, key) { + if (typeof key === 'number') return target[key] + if (key === 'length') return target.length + if (key === 'push') { + return function(value) { + target.push(value) + formData.append(name, value) + } + } + if (typeof target[key] === 'function') { + return function() { + target[key].apply(target, arguments) + formData.delete(name) + target.forEach(function(v) { formData.append(name, v) }) + } + } + + if (target[key] && target[key].length === 1) { + return target[key][0] + } else { + return target[key] + } + }, + set: function(target, index, value) { + target[index] = value + formData.delete(name) + target.forEach(function(v) { formData.append(name, v) }) + return true + } + }) + } + + /** + * @param {FormData} formData + * @returns {Object} + */ + function formDataProxy(formData) { + return new Proxy(formData, { + get: function(target, name) { + if (typeof name === 'symbol') { + // Forward symbol calls to the FormData itself directly + return Reflect.get(target, name) + } + if (name === 'toJSON') { + // Support JSON.stringify call on proxy + return () => Object.fromEntries(formData) + } + if (name in target) { + // Wrap in function with apply to correctly bind the FormData context, as a direct call would result in an illegal invocation error + if (typeof target[name] === 'function') { + return function() { + return formData[name].apply(formData, arguments) + } + } else { + return target[name] + } + } + const array = formData.getAll(name) + // Those 2 undefined & single value returns are for retro-compatibility as we weren't using FormData before + if (array.length === 0) { + return undefined + } else if (array.length === 1) { + return array[0] + } else { + return formDataArrayProxy(target, name, array) + } + }, + set: function(target, name, value) { + if (typeof name !== 'string') { + return false + } + target.delete(name) + if (typeof value.forEach === 'function') { + value.forEach(function(v) { target.append(name, v) }) + } else { + target.append(name, value) + } + return true + }, + deleteProperty: function(target, name) { + if (typeof name === 'string') { + target.delete(name) + } + return true + }, + // Support Object.assign call from proxy + ownKeys: function(target) { + return Reflect.ownKeys(Object.fromEntries(target)) + }, + getOwnPropertyDescriptor: function(target, prop) { + return Reflect.getOwnPropertyDescriptor(Object.fromEntries(target), prop) + } + }) + } + + /** + * @param {HttpVerb} verb + * @param {string} path + * @param {Element} elt + * @param {Event} event + * @param {HtmxAjaxEtc} [etc] + * @param {boolean} [confirmed] + * @return {Promise<void>} + */ + function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { + let resolve = null + let reject = null + etc = etc != null ? etc : {} + if (etc.returnPromise && typeof Promise !== 'undefined') { + var promise = new Promise(function(_resolve, _reject) { + resolve = _resolve + reject = _reject + }) + } + if (elt == null) { + elt = getDocument().body + } + const responseHandler = etc.handler || handleAjaxResponse + const select = etc.select || null - if (path) { - // false indicates no push, return empty object - if (path === "false") { - return {}; - } + if (!bodyContains(elt)) { + // do not issue requests for elements removed from the DOM + maybeCall(resolve) + return promise + } + const target = etc.targetOverride || asElement(getTarget(elt)) + if (target == null || target == DUMMY_ELT) { + triggerErrorEvent(elt, 'htmx:targetError', { target: getAttributeValue(elt, 'hx-target') }) + maybeCall(reject) + return promise + } - // true indicates we want to follow wherever the server ended up sending us - if (path === "true") { - path = responsePath || requestPath; // if there is no response path, go with the original request path - } + let eltData = getInternalData(elt) + const submitter = eltData.lastButtonClicked - // restore any anchor associated with the request - if (responseInfo.pathInfo.anchor && - path.indexOf("#") === -1) { - path = path + "#" + responseInfo.pathInfo.anchor; - } + if (submitter) { + const buttonPath = getRawAttribute(submitter, 'formaction') + if (buttonPath != null) { + path = buttonPath + } - return { - type:saveType, - path: path - } - } else { - return {}; - } + const buttonVerb = getRawAttribute(submitter, 'formmethod') + if (buttonVerb != null) { + // ignore buttons with formmethod="dialog" + if (buttonVerb.toLowerCase() !== 'dialog') { + verb = (/** @type HttpVerb */(buttonVerb)) } + } + } - function handleAjaxResponse(elt, responseInfo) { - var xhr = responseInfo.xhr; - var target = responseInfo.target; - var etc = responseInfo.etc; - var requestConfig = responseInfo.requestConfig; - var select = responseInfo.select; + const confirmQuestion = getClosestAttributeValue(elt, 'hx-confirm') + // allow event-based confirmation w/ a callback + if (confirmed === undefined) { + const issueRequest = function(skipConfirmation) { + return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation) + } + const confirmDetails = { target, elt, path, verb, triggeringEvent: event, etc, issueRequest, question: confirmQuestion } + if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { + maybeCall(resolve) + return promise + } + } - if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; + let syncElt = elt + let syncStrategy = getClosestAttributeValue(elt, 'hx-sync') + let queueStrategy = null + let abortable = false + if (syncStrategy) { + const syncStrings = syncStrategy.split(':') + const selector = syncStrings[0].trim() + if (selector === 'this') { + syncElt = findThisElement(elt, 'hx-sync') + } else { + syncElt = asElement(querySelectorExt(elt, selector)) + } + // default to the drop strategy + syncStrategy = (syncStrings[1] || 'drop').trim() + eltData = getInternalData(syncElt) + if (syncStrategy === 'drop' && eltData.xhr && eltData.abortable !== true) { + maybeCall(resolve) + return promise + } else if (syncStrategy === 'abort') { + if (eltData.xhr) { + maybeCall(resolve) + return promise + } else { + abortable = true + } + } else if (syncStrategy === 'replace') { + triggerEvent(syncElt, 'htmx:abort') // abort the current request and continue + } else if (syncStrategy.indexOf('queue') === 0) { + const queueStrArray = syncStrategy.split(' ') + queueStrategy = (queueStrArray[1] || 'last').trim() + } + } - if (hasHeader(xhr, /HX-Trigger:/i)) { - handleTrigger(xhr, "HX-Trigger", elt); - } + if (eltData.xhr) { + if (eltData.abortable) { + triggerEvent(syncElt, 'htmx:abort') // abort the current request and continue + } else { + if (queueStrategy == null) { + if (event) { + const eventData = getInternalData(event) + if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { + queueStrategy = eventData.triggerSpec.queue + } + } + if (queueStrategy == null) { + queueStrategy = 'last' + } + } + if (eltData.queuedRequests == null) { + eltData.queuedRequests = [] + } + if (queueStrategy === 'first' && eltData.queuedRequests.length === 0) { + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } else if (queueStrategy === 'all') { + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } else if (queueStrategy === 'last') { + eltData.queuedRequests = [] // dump existing queue + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } + maybeCall(resolve) + return promise + } + } - if (hasHeader(xhr, /HX-Location:/i)) { - saveCurrentPageToHistory(); - var redirectPath = xhr.getResponseHeader("HX-Location"); - var swapSpec; - if (redirectPath.indexOf("{") === 0) { - swapSpec = parseJSON(redirectPath); - // what's the best way to throw an error if the user didn't include this - redirectPath = swapSpec['path']; - delete swapSpec['path']; - } - ajaxHelper('GET', redirectPath, swapSpec).then(function(){ - pushUrlIntoHistory(redirectPath); - }); - return; - } + const xhr = new XMLHttpRequest() + eltData.xhr = xhr + eltData.abortable = abortable + const endRequestLock = function() { + eltData.xhr = null + eltData.abortable = false + if (eltData.queuedRequests != null && + eltData.queuedRequests.length > 0) { + const queuedRequest = eltData.queuedRequests.shift() + queuedRequest() + } + } + const promptQuestion = getClosestAttributeValue(elt, 'hx-prompt') + if (promptQuestion) { + var promptResponse = prompt(promptQuestion) + // prompt returns null if cancelled and empty string if accepted with no entry + if (promptResponse === null || + !triggerEvent(elt, 'htmx:prompt', { prompt: promptResponse, target })) { + maybeCall(resolve) + endRequestLock() + return promise + } + } - var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh"); + if (confirmQuestion && !confirmed) { + if (!confirm(confirmQuestion)) { + maybeCall(resolve) + endRequestLock() + return promise + } + } - if (hasHeader(xhr, /HX-Redirect:/i)) { - location.href = xhr.getResponseHeader("HX-Redirect"); - shouldRefresh && location.reload(); - return; - } + let headers = getHeaders(elt, target, promptResponse) - if (shouldRefresh) { - location.reload(); - return; - } + if (verb !== 'get' && !usesFormData(elt)) { + headers['Content-Type'] = 'application/x-www-form-urlencoded' + } - if (hasHeader(xhr,/HX-Retarget:/i)) { - if (xhr.getResponseHeader("HX-Retarget") === "this") { - responseInfo.target = elt; - } else { - responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget")); - } - } + if (etc.headers) { + headers = mergeObjects(headers, etc.headers) + } + const results = getInputValues(elt, verb) + let errors = results.errors + const rawFormData = results.formData + if (etc.values) { + overrideFormData(rawFormData, formDataFromObject(etc.values)) + } + const expressionVars = formDataFromObject(getExpressionVars(elt)) + const allFormData = overrideFormData(rawFormData, expressionVars) + let filteredFormData = filterValues(allFormData, elt) - var historyUpdate = determineHistoryUpdates(elt, responseInfo); - - // by default htmx only swaps on 200 return codes and does not swap - // on 204 'No Content' - // this can be ovverriden by responding to the htmx:beforeSwap event and - // overriding the detail.shouldSwap property - var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; - var serverResponse = xhr.response; - var isError = xhr.status >= 400; - var ignoreTitle = htmx.config.ignoreTitle - var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo); - if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; - - target = beforeSwapDetails.target; // allow re-targeting - serverResponse = beforeSwapDetails.serverResponse; // allow updating content - isError = beforeSwapDetails.isError; // allow updating error - ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title - - responseInfo.target = target; // Make updated target available to response events - responseInfo.failed = isError; // Make failed property available to response events - responseInfo.successful = !isError; // Make successful property available to response events - - if (beforeSwapDetails.shouldSwap) { - if (xhr.status === 286) { - cancelPolling(elt); - } + if (htmx.config.getCacheBusterParam && verb === 'get') { + filteredFormData.set('org.htmx.cache-buster', getRawAttribute(target, 'id') || 'true') + } - withExtensions(elt, function (extension) { - serverResponse = extension.transformResponse(serverResponse, xhr, elt); - }); + // behavior of anchors w/ empty href is to use the current URL + if (path == null || path === '') { + path = getDocument().location.href + } - // Save current page if there will be a history update - if (historyUpdate.type) { - saveCurrentPageToHistory(); - } + /** + * @type {Object} + * @property {boolean} [credentials] + * @property {number} [timeout] + * @property {boolean} [noHeaders] + */ + const requestAttrValues = getValuesForElement(elt, 'hx-request') + + const eltIsBoosted = getInternalData(elt).boosted + + let useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + + /** @type HtmxRequestConfig */ + const requestConfig = { + boosted: eltIsBoosted, + useUrlParams, + formData: filteredFormData, + parameters: formDataProxy(filteredFormData), + unfilteredFormData: allFormData, + unfilteredParameters: formDataProxy(allFormData), + headers, + target, + verb, + errors, + withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, + timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, + path, + triggeringEvent: event + } - var swapOverride = etc.swapOverride; - if (hasHeader(xhr,/HX-Reswap:/i)) { - swapOverride = xhr.getResponseHeader("HX-Reswap"); - } - var swapSpec = getSwapSpecification(elt, swapOverride); + if (!triggerEvent(elt, 'htmx:configRequest', requestConfig)) { + maybeCall(resolve) + endRequestLock() + return promise + } - if (swapSpec.hasOwnProperty('ignoreTitle')) { - ignoreTitle = swapSpec.ignoreTitle; - } + // copy out in case the object was overwritten + path = requestConfig.path + verb = requestConfig.verb + headers = requestConfig.headers + filteredFormData = formDataFromObject(requestConfig.parameters) + errors = requestConfig.errors + useUrlParams = requestConfig.useUrlParams + + if (errors && errors.length > 0) { + triggerEvent(elt, 'htmx:validation:halted', requestConfig) + maybeCall(resolve) + endRequestLock() + return promise + } - target.classList.add(htmx.config.swappingClass); - - // optional transition API promise callbacks - var settleResolve = null; - var settleReject = null; - - var doSwap = function () { - try { - var activeElt = document.activeElement; - var selectionInfo = {}; - try { - selectionInfo = { - elt: activeElt, - // @ts-ignore - start: activeElt ? activeElt.selectionStart : null, - // @ts-ignore - end: activeElt ? activeElt.selectionEnd : null - }; - } catch (e) { - // safari issue - see https://github.com/microsoft/playwright/issues/5894 - } - - var selectOverride; - if (select) { - selectOverride = select; - } - - if (hasHeader(xhr, /HX-Reselect:/i)) { - selectOverride = xhr.getResponseHeader("HX-Reselect"); - } - - // if we need to save history, do so, before swapping so that relative resources have the correct base URL - if (historyUpdate.type) { - triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)); - if (historyUpdate.type === "push") { - pushUrlIntoHistory(historyUpdate.path); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path}); - } else { - replaceUrlInHistory(historyUpdate.path); - triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path}); - } - } - - var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride); - - if (selectionInfo.elt && - !bodyContains(selectionInfo.elt) && - getRawAttribute(selectionInfo.elt, "id")) { - var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id")); - var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; - if (newActiveElt) { - // @ts-ignore - if (selectionInfo.start && newActiveElt.setSelectionRange) { - // @ts-ignore - try { - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); - } catch (e) { - // the setSelectionRange method is present on fields that don't support it, so just let this fail - } - } - newActiveElt.focus(focusOptions); - } - } - - target.classList.remove(htmx.config.swappingClass); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.add(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSwap', responseInfo); - }); - - if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); - } - - var doSettle = function () { - forEach(settleInfo.tasks, function (task) { - task.call(); - }); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.remove(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSettle', responseInfo); - }); - - if (responseInfo.pathInfo.anchor) { - var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor); - if(anchorTarget) { - anchorTarget.scrollIntoView({block:'start', behavior: "auto"}); - } - } - - if(settleInfo.title && !ignoreTitle) { - var titleElt = find("title"); - if(titleElt) { - titleElt.innerHTML = settleInfo.title; - } else { - window.document.title = settleInfo.title; - } - } - - updateScrollState(settleInfo.elts, swapSpec); - - if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); - } - maybeCall(settleResolve); - } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'htmx:swapError', responseInfo); - maybeCall(settleReject); - throw e; - } - }; - - var shouldTransition = htmx.config.globalViewTransitions - if(swapSpec.hasOwnProperty('transition')){ - shouldTransition = swapSpec.transition; - } + const splitPath = path.split('#') + const pathNoAnchor = splitPath[0] + const anchor = splitPath[1] + + let finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor + const hasValues = !filteredFormData.keys().next().done + if (hasValues) { + if (finalPath.indexOf('?') < 0) { + finalPath += '?' + } else { + finalPath += '&' + } + finalPath += urlEncode(filteredFormData) + if (anchor) { + finalPath += '#' + anchor + } + } + } - if(shouldTransition && - triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && - typeof Promise !== "undefined" && document.startViewTransition){ - var settlePromise = new Promise(function (_resolve, _reject) { - settleResolve = _resolve; - settleReject = _reject; - }); - // wrap the original doSwap() in a call to startViewTransition() - var innerDoSwap = doSwap; - doSwap = function() { - document.startViewTransition(function () { - innerDoSwap(); - return settlePromise; - }); - } - } + if (!verifyPath(elt, finalPath, requestConfig)) { + triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) + maybeCall(reject) + return promise + } + xhr.open(verb.toUpperCase(), finalPath, true) + xhr.overrideMimeType('text/html') + xhr.withCredentials = requestConfig.withCredentials + xhr.timeout = requestConfig.timeout - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); - } - } - if (isError) { - triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo)); - } + // request headers + if (requestAttrValues.noHeaders) { + // ignore all headers + } else { + for (const header in headers) { + if (headers.hasOwnProperty(header)) { + const headerValue = headers[header] + safelySetHeaderValue(xhr, header, headerValue) } + } + } - //==================================================================== - // Extensions API - //==================================================================== - - /** @type {Object<string, import("./htmx").HtmxExtension>} */ - var extensions = {}; - - /** - * extensionBase defines the default functions for all extensions. - * @returns {import("./htmx").HtmxExtension} - */ - function extensionBase() { - return { - init: function(api) {return null;}, - onEvent : function(name, evt) {return true;}, - transformResponse : function(text, xhr, elt) {return text;}, - isInlineSwap : function(swapStyle) {return false;}, - handleSwap : function(swapStyle, target, fragment, settleInfo) {return false;}, - encodeParameters : function(xhr, parameters, elt) {return null;} - } - } + /** @type {HtmxResponseInfo} */ + const responseInfo = { + xhr, + target, + requestConfig, + etc, + boosted: eltIsBoosted, + select, + pathInfo: { + requestPath: path, + finalRequestPath: finalPath, + responsePath: null, + anchor + } + } - /** - * defineExtension initializes the extension and adds it to the htmx registry - * - * @param {string} name - * @param {import("./htmx").HtmxExtension} extension - */ - function defineExtension(name, extension) { - if(extension.init) { - extension.init(internalAPI) - } - extensions[name] = mergeObjects(extensionBase(), extension); - } + xhr.onload = function() { + try { + const hierarchy = hierarchyForElt(elt) + responseInfo.pathInfo.responsePath = getPathFromResponse(xhr) + responseHandler(elt, responseInfo) + removeRequestIndicators(indicators, disableElts) + triggerEvent(elt, 'htmx:afterRequest', responseInfo) + triggerEvent(elt, 'htmx:afterOnLoad', responseInfo) + // if the body no longer contains the element, trigger the event on the closest parent + // remaining in the DOM + if (!bodyContains(elt)) { + let secondaryTriggerElt = null + while (hierarchy.length > 0 && secondaryTriggerElt == null) { + const parentEltInHierarchy = hierarchy.shift() + if (bodyContains(parentEltInHierarchy)) { + secondaryTriggerElt = parentEltInHierarchy + } + } + if (secondaryTriggerElt) { + triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo) + triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo) + } + } + maybeCall(resolve) + endRequestLock() + } catch (e) { + triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({ error: e }, responseInfo)) + throw e + } + } + xhr.onerror = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:sendError', responseInfo) + maybeCall(reject) + endRequestLock() + } + xhr.onabort = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo) + maybeCall(reject) + endRequestLock() + } + xhr.ontimeout = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:timeout', responseInfo) + maybeCall(reject) + endRequestLock() + } + if (!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)) { + maybeCall(resolve) + endRequestLock() + return promise + } + var indicators = addRequestIndicatorClasses(elt) + var disableElts = disableElements(elt) + + forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { + forEach([xhr, xhr.upload], function(target) { + target.addEventListener(eventName, function(event) { + triggerEvent(elt, 'htmx:xhr:' + eventName, { + lengthComputable: event.lengthComputable, + loaded: event.loaded, + total: event.total + }) + }) + }) + }) + triggerEvent(elt, 'htmx:beforeSend', responseInfo) + const params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredFormData) + xhr.send(params) + return promise + } + + /** + * @typedef {Object} HtmxHistoryUpdate + * @property {string|null} [type] + * @property {string|null} [path] + */ + + /** + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + * @return {HtmxHistoryUpdate} + */ + function determineHistoryUpdates(elt, responseInfo) { + const xhr = responseInfo.xhr + + //= ========================================== + // First consult response headers + //= ========================================== + let pathFromHeaders = null + let typeFromHeaders = null + if (hasHeader(xhr, /HX-Push:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Push') + typeFromHeaders = 'push' + } else if (hasHeader(xhr, /HX-Push-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Push-Url') + typeFromHeaders = 'push' + } else if (hasHeader(xhr, /HX-Replace-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Replace-Url') + typeFromHeaders = 'replace' + } - /** - * removeExtension removes an extension from the htmx registry - * - * @param {string} name - */ - function removeExtension(name) { - delete extensions[name]; + // if there was a response header, that has priority + if (pathFromHeaders) { + if (pathFromHeaders === 'false') { + return {} + } else { + return { + type: typeFromHeaders, + path: pathFromHeaders } + } + } - /** - * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element - * - * @param {HTMLElement} elt - * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn - * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore - */ - function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + //= ========================================== + // Next resolve via DOM values + //= ========================================== + const requestPath = responseInfo.pathInfo.finalRequestPath + const responsePath = responseInfo.pathInfo.responsePath + + const pushUrl = getClosestAttributeValue(elt, 'hx-push-url') + const replaceUrl = getClosestAttributeValue(elt, 'hx-replace-url') + const elementIsBoosted = getInternalData(elt).boosted + + let saveType = null + let path = null + + if (pushUrl) { + saveType = 'push' + path = pushUrl + } else if (replaceUrl) { + saveType = 'replace' + path = replaceUrl + } else if (elementIsBoosted) { + saveType = 'push' + path = responsePath || requestPath // if there is no response path, go with the original request path + } - if (elt == undefined) { - return extensionsToReturn; - } - if (extensionsToReturn == undefined) { - extensionsToReturn = []; - } - if (extensionsToIgnore == undefined) { - extensionsToIgnore = []; - } - var extensionsForElement = getAttributeValue(elt, "hx-ext"); - if (extensionsForElement) { - forEach(extensionsForElement.split(","), function(extensionName){ - extensionName = extensionName.replace(/ /g, ''); - if (extensionName.slice(0, 7) == "ignore:") { - extensionsToIgnore.push(extensionName.slice(7)); - return; - } - if (extensionsToIgnore.indexOf(extensionName) < 0) { - var extension = extensions[extensionName]; - if (extension && extensionsToReturn.indexOf(extension) < 0) { - extensionsToReturn.push(extension); - } - } - }); - } - return getExtensions(parentElt(elt), extensionsToReturn, extensionsToIgnore); - } + if (path) { + // false indicates no push, return empty object + if (path === 'false') { + return {} + } + + // true indicates we want to follow wherever the server ended up sending us + if (path === 'true') { + path = responsePath || requestPath // if there is no response path, go with the original request path + } + + // restore any anchor associated with the request + if (responseInfo.pathInfo.anchor && path.indexOf('#') === -1) { + path = path + '#' + responseInfo.pathInfo.anchor + } + + return { + type: saveType, + path + } + } else { + return {} + } + } + + /** + * @param {HtmxResponseHandlingConfig} responseHandlingConfig + * @param {number} status + * @return {boolean} + */ + function codeMatches(responseHandlingConfig, status) { + var regExp = new RegExp(responseHandlingConfig.code) + return regExp.test(status.toString(10)) + } + + /** + * @param {XMLHttpRequest} xhr + * @return {HtmxResponseHandlingConfig} + */ + function resolveResponseHandling(xhr) { + for (var i = 0; i < htmx.config.responseHandling.length; i++) { + /** @type HtmxResponseHandlingConfig */ + var responseHandlingElement = htmx.config.responseHandling[i] + if (codeMatches(responseHandlingElement, xhr.status)) { + return responseHandlingElement + } + } + // no matches, return no swap + return { + swap: false + } + } + + /** + * @param {string} title + */ + function handleTitle(title) { + if (title) { + const titleElt = find('title') + if (titleElt) { + titleElt.innerHTML = title + } else { + window.document.title = title + } + } + } + + /** + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + */ + function handleAjaxResponse(elt, responseInfo) { + const xhr = responseInfo.xhr + let target = responseInfo.target + const etc = responseInfo.etc + const responseInfoSelect = responseInfo.select + + if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return + + if (hasHeader(xhr, /HX-Trigger:/i)) { + handleTriggerHeader(xhr, 'HX-Trigger', elt) + } - //==================================================================== - // Initialization - //==================================================================== - var isReady = false - getDocument().addEventListener('DOMContentLoaded', function() { - isReady = true - }) + if (hasHeader(xhr, /HX-Location:/i)) { + saveCurrentPageToHistory() + let redirectPath = xhr.getResponseHeader('HX-Location') + /** @type {HtmxAjaxHelperContext&{path:string}} */ + var redirectSwapSpec + if (redirectPath.indexOf('{') === 0) { + redirectSwapSpec = parseJSON(redirectPath) + // what's the best way to throw an error if the user didn't include this + redirectPath = redirectSwapSpec.path + delete redirectSwapSpec.path + } + ajaxHelper('get', redirectPath, redirectSwapSpec).then(function() { + pushUrlIntoHistory(redirectPath) + }) + return + } - /** - * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. - * - * This function uses isReady because there is no realiable way to ask the browswer whether - * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded - * firing and readystate=complete. - */ - function ready(fn) { - // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by - // some means other than the initial page load. - if (isReady || getDocument().readyState === 'complete') { - fn(); - } else { - getDocument().addEventListener('DOMContentLoaded', fn); - } - } + const shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && xhr.getResponseHeader('HX-Refresh') === 'true' - function insertIndicatorStyles() { - if (htmx.config.includeIndicatorStyles !== false) { - getDocument().head.insertAdjacentHTML("beforeend", - "<style>\ - ." + htmx.config.indicatorClass + "{opacity:0}\ - ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ - ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ - </style>"); - } - } + if (hasHeader(xhr, /HX-Redirect:/i)) { + location.href = xhr.getResponseHeader('HX-Redirect') + shouldRefresh && location.reload() + return + } - function getMetaConfig() { - var element = getDocument().querySelector('meta[name="htmx-config"]'); - if (element) { - // @ts-ignore - return parseJSON(element.content); - } else { - return null; - } - } + if (shouldRefresh) { + location.reload() + return + } - function mergeMetaConfig() { - var metaConfig = getMetaConfig(); - if (metaConfig) { - htmx.config = mergeObjects(htmx.config , metaConfig) - } - } + if (hasHeader(xhr, /HX-Retarget:/i)) { + if (xhr.getResponseHeader('HX-Retarget') === 'this') { + responseInfo.target = elt + } else { + responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget'))) + } + } - // initialize the document - ready(function () { - mergeMetaConfig(); - insertIndicatorStyles(); - var body = getDocument().body; - processNode(body); - var restoredElts = getDocument().querySelectorAll( - "[hx-trigger='restored'],[data-hx-trigger='restored']" - ); - body.addEventListener("htmx:abort", function (evt) { - var target = evt.target; - var internalData = getInternalData(target); - if (internalData && internalData.xhr) { - internalData.xhr.abort(); - } - }); - /** @type {(ev: PopStateEvent) => any} */ - const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null; - /** @type {(ev: PopStateEvent) => any} */ - window.onpopstate = function (event) { - if (event.state && event.state.htmx) { - restoreHistory(); - forEach(restoredElts, function(elt){ - triggerEvent(elt, 'htmx:restored', { - 'document': getDocument(), - 'triggerEvent': triggerEvent - }); - }); - } else { - if (originalPopstate) { - originalPopstate(event); - } - } - }; - setTimeout(function () { - triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event - body = null; // kill reference for gc - }, 0); + const historyUpdate = determineHistoryUpdates(elt, responseInfo) + + const responseHandling = resolveResponseHandling(xhr) + const shouldSwap = responseHandling.swap + let isError = !!responseHandling.error + let ignoreTitle = htmx.config.ignoreTitle || responseHandling.ignoreTitle + let selectOverride = responseHandling.select + if (responseHandling.target) { + responseInfo.target = asElement(querySelectorExt(elt, responseHandling.target)) + } + var swapOverride = etc.swapOverride + if (swapOverride == null && responseHandling.swapOverride) { + swapOverride = responseHandling.swapOverride + } + + // response headers override response handling config + if (hasHeader(xhr, /HX-Retarget:/i)) { + if (xhr.getResponseHeader('HX-Retarget') === 'this') { + responseInfo.target = elt + } else { + responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget'))) + } + } + if (hasHeader(xhr, /HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader('HX-Reswap') + } + + var serverResponse = xhr.response + /** @type HtmxBeforeSwapDetails */ + var beforeSwapDetails = mergeObjects({ + shouldSwap, + serverResponse, + isError, + ignoreTitle, + selectOverride + }, responseInfo) + + if (responseHandling.event && !triggerEvent(target, responseHandling.event, beforeSwapDetails)) return + + if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return + + target = beforeSwapDetails.target // allow re-targeting + serverResponse = beforeSwapDetails.serverResponse // allow updating content + isError = beforeSwapDetails.isError // allow updating error + ignoreTitle = beforeSwapDetails.ignoreTitle // allow updating ignoring title + selectOverride = beforeSwapDetails.selectOverride // allow updating select override + + responseInfo.target = target // Make updated target available to response events + responseInfo.failed = isError // Make failed property available to response events + responseInfo.successful = !isError // Make successful property available to response events + + if (beforeSwapDetails.shouldSwap) { + if (xhr.status === 286) { + cancelPolling(elt) + } + + withExtensions(elt, function(extension) { + serverResponse = extension.transformResponse(serverResponse, xhr, elt) + }) + + // Save current page if there will be a history update + if (historyUpdate.type) { + saveCurrentPageToHistory() + } + + if (hasHeader(xhr, /HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader('HX-Reswap') + } + var swapSpec = getSwapSpecification(elt, swapOverride) + + if (!swapSpec.hasOwnProperty('ignoreTitle')) { + swapSpec.ignoreTitle = ignoreTitle + } + + target.classList.add(htmx.config.swappingClass) + + // optional transition API promise callbacks + let settleResolve = null + let settleReject = null + + if (responseInfoSelect) { + selectOverride = responseInfoSelect + } + + if (hasHeader(xhr, /HX-Reselect:/i)) { + selectOverride = xhr.getResponseHeader('HX-Reselect') + } + + const selectOOB = getClosestAttributeValue(elt, 'hx-select-oob') + const select = getClosestAttributeValue(elt, 'hx-select') + + let doSwap = function() { + try { + // if we need to save history, do so, before swapping so that relative resources have the correct base URL + if (historyUpdate.type) { + triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)) + if (historyUpdate.type === 'push') { + pushUrlIntoHistory(historyUpdate.path) + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', { path: historyUpdate.path }) + } else { + replaceUrlInHistory(historyUpdate.path) + triggerEvent(getDocument().body, 'htmx:replacedInHistory', { path: historyUpdate.path }) + } + } + + swap(target, serverResponse, swapSpec, { + select: selectOverride || select, + selectOOB, + eventInfo: responseInfo, + anchor: responseInfo.pathInfo.anchor, + contextElement: elt, + afterSwapCallback: function() { + if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { + let finalElt = elt + if (!bodyContains(elt)) { + finalElt = getDocument().body + } + handleTriggerHeader(xhr, 'HX-Trigger-After-Swap', finalElt) + } + }, + afterSettleCallback: function() { + if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { + let finalElt = elt + if (!bodyContains(elt)) { + finalElt = getDocument().body + } + handleTriggerHeader(xhr, 'HX-Trigger-After-Settle', finalElt) + } + maybeCall(settleResolve) + } + }) + } catch (e) { + triggerErrorEvent(elt, 'htmx:swapError', responseInfo) + maybeCall(settleReject) + throw e + } + } + + let shouldTransition = htmx.config.globalViewTransitions + if (swapSpec.hasOwnProperty('transition')) { + shouldTransition = swapSpec.transition + } + + if (shouldTransition && + triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && + typeof Promise !== 'undefined' && + // @ts-ignore experimental feature atm + document.startViewTransition) { + const settlePromise = new Promise(function(_resolve, _reject) { + settleResolve = _resolve + settleReject = _reject }) + // wrap the original doSwap() in a call to startViewTransition() + const innerDoSwap = doSwap + doSwap = function() { + // @ts-ignore experimental feature atm + document.startViewTransition(function() { + innerDoSwap() + return settlePromise + }) + } + } + + if (swapSpec.swapDelay > 0) { + getWindow().setTimeout(doSwap, swapSpec.swapDelay) + } else { + doSwap() + } + } + if (isError) { + triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({ error: 'Response Status Error Code ' + xhr.status + ' from ' + responseInfo.pathInfo.requestPath }, responseInfo)) + } + } + + //= =================================================================== + // Extensions API + //= =================================================================== + + /** @type {Object<string, HtmxExtension>} */ + const extensions = {} + + /** + * extensionBase defines the default functions for all extensions. + * @returns {HtmxExtension} + */ + function extensionBase() { + return { + init: function(api) { return null }, + getSelectors: function() { return null }, + onEvent: function(name, evt) { return true }, + transformResponse: function(text, xhr, elt) { return text }, + isInlineSwap: function(swapStyle) { return false }, + handleSwap: function(swapStyle, target, fragment, settleInfo) { return false }, + encodeParameters: function(xhr, parameters, elt) { return null } + } + } + + /** + * defineExtension initializes the extension and adds it to the htmx registry + * + * @see https://htmx.org/api/#defineExtension + * + * @param {string} name the extension name + * @param {HtmxExtension} extension the extension definition + */ + function defineExtension(name, extension) { + if (extension.init) { + extension.init(internalAPI) + } + extensions[name] = mergeObjects(extensionBase(), extension) + } + + /** + * removeExtension removes an extension from the htmx registry + * + * @see https://htmx.org/api/#removeExtension + * + * @param {string} name + */ + function removeExtension(name) { + delete extensions[name] + } + + /** + * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element + * + * @param {Element} elt + * @param {HtmxExtension[]=} extensionsToReturn + * @param {string[]=} extensionsToIgnore + * @returns {HtmxExtension[]} + */ + function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + if (extensionsToReturn == undefined) { + extensionsToReturn = [] + } + if (elt == undefined) { + return extensionsToReturn + } + if (extensionsToIgnore == undefined) { + extensionsToIgnore = [] + } + const extensionsForElement = getAttributeValue(elt, 'hx-ext') + if (extensionsForElement) { + forEach(extensionsForElement.split(','), function(extensionName) { + extensionName = extensionName.replace(/ /g, '') + if (extensionName.slice(0, 7) == 'ignore:') { + extensionsToIgnore.push(extensionName.slice(7)) + return + } + if (extensionsToIgnore.indexOf(extensionName) < 0) { + const extension = extensions[extensionName] + if (extension && extensionsToReturn.indexOf(extension) < 0) { + extensionsToReturn.push(extension) + } + } + }) + } + return getExtensions(asElement(parentElt(elt)), extensionsToReturn, extensionsToIgnore) + } + + //= =================================================================== + // Initialization + //= =================================================================== + var isReady = false + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true + }) + + /** + * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. + * + * This function uses isReady because there is no reliable way to ask the browser whether + * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded + * firing and readystate=complete. + */ + function ready(fn) { + // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by + // some means other than the initial page load. + if (isReady || getDocument().readyState === 'complete') { + fn() + } else { + getDocument().addEventListener('DOMContentLoaded', fn) + } + } + + function insertIndicatorStyles() { + if (htmx.config.includeIndicatorStyles !== false) { + const nonceAttribute = htmx.config.inlineStyleNonce ? ` nonce="${htmx.config.inlineStyleNonce}"` : '' + getDocument().head.insertAdjacentHTML('beforeend', + '<style' + nonceAttribute + '>\ + .' + htmx.config.indicatorClass + '{opacity:0}\ + .' + htmx.config.requestClass + ' .' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\ + .' + htmx.config.requestClass + '.' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\ + </style>') + } + } + + function getMetaConfig() { + /** @type HTMLMetaElement */ + const element = getDocument().querySelector('meta[name="htmx-config"]') + if (element) { + return parseJSON(element.content) + } else { + return null + } + } - return htmx; + function mergeMetaConfig() { + const metaConfig = getMetaConfig() + if (metaConfig) { + htmx.config = mergeObjects(htmx.config, metaConfig) + } + } + + // initialize the document + ready(function() { + mergeMetaConfig() + insertIndicatorStyles() + let body = getDocument().body + processNode(body) + const restoredElts = getDocument().querySelectorAll( + "[hx-trigger='restored'],[data-hx-trigger='restored']" + ) + body.addEventListener('htmx:abort', function(evt) { + const target = evt.target + const internalData = getInternalData(target) + if (internalData && internalData.xhr) { + internalData.xhr.abort() + } + }) + /** @type {(ev: PopStateEvent) => any} */ + const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null + /** @type {(ev: PopStateEvent) => any} */ + window.onpopstate = function(event) { + if (event.state && event.state.htmx) { + restoreHistory() + forEach(restoredElts, function(elt) { + triggerEvent(elt, 'htmx:restored', { + document: getDocument(), + triggerEvent + }) + }) + } else { + if (originalPopstate) { + originalPopstate(event) + } + } } -)() -})); + getWindow().setTimeout(function() { + triggerEvent(body, 'htmx:load', {}) // give ready handlers a chance to load up before firing this event + body = null // kill reference for gc + }, 0) + }) + + return htmx +})() + +/** @typedef {'get'|'head'|'post'|'put'|'delete'|'connect'|'options'|'trace'|'patch'} HttpVerb */ + +/** + * @typedef {Object} SwapOptions + * @property {string} [select] + * @property {string} [selectOOB] + * @property {*} [eventInfo] + * @property {string} [anchor] + * @property {Element} [contextElement] + * @property {swapCallback} [afterSwapCallback] + * @property {swapCallback} [afterSettleCallback] + */ + +/** + * @callback swapCallback + */ + +/** + * @typedef {'innerHTML' | 'outerHTML' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'delete' | 'none' | string} HtmxSwapStyle + */ + +/** + * @typedef HtmxSwapSpecification + * @property {HtmxSwapStyle} swapStyle + * @property {number} swapDelay + * @property {number} settleDelay + * @property {boolean} [transition] + * @property {boolean} [ignoreTitle] + * @property {string} [head] + * @property {'top' | 'bottom'} [scroll] + * @property {string} [scrollTarget] + * @property {string} [show] + * @property {string} [showTarget] + * @property {boolean} [focusScroll] + */ + +/** + * @typedef {((this:Node, evt:Event) => boolean) & {source: string}} ConditionalFunction + */ + +/** + * @typedef {Object} HtmxTriggerSpecification + * @property {string} trigger + * @property {number} [pollInterval] + * @property {ConditionalFunction} [eventFilter] + * @property {boolean} [changed] + * @property {boolean} [once] + * @property {boolean} [consume] + * @property {number} [delay] + * @property {string} [from] + * @property {string} [target] + * @property {number} [throttle] + * @property {string} [queue] + * @property {string} [root] + * @property {string} [threshold] + */ + +/** + * @typedef {{elt: Element, message: string, validity: ValidityState}} HtmxElementValidationError + */ + +/** + * @typedef {Record<string, string>} HtmxHeaderSpecification + * @property {'true'} HX-Request + * @property {string|null} HX-Trigger + * @property {string|null} HX-Trigger-Name + * @property {string|null} HX-Target + * @property {string} HX-Current-URL + * @property {string} [HX-Prompt] + * @property {'true'} [HX-Boosted] + * @property {string} [Content-Type] + * @property {'true'} [HX-History-Restore-Request] + */ + +/** @typedef HtmxAjaxHelperContext + * @property {Element|string} [source] + * @property {Event} [event] + * @property {HtmxAjaxHandler} [handler] + * @property {Element|string} target + * @property {HtmxSwapStyle} [swap] + * @property {Object|FormData} [values] + * @property {Record<string,string>} [headers] + * @property {string} [select] + */ + +/** + * @typedef {Object} HtmxRequestConfig + * @property {boolean} boosted + * @property {boolean} useUrlParams + * @property {FormData} formData + * @property {Object} parameters formData proxy + * @property {FormData} unfilteredFormData + * @property {Object} unfilteredParameters unfilteredFormData proxy + * @property {HtmxHeaderSpecification} headers + * @property {Element} target + * @property {HttpVerb} verb + * @property {HtmxElementValidationError[]} errors + * @property {boolean} withCredentials + * @property {number} timeout + * @property {string} path + * @property {Event} triggeringEvent + */ + +/** + * @typedef {Object} HtmxResponseInfo + * @property {XMLHttpRequest} xhr + * @property {Element} target + * @property {HtmxRequestConfig} requestConfig + * @property {HtmxAjaxEtc} etc + * @property {boolean} boosted + * @property {string} select + * @property {{requestPath: string, finalRequestPath: string, responsePath: string|null, anchor: string}} pathInfo + * @property {boolean} [failed] + * @property {boolean} [successful] + */ + +/** + * @typedef {Object} HtmxAjaxEtc + * @property {boolean} [returnPromise] + * @property {HtmxAjaxHandler} [handler] + * @property {string} [select] + * @property {Element} [targetOverride] + * @property {HtmxSwapStyle} [swapOverride] + * @property {Record<string,string>} [headers] + * @property {Object|FormData} [values] + * @property {boolean} [credentials] + * @property {number} [timeout] + */ + +/** + * @typedef {Object} HtmxResponseHandlingConfig + * @property {string} [code] + * @property {boolean} swap + * @property {boolean} [error] + * @property {boolean} [ignoreTitle] + * @property {string} [select] + * @property {string} [target] + * @property {string} [swapOverride] + * @property {string} [event] + */ + +/** + * @typedef {HtmxResponseInfo & {shouldSwap: boolean, serverResponse: any, isError: boolean, ignoreTitle: boolean, selectOverride:string}} HtmxBeforeSwapDetails + */ + +/** + * @callback HtmxAjaxHandler + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + */ + +/** + * @typedef {(() => void)} HtmxSettleTask + */ + +/** + * @typedef {Object} HtmxSettleInfo + * @property {HtmxSettleTask[]} tasks + * @property {Element[]} elts + * @property {string} [title] + */ + +/** + * @typedef {Object} HtmxExtension + * @see https://htmx.org/extensions/#defining + * @property {(api: any) => void} init + * @property {(name: string, event: Event|CustomEvent) => boolean} onEvent + * @property {(text: string, xhr: XMLHttpRequest, elt: Element) => string} transformResponse + * @property {(swapStyle: HtmxSwapStyle) => boolean} isInlineSwap + * @property {(swapStyle: HtmxSwapStyle, target: Element, fragment: Node, settleInfo: HtmxSettleInfo) => boolean} handleSwap + * @property {(xhr: XMLHttpRequest, parameters: FormData, elt: Element) => *|string|null} encodeParameters + */ diff --git a/code/ch4_app/ch4_final_video_collector/static/js/htmx.min.js b/code/ch4_app/ch4_final_video_collector/static/js/htmx.min.js index 53bbdf6..d66acce 100644 --- a/code/ch4_app/ch4_final_video_collector/static/js/htmx.min.js +++ b/code/ch4_app/ch4_final_video_collector/static/js/htmx.min.js @@ -1,4 +1,2 @@ -// /////////////////////////////////////////////////////////////////// -// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js -// -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(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 a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/<body/.test(e)}function l(e){var t=!N(e);var r=A(e);var n=e;if(r==="head"){n=n.replace(S,"")}if(Q.config.useTemplateFragments&&t){var i=a("<body><template>"+n+"</template></body>",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a("<table>"+n+"</table>",1);case"col":return a("<table><colgroup>"+n+"</colgroup></table>",2);case"tr":return a("<table><tbody>"+n+"</tbody></table>",2);case"td":case"th":return a("<table><tbody><tr>"+n+"</tr></tbody></table>",3);case"script":case"style":return a("<div>"+n+"</div>",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function oe(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function X(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var Y=function(e,t){var r=re().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function we(t,r){oe(t.attributes,function(e){if(!r.hasAttribute(e.name)&&be(e.name)){t.removeAttribute(e.name)}});oe(r.attributes,function(e){if(be(e.name)){t.setAttribute(e.name,e.value)}})}function Se(e,t){var r=Fr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){b(e)}}return e==="outerHTML"}function Ee(e,i,a){var t="#"+ee(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a<i.length;a++){var o=i[a].split(":",2);var s=o[0].trim();if(s.indexOf("#")===0){s=s.substring(1)}var l=o[1]||"true";var u=t.querySelector("#"+s);if(u){Ee(l,u,r)}}}oe(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=te(e,"hx-swap-oob");if(t!=null){Ee(t,e,r)}})}function Re(e){oe(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=te(e,"id");var r=re().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function Te(o,e,s){oe(e.querySelectorAll("[id]"),function(e){var t=ee(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Le(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=He(n.name,t);t=He(n.value,t)}}}return t}function Ae(e){var t=ae(e);if(t.onHandlers){for(var r=0;r<t.onHandlers.length;r++){const n=t.onHandlers[r];e.removeEventListener(n.event,n.listener)}delete t.onHandlers}}function Ne(e){var t=ae(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){oe(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}Ae(e);oe(Object.keys(t),function(e){delete t[e]})}function p(e){ce(e,"htmx:beforeCleanupElement");Ne(e);if(e.children){oe(e.children,function(e){p(e)})}}function Ie(t,e,r){if(t.tagName==="BODY"){return Ue(t,e,r)}else{var n;var i=t.previousSibling;m(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}p(t);u(t).removeChild(t)}}function ke(e,t,r){return m(e,e.firstChild,t,r)}function Pe(e,t,r){return m(u(e),e,t,r)}function Me(e,t,r){return m(e,null,t,r)}function Xe(e,t,r){return m(u(e),e.nextSibling,t,r)}function De(e,t,r){p(e);return u(e).removeChild(e)}function Ue(e,t,r){var n=e.firstChild;m(e,n,t,r);if(n){while(n.nextSibling){p(n.nextSibling);e.removeChild(n.nextSibling)}p(n);e.removeChild(n)}}function Be(e,t,r){var n=r||ne(e,"hx-select");if(n){var i=re().createDocumentFragment();oe(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function Fe(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Ie(r,n,i);return;case"afterbegin":ke(r,n,i);return;case"beforebegin":Pe(r,n,i);return;case"beforeend":Me(r,n,i);return;case"afterend":Xe(r,n,i);return;case"delete":De(r,n,i);return;default:var a=Fr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Oe(f))}}}return}}catch(e){b(e)}}if(e==="innerHTML"){Ue(r,n,i)}else{Fe(Q.config.defaultSwapStyle,t,r,n,i)}}}function Ve(e){if(e.indexOf("<title")>-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){ce(r,s[l].trim(),[])}}}var ze=/\s/;var x=/[\s,]/;var $e=/[_$a-zA-Z]/;var We=/[_$a-zA-Z0-9]/;var Ge=['"',"'","/"];var Je=/[^\s]/;var Ze=/[{(]/;var Ke=/[})]/;function Ye(e){var t=[];var r=0;while(r<e.length){if($e.exec(e.charAt(r))){var n=r;while(We.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ge.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function Qe(e,t,r){return $e.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function et(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){xt(e,a[1],0)}if(a[0]==="send"){bt(e)}}}function xt(s,r,n){if(!se(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=Q.createWebSocket(r);t.onerror=function(e){fe(s,"htmx:wsError",{error:e,socket:t});yt(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a<i.length;a++){var o=i[a];Ee(te(o,"hx-swap-oob")||"true",o,r)}nr(r.tasks)})}function yt(e){if(!se(e)){ae(e).webSocket.close();return true}}function bt(u){var f=c(u,function(e){return ae(e).webSocket!=null});if(f){u.addEventListener(it(u)[0].trigger,function(e){var t=ae(f).webSocket;var r=xr(u,f);var n=dr(u,"post");var i=n.errors;var a=n.values;var o=Hr(u);var s=le(a,o);var l=yr(s,u);l["HEADERS"]=r;if(i&&i.length>0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){Et(e,a[1])}if(a[0]==="swap"){Ct(e,a[1])}}}function Et(t,e){var r=Q.createEventSource(e);r.onerror=function(e){fe(t,"htmx:sseError",{error:e,source:r});Tt(t)};ae(t).sseEventSource=r}function Ct(a,o){var s=c(a,Ot);if(s){var l=ae(s).sseEventSource;var u=function(e){if(Tt(s)){return}if(!se(a)){l.removeEventListener(o,u);return}var t=e.data;R(a,function(e){t=e.transformResponse(t,null,a)});var r=wr(a);var n=ye(a);var i=T(a);je(r.swapStyle,n,a,t,i);nr(i.tasks);ce(a,"htmx:sseMessage",e)};ae(a).sseListener=u;l.addEventListener(o,u)}else{fe(a,"htmx:noSSESourceError")}}function Rt(e,t,r){var n=c(e,Ot);if(n){var i=ae(n).sseEventSource;var a=function(){if(!Tt(n)){if(se(e)){t(e)}else{i.removeEventListener(r,a)}}};ae(e).sseListener=a;i.addEventListener(r,a)}else{fe(e,"htmx:noSSESourceError")}}function Tt(e){if(!se(e)){ae(e).sseEventSource.close();return true}}function Ot(e){return ae(e).sseEventSource!=null}function qt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n>0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){ce(n,"intersect");break}}},i);a.observe(n);ht(n,r,t,e)}else if(e.trigger==="load"){if(!ct(e,n,Wt("load",{elt:n}))){qt(n,r,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r<t.length;r++){var n=t[r].name;if(s(n,"hx-on:")||s(n,"data-hx-on:")||s(n,"hx-on-")||s(n,"data-hx-on-")){return true}}return false}function kt(e){var t=null;var r=[];if(It(e)){r.push(e)}if(document.evaluate){var n=document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]',e);while(t=n.iterateNext())r.push(t)}else{var i=e.getElementsByTagName("*");for(var a=0;a<i.length;a++){if(It(i[a])){r.push(i[a])}}}return r}function Pt(e){if(e.querySelectorAll){var t=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";var r=e.querySelectorAll(i+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Mt(e){var t=v(e.target,"button, input[type='submit']");var r=Dt(e);if(r){r.lastButtonClicked=t}}function Xt(e){var t=Dt(e);if(t){t.lastButtonClicked=null}}function Dt(e){var t=v(e.target,"button, input[type='submit']");if(!t){return}var r=g("#"+ee(t,"form"))||v(t,"form");if(!r){return}return ae(r)}function Ut(e){e.addEventListener("click",Mt);e.addEventListener("focusin",Mt);e.addEventListener("focusout",Xt)}function Bt(e){var t=Ye(e);var r=0;for(var n=0;n<t.length;n++){const i=t[n];if(i==="{"){r++}else if(i==="}"){r--}}return r}function Ft(t,e,r){var n=ae(t);if(!Array.isArray(n.onHandlers)){n.onHandlers=[]}var i;var a=function(e){return Tr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Vt(e){var t=te(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;t<e.attributes.length;t++){var r=e.attributes[t].name;var n=e.attributes[t].value;if(s(r,"hx-on")||s(r,"data-hx-on")){var i=r.indexOf("-on")+3;var a=r.slice(i,i+1);if(a==="-"||a===":"){var o=r.slice(i+1);if(s(o,":")){o="htmx"+o}else if(s(o,"-")){o="htmx:"+o.slice(1)}else if(s(o,"htmx-")){o="htmx:"+o.slice(5)}Ft(e,o,n)}}}}function _t(t){if(v(t,Q.config.disableSelector)){p(t);return}var r=ae(t);if(r.initHash!==Le(t)){Ne(t);r.initHash=Le(t);Vt(t);ce(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=it(t);var n=Ht(t,r,e);if(!n){if(ne(t,"hx-boost")==="true"){lt(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){Lt(t,e,r,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&o(t,"form")){Ut(t)}var i=te(t,"hx-sse");if(i){St(t,r,i)}var a=te(t,"hx-ws");if(a){pt(t,r,a)}ce(t,"htmx:afterProcessNode")}}function zt(e){e=g(e);if(v(e,Q.config.disableSelector)){p(e);return}_t(e);oe(Pt(e),function(e){_t(e)});oe(kt(e),jt)}function $t(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=re().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function fe(e,t,r){ce(e,t,le({error:t},r))}function Gt(e){return e==="htmx:afterProcessNode"}function R(e,t){oe(Fr(e),function(e){try{t(e)}catch(e){b(e)}})}function b(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ce(e,t,r){e=g(e);if(r==null){r={}}r["elt"]=e;var n=Wt(t,r);if(Q.logger&&!Gt(t)){Q.logger(e,t,r)}if(r.error){b(r.error);ce(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=$t(t);if(i&&a!==t){var o=Wt(a,n.detail);i=i&&e.dispatchEvent(o)}R(e,function(e){i=i&&(e.onEvent(t,n)!==false&&!n.defaultPrevented)});return i}var Jt=location.pathname+location.search;function Zt(){var e=re().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||re().body}function Kt(e,t,r,n){if(!U()){return}if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}e=B(e);var i=E(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};ce(re().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Qt(e){var t=Q.config.requestClass;var r=e.cloneNode(true);oe(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function er(){var e=Zt();var t=Jt||location.pathname+location.search;var r;try{r=re().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){r=re().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!r){ce(re().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Kt(t,Qt(e),re().title,window.scrollY)}if(Q.config.historyEnabled)history.replaceState({htmx:true},re().title,window.location.href)}function tr(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(G(e,"&")||G(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Jt=e}function rr(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Jt=e}function nr(e){oe(e,function(e){e.call()})}function ir(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};ce(re().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",re().location.href);e.onload=function(){if(this.status>=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function fr(e){if(e.name===""||e.name==null||e.disabled||v(e,"fieldset[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 cr(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function hr(t,r,n,e,i){if(e==null||ur(t,e)){return}else{t.push(e)}if(fr(e)){var a=ee(e,"name");var o=e.value;if(e.multiple&&e.tagName==="SELECT"){o=M(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=M(e.files)}cr(a,o,r);if(i){vr(e,n)}}if(h(e,"form")){var s=e.elements;oe(s,function(e){hr(t,r,n,e,i)})}}function vr(e,t){if(e.willValidate){ce(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});ce(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function dr(e,t){var r=[];var n={};var i={};var a=[];var o=ae(e);if(o.lastButtonClicked&&!se(o.lastButtonClicked)){o.lastButtonClicked=null}var s=h(e,"form")&&e.noValidate!==true||te(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){hr(r,i,a,v(e,"form"),s)}hr(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=ee(l,"name");cr(u,l.value,i)}var f=pe(e,"hx-include");oe(f,function(e){hr(r,n,a,e,s);if(!h(e,"form")){oe(e.querySelectorAll(rt),function(e){hr(r,n,a,e,s)})}});n=le(n,i);return{errors:a,values:n}}function gr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function mr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t=gr(t,r,e)})}else{t=gr(t,r,n)}}}return t}function pr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function xr(e,t,r){var n={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":re().location.href};Rr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ae(e).boosted){n["HX-Boosted"]="true"}return n}function yr(t,e){var r=ne(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){oe(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};oe(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function br(e){return ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=d(o.substr(5))}else if(o.indexOf("settle:")===0){n["settleDelay"]=d(o.substr(7))}else if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}else if(o.indexOf("ignoreTitle:")===0){n["ignoreTitle"]=o.substr(12)==="true"}else if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","<style> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file +// v2.0.0 from https://github.com/bigskysoftware/htmx/releases +var htmx=function(){"use strict";const Q={onLoad:null,process:null,on:null,off:null,trigger:null,ajax:null,find:null,findAll:null,closest:null,values:function(e,t){const n=cn(e,t||"post");return n.values},remove:null,addClass:null,removeClass:null,toggleClass:null,takeClass:null,swap:null,defineExtension:null,removeExtension:null,logAll:null,logNone:null,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",inlineStyleNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",scrollBehavior:"instant",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get","delete"],selfRequestsOnly:true,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null,disableInheritance:false,responseHandling:[{code:"204",swap:false},{code:"[23]..",swap:true},{code:"[45]..",swap:false,error:true}],allowNestedOobSwaps:true},parseInterval:null,_:null,version:"2.0.0"};Q.onLoad=$;Q.process=Dt;Q.on=be;Q.off=we;Q.trigger=he;Q.ajax=Hn;Q.find=r;Q.findAll=p;Q.closest=g;Q.remove=K;Q.addClass=W;Q.removeClass=o;Q.toggleClass=Y;Q.takeClass=ge;Q.swap=ze;Q.defineExtension=Un;Q.removeExtension=Bn;Q.logAll=z;Q.logNone=J;Q.parseInterval=d;Q._=_;const n={addTriggerHandler:Et,bodyContains:le,canAccessLocalStorage:j,findThisElement:Ee,filterValues:dn,swap:ze,hasAttribute:s,getAttributeValue:te,getClosestAttributeValue:re,getClosestMatch:T,getExpressionVars:Cn,getHeaders:hn,getInputValues:cn,getInternalData:ie,getSwapSpecification:pn,getTriggerSpecs:lt,getTarget:Ce,makeFragment:D,mergeObjects:ue,makeSettleInfo:xn,oobSwap:Te,querySelectorExt:fe,settleImmediately:Gt,shouldCancel:dt,triggerEvent:he,triggerErrorEvent:ae,withExtensions:Ut};const v=["get","post","put","delete","patch"];const R=v.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");const O=e("head");function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e instanceof Element&&e.getAttribute(t)}function s(e,t){return!!e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){const t=e.parentElement;if(!t&&e.parentNode instanceof ShadowRoot)return e.parentNode;return t}function ne(){return document}function H(e,t){return e.getRootNode?e.getRootNode({composed:t}):ne()}function T(e,t){while(e&&!t(e)){e=u(e)}return e||null}function q(e,t,n){const r=te(t,n);const o=te(t,"hx-disinherit");var i=te(t,"hx-inherit");if(e!==t){if(Q.config.disableInheritance){if(i&&(i==="*"||i.split(" ").indexOf(n)>=0)){return r}else{return null}}if(o&&(o==="*"||o.split(" ").indexOf(n)>=0)){return"unset"}}return r}function re(t,n){let r=null;T(t,function(e){return!!(r=q(t,ce(e),n))});if(r!=="unset"){return r}}function a(e,t){const n=e instanceof Element&&(e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector);return!!n&&n.call(e,t)}function L(e){const t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;const n=t.exec(e);if(n){return n[1].toLowerCase()}else{return""}}function N(e){const t=new DOMParser;return t.parseFromString(e,"text/html")}function A(e,t){while(t.childNodes.length>0){e.append(t.childNodes[0])}}function I(e){const t=ne().createElement("script");se(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}return t}function P(e){return e.matches("script")&&(e.type==="text/javascript"||e.type==="module"||e.type==="")}function k(e){Array.from(e.querySelectorAll("script")).forEach(e=>{if(P(e)){const t=I(e);const n=e.parentNode;try{n.insertBefore(t,e)}catch(e){w(e)}finally{e.remove()}}})}function D(e){const t=e.replace(O,"");const n=L(t);let r;if(n==="html"){r=new DocumentFragment;const i=N(e);A(r,i.body);r.title=i.title}else if(n==="body"){r=new DocumentFragment;const i=N(t);A(r,i.body);r.title=i.title}else{const i=N('<body><template class="internal-htmx-wrapper">'+t+"</template></body>");r=i.querySelector("template").content;r.title=i.title;var o=r.querySelector("title");if(o&&o.parentNode===r){o.remove();r.title=o.innerText}}if(r){if(Q.config.allowScriptTags){k(r)}else{r.querySelectorAll("script").forEach(e=>e.remove())}}return r}function oe(e){if(e){e()}}function t(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function M(e){return typeof e==="function"}function X(e){return t(e,"Object")}function ie(e){const t="htmx-internal-data";let n=e[t];if(!n){n=e[t]={}}return n}function F(t){const n=[];if(t){for(let e=0;e<t.length;e++){n.push(t[e])}}return n}function se(t,n){if(t){for(let e=0;e<t.length;e++){n(t[e])}}}function U(e){const t=e.getBoundingClientRect();const n=t.top;const r=t.bottom;return n<window.innerHeight&&r>=0}function le(e){const t=e.getRootNode&&e.getRootNode();if(t&&t instanceof window.ShadowRoot){return ne().body.contains(t.host)}else{return ne().body.contains(e)}}function B(e){return e.trim().split(/\s+/)}function ue(e,t){for(const n in t){if(t.hasOwnProperty(n)){e[n]=t[n]}}return e}function S(e){try{return JSON.parse(e)}catch(e){w(e);return null}}function j(){const e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function V(t){try{const e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function _(e){return vn(ne().body,function(){return eval(e)})}function $(t){const e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function z(){Q.logger=function(e,t,n){if(console){console.log(t,e,n)}}}function J(){Q.logger=null}function r(e,t){if(typeof e!=="string"){return e.querySelector(t)}else{return r(ne(),e)}}function p(e,t){if(typeof e!=="string"){return e.querySelectorAll(t)}else{return p(ne(),e)}}function E(){return window}function K(e,t){e=y(e);if(t){E().setTimeout(function(){K(e);e=null},t)}else{u(e).removeChild(e)}}function ce(e){return e instanceof Element?e:null}function G(e){return e instanceof HTMLElement?e:null}function Z(e){return typeof e==="string"?e:null}function h(e){return e instanceof Element||e instanceof Document||e instanceof DocumentFragment?e:null}function W(e,t,n){e=ce(y(e));if(!e){return}if(n){E().setTimeout(function(){W(e,t);e=null},n)}else{e.classList&&e.classList.add(t)}}function o(e,t,n){let r=ce(y(e));if(!r){return}if(n){E().setTimeout(function(){o(r,t);r=null},n)}else{if(r.classList){r.classList.remove(t);if(r.classList.length===0){r.removeAttribute("class")}}}}function Y(e,t){e=y(e);e.classList.toggle(t)}function ge(e,t){e=y(e);se(e.parentElement.children,function(e){o(e,t)});W(ce(e),t)}function g(e,t){e=ce(y(e));if(e&&e.closest){return e.closest(t)}else{do{if(e==null||a(e,t)){return e}}while(e=e&&ce(u(e)));return null}}function l(e,t){return e.substring(0,t.length)===t}function pe(e,t){return e.substring(e.length-t.length)===t}function i(e){const t=e.trim();if(l(t,"<")&&pe(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function m(e,t,n){e=y(e);if(t.indexOf("closest ")===0){return[g(ce(e),i(t.substr(8)))]}else if(t.indexOf("find ")===0){return[r(h(e),i(t.substr(5)))]}else if(t==="next"){return[ce(e).nextElementSibling]}else if(t.indexOf("next ")===0){return[me(e,i(t.substr(5)),!!n)]}else if(t==="previous"){return[ce(e).previousElementSibling]}else if(t.indexOf("previous ")===0){return[ye(e,i(t.substr(9)),!!n)]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else if(t==="root"){return[H(e,!!n)]}else if(t.indexOf("global ")===0){return m(e,t.slice(7),true)}else{return F(h(H(e,!!n)).querySelectorAll(i(t)))}}var me=function(t,e,n){const r=h(H(t,n)).querySelectorAll(e);for(let e=0;e<r.length;e++){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_PRECEDING){return o}}};var ye=function(t,e,n){const r=h(H(t,n)).querySelectorAll(e);for(let e=r.length-1;e>=0;e--){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_FOLLOWING){return o}}};function fe(e,t){if(typeof e!=="string"){return m(e,t)[0]}else{return m(ne().body,e)[0]}}function y(e,t){if(typeof e==="string"){return r(h(t)||document,e)}else{return e}}function xe(e,t,n){if(M(t)){return{target:ne().body,event:Z(e),listener:t}}else{return{target:y(e),event:Z(t),listener:n}}}function be(t,n,r){_n(function(){const e=xe(t,n,r);e.target.addEventListener(e.event,e.listener)});const e=M(n);return e?n:r}function we(t,n,r){_n(function(){const e=xe(t,n,r);e.target.removeEventListener(e.event,e.listener)});return M(n)?n:r}const ve=ne().createElement("output");function Se(e,t){const n=re(e,t);if(n){if(n==="this"){return[Ee(e,t)]}else{const r=m(e,n);if(r.length===0){w('The selector "'+n+'" on '+t+" returned no matches!");return[ve]}else{return r}}}}function Ee(e,t){return ce(T(e,function(e){return te(ce(e),t)!=null}))}function Ce(e){const t=re(e,"hx-target");if(t){if(t==="this"){return Ee(e,"hx-target")}else{return fe(e,t)}}else{const n=ie(e);if(n.boosted){return ne().body}else{return e}}}function Re(t){const n=Q.config.attributesToSettle;for(let e=0;e<n.length;e++){if(t===n[e]){return true}}return false}function Oe(t,n){se(t.attributes,function(e){if(!n.hasAttribute(e.name)&&Re(e.name)){t.removeAttribute(e.name)}});se(n.attributes,function(e){if(Re(e.name)){t.setAttribute(e.name,e.value)}})}function He(t,e){const n=jn(e);for(let e=0;e<n.length;e++){const r=n[e];try{if(r.isInlineSwap(t)){return true}}catch(e){w(e)}}return t==="outerHTML"}function Te(e,o,i){let t="#"+ee(o,"id");let s="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){s=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{s=e}const n=ne().querySelectorAll(t);if(n){se(n,function(e){let t;const n=o.cloneNode(true);t=ne().createDocumentFragment();t.appendChild(n);if(!He(s,e)){t=h(n)}const r={shouldSwap:true,target:e,fragment:t};if(!he(e,"htmx:oobBeforeSwap",r))return;e=r.target;if(r.shouldSwap){_e(s,e,e,t,i)}se(i.elts,function(e){he(e,"htmx:oobAfterSwap",r)})});o.parentNode.removeChild(o)}else{o.parentNode.removeChild(o);ae(ne().body,"htmx:oobErrorNoTarget",{content:o})}return e}function qe(e){se(p(e,"[hx-preserve], [data-hx-preserve]"),function(e){const t=te(e,"id");const n=ne().getElementById(t);if(n!=null){e.parentNode.replaceChild(n,e)}})}function Le(l,e,u){se(e.querySelectorAll("[id]"),function(t){const n=ee(t,"id");if(n&&n.length>0){const r=n.replace("'","\\'");const o=t.tagName.replace(":","\\:");const e=h(l);const i=e&&e.querySelector(o+"[id='"+r+"']");if(i&&i!==e){const s=t.cloneNode();Oe(t,i);u.tasks.push(function(){Oe(t,s)})}}})}function Ne(e){return function(){o(e,Q.config.addedClass);Dt(ce(e));Ae(h(e));he(e,"htmx:load")}}function Ae(e){const t="[autofocus]";const n=G(a(e,t)?e:e.querySelector(t));if(n!=null){n.focus()}}function c(e,t,n,r){Le(e,n,r);while(n.childNodes.length>0){const o=n.firstChild;W(ce(o),Q.config.addedClass);e.insertBefore(o,t);if(o.nodeType!==Node.TEXT_NODE&&o.nodeType!==Node.COMMENT_NODE){r.tasks.push(Ne(o))}}}function Ie(e,t){let n=0;while(n<e.length){t=(t<<5)-t+e.charCodeAt(n++)|0}return t}function Pe(t){let n=0;if(t.attributes){for(let e=0;e<t.attributes.length;e++){const r=t.attributes[e];if(r.value){n=Ie(r.name,n);n=Ie(r.value,n)}}}return n}function ke(t){const n=ie(t);if(n.onHandlers){for(let e=0;e<n.onHandlers.length;e++){const r=n.onHandlers[e];we(t,r.event,r.listener)}delete n.onHandlers}}function De(e){const t=ie(e);if(t.timeout){clearTimeout(t.timeout)}if(t.listenerInfos){se(t.listenerInfos,function(e){if(e.on){we(e.on,e.trigger,e.listener)}})}ke(e);se(Object.keys(t),function(e){delete t[e]})}function f(e){he(e,"htmx:beforeCleanupElement");De(e);if(e.children){se(e.children,function(e){f(e)})}}function Me(t,e,n){let r;const o=t.previousSibling;c(u(t),t,e,n);if(o==null){r=u(t).firstChild}else{r=o.nextSibling}n.elts=n.elts.filter(function(e){return e!==t});while(r&&r!==t){if(r instanceof Element){n.elts.push(r);r=r.nextElementSibling}else{r=null}}f(t);if(t instanceof Element){t.remove()}else{t.parentNode.removeChild(t)}}function Xe(e,t,n){return c(e,e.firstChild,t,n)}function Fe(e,t,n){return c(u(e),e,t,n)}function Ue(e,t,n){return c(e,null,t,n)}function Be(e,t,n){return c(u(e),e.nextSibling,t,n)}function je(e){f(e);return u(e).removeChild(e)}function Ve(e,t,n){const r=e.firstChild;c(e,r,t,n);if(r){while(r.nextSibling){f(r.nextSibling);e.removeChild(r.nextSibling)}f(r);e.removeChild(r)}}function _e(t,e,n,r,o){switch(t){case"none":return;case"outerHTML":Me(n,r,o);return;case"afterbegin":Xe(n,r,o);return;case"beforebegin":Fe(n,r,o);return;case"beforeend":Ue(n,r,o);return;case"afterend":Be(n,r,o);return;case"delete":je(n);return;default:var i=jn(e);for(let e=0;e<i.length;e++){const s=i[e];try{const l=s.handleSwap(t,n,r,o);if(l){if(typeof l.length!=="undefined"){for(let e=0;e<l.length;e++){const u=l[e];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){o.tasks.push(Ne(u))}}}return}}catch(e){w(e)}}if(t==="innerHTML"){Ve(n,r,o)}else{_e(Q.config.defaultSwapStyle,e,n,r,o)}}}function $e(e,n){se(p(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){if(Q.config.allowNestedOobSwaps||e.parentElement===null){const t=te(e,"hx-swap-oob");if(t!=null){Te(t,e,n)}}else{e.removeAttribute("hx-swap-oob");e.removeAttribute("data-hx-swap-oob")}})}function ze(e,t,r,o){if(!o){o={}}e=y(e);const n=document.activeElement;let i={};try{i={elt:n,start:n?n.selectionStart:null,end:n?n.selectionEnd:null}}catch(e){}const s=xn(e);if(r.swapStyle==="textContent"){e.textContent=t}else{let n=D(t);s.title=n.title;if(o.selectOOB){const u=o.selectOOB.split(",");for(let t=0;t<u.length;t++){const c=u[t].split(":",2);let e=c[0].trim();if(e.indexOf("#")===0){e=e.substring(1)}const f=c[1]||"true";const a=n.querySelector("#"+e);if(a){Te(f,a,s)}}}$e(n,s);se(p(n,"template"),function(e){$e(e.content,s);if(e.content.childElementCount===0){e.remove()}});if(o.select){const h=ne().createDocumentFragment();se(n.querySelectorAll(o.select),function(e){h.appendChild(e)});n=h}qe(n);_e(r.swapStyle,o.contextElement,e,n,s)}if(i.elt&&!le(i.elt)&&ee(i.elt,"id")){const d=document.getElementById(ee(i.elt,"id"));const g={preventScroll:r.focusScroll!==undefined?!r.focusScroll:!Q.config.defaultFocusScroll};if(d){if(i.start&&d.setSelectionRange){try{d.setSelectionRange(i.start,i.end)}catch(e){}}d.focus(g)}}e.classList.remove(Q.config.swappingClass);se(s.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}he(e,"htmx:afterSwap",o.eventInfo)});if(o.afterSwapCallback){o.afterSwapCallback()}if(!r.ignoreTitle){Dn(s.title)}const l=function(){se(s.tasks,function(e){e.call()});se(s.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}he(e,"htmx:afterSettle",o.eventInfo)});if(o.anchor){const e=ce(y("#"+o.anchor));if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}bn(s.elts,r);if(o.afterSettleCallback){o.afterSettleCallback()}};if(r.settleDelay>0){E().setTimeout(l,r.settleDelay)}else{l()}}function Je(e,t,n){const r=e.getResponseHeader(t);if(r.indexOf("{")===0){const o=S(r);for(const i in o){if(o.hasOwnProperty(i)){let e=o[i];if(!X(e)){e={value:e}}he(n,i,e)}}}else{const s=r.split(",");for(let e=0;e<s.length;e++){he(n,s[e].trim(),[])}}}const Ke=/\s/;const x=/[\s,]/;const Ge=/[_$a-zA-Z]/;const Ze=/[_$a-zA-Z0-9]/;const We=['"',"'","/"];const Ye=/[^\s]/;const Qe=/[{(]/;const et=/[})]/;function tt(e){const t=[];let n=0;while(n<e.length){if(Ge.exec(e.charAt(n))){var r=n;while(Ze.exec(e.charAt(n+1))){n++}t.push(e.substr(r,n-r+1))}else if(We.indexOf(e.charAt(n))!==-1){const o=e.charAt(n);var r=n;n++;while(n<e.length&&e.charAt(n)!==o){if(e.charAt(n)==="\\"){n++}n++}t.push(e.substr(r,n-r+1))}else{const i=e.charAt(n);t.push(i)}n++}return t}function nt(e,t,n){return Ge.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==n&&t!=="."}function rt(r,o,i){if(o[0]==="["){o.shift();let e=1;let t=" return (function("+i+"){ return (";let n=null;while(o.length>0){const s=o[0];if(s==="]"){e--;if(e===0){if(n===null){t=t+"true"}o.shift();t+=")})";try{const l=vn(r,function(){return Function(t)()},function(){return true});l.source=t;return l}catch(e){ae(ne().body,"htmx:syntax:error",{error:e,source:t});return null}}}else if(s==="["){e++}if(nt(s,n,i)){t+="(("+i+"."+s+") ? ("+i+"."+s+") : (window."+s+"))"}else{t=t+s}n=o.shift()}}}function b(e,t){let n="";while(e.length>0&&!t.test(e[0])){n+=e.shift()}return n}function ot(e){let t;if(e.length>0&&Qe.test(e[0])){e.shift();t=b(e,et).trim();e.shift()}else{t=b(e,x)}return t}const it="input, textarea, select";function st(e,t,n){const r=[];const o=tt(t);do{b(o,Ye);const l=o.length;const u=b(o,/[,\[\s]/);if(u!==""){if(u==="every"){const c={trigger:"every"};b(o,Ye);c.pollInterval=d(b(o,/[,\[\s]/));b(o,Ye);var i=rt(e,o,"event");if(i){c.eventFilter=i}r.push(c)}else{const f={trigger:u};var i=rt(e,o,"event");if(i){f.eventFilter=i}while(o.length>0&&o[0]!==","){b(o,Ye);const a=o.shift();if(a==="changed"){f.changed=true}else if(a==="once"){f.once=true}else if(a==="consume"){f.consume=true}else if(a==="delay"&&o[0]===":"){o.shift();f.delay=d(b(o,x))}else if(a==="from"&&o[0]===":"){o.shift();if(Qe.test(o[0])){var s=ot(o)}else{var s=b(o,x);if(s==="closest"||s==="find"||s==="next"||s==="previous"){o.shift();const h=ot(o);if(h.length>0){s+=" "+h}}}f.from=s}else if(a==="target"&&o[0]===":"){o.shift();f.target=ot(o)}else if(a==="throttle"&&o[0]===":"){o.shift();f.throttle=d(b(o,x))}else if(a==="queue"&&o[0]===":"){o.shift();f.queue=b(o,x)}else if(a==="root"&&o[0]===":"){o.shift();f[a]=ot(o)}else if(a==="threshold"&&o[0]===":"){o.shift();f[a]=b(o,x)}else{ae(e,"htmx:syntax:error",{token:o.shift()})}}r.push(f)}}if(o.length===l){ae(e,"htmx:syntax:error",{token:o.shift()})}b(o,Ye)}while(o[0]===","&&o.shift());if(n){n[t]=r}return r}function lt(e){const t=te(e,"hx-trigger");let n=[];if(t){const r=Q.config.triggerSpecsCache;n=r&&r[t]||st(e,t,r)}if(n.length>0){return n}else if(a(e,"form")){return[{trigger:"submit"}]}else if(a(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(a(e,it)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function ut(e){ie(e).cancelled=true}function ct(e,t,n){const r=ie(e);r.timeout=E().setTimeout(function(){if(le(e)&&r.cancelled!==true){if(!pt(n,e,Xt("hx:poll:trigger",{triggerSpec:n,target:e}))){t(e)}ct(e,t,n)}},n.pollInterval)}function ft(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function at(e){return g(e,Q.config.disableSelector)}function ht(t,n,e){if(t instanceof HTMLAnchorElement&&ft(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){n.boosted=true;let r,o;if(t.tagName==="A"){r="get";o=ee(t,"href")}else{const i=ee(t,"method");r=i?i.toLowerCase():"get";if(r==="get"){}o=ee(t,"action")}e.forEach(function(e){mt(t,function(e,t){const n=ce(e);if(at(n)){f(n);return}de(r,o,n,t)},n,e,true)})}}function dt(e,t){const n=ce(t);if(!n){return false}if(e.type==="submit"||e.type==="click"){if(n.tagName==="FORM"){return true}if(a(n,'input[type="submit"], button')&&g(n,"form")!==null){return true}if(n instanceof HTMLAnchorElement&&n.href&&(n.getAttribute("href")==="#"||n.getAttribute("href").indexOf("#")!==0)){return true}}return false}function gt(e,t){return ie(e).boosted&&e instanceof HTMLAnchorElement&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function pt(e,t,n){const r=e.eventFilter;if(r){try{return r.call(t,n)!==true}catch(e){const o=r.source;ae(ne().body,"htmx:eventFilter:error",{error:e,source:o});return true}}return false}function mt(s,l,e,u,c){const f=ie(s);let t;if(u.from){t=m(s,u.from)}else{t=[s]}if(u.changed){t.forEach(function(e){const t=ie(e);t.lastValue=e.value})}se(t,function(o){const i=function(e){if(!le(s)){o.removeEventListener(u.trigger,i);return}if(gt(s,e)){return}if(c||dt(e,s)){e.preventDefault()}if(pt(u,s,e)){return}const t=ie(e);t.triggerSpec=u;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(s)<0){t.handledFor.push(s);if(u.consume){e.stopPropagation()}if(u.target&&e.target){if(!a(ce(e.target),u.target)){return}}if(u.once){if(f.triggeredOnce){return}else{f.triggeredOnce=true}}if(u.changed){const n=ie(o);const r=o.value;if(n.lastValue===r){return}n.lastValue=r}if(f.delayed){clearTimeout(f.delayed)}if(f.throttle){return}if(u.throttle>0){if(!f.throttle){l(s,e);f.throttle=E().setTimeout(function(){f.throttle=null},u.throttle)}}else if(u.delay>0){f.delayed=E().setTimeout(function(){l(s,e)},u.delay)}else{he(s,"htmx:trigger");l(s,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:u.trigger,listener:i,on:o});o.addEventListener(u.trigger,i)})}let yt=false;let xt=null;function bt(){if(!xt){xt=function(){yt=true};window.addEventListener("scroll",xt);setInterval(function(){if(yt){yt=false;se(ne().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"),function(e){wt(e)})}},200)}}function wt(e){if(!s(e,"data-hx-revealed")&&U(e)){e.setAttribute("data-hx-revealed","true");const t=ie(e);if(t.initHash){he(e,"revealed")}else{e.addEventListener("htmx:afterProcessNode",function(){he(e,"revealed")},{once:true})}}}function vt(e,t,n,r){const o=function(){if(!n.loaded){n.loaded=true;t(e)}};if(r>0){E().setTimeout(o,r)}else{o()}}function St(t,n,e){let i=false;se(v,function(r){if(s(t,"hx-"+r)){const o=te(t,"hx-"+r);i=true;n.path=o;n.verb=r;e.forEach(function(e){Et(t,e,n,function(e,t){const n=ce(e);if(g(n,Q.config.disableSelector)){f(n);return}de(r,o,n,t)})})}});return i}function Et(r,e,t,n){if(e.trigger==="revealed"){bt();mt(r,n,t,e);wt(ce(r))}else if(e.trigger==="intersect"){const o={};if(e.root){o.root=fe(r,e.root)}if(e.threshold){o.threshold=parseFloat(e.threshold)}const i=new IntersectionObserver(function(t){for(let e=0;e<t.length;e++){const n=t[e];if(n.isIntersecting){he(r,"intersect");break}}},o);i.observe(ce(r));mt(ce(r),n,t,e)}else if(e.trigger==="load"){if(!pt(e,r,Xt("load",{elt:r}))){vt(ce(r),n,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ct(ce(r),n,e)}else{mt(r,n,t,e)}}function Ct(e){const t=ce(e);if(!t){return false}const n=t.attributes;for(let e=0;e<n.length;e++){const r=n[e].name;if(l(r,"hx-on:")||l(r,"data-hx-on:")||l(r,"hx-on-")||l(r,"data-hx-on-")){return true}}return false}const Rt=(new XPathEvaluator).createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]');function Ot(e,t){if(Ct(e)){t.push(ce(e))}const n=Rt.evaluate(e);let r=null;while(r=n.iterateNext())t.push(ce(r))}function Ht(e){const t=[];if(e instanceof DocumentFragment){for(const n of e.childNodes){Ot(n,t)}}else{Ot(e,t)}return t}function Tt(e){if(e.querySelectorAll){const n=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";const r=[];for(const i in Xn){const s=Xn[i];if(s.getSelectors){var t=s.getSelectors();if(t){r.push(t)}}}const o=e.querySelectorAll(R+n+", form, [type='submit'],"+" [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]"+r.flat().map(e=>", "+e).join(""));return o}else{return[]}}function qt(e){const t=g(ce(e.target),"button, input[type='submit']");const n=Nt(e);if(n){n.lastButtonClicked=t}}function Lt(e){const t=Nt(e);if(t){t.lastButtonClicked=null}}function Nt(e){const t=g(ce(e.target),"button, input[type='submit']");if(!t){return}const n=y("#"+ee(t,"form"),t.getRootNode())||g(t,"form");if(!n){return}return ie(n)}function At(e){e.addEventListener("click",qt);e.addEventListener("focusin",qt);e.addEventListener("focusout",Lt)}function It(t,e,n){const r=ie(t);if(!Array.isArray(r.onHandlers)){r.onHandlers=[]}let o;const i=function(e){vn(t,function(){if(at(t)){return}if(!o){o=new Function("event",n)}o.call(t,e)})};t.addEventListener(e,i);r.onHandlers.push({event:e,listener:i})}function Pt(t){ke(t);for(let e=0;e<t.attributes.length;e++){const n=t.attributes[e].name;const r=t.attributes[e].value;if(l(n,"hx-on")||l(n,"data-hx-on")){const o=n.indexOf("-on")+3;const i=n.slice(o,o+1);if(i==="-"||i===":"){let e=n.slice(o+1);if(l(e,":")){e="htmx"+e}else if(l(e,"-")){e="htmx:"+e.slice(1)}else if(l(e,"htmx-")){e="htmx:"+e.slice(5)}It(t,e,r)}}}}function kt(t){if(g(t,Q.config.disableSelector)){f(t);return}const n=ie(t);if(n.initHash!==Pe(t)){De(t);n.initHash=Pe(t);he(t,"htmx:beforeProcessNode");if(t.value){n.lastValue=t.value}const e=lt(t);const r=St(t,n,e);if(!r){if(re(t,"hx-boost")==="true"){ht(t,n,e)}else if(s(t,"hx-trigger")){e.forEach(function(e){Et(t,e,n,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&s(t,"form")){At(t)}he(t,"htmx:afterProcessNode")}}function Dt(e){e=y(e);if(g(e,Q.config.disableSelector)){f(e);return}kt(e);se(Tt(e),function(e){kt(e)});se(Ht(e),Pt)}function Mt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Xt(e,t){let n;if(window.CustomEvent&&typeof window.CustomEvent==="function"){n=new CustomEvent(e,{bubbles:true,cancelable:true,composed:true,detail:t})}else{n=ne().createEvent("CustomEvent");n.initCustomEvent(e,true,true,t)}return n}function ae(e,t,n){he(e,t,ue({error:t},n))}function Ft(e){return e==="htmx:afterProcessNode"}function Ut(e,t){se(jn(e),function(e){try{t(e)}catch(e){w(e)}})}function w(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function he(e,t,n){e=y(e);if(n==null){n={}}n.elt=e;const r=Xt(t,n);if(Q.logger&&!Ft(t)){Q.logger(e,t,n)}if(n.error){w(n.error);he(e,"htmx:error",{errorInfo:n})}let o=e.dispatchEvent(r);const i=Mt(t);if(o&&i!==t){const s=Xt(i,r.detail);o=o&&e.dispatchEvent(s)}Ut(ce(e),function(e){o=o&&(e.onEvent(t,r)!==false&&!r.defaultPrevented)});return o}let Bt=location.pathname+location.search;function jt(){const e=ne().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||ne().body}function Vt(t,e){if(!j()){return}const n=$t(e);const r=ne().title;const o=window.scrollY;if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}t=V(t);const i=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e<i.length;e++){if(i[e].url===t){i.splice(e,1);break}}const s={url:t,content:n,title:r,scroll:o};he(ne().body,"htmx:historyItemCreated",{item:s,cache:i});i.push(s);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ae(ne().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function _t(t){if(!j()){return null}t=V(t);const n=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e<n.length;e++){if(n[e].url===t){return n[e]}}return null}function $t(e){const t=Q.config.requestClass;const n=e.cloneNode(true);se(p(n,"."+t),function(e){o(e,t)});return n.innerHTML}function zt(){const e=jt();const t=Bt||location.pathname+location.search;let n;try{n=ne().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){n=ne().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!n){he(ne().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Vt(t,e)}if(Q.config.historyEnabled)history.replaceState({htmx:true},ne().title,window.location.href)}function Jt(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(pe(e,"&")||pe(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Bt=e}function Kt(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Bt=e}function Gt(e){se(e,function(e){e.call(undefined)})}function Zt(o){const e=new XMLHttpRequest;const i={path:o,xhr:e};he(ne().body,"htmx:historyCacheMiss",i);e.open("GET",o,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",ne().location.href);e.onload=function(){if(this.status>=200&&this.status<400){he(ne().body,"htmx:historyCacheMissLoad",i);const e=D(this.response);const t=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;const n=jt();const r=xn(n);Dn(e.title);Ve(n,t,r);Gt(r.tasks);Bt=o;he(ne().body,"htmx:historyRestore",{path:o,cacheMiss:true,serverResponse:this.response})}else{ae(ne().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Wt(e){zt();e=e||location.pathname+location.search;const t=_t(e);if(t){const n=D(t.content);const r=jt();const o=xn(r);Dn(n.title);Ve(r,n,o);Gt(o.tasks);E().setTimeout(function(){window.scrollTo(0,t.scroll)},0);Bt=e;he(ne().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{Zt(e)}}}function Yt(e){let t=Se(e,"hx-indicator");if(t==null){t=[e]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.classList.add.call(e.classList,Q.config.requestClass)});return t}function Qt(e){let t=Se(e,"hx-disabled-elt");if(t==null){t=[]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function en(e,t){se(e,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList.remove.call(e.classList,Q.config.requestClass)}});se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function tn(t,n){for(let e=0;e<t.length;e++){const r=t[e];if(r.isSameNode(n)){return true}}return false}function nn(e){const t=e;if(t.name===""||t.name==null||t.disabled||g(t,"fieldset[disabled]")){return false}if(t.type==="button"||t.type==="submit"||t.tagName==="image"||t.tagName==="reset"||t.tagName==="file"){return false}if(t.type==="checkbox"||t.type==="radio"){return t.checked}return true}function rn(t,e,n){if(t!=null&&e!=null){if(Array.isArray(e)){e.forEach(function(e){n.append(t,e)})}else{n.append(t,e)}}}function on(t,n,r){if(t!=null&&n!=null){let e=r.getAll(t);if(Array.isArray(n)){e=e.filter(e=>n.indexOf(e)<0)}else{e=e.filter(e=>e!==n)}r.delete(t);se(e,e=>r.append(t,e))}}function sn(t,n,r,o,i){if(o==null||tn(t,o)){return}else{t.push(o)}if(nn(o)){const s=ee(o,"name");let e=o.value;if(o instanceof HTMLSelectElement&&o.multiple){e=F(o.querySelectorAll("option:checked")).map(function(e){return e.value})}if(o instanceof HTMLInputElement&&o.files){e=F(o.files)}rn(s,e,n);if(i){ln(o,r)}}if(o instanceof HTMLFormElement){se(o.elements,function(e){if(t.indexOf(e)>=0){on(e.name,e.value,n)}else{t.push(e)}if(i){ln(e,r)}});new FormData(o).forEach(function(e,t){if(e instanceof File&&e.name===""){return}rn(t,e,n)})}}function ln(e,t){const n=e;if(n.willValidate){he(n,"htmx:validation:validate");if(!n.checkValidity()){t.push({elt:n,message:n.validationMessage,validity:n.validity});he(n,"htmx:validation:failed",{message:n.validationMessage,validity:n.validity})}}}function un(t,e){for(const n of e.keys()){t.delete(n);e.getAll(n).forEach(function(e){t.append(n,e)})}return t}function cn(e,t){const n=[];const r=new FormData;const o=new FormData;const i=[];const s=ie(e);if(s.lastButtonClicked&&!le(s.lastButtonClicked)){s.lastButtonClicked=null}let l=e instanceof HTMLFormElement&&e.noValidate!==true||te(e,"hx-validate")==="true";if(s.lastButtonClicked){l=l&&s.lastButtonClicked.formNoValidate!==true}if(t!=="get"){sn(n,o,i,g(e,"form"),l)}sn(n,r,i,e,l);if(s.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){const c=s.lastButtonClicked||e;const f=ee(c,"name");rn(f,c.value,o)}const u=Se(e,"hx-include");se(u,function(e){sn(n,r,i,ce(e),l);if(!a(e,"form")){se(h(e).querySelectorAll(it),function(e){sn(n,r,i,e,l)})}});un(r,o);return{errors:i,formData:r,values:An(r)}}function fn(e,t,n){if(e!==""){e+="&"}if(String(n)==="[object Object]"){n=JSON.stringify(n)}const r=encodeURIComponent(n);e+=encodeURIComponent(t)+"="+r;return e}function an(e){e=Ln(e);let n="";e.forEach(function(e,t){n=fn(n,t,e)});return n}function hn(e,t,n){const r={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":ne().location.href};wn(e,"hx-headers",false,r);if(n!==undefined){r["HX-Prompt"]=n}if(ie(e).boosted){r["HX-Boosted"]="true"}return r}function dn(n,e){const t=re(e,"hx-params");if(t){if(t==="none"){return new FormData}else if(t==="*"){return n}else if(t.indexOf("not ")===0){se(t.substr(4).split(","),function(e){e=e.trim();n.delete(e)});return n}else{const r=new FormData;se(t.split(","),function(t){t=t.trim();if(n.has(t)){n.getAll(t).forEach(function(e){r.append(t,e)})}});return r}}else{return n}}function gn(e){return!!ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function pn(e,t){const n=t||re(e,"hx-swap");const r={swapStyle:ie(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ie(e).boosted&&!gn(e)){r.show="top"}if(n){const s=B(n);if(s.length>0){for(let e=0;e<s.length;e++){const l=s[e];if(l.indexOf("swap:")===0){r.swapDelay=d(l.substr(5))}else if(l.indexOf("settle:")===0){r.settleDelay=d(l.substr(7))}else if(l.indexOf("transition:")===0){r.transition=l.substr(11)==="true"}else if(l.indexOf("ignoreTitle:")===0){r.ignoreTitle=l.substr(12)==="true"}else if(l.indexOf("scroll:")===0){const u=l.substr(7);var o=u.split(":");const c=o.pop();var i=o.length>0?o.join(":"):null;r.scroll=c;r.scrollTarget=i}else if(l.indexOf("show:")===0){const f=l.substr(5);var o=f.split(":");const a=o.pop();var i=o.length>0?o.join(":"):null;r.show=a;r.showTarget=i}else if(l.indexOf("focus-scroll:")===0){const h=l.substr("focus-scroll:".length);r.focusScroll=h=="true"}else if(e==0){r.swapStyle=l}else{w("Unknown modifier in hx-swap: "+l)}}}}return r}function mn(e){return re(e,"hx-encoding")==="multipart/form-data"||a(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function yn(t,n,r){let o=null;Ut(n,function(e){if(o==null){o=e.encodeParameters(t,r,n)}});if(o!=null){return o}else{if(mn(n)){return un(new FormData,Ln(r))}else{return an(r)}}}function xn(e){return{tasks:[],elts:[e]}}function bn(e,t){const n=e[0];const r=e[e.length-1];if(t.scroll){var o=null;if(t.scrollTarget){o=ce(fe(n,t.scrollTarget))}if(t.scroll==="top"&&(n||o)){o=o||n;o.scrollTop=0}if(t.scroll==="bottom"&&(r||o)){o=o||r;o.scrollTop=o.scrollHeight}}if(t.show){var o=null;if(t.showTarget){let e=t.showTarget;if(t.showTarget==="window"){e="body"}o=ce(fe(n,e))}if(t.show==="top"&&(n||o)){o=o||n;o.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(r||o)){o=o||r;o.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function wn(r,e,o,i){if(i==null){i={}}if(r==null){return i}const s=te(r,e);if(s){let e=s.trim();let t=o;if(e==="unset"){return null}if(e.indexOf("javascript:")===0){e=e.substr(11);t=true}else if(e.indexOf("js:")===0){e=e.substr(3);t=true}if(e.indexOf("{")!==0){e="{"+e+"}"}let n;if(t){n=vn(r,function(){return Function("return ("+e+")")()},{})}else{n=S(e)}for(const l in n){if(n.hasOwnProperty(l)){if(i[l]==null){i[l]=n[l]}}}}return wn(ce(u(r)),e,o,i)}function vn(e,t,n){if(Q.config.allowEval){return t()}else{ae(e,"htmx:evalDisallowedError");return n}}function Sn(e,t){return wn(e,"hx-vars",true,t)}function En(e,t){return wn(e,"hx-vals",false,t)}function Cn(e){return ue(Sn(e),En(e))}function Rn(t,n,r){if(r!==null){try{t.setRequestHeader(n,r)}catch(e){t.setRequestHeader(n,encodeURIComponent(r));t.setRequestHeader(n+"-URI-AutoEncoded","true")}}}function On(t){if(t.responseURL&&typeof URL!=="undefined"){try{const e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ae(ne().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function C(e,t){return t.test(e.getAllResponseHeaders())}function Hn(e,t,n){e=e.toLowerCase();if(n){if(n instanceof Element||typeof n==="string"){return de(e,t,null,null,{targetOverride:y(n),returnPromise:true})}else{return de(e,t,y(n.source),n.event,{handler:n.handler,headers:n.headers,values:n.values,targetOverride:y(n.target),swapOverride:n.swap,select:n.select,returnPromise:true})}}else{return de(e,t,null,null,{returnPromise:true})}}function Tn(e){const t=[];while(e){t.push(e);e=e.parentElement}return t}function qn(e,t,n){let r;let o;if(typeof URL==="function"){o=new URL(t,document.location.href);const i=document.location.origin;r=i===o.origin}else{o=t;r=l(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!r){return false}}return he(e,"htmx:validateUrl",ue({url:o,sameHost:r},n))}function Ln(e){if(e instanceof FormData)return e;const t=new FormData;for(const n in e){if(e.hasOwnProperty(n)){if(typeof e[n].forEach==="function"){e[n].forEach(function(e){t.append(n,e)})}else if(typeof e[n]==="object"){t.append(n,JSON.stringify(e[n]))}else{t.append(n,e[n])}}}return t}function Nn(r,o,e){return new Proxy(e,{get:function(t,e){if(typeof e==="number")return t[e];if(e==="length")return t.length;if(e==="push"){return function(e){t.push(e);r.append(o,e)}}if(typeof t[e]==="function"){return function(){t[e].apply(t,arguments);r.delete(o);t.forEach(function(e){r.append(o,e)})}}if(t[e]&&t[e].length===1){return t[e][0]}else{return t[e]}},set:function(e,t,n){e[t]=n;r.delete(o);e.forEach(function(e){r.append(o,e)});return true}})}function An(r){return new Proxy(r,{get:function(e,t){if(typeof t==="symbol"){return Reflect.get(e,t)}if(t==="toJSON"){return()=>Object.fromEntries(r)}if(t in e){if(typeof e[t]==="function"){return function(){return r[t].apply(r,arguments)}}else{return e[t]}}const n=r.getAll(t);if(n.length===0){return undefined}else if(n.length===1){return n[0]}else{return Nn(e,t,n)}},set:function(t,n,e){if(typeof n!=="string"){return false}t.delete(n);if(typeof e.forEach==="function"){e.forEach(function(e){t.append(n,e)})}else{t.append(n,e)}return true},deleteProperty:function(e,t){if(typeof t==="string"){e.delete(t)}return true},ownKeys:function(e){return Reflect.ownKeys(Object.fromEntries(e))},getOwnPropertyDescriptor:function(e,t){return Reflect.getOwnPropertyDescriptor(Object.fromEntries(e),t)}})}function de(t,n,r,o,i,D){let s=null;let l=null;i=i!=null?i:{};if(i.returnPromise&&typeof Promise!=="undefined"){var e=new Promise(function(e,t){s=e;l=t})}if(r==null){r=ne().body}const M=i.handler||Mn;const X=i.select||null;if(!le(r)){oe(s);return e}const u=i.targetOverride||ce(Ce(r));if(u==null||u==ve){ae(r,"htmx:targetError",{target:te(r,"hx-target")});oe(l);return e}let c=ie(r);const f=c.lastButtonClicked;if(f){const L=ee(f,"formaction");if(L!=null){n=L}const N=ee(f,"formmethod");if(N!=null){if(N.toLowerCase()!=="dialog"){t=N}}}const a=re(r,"hx-confirm");if(D===undefined){const K=function(e){return de(t,n,r,o,i,!!e)};const G={target:u,elt:r,path:n,verb:t,triggeringEvent:o,etc:i,issueRequest:K,question:a};if(he(r,"htmx:confirm",G)===false){oe(s);return e}}let h=r;let d=re(r,"hx-sync");let g=null;let F=false;if(d){const A=d.split(":");const I=A[0].trim();if(I==="this"){h=Ee(r,"hx-sync")}else{h=ce(fe(r,I))}d=(A[1]||"drop").trim();c=ie(h);if(d==="drop"&&c.xhr&&c.abortable!==true){oe(s);return e}else if(d==="abort"){if(c.xhr){oe(s);return e}else{F=true}}else if(d==="replace"){he(h,"htmx:abort")}else if(d.indexOf("queue")===0){const Z=d.split(" ");g=(Z[1]||"last").trim()}}if(c.xhr){if(c.abortable){he(h,"htmx:abort")}else{if(g==null){if(o){const P=ie(o);if(P&&P.triggerSpec&&P.triggerSpec.queue){g=P.triggerSpec.queue}}if(g==null){g="last"}}if(c.queuedRequests==null){c.queuedRequests=[]}if(g==="first"&&c.queuedRequests.length===0){c.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="all"){c.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="last"){c.queuedRequests=[];c.queuedRequests.push(function(){de(t,n,r,o,i)})}oe(s);return e}}const p=new XMLHttpRequest;c.xhr=p;c.abortable=F;const m=function(){c.xhr=null;c.abortable=false;if(c.queuedRequests!=null&&c.queuedRequests.length>0){const e=c.queuedRequests.shift();e()}};const U=re(r,"hx-prompt");if(U){var y=prompt(U);if(y===null||!he(r,"htmx:prompt",{prompt:y,target:u})){oe(s);m();return e}}if(a&&!D){if(!confirm(a)){oe(s);m();return e}}let x=hn(r,u,y);if(t!=="get"&&!mn(r)){x["Content-Type"]="application/x-www-form-urlencoded"}if(i.headers){x=ue(x,i.headers)}const B=cn(r,t);let b=B.errors;const j=B.formData;if(i.values){un(j,Ln(i.values))}const V=Ln(Cn(r));const w=un(j,V);let v=dn(w,r);if(Q.config.getCacheBusterParam&&t==="get"){v.set("org.htmx.cache-buster",ee(u,"id")||"true")}if(n==null||n===""){n=ne().location.href}const S=wn(r,"hx-request");const _=ie(r).boosted;let E=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;const C={boosted:_,useUrlParams:E,formData:v,parameters:An(v),unfilteredFormData:w,unfilteredParameters:An(w),headers:x,target:u,verb:t,errors:b,withCredentials:i.credentials||S.credentials||Q.config.withCredentials,timeout:i.timeout||S.timeout||Q.config.timeout,path:n,triggeringEvent:o};if(!he(r,"htmx:configRequest",C)){oe(s);m();return e}n=C.path;t=C.verb;x=C.headers;v=Ln(C.parameters);b=C.errors;E=C.useUrlParams;if(b&&b.length>0){he(r,"htmx:validation:halted",C);oe(s);m();return e}const $=n.split("#");const z=$[0];const R=$[1];let O=n;if(E){O=z;const W=!v.keys().next().done;if(W){if(O.indexOf("?")<0){O+="?"}else{O+="&"}O+=an(v);if(R){O+="#"+R}}}if(!qn(r,O,C)){ae(r,"htmx:invalidPath",C);oe(l);return e}p.open(t.toUpperCase(),O,true);p.overrideMimeType("text/html");p.withCredentials=C.withCredentials;p.timeout=C.timeout;if(S.noHeaders){}else{for(const k in x){if(x.hasOwnProperty(k)){const Y=x[k];Rn(p,k,Y)}}}const H={xhr:p,target:u,requestConfig:C,etc:i,boosted:_,select:X,pathInfo:{requestPath:n,finalRequestPath:O,responsePath:null,anchor:R}};p.onload=function(){try{const t=Tn(r);H.pathInfo.responsePath=On(p);M(r,H);en(T,q);he(r,"htmx:afterRequest",H);he(r,"htmx:afterOnLoad",H);if(!le(r)){let e=null;while(t.length>0&&e==null){const n=t.shift();if(le(n)){e=n}}if(e){he(e,"htmx:afterRequest",H);he(e,"htmx:afterOnLoad",H)}}oe(s);m()}catch(e){ae(r,"htmx:onLoadError",ue({error:e},H));throw e}};p.onerror=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:sendError",H);oe(l);m()};p.onabort=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:sendAbort",H);oe(l);m()};p.ontimeout=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:timeout",H);oe(l);m()};if(!he(r,"htmx:beforeRequest",H)){oe(s);m();return e}var T=Yt(r);var q=Qt(r);se(["loadstart","loadend","progress","abort"],function(t){se([p,p.upload],function(e){e.addEventListener(t,function(e){he(r,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});he(r,"htmx:beforeSend",H);const J=E?null:yn(p,r,v);p.send(J);return e}function In(e,t){const n=t.xhr;let r=null;let o=null;if(C(n,/HX-Push:/i)){r=n.getResponseHeader("HX-Push");o="push"}else if(C(n,/HX-Push-Url:/i)){r=n.getResponseHeader("HX-Push-Url");o="push"}else if(C(n,/HX-Replace-Url:/i)){r=n.getResponseHeader("HX-Replace-Url");o="replace"}if(r){if(r==="false"){return{}}else{return{type:o,path:r}}}const i=t.pathInfo.finalRequestPath;const s=t.pathInfo.responsePath;const l=re(e,"hx-push-url");const u=re(e,"hx-replace-url");const c=ie(e).boosted;let f=null;let a=null;if(l){f="push";a=l}else if(u){f="replace";a=u}else if(c){f="push";a=s||i}if(a){if(a==="false"){return{}}if(a==="true"){a=s||i}if(t.pathInfo.anchor&&a.indexOf("#")===-1){a=a+"#"+t.pathInfo.anchor}return{type:f,path:a}}else{return{}}}function Pn(e,t){var n=new RegExp(e.code);return n.test(t.toString(10))}function kn(e){for(var t=0;t<Q.config.responseHandling.length;t++){var n=Q.config.responseHandling[t];if(Pn(n,e.status)){return n}}return{swap:false}}function Dn(e){if(e){const t=r("title");if(t){t.innerHTML=e}else{window.document.title=e}}}function Mn(o,i){const s=i.xhr;let l=i.target;const e=i.etc;const u=i.select;if(!he(o,"htmx:beforeOnLoad",i))return;if(C(s,/HX-Trigger:/i)){Je(s,"HX-Trigger",o)}if(C(s,/HX-Location:/i)){zt();let e=s.getResponseHeader("HX-Location");var t;if(e.indexOf("{")===0){t=S(e);e=t.path;delete t.path}Hn("get",e,t).then(function(){Jt(e)});return}const n=C(s,/HX-Refresh:/i)&&s.getResponseHeader("HX-Refresh")==="true";if(C(s,/HX-Redirect:/i)){location.href=s.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(C(s,/HX-Retarget:/i)){if(s.getResponseHeader("HX-Retarget")==="this"){i.target=o}else{i.target=ce(fe(o,s.getResponseHeader("HX-Retarget")))}}const c=In(o,i);const r=kn(s);const f=r.swap;let a=!!r.error;let h=Q.config.ignoreTitle||r.ignoreTitle;let d=r.select;if(r.target){i.target=ce(fe(o,r.target))}var g=e.swapOverride;if(g==null&&r.swapOverride){g=r.swapOverride}if(C(s,/HX-Retarget:/i)){if(s.getResponseHeader("HX-Retarget")==="this"){i.target=o}else{i.target=ce(fe(o,s.getResponseHeader("HX-Retarget")))}}if(C(s,/HX-Reswap:/i)){g=s.getResponseHeader("HX-Reswap")}var p=s.response;var m=ue({shouldSwap:f,serverResponse:p,isError:a,ignoreTitle:h,selectOverride:d},i);if(r.event&&!he(l,r.event,m))return;if(!he(l,"htmx:beforeSwap",m))return;l=m.target;p=m.serverResponse;a=m.isError;h=m.ignoreTitle;d=m.selectOverride;i.target=l;i.failed=a;i.successful=!a;if(m.shouldSwap){if(s.status===286){ut(o)}Ut(o,function(e){p=e.transformResponse(p,s,o)});if(c.type){zt()}if(C(s,/HX-Reswap:/i)){g=s.getResponseHeader("HX-Reswap")}var y=pn(o,g);if(!y.hasOwnProperty("ignoreTitle")){y.ignoreTitle=h}l.classList.add(Q.config.swappingClass);let n=null;let r=null;if(u){d=u}if(C(s,/HX-Reselect:/i)){d=s.getResponseHeader("HX-Reselect")}const x=re(o,"hx-select-oob");const b=re(o,"hx-select");let e=function(){try{if(c.type){he(ne().body,"htmx:beforeHistoryUpdate",ue({history:c},i));if(c.type==="push"){Jt(c.path);he(ne().body,"htmx:pushedIntoHistory",{path:c.path})}else{Kt(c.path);he(ne().body,"htmx:replacedInHistory",{path:c.path})}}ze(l,p,y,{select:d||b,selectOOB:x,eventInfo:i,anchor:i.pathInfo.anchor,contextElement:o,afterSwapCallback:function(){if(C(s,/HX-Trigger-After-Swap:/i)){let e=o;if(!le(o)){e=ne().body}Je(s,"HX-Trigger-After-Swap",e)}},afterSettleCallback:function(){if(C(s,/HX-Trigger-After-Settle:/i)){let e=o;if(!le(o)){e=ne().body}Je(s,"HX-Trigger-After-Settle",e)}oe(n)}})}catch(e){ae(o,"htmx:swapError",i);oe(r);throw e}};let t=Q.config.globalViewTransitions;if(y.hasOwnProperty("transition")){t=y.transition}if(t&&he(o,"htmx:beforeTransition",i)&&typeof Promise!=="undefined"&&document.startViewTransition){const w=new Promise(function(e,t){n=e;r=t});const v=e;e=function(){document.startViewTransition(function(){v();return w})}}if(y.swapDelay>0){E().setTimeout(e,y.swapDelay)}else{e()}}if(a){ae(o,"htmx:responseError",ue({error:"Response Status Error Code "+s.status+" from "+i.pathInfo.requestPath},i))}}const Xn={};function Fn(){return{init:function(e){return null},getSelectors:function(){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,n){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,n,r){return false},encodeParameters:function(e,t,n){return null}}}function Un(e,t){if(t.init){t.init(n)}Xn[e]=ue(Fn(),t)}function Bn(e){delete Xn[e]}function jn(e,n,r){if(n==undefined){n=[]}if(e==undefined){return n}if(r==undefined){r=[]}const t=te(e,"hx-ext");if(t){se(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){r.push(e.slice(7));return}if(r.indexOf(e)<0){const t=Xn[e];if(t&&n.indexOf(t)<0){n.push(t)}}})}return jn(ce(u(e)),n,r)}var Vn=false;ne().addEventListener("DOMContentLoaded",function(){Vn=true});function _n(e){if(Vn||ne().readyState==="complete"){e()}else{ne().addEventListener("DOMContentLoaded",e)}}function $n(){if(Q.config.includeIndicatorStyles!==false){const e=Q.config.inlineStyleNonce?` nonce="${Q.config.inlineStyleNonce}"`:"";ne().head.insertAdjacentHTML("beforeend","<style"+e+"> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zn(){const e=ne().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function Jn(){const e=zn();if(e){Q.config=ue(Q.config,e)}}_n(function(){Jn();$n();let e=ne().body;Dt(e);const t=ne().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){const t=e.target;const n=ie(t);if(n&&n.xhr){n.xhr.abort()}});const n=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){Wt();se(t,function(e){he(e,"htmx:restored",{document:ne(),triggerEvent:he})})}else{if(n){n(e)}}};E().setTimeout(function(){he(e,"htmx:load",{});e=null},0)});return Q}(); \ No newline at end of file diff --git a/code/ch4_app/ch4_final_video_collector/templates/shared/_layout.html b/code/ch4_app/ch4_final_video_collector/templates/shared/_layout.html index b4738bb..d8fe9b9 100644 --- a/code/ch4_app/ch4_final_video_collector/templates/shared/_layout.html +++ b/code/ch4_app/ch4_final_video_collector/templates/shared/_layout.html @@ -51,7 +51,7 @@ </footer> -<script src="/https/github.com/static/js/htmx.min.js?v=1.5.0"></script> +<script src="/https/github.com/static/js/htmx.min.js?v=2.0.0"></script> <script src="/https/github.com/static/js/jquery-3.5.1.slim.min.js"></script> <script src="/https/github.com/static/js/popper-1.16.1.min.js"></script> diff --git a/code/ch4_app/ch4_starter_video_collector/static/js/htmx.d.ts b/code/ch4_app/ch4_starter_video_collector/static/js/htmx.d.ts new file mode 100644 index 0000000..3775459 --- /dev/null +++ b/code/ch4_app/ch4_starter_video_collector/static/js/htmx.d.ts @@ -0,0 +1,195 @@ +declare namespace htmx { + const onLoad: (callback: (elt: Node) => void) => EventListener; + const process: (elt: string | Element) => void; + const on: (arg1: string | EventTarget, arg2: string | EventListener, arg3?: EventListener) => EventListener; + const off: (arg1: string | EventTarget, arg2: string | EventListener, arg3?: EventListener) => EventListener; + const trigger: (elt: string | EventTarget, eventName: string, detail?: any) => boolean; + const ajax: (verb: HttpVerb, path: string, context: string | Element | HtmxAjaxHelperContext) => Promise<void>; + const find: (eltOrSelector: string | ParentNode, selector?: string) => Element; + const findAll: (eltOrSelector: string | ParentNode, selector?: string) => NodeListOf<Element>; + const closest: (elt: string | Element, selector: string) => Element; + function values(elt: Element, type: HttpVerb): any; + const remove: (elt: Node, delay?: number) => void; + const addClass: (elt: string | Element, clazz: string, delay?: number) => void; + const removeClass: (node: string | Node, clazz: string, delay?: number) => void; + const toggleClass: (elt: string | Element, clazz: string) => void; + const takeClass: (elt: string | Node, clazz: string) => void; + const swap: (target: string | Element, content: string, swapSpec: HtmxSwapSpecification, swapOptions?: SwapOptions) => void; + const defineExtension: (name: string, extension: any) => void; + const removeExtension: (name: string) => void; + const logAll: () => void; + const logNone: () => void; + const logger: any; + namespace config { + const historyEnabled: boolean; + const historyCacheSize: number; + const refreshOnHistoryMiss: boolean; + const defaultSwapStyle: HtmxSwapStyle; + const defaultSwapDelay: number; + const defaultSettleDelay: number; + const includeIndicatorStyles: boolean; + const indicatorClass: string; + const requestClass: string; + const addedClass: string; + const settlingClass: string; + const swappingClass: string; + const allowEval: boolean; + const allowScriptTags: boolean; + const inlineScriptNonce: string; + const inlineStyleNonce: string; + const attributesToSettle: string[]; + const withCredentials: boolean; + const timeout: number; + const wsReconnectDelay: "full-jitter" | ((retryCount: number) => number); + const wsBinaryType: BinaryType; + const disableSelector: string; + const scrollBehavior: 'auto' | 'instant' | 'smooth'; + const defaultFocusScroll: boolean; + const getCacheBusterParam: boolean; + const globalViewTransitions: boolean; + const methodsThatUseUrlParams: (HttpVerb)[]; + const selfRequestsOnly: boolean; + const ignoreTitle: boolean; + const scrollIntoViewOnBoost: boolean; + const triggerSpecsCache: any | null; + const disableInheritance: boolean; + const responseHandling: HtmxResponseHandlingConfig[]; + const allowNestedOobSwaps: boolean; + } + const parseInterval: (str: string) => number; + const _: (str: string) => any; + const version: string; +} +type HttpVerb = 'get' | 'head' | 'post' | 'put' | 'delete' | 'connect' | 'options' | 'trace' | 'patch'; +type SwapOptions = { + select?: string; + selectOOB?: string; + eventInfo?: any; + anchor?: string; + contextElement?: Element; + afterSwapCallback?: swapCallback; + afterSettleCallback?: swapCallback; +}; +type swapCallback = () => any; +type HtmxSwapStyle = 'innerHTML' | 'outerHTML' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'delete' | 'none' | string; +type HtmxSwapSpecification = { + swapStyle: HtmxSwapStyle; + swapDelay: number; + settleDelay: number; + transition?: boolean; + ignoreTitle?: boolean; + head?: string; + scroll?: 'top' | 'bottom'; + scrollTarget?: string; + show?: string; + showTarget?: string; + focusScroll?: boolean; +}; +type ConditionalFunction = ((this: Node, evt: Event) => boolean) & { + source: string; +}; +type HtmxTriggerSpecification = { + trigger: string; + pollInterval?: number; + eventFilter?: ConditionalFunction; + changed?: boolean; + once?: boolean; + consume?: boolean; + delay?: number; + from?: string; + target?: string; + throttle?: number; + queue?: string; + root?: string; + threshold?: string; +}; +type HtmxElementValidationError = { + elt: Element; + message: string; + validity: ValidityState; +}; +type HtmxHeaderSpecification = Record<string, string>; +type HtmxAjaxHelperContext = { + source?: Element | string; + event?: Event; + handler?: HtmxAjaxHandler; + target: Element | string; + swap?: HtmxSwapStyle; + values?: any | FormData; + headers?: Record<string, string>; + select?: string; +}; +type HtmxRequestConfig = { + boosted: boolean; + useUrlParams: boolean; + formData: FormData; + /** + * formData proxy + */ + parameters: any; + unfilteredFormData: FormData; + /** + * unfilteredFormData proxy + */ + unfilteredParameters: any; + headers: HtmxHeaderSpecification; + target: Element; + verb: HttpVerb; + errors: HtmxElementValidationError[]; + withCredentials: boolean; + timeout: number; + path: string; + triggeringEvent: Event; +}; +type HtmxResponseInfo = { + xhr: XMLHttpRequest; + target: Element; + requestConfig: HtmxRequestConfig; + etc: HtmxAjaxEtc; + boosted: boolean; + select: string; + pathInfo: { + requestPath: string; + finalRequestPath: string; + responsePath: string | null; + anchor: string; + }; + failed?: boolean; + successful?: boolean; +}; +type HtmxAjaxEtc = { + returnPromise?: boolean; + handler?: HtmxAjaxHandler; + select?: string; + targetOverride?: Element; + swapOverride?: HtmxSwapStyle; + headers?: Record<string, string>; + values?: any | FormData; + credentials?: boolean; + timeout?: number; +}; +type HtmxResponseHandlingConfig = { + code?: string; + swap: boolean; + error?: boolean; + ignoreTitle?: boolean; + select?: string; + target?: string; + swapOverride?: string; + event?: string; +}; +type HtmxBeforeSwapDetails = HtmxResponseInfo & { + shouldSwap: boolean; + serverResponse: any; + isError: boolean; + ignoreTitle: boolean; + selectOverride: string; +}; +type HtmxAjaxHandler = (elt: Element, responseInfo: HtmxResponseInfo) => any; +type HtmxSettleTask = (() => void); +type HtmxSettleInfo = { + tasks: HtmxSettleTask[]; + elts: Element[]; + title?: string; +}; +type HtmxExtension = any; diff --git a/code/ch4_app/ch4_starter_video_collector/static/js/htmx.js b/code/ch4_app/ch4_starter_video_collector/static/js/htmx.js index 86e7668..c57bcd7 100644 --- a/code/ch4_app/ch4_starter_video_collector/static/js/htmx.js +++ b/code/ch4_app/ch4_starter_video_collector/static/js/htmx.js @@ -1,3909 +1,5131 @@ -// /////////////////////////////////////////////////////////////////// -// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.js -// - -// UMD insanity -// This code sets up support for (in order) AMD, ES6 modules, and globals. -(function (root, factory) { - //@ts-ignore - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - //@ts-ignore - define([], factory); - } else if (typeof module === 'object' && module.exports) { - // Node. Does not work with strict CommonJS, but - // only CommonJS-like environments that support module.exports, - // like Node. - module.exports = factory(); - } else { - // Browser globals - root.htmx = root.htmx || factory(); - } -}(typeof self !== 'undefined' ? self : this, function () { -return (function () { - 'use strict'; - - // Public API - //** @type {import("./htmx").HtmxApi} */ - // TODO: list all methods in public API - var htmx = { - onLoad: onLoadHelper, - process: processNode, - on: addEventListenerImpl, - off: removeEventListenerImpl, - trigger : triggerEvent, - ajax : ajaxHelper, - find : find, - findAll : findAll, - closest : closest, - values : function(elt, type){ - var inputValues = getInputValues(elt, type || "post"); - return inputValues.values; - }, - remove : removeElement, - addClass : addClassToElement, - removeClass : removeClassFromElement, - toggleClass : toggleClassOnElement, - takeClass : takeClassForElement, - defineExtension : defineExtension, - removeExtension : removeExtension, - logAll : logAll, - logNone : logNone, - logger : null, - config : { - historyEnabled:true, - historyCacheSize:10, - refreshOnHistoryMiss:false, - defaultSwapStyle:'innerHTML', - defaultSwapDelay:0, - defaultSettleDelay:20, - includeIndicatorStyles:true, - indicatorClass:'htmx-indicator', - requestClass:'htmx-request', - addedClass:'htmx-added', - settlingClass:'htmx-settling', - swappingClass:'htmx-swapping', - allowEval:true, - allowScriptTags:true, - inlineScriptNonce:'', - attributesToSettle:["class", "style", "width", "height"], - withCredentials:false, - timeout:0, - wsReconnectDelay: 'full-jitter', - wsBinaryType: 'blob', - disableSelector: "[hx-disable], [data-hx-disable]", - useTemplateFragments: false, - scrollBehavior: 'smooth', - defaultFocusScroll: false, - getCacheBusterParam: false, - globalViewTransitions: false, - methodsThatUseUrlParams: ["get"], - selfRequestsOnly: false, - ignoreTitle: false, - scrollIntoViewOnBoost: true, - triggerSpecsCache: null, - }, - parseInterval:parseInterval, - _:internalEval, - createEventSource: function(url){ - return new EventSource(url, {withCredentials:true}) - }, - createWebSocket: function(url){ - var sock = new WebSocket(url, []); - sock.binaryType = htmx.config.wsBinaryType; - return sock; - }, - version: "1.9.10" - }; - - /** @type {import("./htmx").HtmxInternalApi} */ - var internalAPI = { - addTriggerHandler: addTriggerHandler, - bodyContains: bodyContains, - canAccessLocalStorage: canAccessLocalStorage, - findThisElement: findThisElement, - filterValues: filterValues, - hasAttribute: hasAttribute, - getAttributeValue: getAttributeValue, - getClosestAttributeValue: getClosestAttributeValue, - getClosestMatch: getClosestMatch, - getExpressionVars: getExpressionVars, - getHeaders: getHeaders, - getInputValues: getInputValues, - getInternalData: getInternalData, - getSwapSpecification: getSwapSpecification, - getTriggerSpecs: getTriggerSpecs, - getTarget: getTarget, - makeFragment: makeFragment, - mergeObjects: mergeObjects, - makeSettleInfo: makeSettleInfo, - oobSwap: oobSwap, - querySelectorExt: querySelectorExt, - selectAndSwap: selectAndSwap, - settleImmediately: settleImmediately, - shouldCancel: shouldCancel, - triggerEvent: triggerEvent, - triggerErrorEvent: triggerErrorEvent, - withExtensions: withExtensions, - } - - var VERBS = ['get', 'post', 'put', 'delete', 'patch']; - var VERB_SELECTOR = VERBS.map(function(verb){ - return "[hx-" + verb + "], [data-hx-" + verb + "]" - }).join(", "); - - var HEAD_TAG_REGEX = makeTagRegEx('head'), - TITLE_TAG_REGEX = makeTagRegEx('title'), - SVG_TAGS_REGEX = makeTagRegEx('svg', true); - - //==================================================================== - // Utilities - //==================================================================== - - /** - * @param {string} tag - * @param {boolean} global - * @returns {RegExp} - */ - function makeTagRegEx(tag, global = false) { - return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, - global ? 'gim' : 'im'); - } - - function parseInterval(str) { - if (str == undefined) { - return undefined; - } - - let interval = NaN; - if (str.slice(-2) == "ms") { - interval = parseFloat(str.slice(0, -2)); - } else if (str.slice(-1) == "s") { - interval = parseFloat(str.slice(0, -1)) * 1000; - } else if (str.slice(-1) == "m") { - interval = parseFloat(str.slice(0, -1)) * 1000 * 60; - } else { - interval = parseFloat(str); - } - return isNaN(interval) ? undefined : interval; - } - - /** - * @param {HTMLElement} elt - * @param {string} name - * @returns {(string | null)} - */ - function getRawAttribute(elt, name) { - return elt.getAttribute && elt.getAttribute(name); - } - - // resolve with both hx and data-hx prefixes - function hasAttribute(elt, qualifiedName) { - return elt.hasAttribute && (elt.hasAttribute(qualifiedName) || - elt.hasAttribute("data-" + qualifiedName)); - } - - /** - * - * @param {HTMLElement} elt - * @param {string} qualifiedName - * @returns {(string | null)} - */ - function getAttributeValue(elt, qualifiedName) { - return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); - } - - /** - * @param {HTMLElement} elt - * @returns {HTMLElement | null} - */ - function parentElt(elt) { - return elt.parentElement; - } - - /** - * @returns {Document} - */ - function getDocument() { - return document; - } - - /** - * @param {HTMLElement} elt - * @param {(e:HTMLElement) => boolean} condition - * @returns {HTMLElement | null} - */ - function getClosestMatch(elt, condition) { - while (elt && !condition(elt)) { - elt = parentElt(elt); - } - - return elt ? elt : null; - } - - function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ - var attributeValue = getAttributeValue(ancestor, attributeName); - var disinherit = getAttributeValue(ancestor, "hx-disinherit"); - if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) { - return "unset"; - } else { - return attributeValue - } - } - - /** - * @param {HTMLElement} elt - * @param {string} attributeName - * @returns {string | null} - */ - function getClosestAttributeValue(elt, attributeName) { - var closestAttr = null; - getClosestMatch(elt, function (e) { - return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName); - }); - if (closestAttr !== "unset") { - return closestAttr; - } - } - - /** - * @param {HTMLElement} elt - * @param {string} selector - * @returns {boolean} - */ - function matches(elt, selector) { - // @ts-ignore: non-standard properties for browser compatibility - // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; - return matchesFunction && matchesFunction.call(elt, selector); - } - - /** - * @param {string} str - * @returns {string} - */ - 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 ""; - } - } - - /** - * - * @param {string} resp - * @param {number} depth - * @returns {Element} - */ - function parseHTML(resp, depth) { - var parser = new DOMParser(); - var responseDoc = parser.parseFromString(resp, "text/html"); - - /** @type {Element} */ - var responseNode = responseDoc.body; - while (depth > 0) { - depth--; - // @ts-ignore - responseNode = responseNode.firstChild; - } - if (responseNode == null) { - // @ts-ignore - responseNode = getDocument().createDocumentFragment(); - } - return responseNode; - } - - function aFullPageResponse(resp) { - return /<body/.test(resp) - } +// v2.0.0 from https://github.com/bigskysoftware/htmx/releases + +var htmx = (function() { + 'use strict' + + // Public API + const htmx = { + // Tsc madness here, assigning the functions directly results in an invalid TypeScript output, but reassigning is fine + /* Event processing */ + /** @type {typeof onLoadHelper} */ + onLoad: null, + /** @type {typeof processNode} */ + process: null, + /** @type {typeof addEventListenerImpl} */ + on: null, + /** @type {typeof removeEventListenerImpl} */ + off: null, + /** @type {typeof triggerEvent} */ + trigger: null, + /** @type {typeof ajaxHelper} */ + ajax: null, + /* DOM querying helpers */ + /** @type {typeof find} */ + find: null, + /** @type {typeof findAll} */ + findAll: null, + /** @type {typeof closest} */ + closest: null, + /** + * Returns the input values that would resolve for a given element via the htmx value resolution mechanism + * + * @see https://htmx.org/api/#values + * + * @param {Element} elt the element to resolve values on + * @param {HttpVerb} type the request type (e.g. **get** or **post**) non-GET's will include the enclosing form of the element. Defaults to **post** + * @returns {Object} + */ + values: function(elt, type) { + const inputValues = getInputValues(elt, type || 'post') + return inputValues.values + }, + /* DOM manipulation helpers */ + /** @type {typeof removeElement} */ + remove: null, + /** @type {typeof addClassToElement} */ + addClass: null, + /** @type {typeof removeClassFromElement} */ + removeClass: null, + /** @type {typeof toggleClassOnElement} */ + toggleClass: null, + /** @type {typeof takeClassForElement} */ + takeClass: null, + /** @type {typeof swap} */ + swap: null, + /* Extension entrypoints */ + /** @type {typeof defineExtension} */ + defineExtension: null, + /** @type {typeof removeExtension} */ + removeExtension: null, + /* Debugging */ + /** @type {typeof logAll} */ + logAll: null, + /** @type {typeof logNone} */ + logNone: null, + /* Debugging */ + /** + * The logger htmx uses to log with + * + * @see https://htmx.org/api/#logger + */ + logger: null, + /** + * A property holding the configuration htmx uses at runtime. + * + * Note that using a [meta tag](https://htmx.org/docs/#config) is the preferred mechanism for setting these properties. + * + * @see https://htmx.org/api/#config + */ + config: { + /** + * Whether to use history. + * @type boolean + * @default true + */ + historyEnabled: true, + /** + * The number of pages to keep in **localStorage** for history support. + * @type number + * @default 10 + */ + historyCacheSize: 10, + /** + * @type boolean + * @default false + */ + refreshOnHistoryMiss: false, + /** + * The default swap style to use if **[hx-swap](https://htmx.org/attributes/hx-swap)** is omitted. + * @type HtmxSwapStyle + * @default 'innerHTML' + */ + defaultSwapStyle: 'innerHTML', + /** + * The default delay between receiving a response from the server and doing the swap. + * @type number + * @default 0 + */ + defaultSwapDelay: 0, + /** + * The default delay between completing the content swap and settling attributes. + * @type number + * @default 20 + */ + defaultSettleDelay: 20, + /** + * If true, htmx will inject a small amount of CSS into the page to make indicators invisible unless the **htmx-indicator** class is present. + * @type boolean + * @default true + */ + includeIndicatorStyles: true, + /** + * The class to place on indicators when a request is in flight. + * @type string + * @default 'htmx-indicator' + */ + indicatorClass: 'htmx-indicator', + /** + * The class to place on triggering elements when a request is in flight. + * @type string + * @default 'htmx-request' + */ + requestClass: 'htmx-request', + /** + * The class to temporarily place on elements that htmx has added to the DOM. + * @type string + * @default 'htmx-added' + */ + addedClass: 'htmx-added', + /** + * The class to place on target elements when htmx is in the settling phase. + * @type string + * @default 'htmx-settling' + */ + settlingClass: 'htmx-settling', + /** + * The class to place on target elements when htmx is in the swapping phase. + * @type string + * @default 'htmx-swapping' + */ + swappingClass: 'htmx-swapping', + /** + * Allows the use of eval-like functionality in htmx, to enable **hx-vars**, trigger conditions & script tag evaluation. Can be set to **false** for CSP compatibility. + * @type boolean + * @default true + */ + allowEval: true, + /** + * If set to false, disables the interpretation of script tags. + * @type boolean + * @default true + */ + allowScriptTags: true, + /** + * If set, the nonce will be added to inline scripts. + * @type string + * @default '' + */ + inlineScriptNonce: '', + /** + * If set, the nonce will be added to inline styles. + * @type string + * @default '' + */ + inlineStyleNonce: '', + /** + * The attributes to settle during the settling phase. + * @type string[] + * @default ['class', 'style', 'width', 'height'] + */ + attributesToSettle: ['class', 'style', 'width', 'height'], + /** + * Allow cross-site Access-Control requests using credentials such as cookies, authorization headers or TLS client certificates. + * @type boolean + * @default false + */ + withCredentials: false, + /** + * @type number + * @default 0 + */ + timeout: 0, + /** + * The default implementation of **getWebSocketReconnectDelay** for reconnecting after unexpected connection loss by the event code **Abnormal Closure**, **Service Restart** or **Try Again Later**. + * @type {'full-jitter' | ((retryCount:number) => number)} + * @default "full-jitter" + */ + wsReconnectDelay: 'full-jitter', + /** + * The type of binary data being received over the WebSocket connection + * @type BinaryType + * @default 'blob' + */ + wsBinaryType: 'blob', + /** + * @type string + * @default '[hx-disable], [data-hx-disable]' + */ + disableSelector: '[hx-disable], [data-hx-disable]', + /** + * @type {'auto' | 'instant' | 'smooth'} + * @default 'smooth' + */ + scrollBehavior: 'instant', + /** + * If the focused element should be scrolled into view. + * @type boolean + * @default false + */ + defaultFocusScroll: false, + /** + * If set to true htmx will include a cache-busting parameter in GET requests to avoid caching partial responses by the browser + * @type boolean + * @default false + */ + getCacheBusterParam: false, + /** + * If set to true, htmx will use the View Transition API when swapping in new content. + * @type boolean + * @default false + */ + globalViewTransitions: false, + /** + * htmx will format requests with these methods by encoding their parameters in the URL, not the request body + * @type {(HttpVerb)[]} + * @default ['get', 'delete'] + */ + methodsThatUseUrlParams: ['get', 'delete'], + /** + * If set to true, disables htmx-based requests to non-origin hosts. + * @type boolean + * @default false + */ + selfRequestsOnly: true, + /** + * If set to true htmx will not update the title of the document when a title tag is found in new content + * @type boolean + * @default false + */ + ignoreTitle: false, + /** + * Whether the target of a boosted element is scrolled into the viewport. + * @type boolean + * @default true + */ + scrollIntoViewOnBoost: true, + /** + * The cache to store evaluated trigger specifications into. + * You may define a simple object to use a never-clearing cache, or implement your own system using a [proxy object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Proxy) + * @type {Object|null} + * @default null + */ + triggerSpecsCache: null, + /** @type boolean */ + disableInheritance: false, + /** @type HtmxResponseHandlingConfig[] */ + responseHandling: [ + { code: '204', swap: false }, + { code: '[23]..', swap: true }, + { code: '[45]..', swap: false, error: true } + ], + /** + * Whether to process OOB swaps on elements that are nested within the main response element. + * @type boolean + * @default true + */ + allowNestedOobSwaps: true + }, + /** @type {typeof parseInterval} */ + parseInterval: null, + /** @type {typeof internalEval} */ + _: null, + version: '2.0.0' + } + // Tsc madness part 2 + htmx.onLoad = onLoadHelper + htmx.process = processNode + htmx.on = addEventListenerImpl + htmx.off = removeEventListenerImpl + htmx.trigger = triggerEvent + htmx.ajax = ajaxHelper + htmx.find = find + htmx.findAll = findAll + htmx.closest = closest + htmx.remove = removeElement + htmx.addClass = addClassToElement + htmx.removeClass = removeClassFromElement + htmx.toggleClass = toggleClassOnElement + htmx.takeClass = takeClassForElement + htmx.swap = swap + htmx.defineExtension = defineExtension + htmx.removeExtension = removeExtension + htmx.logAll = logAll + htmx.logNone = logNone + htmx.parseInterval = parseInterval + htmx._ = internalEval + + const internalAPI = { + addTriggerHandler, + bodyContains, + canAccessLocalStorage, + findThisElement, + filterValues, + swap, + hasAttribute, + getAttributeValue, + getClosestAttributeValue, + getClosestMatch, + getExpressionVars, + getHeaders, + getInputValues, + getInternalData, + getSwapSpecification, + getTriggerSpecs, + getTarget, + makeFragment, + mergeObjects, + makeSettleInfo, + oobSwap, + querySelectorExt, + settleImmediately, + shouldCancel, + triggerEvent, + triggerErrorEvent, + withExtensions + } + + const VERBS = ['get', 'post', 'put', 'delete', 'patch'] + const VERB_SELECTOR = VERBS.map(function(verb) { + return '[hx-' + verb + '], [data-hx-' + verb + ']' + }).join(', ') + + const HEAD_TAG_REGEX = makeTagRegEx('head') + + //= =================================================================== + // Utilities + //= =================================================================== + + /** + * @param {string} tag + * @param {boolean} global + * @returns {RegExp} + */ + function makeTagRegEx(tag, global = false) { + return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, + global ? 'gim' : 'im') + } + + /** + * Parses an interval string consistent with the way htmx does. Useful for plugins that have timing-related attributes. + * + * Caution: Accepts an int followed by either **s** or **ms**. All other values use **parseFloat** + * + * @see https://htmx.org/api/#parseInterval + * + * @param {string} str timing string + * @returns {number|undefined} + */ + function parseInterval(str) { + if (str == undefined) { + return undefined + } - /** - * - * @param {string} response - * @returns {Element} - */ - function makeFragment(response) { - var partialResponse = !aFullPageResponse(response); - var startTag = getStartTag(response); - var content = response; - if (startTag === 'head') { - content = content.replace(HEAD_TAG_REGEX, ''); - } - if (htmx.config.useTemplateFragments && partialResponse) { - var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0); - // @ts-ignore type mismatch between DocumentFragment and Element. - // TODO: Are these close enough for htmx to use interchangeably? - return documentFragment.querySelector('template').content; - } - switch (startTag) { - case "thead": - case "tbody": - case "tfoot": - case "colgroup": - case "caption": - return parseHTML("<table>" + content + "</table>", 1); - case "col": - return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2); - case "tr": - return parseHTML("<table><tbody>" + content + "</tbody></table>", 2); - case "td": - case "th": - return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3); - case "script": - case "style": - return parseHTML("<div>" + content + "</div>", 1); - default: - return parseHTML(content, 0); - } - } + let interval = NaN + if (str.slice(-2) == 'ms') { + interval = parseFloat(str.slice(0, -2)) + } else if (str.slice(-1) == 's') { + interval = parseFloat(str.slice(0, -1)) * 1000 + } else if (str.slice(-1) == 'm') { + interval = parseFloat(str.slice(0, -1)) * 1000 * 60 + } else { + interval = parseFloat(str) + } + return isNaN(interval) ? undefined : interval + } + + /** + * @param {Node} elt + * @param {string} name + * @returns {(string | null)} + */ + function getRawAttribute(elt, name) { + return elt instanceof Element && elt.getAttribute(name) + } + + /** + * @param {Element} elt + * @param {string} qualifiedName + * @returns {boolean} + */ + // resolve with both hx and data-hx prefixes + function hasAttribute(elt, qualifiedName) { + return !!elt.hasAttribute && (elt.hasAttribute(qualifiedName) || + elt.hasAttribute('data-' + qualifiedName)) + } + + /** + * + * @param {Node} elt + * @param {string} qualifiedName + * @returns {(string | null)} + */ + function getAttributeValue(elt, qualifiedName) { + return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, 'data-' + qualifiedName) + } + + /** + * @param {Node} elt + * @returns {Node | null} + */ + function parentElt(elt) { + const parent = elt.parentElement + if (!parent && elt.parentNode instanceof ShadowRoot) return elt.parentNode + return parent + } + + /** + * @returns {Document} + */ + function getDocument() { + return document + } + + /** + * @param {Node} elt + * @param {boolean} global + * @returns {Node|Document} + */ + function getRootNode(elt, global) { + return elt.getRootNode ? elt.getRootNode({ composed: global }) : getDocument() + } + + /** + * @param {Node} elt + * @param {(e:Node) => boolean} condition + * @returns {Node | null} + */ + function getClosestMatch(elt, condition) { + while (elt && !condition(elt)) { + elt = parentElt(elt) + } - /** - * @param {Function} func - */ - function maybeCall(func){ - if(func) { - func(); - } + return elt || null + } + + /** + * @param {Element} initialElement + * @param {Element} ancestor + * @param {string} attributeName + * @returns {string|null} + */ + function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName) { + const attributeValue = getAttributeValue(ancestor, attributeName) + const disinherit = getAttributeValue(ancestor, 'hx-disinherit') + var inherit = getAttributeValue(ancestor, 'hx-inherit') + if (initialElement !== ancestor) { + if (htmx.config.disableInheritance) { + if (inherit && (inherit === '*' || inherit.split(' ').indexOf(attributeName) >= 0)) { + return attributeValue + } else { + return null + } + } + if (disinherit && (disinherit === '*' || disinherit.split(' ').indexOf(attributeName) >= 0)) { + return 'unset' + } + } + return attributeValue + } + + /** + * @param {Element} elt + * @param {string} attributeName + * @returns {string | null} + */ + function getClosestAttributeValue(elt, attributeName) { + let closestAttr = null + getClosestMatch(elt, function(e) { + return !!(closestAttr = getAttributeValueWithDisinheritance(elt, asElement(e), attributeName)) + }) + if (closestAttr !== 'unset') { + return closestAttr + } + } + + /** + * @param {Node} elt + * @param {string} selector + * @returns {boolean} + */ + function matches(elt, selector) { + // @ts-ignore: non-standard properties for browser compatibility + // noinspection JSUnresolvedVariable + const matchesFunction = elt instanceof Element && (elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector) + return !!matchesFunction && matchesFunction.call(elt, selector) + } + + /** + * @param {string} str + * @returns {string} + */ + function getStartTag(str) { + const tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i + const match = tagMatcher.exec(str) + if (match) { + return match[1].toLowerCase() + } else { + return '' + } + } + + /** + * @param {string} resp + * @returns {Document} + */ + function parseHTML(resp) { + const parser = new DOMParser() + return parser.parseFromString(resp, 'text/html') + } + + /** + * @param {DocumentFragment} fragment + * @param {Node} elt + */ + function takeChildrenFor(fragment, elt) { + while (elt.childNodes.length > 0) { + fragment.append(elt.childNodes[0]) + } + } + + /** + * @param {HTMLScriptElement} script + * @returns {HTMLScriptElement} + */ + function duplicateScript(script) { + const newScript = getDocument().createElement('script') + forEach(script.attributes, function(attr) { + newScript.setAttribute(attr.name, attr.value) + }) + newScript.textContent = script.textContent + newScript.async = false + if (htmx.config.inlineScriptNonce) { + newScript.nonce = htmx.config.inlineScriptNonce + } + return newScript + } + + /** + * @param {HTMLScriptElement} script + * @returns {boolean} + */ + function isJavaScriptScriptNode(script) { + return script.matches('script') && (script.type === 'text/javascript' || script.type === 'module' || script.type === '') + } + + /** + * we have to make new copies of script tags that we are going to insert because + * SOME browsers (not saying who, but it involves an element and an animal) don't + * execute scripts created in <template> tags when they are inserted into the DOM + * and all the others do lmao + * @param {DocumentFragment} fragment + */ + function normalizeScriptTags(fragment) { + Array.from(fragment.querySelectorAll('script')).forEach(/** @param {HTMLScriptElement} script */ (script) => { + if (isJavaScriptScriptNode(script)) { + const newScript = duplicateScript(script) + const parent = script.parentNode + try { + parent.insertBefore(newScript, script) + } catch (e) { + logError(e) + } finally { + script.remove() + } + } + }) + } + + /** + * @typedef {DocumentFragment & {title?: string}} DocumentFragmentWithTitle + * @description a document fragment representing the response HTML, including + * a `title` property for any title information found + */ + + /** + * @param {string} response HTML + * @returns {DocumentFragmentWithTitle} + */ + function makeFragment(response) { + // strip head tag to determine shape of response we are dealing with + const responseWithNoHead = response.replace(HEAD_TAG_REGEX, '') + const startTag = getStartTag(responseWithNoHead) + /** @type DocumentFragmentWithTitle */ + let fragment + if (startTag === 'html') { + // if it is a full document, parse it and return the body + fragment = /** @type DocumentFragmentWithTitle */ (new DocumentFragment()) + const doc = parseHTML(response) + takeChildrenFor(fragment, doc.body) + fragment.title = doc.title + } else if (startTag === 'body') { + // parse body w/o wrapping in template + fragment = /** @type DocumentFragmentWithTitle */ (new DocumentFragment()) + const doc = parseHTML(responseWithNoHead) + takeChildrenFor(fragment, doc.body) + fragment.title = doc.title + } else { + // otherwise we have non-body partial HTML content, so wrap it in a template to maximize parsing flexibility + const doc = parseHTML('<body><template class="internal-htmx-wrapper">' + responseWithNoHead + '</template></body>') + fragment = /** @type DocumentFragmentWithTitle */ (doc.querySelector('template').content) + // extract title into fragment for later processing + fragment.title = doc.title + + // for legacy reasons we support a title tag at the root level of non-body responses, so we need to handle it + var titleElement = fragment.querySelector('title') + if (titleElement && titleElement.parentNode === fragment) { + titleElement.remove() + fragment.title = titleElement.innerText + } + } + if (fragment) { + if (htmx.config.allowScriptTags) { + normalizeScriptTags(fragment) + } else { + // remove all script tags if scripts are disabled + fragment.querySelectorAll('script').forEach((script) => script.remove()) + } + } + return fragment + } + + /** + * @param {Function} func + */ + function maybeCall(func) { + if (func) { + func() + } + } + + /** + * @param {any} o + * @param {string} type + * @returns + */ + function isType(o, type) { + return Object.prototype.toString.call(o) === '[object ' + type + ']' + } + + /** + * @param {*} o + * @returns {o is Function} + */ + function isFunction(o) { + return typeof o === 'function' + } + + /** + * @param {*} o + * @returns {o is Object} + */ + function isRawObject(o) { + return isType(o, 'Object') + } + + /** + * @typedef {Object} OnHandler + * @property {(keyof HTMLElementEventMap)|string} event + * @property {EventListener} listener + */ + + /** + * @typedef {Object} ListenerInfo + * @property {string} trigger + * @property {EventListener} listener + * @property {EventTarget} on + */ + + /** + * @typedef {Object} HtmxNodeInternalData + * Element data + * @property {number} [initHash] + * @property {boolean} [boosted] + * @property {OnHandler[]} [onHandlers] + * @property {number} [timeout] + * @property {ListenerInfo[]} [listenerInfos] + * @property {boolean} [cancelled] + * @property {boolean} [triggeredOnce] + * @property {number} [delayed] + * @property {number|null} [throttle] + * @property {string} [lastValue] + * @property {boolean} [loaded] + * @property {string} [path] + * @property {string} [verb] + * @property {boolean} [polling] + * @property {HTMLButtonElement|HTMLInputElement|null} [lastButtonClicked] + * @property {number} [requestCount] + * @property {XMLHttpRequest} [xhr] + * @property {(() => void)[]} [queuedRequests] + * @property {boolean} [abortable] + * + * Event data + * @property {HtmxTriggerSpecification} [triggerSpec] + * @property {EventTarget[]} [handledFor] + */ + + /** + * getInternalData retrieves "private" data stored by htmx within an element + * @param {EventTarget|Event} elt + * @returns {HtmxNodeInternalData} + */ + function getInternalData(elt) { + const dataProp = 'htmx-internal-data' + let data = elt[dataProp] + if (!data) { + data = elt[dataProp] = {} + } + return data + } + + /** + * toArray converts an ArrayLike object into a real array. + * @template T + * @param {ArrayLike<T>} arr + * @returns {T[]} + */ + function toArray(arr) { + const returnArr = [] + if (arr) { + for (let i = 0; i < arr.length; i++) { + returnArr.push(arr[i]) + } + } + return returnArr + } + + /** + * @template T + * @param {T[]|NamedNodeMap|HTMLCollection|HTMLFormControlsCollection|ArrayLike<T>} arr + * @param {(T) => void} func + */ + function forEach(arr, func) { + if (arr) { + for (let i = 0; i < arr.length; i++) { + func(arr[i]) + } + } + } + + /** + * @param {Element} el + * @returns {boolean} + */ + function isScrolledIntoView(el) { + const rect = el.getBoundingClientRect() + const elemTop = rect.top + const elemBottom = rect.bottom + return elemTop < window.innerHeight && elemBottom >= 0 + } + + /** + * @param {Node} elt + * @returns {boolean} + */ + function bodyContains(elt) { + // IE Fix + const rootNode = elt.getRootNode && elt.getRootNode() + if (rootNode && rootNode instanceof window.ShadowRoot) { + return getDocument().body.contains(rootNode.host) + } else { + return getDocument().body.contains(elt) + } + } + + /** + * @param {string} trigger + * @returns {string[]} + */ + function splitOnWhitespace(trigger) { + return trigger.trim().split(/\s+/) + } + + /** + * mergeObjects takes all the keys from + * obj2 and duplicates them into obj1 + * @template T1 + * @template T2 + * @param {T1} obj1 + * @param {T2} obj2 + * @returns {T1 & T2} + */ + function mergeObjects(obj1, obj2) { + for (const key in obj2) { + if (obj2.hasOwnProperty(key)) { + // @ts-ignore tsc doesn't seem to properly handle types merging + obj1[key] = obj2[key] + } + } + // @ts-ignore tsc doesn't seem to properly handle types merging + return obj1 + } + + /** + * @param {string} jString + * @returns {any|null} + */ + function parseJSON(jString) { + try { + return JSON.parse(jString) + } catch (error) { + logError(error) + return null + } + } + + /** + * @returns {boolean} + */ + function canAccessLocalStorage() { + const test = 'htmx:localStorageTest' + try { + localStorage.setItem(test, test) + localStorage.removeItem(test) + return true + } catch (e) { + return false + } + } + + /** + * @param {string} path + * @returns {string} + */ + function normalizePath(path) { + try { + const url = new URL(path) + if (url) { + path = url.pathname + url.search + } + // remove trailing slash, unless index page + if (!(/^\/$/.test(path))) { + path = path.replace(/\/+$/, '') + } + return path + } catch (e) { + // be kind to IE11, which doesn't support URL() + return path + } + } + + //= ========================================================================================= + // public API + //= ========================================================================================= + + /** + * @param {string} str + * @returns {any} + */ + function internalEval(str) { + return maybeEval(getDocument().body, function() { + return eval(str) + }) + } + + /** + * Adds a callback for the **htmx:load** event. This can be used to process new content, for example initializing the content with a javascript library + * + * @see https://htmx.org/api/#onLoad + * + * @param {(elt: Node) => void} callback the callback to call on newly loaded content + * @returns {EventListener} + */ + function onLoadHelper(callback) { + const value = htmx.on('htmx:load', /** @param {CustomEvent} evt */ function(evt) { + callback(evt.detail.elt) + }) + return value + } + + /** + * Log all htmx events, useful for debugging. + * + * @see https://htmx.org/api/#logAll + */ + function logAll() { + htmx.logger = function(elt, event, data) { + if (console) { + console.log(event, elt, data) + } + } + } + + function logNone() { + htmx.logger = null + } + + /** + * Finds an element matching the selector + * + * @see https://htmx.org/api/#find + * + * @param {ParentNode|string} eltOrSelector the root element to find the matching element in, inclusive | the selector to match + * @param {string} [selector] the selector to match + * @returns {Element|null} + */ + function find(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return eltOrSelector.querySelector(selector) + } else { + return find(getDocument(), eltOrSelector) + } + } + + /** + * Finds all elements matching the selector + * + * @see https://htmx.org/api/#findAll + * + * @param {ParentNode|string} eltOrSelector the root element to find the matching elements in, inclusive | the selector to match + * @param {string} [selector] the selector to match + * @returns {NodeListOf<Element>} + */ + function findAll(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return eltOrSelector.querySelectorAll(selector) + } else { + return findAll(getDocument(), eltOrSelector) + } + } + + /** + * @returns Window + */ + function getWindow() { + return window + } + + /** + * Removes an element from the DOM + * + * @see https://htmx.org/api/#remove + * + * @param {Node} elt + * @param {number} [delay] + */ + function removeElement(elt, delay) { + elt = resolveTarget(elt) + if (delay) { + getWindow().setTimeout(function() { + removeElement(elt) + elt = null + }, delay) + } else { + parentElt(elt).removeChild(elt) + } + } + + /** + * @param {any} elt + * @return {Element|null} + */ + function asElement(elt) { + return elt instanceof Element ? elt : null + } + + /** + * @param {any} elt + * @return {HTMLElement|null} + */ + function asHtmlElement(elt) { + return elt instanceof HTMLElement ? elt : null + } + + /** + * @param {any} value + * @return {string|null} + */ + function asString(value) { + return typeof value === 'string' ? value : null + } + + /** + * @param {EventTarget} elt + * @return {ParentNode|null} + */ + function asParentNode(elt) { + return elt instanceof Element || elt instanceof Document || elt instanceof DocumentFragment ? elt : null + } + + /** + * This method adds a class to the given element. + * + * @see https://htmx.org/api/#addClass + * + * @param {Element|string} elt the element to add the class to + * @param {string} clazz the class to add + * @param {number} [delay] the delay (in milliseconds) before class is added + */ + function addClassToElement(elt, clazz, delay) { + elt = asElement(resolveTarget(elt)) + if (!elt) { + return + } + if (delay) { + getWindow().setTimeout(function() { + addClassToElement(elt, clazz) + elt = null + }, delay) + } else { + elt.classList && elt.classList.add(clazz) + } + } + + /** + * Removes a class from the given element + * + * @see https://htmx.org/api/#removeClass + * + * @param {Node|string} node element to remove the class from + * @param {string} clazz the class to remove + * @param {number} [delay] the delay (in milliseconds before class is removed) + */ + function removeClassFromElement(node, clazz, delay) { + let elt = asElement(resolveTarget(node)) + if (!elt) { + return + } + if (delay) { + getWindow().setTimeout(function() { + removeClassFromElement(elt, clazz) + elt = null + }, delay) + } else { + if (elt.classList) { + elt.classList.remove(clazz) + // if there are no classes left, remove the class attribute + if (elt.classList.length === 0) { + elt.removeAttribute('class') } + } + } + } + + /** + * Toggles the given class on an element + * + * @see https://htmx.org/api/#toggleClass + * + * @param {Element|string} elt the element to toggle the class on + * @param {string} clazz the class to toggle + */ + function toggleClassOnElement(elt, clazz) { + elt = resolveTarget(elt) + elt.classList.toggle(clazz) + } + + /** + * Takes the given class from its siblings, so that among its siblings, only the given element will have the class. + * + * @see https://htmx.org/api/#takeClass + * + * @param {Node|string} elt the element that will take the class + * @param {string} clazz the class to take + */ + function takeClassForElement(elt, clazz) { + elt = resolveTarget(elt) + forEach(elt.parentElement.children, function(child) { + removeClassFromElement(child, clazz) + }) + addClassToElement(asElement(elt), clazz) + } + + /** + * Finds the closest matching element in the given elements parentage, inclusive of the element + * + * @see https://htmx.org/api/#closest + * + * @param {Element|string} elt the element to find the selector from + * @param {string} selector the selector to find + * @returns {Element|null} + */ + function closest(elt, selector) { + elt = asElement(resolveTarget(elt)) + if (elt && elt.closest) { + return elt.closest(selector) + } else { + // TODO remove when IE goes away + do { + if (elt == null || matches(elt, selector)) { + return elt + } + } + while (elt = elt && asElement(parentElt(elt))) + return null + } + } + + /** + * @param {string} str + * @param {string} prefix + * @returns {boolean} + */ + function startsWith(str, prefix) { + return str.substring(0, prefix.length) === prefix + } + + /** + * @param {string} str + * @param {string} suffix + * @returns {boolean} + */ + function endsWith(str, suffix) { + return str.substring(str.length - suffix.length) === suffix + } + + /** + * @param {string} selector + * @returns {string} + */ + function normalizeSelector(selector) { + const trimmedSelector = selector.trim() + if (startsWith(trimmedSelector, '<') && endsWith(trimmedSelector, '/>')) { + return trimmedSelector.substring(1, trimmedSelector.length - 2) + } else { + return trimmedSelector + } + } + + /** + * @param {Node|Element|Document|string} elt + * @param {string} selector + * @param {boolean=} global + * @returns {(Node|Window)[]} + */ + function querySelectorAllExt(elt, selector, global) { + elt = resolveTarget(elt) + if (selector.indexOf('closest ') === 0) { + return [closest(asElement(elt), normalizeSelector(selector.substr(8)))] + } else if (selector.indexOf('find ') === 0) { + return [find(asParentNode(elt), normalizeSelector(selector.substr(5)))] + } else if (selector === 'next') { + return [asElement(elt).nextElementSibling] + } else if (selector.indexOf('next ') === 0) { + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)), !!global)] + } else if (selector === 'previous') { + return [asElement(elt).previousElementSibling] + } else if (selector.indexOf('previous ') === 0) { + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)), !!global)] + } else if (selector === 'document') { + return [document] + } else if (selector === 'window') { + return [window] + } else if (selector === 'body') { + return [document.body] + } else if (selector === 'root') { + return [getRootNode(elt, !!global)] + } else if (selector.indexOf('global ') === 0) { + return querySelectorAllExt(elt, selector.slice(7), true) + } else { + return toArray(asParentNode(getRootNode(elt, !!global)).querySelectorAll(normalizeSelector(selector))) + } + } + + /** + * @param {Node} start + * @param {string} match + * @param {boolean} global + * @returns {Element} + */ + var scanForwardQuery = function(start, match, global) { + const results = asParentNode(getRootNode(start, global)).querySelectorAll(match) + for (let i = 0; i < results.length; i++) { + const elt = results[i] + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { + return elt + } + } + } + + /** + * @param {Node} start + * @param {string} match + * @param {boolean} global + * @returns {Element} + */ + var scanBackwardsQuery = function(start, match, global) { + const results = asParentNode(getRootNode(start, global)).querySelectorAll(match) + for (let i = results.length - 1; i >= 0; i--) { + const elt = results[i] + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { + return elt + } + } + } + + /** + * @param {Node|string} eltOrSelector + * @param {string=} selector + * @returns {Node|Window} + */ + function querySelectorExt(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return querySelectorAllExt(eltOrSelector, selector)[0] + } else { + return querySelectorAllExt(getDocument().body, eltOrSelector)[0] + } + } + + /** + * @template {EventTarget} T + * @param {T|string} eltOrSelector + * @param {T} [context] + * @returns {Element|T|null} + */ + function resolveTarget(eltOrSelector, context) { + if (typeof eltOrSelector === 'string') { + return find(asParentNode(context) || document, eltOrSelector) + } else { + return eltOrSelector + } + } + + /** + * @typedef {keyof HTMLElementEventMap|string} AnyEventName + */ + + /** + * @typedef {Object} EventArgs + * @property {EventTarget} target + * @property {AnyEventName} event + * @property {EventListener} listener + */ + + /** + * @param {EventTarget|AnyEventName} arg1 + * @param {AnyEventName|EventListener} arg2 + * @param {EventListener} [arg3] + * @returns {EventArgs} + */ + function processEventArgs(arg1, arg2, arg3) { + if (isFunction(arg2)) { + return { + target: getDocument().body, + event: asString(arg1), + listener: arg2 + } + } else { + return { + target: resolveTarget(arg1), + event: asString(arg2), + listener: arg3 + } + } + } + + /** + * Adds an event listener to an element + * + * @see https://htmx.org/api/#on + * + * @param {EventTarget|string} arg1 the element to add the listener to | the event name to add the listener for + * @param {string|EventListener} arg2 the event name to add the listener for | the listener to add + * @param {EventListener} [arg3] the listener to add + * @returns {EventListener} + */ + function addEventListenerImpl(arg1, arg2, arg3) { + ready(function() { + const eventArgs = processEventArgs(arg1, arg2, arg3) + eventArgs.target.addEventListener(eventArgs.event, eventArgs.listener) + }) + const b = isFunction(arg2) + return b ? arg2 : arg3 + } + + /** + * Removes an event listener from an element + * + * @see https://htmx.org/api/#off + * + * @param {EventTarget|string} arg1 the element to remove the listener from | the event name to remove the listener from + * @param {string|EventListener} arg2 the event name to remove the listener from | the listener to remove + * @param {EventListener} [arg3] the listener to remove + * @returns {EventListener} + */ + function removeEventListenerImpl(arg1, arg2, arg3) { + ready(function() { + const eventArgs = processEventArgs(arg1, arg2, arg3) + eventArgs.target.removeEventListener(eventArgs.event, eventArgs.listener) + }) + return isFunction(arg2) ? arg2 : arg3 + } + + //= =================================================================== + // Node processing + //= =================================================================== + + const DUMMY_ELT = getDocument().createElement('output') // dummy element for bad selectors + /** + * @param {Element} elt + * @param {string} attrName + * @returns {(Node|Window)[]} + */ + function findAttributeTargets(elt, attrName) { + const attrTarget = getClosestAttributeValue(elt, attrName) + if (attrTarget) { + if (attrTarget === 'this') { + return [findThisElement(elt, attrName)] + } else { + const result = querySelectorAllExt(elt, attrTarget) + if (result.length === 0) { + logError('The selector "' + attrTarget + '" on ' + attrName + ' returned no matches!') + return [DUMMY_ELT] + } else { + return result + } + } + } + } + + /** + * @param {Element} elt + * @param {string} attribute + * @returns {Element|null} + */ + function findThisElement(elt, attribute) { + return asElement(getClosestMatch(elt, function(elt) { + return getAttributeValue(asElement(elt), attribute) != null + })) + } + + /** + * @param {Element} elt + * @returns {Node|Window|null} + */ + function getTarget(elt) { + const targetStr = getClosestAttributeValue(elt, 'hx-target') + if (targetStr) { + if (targetStr === 'this') { + return findThisElement(elt, 'hx-target') + } else { + return querySelectorExt(elt, targetStr) + } + } else { + const data = getInternalData(elt) + if (data.boosted) { + return getDocument().body + } else { + return elt + } + } + } + + /** + * @param {string} name + * @returns {boolean} + */ + function shouldSettleAttribute(name) { + const attributesToSettle = htmx.config.attributesToSettle + for (let i = 0; i < attributesToSettle.length; i++) { + if (name === attributesToSettle[i]) { + return true + } + } + return false + } + + /** + * @param {Element} mergeTo + * @param {Element} mergeFrom + */ + function cloneAttributes(mergeTo, mergeFrom) { + forEach(mergeTo.attributes, function(attr) { + if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) { + mergeTo.removeAttribute(attr.name) + } + }) + forEach(mergeFrom.attributes, function(attr) { + if (shouldSettleAttribute(attr.name)) { + mergeTo.setAttribute(attr.name, attr.value) + } + }) + } + + /** + * @param {HtmxSwapStyle} swapStyle + * @param {Element} target + * @returns {boolean} + */ + function isInlineSwap(swapStyle, target) { + const extensions = getExtensions(target) + for (let i = 0; i < extensions.length; i++) { + const extension = extensions[i] + try { + if (extension.isInlineSwap(swapStyle)) { + return true + } + } catch (e) { + logError(e) + } + } + return swapStyle === 'outerHTML' + } + + /** + * @param {string} oobValue + * @param {Element} oobElement + * @param {HtmxSettleInfo} settleInfo + * @returns + */ + function oobSwap(oobValue, oobElement, settleInfo) { + let selector = '#' + getRawAttribute(oobElement, 'id') + /** @type HtmxSwapStyle */ + let swapStyle = 'outerHTML' + if (oobValue === 'true') { + // do nothing + } else if (oobValue.indexOf(':') > 0) { + swapStyle = oobValue.substr(0, oobValue.indexOf(':')) + selector = oobValue.substr(oobValue.indexOf(':') + 1, oobValue.length) + } else { + swapStyle = oobValue + } - /** - * @param {any} o - * @param {string} type - * @returns - */ - function isType(o, type) { - return Object.prototype.toString.call(o) === "[object " + type + "]"; - } - - /** - * @param {*} o - * @returns {o is Function} - */ - function isFunction(o) { - return isType(o, "Function"); - } - - /** - * @param {*} o - * @returns {o is Object} - */ - function isRawObject(o) { - return isType(o, "Object"); - } - - /** - * getInternalData retrieves "private" data stored by htmx within an element - * @param {HTMLElement} elt - * @returns {*} - */ - function getInternalData(elt) { - var dataProp = 'htmx-internal-data'; - var data = elt[dataProp]; - if (!data) { - data = elt[dataProp] = {}; - } - return data; - } - - /** - * toArray converts an ArrayLike object into a real array. - * @param {ArrayLike} arr - * @returns {any[]} - */ - function toArray(arr) { - var returnArr = []; - if (arr) { - for (var i = 0; i < arr.length; i++) { - returnArr.push(arr[i]); - } - } - return returnArr + const targets = getDocument().querySelectorAll(selector) + if (targets) { + forEach( + targets, + function(target) { + let fragment + const oobElementClone = oobElement.cloneNode(true) + fragment = getDocument().createDocumentFragment() + fragment.appendChild(oobElementClone) + if (!isInlineSwap(swapStyle, target)) { + fragment = asParentNode(oobElementClone) // if this is not an inline swap, we use the content of the node, not the node itself + } + + const beforeSwapDetails = { shouldSwap: true, target, fragment } + if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return + + target = beforeSwapDetails.target // allow re-targeting + if (beforeSwapDetails.shouldSwap) { + swapWithStyle(swapStyle, target, target, fragment, settleInfo) + } + forEach(settleInfo.elts, function(elt) { + triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails) + }) + } + ) + oobElement.parentNode.removeChild(oobElement) + } else { + oobElement.parentNode.removeChild(oobElement) + triggerErrorEvent(getDocument().body, 'htmx:oobErrorNoTarget', { content: oobElement }) + } + return oobValue + } + + /** + * @param {DocumentFragment} fragment + */ + function handlePreservedElements(fragment) { + forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function(preservedElt) { + const id = getAttributeValue(preservedElt, 'id') + const oldElt = getDocument().getElementById(id) + if (oldElt != null) { + preservedElt.parentNode.replaceChild(oldElt, preservedElt) + } + }) + } + + /** + * @param {Node} parentNode + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function handleAttributes(parentNode, fragment, settleInfo) { + forEach(fragment.querySelectorAll('[id]'), function(newNode) { + const id = getRawAttribute(newNode, 'id') + if (id && id.length > 0) { + const normalizedId = id.replace("'", "\\'") + const normalizedTag = newNode.tagName.replace(':', '\\:') + const parentElt = asParentNode(parentNode) + const oldNode = parentElt && parentElt.querySelector(normalizedTag + "[id='" + normalizedId + "']") + if (oldNode && oldNode !== parentElt) { + const newAttributes = newNode.cloneNode() + cloneAttributes(newNode, oldNode) + settleInfo.tasks.push(function() { + cloneAttributes(newNode, newAttributes) + }) + } + } + }) + } + + /** + * @param {Node} child + * @returns {HtmxSettleTask} + */ + function makeAjaxLoadTask(child) { + return function() { + removeClassFromElement(child, htmx.config.addedClass) + processNode(asElement(child)) + processFocus(asParentNode(child)) + triggerEvent(child, 'htmx:load') + } + } + + /** + * @param {ParentNode} child + */ + function processFocus(child) { + const autofocus = '[autofocus]' + const autoFocusedElt = asHtmlElement(matches(child, autofocus) ? child : child.querySelector(autofocus)) + if (autoFocusedElt != null) { + autoFocusedElt.focus() + } + } + + /** + * @param {Node} parentNode + * @param {Node} insertBefore + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) { + handleAttributes(parentNode, fragment, settleInfo) + while (fragment.childNodes.length > 0) { + const child = fragment.firstChild + addClassToElement(asElement(child), htmx.config.addedClass) + parentNode.insertBefore(child, insertBefore) + if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { + settleInfo.tasks.push(makeAjaxLoadTask(child)) + } + } + } + + /** + * based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, + * derived from Java's string hashcode implementation + * @param {string} string + * @param {number} hash + * @returns {number} + */ + function stringHash(string, hash) { + let char = 0 + while (char < string.length) { + hash = (hash << 5) - hash + string.charCodeAt(char++) | 0 // bitwise or ensures we have a 32-bit int + } + return hash + } + + /** + * @param {Element} elt + * @returns {number} + */ + function attributeHash(elt) { + let hash = 0 + // IE fix + if (elt.attributes) { + for (let i = 0; i < elt.attributes.length; i++) { + const attribute = elt.attributes[i] + if (attribute.value) { // only include attributes w/ actual values (empty is same as non-existent) + hash = stringHash(attribute.name, hash) + hash = stringHash(attribute.value, hash) + } + } + } + return hash + } + + /** + * @param {EventTarget} elt + */ + function deInitOnHandlers(elt) { + const internalData = getInternalData(elt) + if (internalData.onHandlers) { + for (let i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i] + removeEventListenerImpl(elt, handlerInfo.event, handlerInfo.listener) + } + delete internalData.onHandlers + } + } + + /** + * @param {Node} element + */ + function deInitNode(element) { + const internalData = getInternalData(element) + if (internalData.timeout) { + clearTimeout(internalData.timeout) + } + if (internalData.listenerInfos) { + forEach(internalData.listenerInfos, function(info) { + if (info.on) { + removeEventListenerImpl(info.on, info.trigger, info.listener) } - - function forEach(arr, func) { - if (arr) { - for (var i = 0; i < arr.length; i++) { - func(arr[i]); - } - } + }) + } + deInitOnHandlers(element) + forEach(Object.keys(internalData), function(key) { delete internalData[key] }) + } + + /** + * @param {Node} element + */ + function cleanUpElement(element) { + triggerEvent(element, 'htmx:beforeCleanupElement') + deInitNode(element) + // @ts-ignore IE11 code + // noinspection JSUnresolvedReference + if (element.children) { // IE + // @ts-ignore + forEach(element.children, function(child) { cleanUpElement(child) }) + } + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapOuterHTML(target, fragment, settleInfo) { + /** @type {Node} */ + let newElt + const eltBeforeNewContent = target.previousSibling + insertNodesBefore(parentElt(target), target, fragment, settleInfo) + if (eltBeforeNewContent == null) { + newElt = parentElt(target).firstChild + } else { + newElt = eltBeforeNewContent.nextSibling + } + settleInfo.elts = settleInfo.elts.filter(function(e) { return e !== target }) + while (newElt && newElt !== target) { + if (newElt instanceof Element) { + settleInfo.elts.push(newElt) + newElt = newElt.nextElementSibling + } else { + newElt = null + } + } + cleanUpElement(target) + if (target instanceof Element) { + target.remove() + } else { + target.parentNode.removeChild(target) + } + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapAfterBegin(target, fragment, settleInfo) { + return insertNodesBefore(target, target.firstChild, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapBeforeBegin(target, fragment, settleInfo) { + return insertNodesBefore(parentElt(target), target, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapBeforeEnd(target, fragment, settleInfo) { + return insertNodesBefore(target, null, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapAfterEnd(target, fragment, settleInfo) { + return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo) + } + + /** + * @param {Node} target + */ + function swapDelete(target) { + cleanUpElement(target) + return parentElt(target).removeChild(target) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapInnerHTML(target, fragment, settleInfo) { + const firstChild = target.firstChild + insertNodesBefore(target, firstChild, fragment, settleInfo) + if (firstChild) { + while (firstChild.nextSibling) { + cleanUpElement(firstChild.nextSibling) + target.removeChild(firstChild.nextSibling) + } + cleanUpElement(firstChild) + target.removeChild(firstChild) + } + } + + /** + * @param {HtmxSwapStyle} swapStyle + * @param {Element} elt + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapWithStyle(swapStyle, elt, target, fragment, settleInfo) { + switch (swapStyle) { + case 'none': + return + case 'outerHTML': + swapOuterHTML(target, fragment, settleInfo) + return + case 'afterbegin': + swapAfterBegin(target, fragment, settleInfo) + return + case 'beforebegin': + swapBeforeBegin(target, fragment, settleInfo) + return + case 'beforeend': + swapBeforeEnd(target, fragment, settleInfo) + return + case 'afterend': + swapAfterEnd(target, fragment, settleInfo) + return + case 'delete': + swapDelete(target) + return + default: + var extensions = getExtensions(elt) + for (let i = 0; i < extensions.length; i++) { + const ext = extensions[i] + try { + const newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo) + if (newElements) { + if (typeof newElements.length !== 'undefined') { + // if handleSwap returns an array (like) of elements, we handle them + for (let j = 0; j < newElements.length; j++) { + const child = newElements[j] + if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { + settleInfo.tasks.push(makeAjaxLoadTask(child)) + } + } + } + return + } + } catch (e) { + logError(e) + } + } + if (swapStyle === 'innerHTML') { + swapInnerHTML(target, fragment, settleInfo) + } else { + swapWithStyle(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo) } + } + } + + /** + * @param {DocumentFragment} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function findAndSwapOobElements(fragment, settleInfo) { + forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function(oobElement) { + if (htmx.config.allowNestedOobSwaps || oobElement.parentElement === null) { + const oobValue = getAttributeValue(oobElement, 'hx-swap-oob') + if (oobValue != null) { + oobSwap(oobValue, oobElement, settleInfo) + } + } else { + oobElement.removeAttribute('hx-swap-oob') + oobElement.removeAttribute('data-hx-swap-oob') + } + }) + } + + /** + * Implements complete swapping pipeline, including: focus and selection preservation, + * title updates, scroll, OOB swapping, normal swapping and settling + * @param {string|Element} target + * @param {string} content + * @param {HtmxSwapSpecification} swapSpec + * @param {SwapOptions} [swapOptions] + */ + function swap(target, content, swapSpec, swapOptions) { + if (!swapOptions) { + swapOptions = {} + } - function isScrolledIntoView(el) { - var rect = el.getBoundingClientRect(); - var elemTop = rect.top; - var elemBottom = rect.bottom; - return elemTop < window.innerHeight && elemBottom >= 0; - } + target = resolveTarget(target) + + // preserve focus and selection + const activeElt = document.activeElement + let selectionInfo = {} + try { + selectionInfo = { + elt: activeElt, + // @ts-ignore + start: activeElt ? activeElt.selectionStart : null, + // @ts-ignore + end: activeElt ? activeElt.selectionEnd : null + } + } catch (e) { + // safari issue - see https://github.com/microsoft/playwright/issues/5894 + } + const settleInfo = makeSettleInfo(target) - function bodyContains(elt) { - // IE Fix - if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) { - return getDocument().body.contains(elt.getRootNode().host); - } else { - return getDocument().body.contains(elt); - } - } + // For text content swaps, don't parse the response as HTML, just insert it + if (swapSpec.swapStyle === 'textContent') { + target.textContent = content + // Otherwise, make the fragment and process it + } else { + let fragment = makeFragment(content) + + settleInfo.title = fragment.title + + // select-oob swaps + if (swapOptions.selectOOB) { + const oobSelectValues = swapOptions.selectOOB.split(',') + for (let i = 0; i < oobSelectValues.length; i++) { + const oobSelectValue = oobSelectValues[i].split(':', 2) + let id = oobSelectValue[0].trim() + if (id.indexOf('#') === 0) { + id = id.substring(1) + } + const oobValue = oobSelectValue[1] || 'true' + const oobElement = fragment.querySelector('#' + id) + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo) + } + } + } + // oob swaps + findAndSwapOobElements(fragment, settleInfo) + forEach(findAll(fragment, 'template'), /** @param {HTMLTemplateElement} template */function(template) { + findAndSwapOobElements(template.content, settleInfo) + if (template.content.childElementCount === 0) { + // Avoid polluting the DOM with empty templates that were only used to encapsulate oob swap + template.remove() + } + }) + + // normal swap + if (swapOptions.select) { + const newFragment = getDocument().createDocumentFragment() + forEach(fragment.querySelectorAll(swapOptions.select), function(node) { + newFragment.appendChild(node) + }) + fragment = newFragment + } + handlePreservedElements(fragment) + swapWithStyle(swapSpec.swapStyle, swapOptions.contextElement, target, fragment, settleInfo) + } - function splitOnWhitespace(trigger) { - return trigger.trim().split(/\s+/); - } + // apply saved focus and selection information to swapped content + if (selectionInfo.elt && + !bodyContains(selectionInfo.elt) && + getRawAttribute(selectionInfo.elt, 'id')) { + const newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, 'id')) + const focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll } + if (newActiveElt) { + // @ts-ignore + if (selectionInfo.start && newActiveElt.setSelectionRange) { + try { + // @ts-ignore + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end) + } catch (e) { + // the setSelectionRange method is present on fields that don't support it, so just let this fail + } + } + newActiveElt.focus(focusOptions) + } + } - /** - * mergeObjects takes all of the keys from - * obj2 and duplicates them into obj1 - * @param {Object} obj1 - * @param {Object} obj2 - * @returns {Object} - */ - function mergeObjects(obj1, obj2) { - for (var key in obj2) { - if (obj2.hasOwnProperty(key)) { - obj1[key] = obj2[key]; - } - } - return obj1; - } + target.classList.remove(htmx.config.swappingClass) + forEach(settleInfo.elts, function(elt) { + if (elt.classList) { + elt.classList.add(htmx.config.settlingClass) + } + triggerEvent(elt, 'htmx:afterSwap', swapOptions.eventInfo) + }) + if (swapOptions.afterSwapCallback) { + swapOptions.afterSwapCallback() + } - function parseJSON(jString) { - try { - return JSON.parse(jString); - } catch(error) { - logError(error); - return null; - } - } + // merge in new title after swap but before settle + if (!swapSpec.ignoreTitle) { + handleTitle(settleInfo.title) + } - function canAccessLocalStorage() { - var test = 'htmx:localStorageTest'; - try { - localStorage.setItem(test, test); - localStorage.removeItem(test); - return true; - } catch(e) { - return false; - } - } + // settle + const doSettle = function() { + forEach(settleInfo.tasks, function(task) { + task.call() + }) + forEach(settleInfo.elts, function(elt) { + if (elt.classList) { + elt.classList.remove(htmx.config.settlingClass) + } + triggerEvent(elt, 'htmx:afterSettle', swapOptions.eventInfo) + }) + + if (swapOptions.anchor) { + const anchorTarget = asElement(resolveTarget('#' + swapOptions.anchor)) + if (anchorTarget) { + anchorTarget.scrollIntoView({ block: 'start', behavior: 'auto' }) + } + } + + updateScrollState(settleInfo.elts, swapSpec) + if (swapOptions.afterSettleCallback) { + swapOptions.afterSettleCallback() + } + } - function normalizePath(path) { + if (swapSpec.settleDelay > 0) { + getWindow().setTimeout(doSettle, swapSpec.settleDelay) + } else { + doSettle() + } + } + + /** + * @param {XMLHttpRequest} xhr + * @param {string} header + * @param {EventTarget} elt + */ + function handleTriggerHeader(xhr, header, elt) { + const triggerBody = xhr.getResponseHeader(header) + if (triggerBody.indexOf('{') === 0) { + const triggers = parseJSON(triggerBody) + for (const eventName in triggers) { + if (triggers.hasOwnProperty(eventName)) { + let detail = triggers[eventName] + if (!isRawObject(detail)) { + detail = { value: detail } + } + triggerEvent(elt, eventName, detail) + } + } + } else { + const eventNames = triggerBody.split(',') + for (let i = 0; i < eventNames.length; i++) { + triggerEvent(elt, eventNames[i].trim(), []) + } + } + } + + const WHITESPACE = /\s/ + const WHITESPACE_OR_COMMA = /[\s,]/ + const SYMBOL_START = /[_$a-zA-Z]/ + const SYMBOL_CONT = /[_$a-zA-Z0-9]/ + const STRINGISH_START = ['"', "'", '/'] + const NOT_WHITESPACE = /[^\s]/ + const COMBINED_SELECTOR_START = /[{(]/ + const COMBINED_SELECTOR_END = /[})]/ + + /** + * @param {string} str + * @returns {string[]} + */ + function tokenizeString(str) { + /** @type string[] */ + const tokens = [] + let position = 0 + while (position < str.length) { + if (SYMBOL_START.exec(str.charAt(position))) { + var startPosition = position + while (SYMBOL_CONT.exec(str.charAt(position + 1))) { + position++ + } + tokens.push(str.substr(startPosition, position - startPosition + 1)) + } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) { + const startChar = str.charAt(position) + var startPosition = position + position++ + while (position < str.length && str.charAt(position) !== startChar) { + if (str.charAt(position) === '\\') { + position++ + } + position++ + } + tokens.push(str.substr(startPosition, position - startPosition + 1)) + } else { + const symbol = str.charAt(position) + tokens.push(symbol) + } + position++ + } + return tokens + } + + /** + * @param {string} token + * @param {string|null} last + * @param {string} paramName + * @returns {boolean} + */ + function isPossibleRelativeReference(token, last, paramName) { + return SYMBOL_START.exec(token.charAt(0)) && + token !== 'true' && + token !== 'false' && + token !== 'this' && + token !== paramName && + last !== '.' + } + + /** + * @param {EventTarget|string} elt + * @param {string[]} tokens + * @param {string} paramName + * @returns {ConditionalFunction|null} + */ + function maybeGenerateConditional(elt, tokens, paramName) { + if (tokens[0] === '[') { + tokens.shift() + let bracketCount = 1 + let conditionalSource = ' return (function(' + paramName + '){ return (' + let last = null + while (tokens.length > 0) { + const token = tokens[0] + // @ts-ignore For some reason tsc doesn't understand the shift call, and thinks we're comparing the same value here, i.e. '[' vs ']' + if (token === ']') { + bracketCount-- + if (bracketCount === 0) { + if (last === null) { + conditionalSource = conditionalSource + 'true' + } + tokens.shift() + conditionalSource += ')})' try { - var url = new URL(path); - if (url) { - path = url.pathname + url.search; - } - // remove trailing slash, unless index page - if (!(/^\/$/.test(path))) { - path = path.replace(/\/+$/, ''); - } - return path; + const conditionFunction = maybeEval(elt, function() { + return Function(conditionalSource)() + }, + function() { return true }) + conditionFunction.source = conditionalSource + return conditionFunction } catch (e) { - // be kind to IE11, which doesn't support URL() - return path; - } - } - - //========================================================================================== - // public API - //========================================================================================== - - function internalEval(str){ - return maybeEval(getDocument().body, function () { - return eval(str); - }); - } - - function onLoadHelper(callback) { - var value = htmx.on("htmx:load", function(evt) { - callback(evt.detail.elt); - }); - return value; - } - - function logAll(){ - htmx.logger = function(elt, event, data) { - if(console) { - console.log(event, elt, data); - } - } - } - - function logNone() { - htmx.logger = null - } - - function find(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelector(selector); - } else { - return find(getDocument(), eltOrSelector); - } - } - - function findAll(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelectorAll(selector); - } else { - return findAll(getDocument(), eltOrSelector); - } - } - - function removeElement(elt, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - removeElement(elt); - elt = null; - }, delay); - } else { - elt.parentElement.removeChild(elt); - } - } - - function addClassToElement(elt, clazz, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - addClassToElement(elt, clazz); - elt = null; - }, delay); - } else { - elt.classList && elt.classList.add(clazz); - } - } - - function removeClassFromElement(elt, clazz, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - removeClassFromElement(elt, clazz); - elt = null; - }, delay); - } else { - if (elt.classList) { - elt.classList.remove(clazz); - // if there are no classes left, remove the class attribute - if (elt.classList.length === 0) { - elt.removeAttribute("class"); - } - } - } - } - - function toggleClassOnElement(elt, clazz) { - elt = resolveTarget(elt); - elt.classList.toggle(clazz); - } - - function takeClassForElement(elt, clazz) { - elt = resolveTarget(elt); - forEach(elt.parentElement.children, function(child){ - removeClassFromElement(child, clazz); - }) - addClassToElement(elt, clazz); - } - - function closest(elt, selector) { - elt = resolveTarget(elt); - if (elt.closest) { - return elt.closest(selector); - } else { - // TODO remove when IE goes away - do{ - if (elt == null || matches(elt, selector)){ - return elt; - } - } - while (elt = elt && parentElt(elt)); - return null; - } - } - - function startsWith(str, prefix) { - return str.substring(0, prefix.length) === prefix - } - - function endsWith(str, suffix) { - return str.substring(str.length - suffix.length) === suffix - } - - function normalizeSelector(selector) { - var trimmedSelector = selector.trim(); - if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) { - return trimmedSelector.substring(1, trimmedSelector.length - 2); - } else { - return trimmedSelector; - } - } - - function querySelectorAllExt(elt, selector) { - if (selector.indexOf("closest ") === 0) { - return [closest(elt, normalizeSelector(selector.substr(8)))]; - } else if (selector.indexOf("find ") === 0) { - return [find(elt, normalizeSelector(selector.substr(5)))]; - } else if (selector === "next") { - return [elt.nextElementSibling] - } else if (selector.indexOf("next ") === 0) { - return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; - } else if (selector === "previous") { - return [elt.previousElementSibling] - } else if (selector.indexOf("previous ") === 0) { - return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; - } else if (selector === 'document') { - return [document]; - } else if (selector === 'window') { - return [window]; - } else if (selector === 'body') { - return [document.body]; - } else { - return getDocument().querySelectorAll(normalizeSelector(selector)); - } - } - - var scanForwardQuery = function(start, match) { - var results = getDocument().querySelectorAll(match); - for (var i = 0; i < results.length; i++) { - var elt = results[i]; - if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { - return elt; - } - } - } - - var scanBackwardsQuery = function(start, match) { - var results = getDocument().querySelectorAll(match); - for (var i = results.length - 1; i >= 0; i--) { - var elt = results[i]; - if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { - return elt; - } - } - } - - function querySelectorExt(eltOrSelector, selector) { - if (selector) { - return querySelectorAllExt(eltOrSelector, selector)[0]; - } else { - return querySelectorAllExt(getDocument().body, eltOrSelector)[0]; - } - } - - function resolveTarget(arg2) { - if (isType(arg2, 'String')) { - return find(arg2); - } else { - return arg2; - } - } - - function processEventArgs(arg1, arg2, arg3) { - if (isFunction(arg2)) { - return { - target: getDocument().body, - event: arg1, - listener: arg2 - } - } else { - return { - target: resolveTarget(arg1), - event: arg2, - listener: arg3 - } - } - - } - - function addEventListenerImpl(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 removeEventListenerImpl(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 - //==================================================================== - - var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors - function findAttributeTargets(elt, attrName) { - var attrTarget = getClosestAttributeValue(elt, attrName); - if (attrTarget) { - if (attrTarget === "this") { - return [findThisElement(elt, attrName)]; - } else { - var result = querySelectorAllExt(elt, attrTarget); - if (result.length === 0) { - logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!"); - return [DUMMY_ELT] - } else { - return result; - } - } - } - } - - function findThisElement(elt, attribute){ - return getClosestMatch(elt, function (elt) { - return getAttributeValue(elt, attribute) != null; - }) - } - - function getTarget(elt) { - var targetStr = getClosestAttributeValue(elt, "hx-target"); - if (targetStr) { - if (targetStr === "this") { - return findThisElement(elt,'hx-target'); - } else { - return querySelectorExt(elt, targetStr) - } - } else { - var data = getInternalData(elt); - if (data.boosted) { - return getDocument().body; - } else { - return elt; - } - } - } - - function shouldSettleAttribute(name) { - var attributesToSettle = htmx.config.attributesToSettle; - for (var i = 0; i < attributesToSettle.length; i++) { - if (name === attributesToSettle[i]) { - return true; - } - } - return false; - } - - function cloneAttributes(mergeTo, mergeFrom) { - forEach(mergeTo.attributes, function (attr) { - if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) { - mergeTo.removeAttribute(attr.name) - } - }); - forEach(mergeFrom.attributes, function (attr) { - if (shouldSettleAttribute(attr.name)) { - mergeTo.setAttribute(attr.name, attr.value); - } - }); - } - - function isInlineSwap(swapStyle, target) { - var extensions = getExtensions(target); - for (var i = 0; i < extensions.length; i++) { - var extension = extensions[i]; - try { - if (extension.isInlineSwap(swapStyle)) { - return true; - } - } catch(e) { - logError(e); - } - } - return swapStyle === "outerHTML"; - } - - /** - * - * @param {string} oobValue - * @param {HTMLElement} oobElement - * @param {*} settleInfo - * @returns - */ - function oobSwap(oobValue, oobElement, settleInfo) { - var selector = "#" + getRawAttribute(oobElement, "id"); - var swapStyle = "outerHTML"; - if (oobValue === "true") { - // do nothing - } else if (oobValue.indexOf(":") > 0) { - swapStyle = oobValue.substr(0, oobValue.indexOf(":")); - selector = oobValue.substr(oobValue.indexOf(":") + 1, oobValue.length); - } else { - swapStyle = oobValue; - } - - var targets = getDocument().querySelectorAll(selector); - if (targets) { - forEach( - targets, - function (target) { - var fragment; - var oobElementClone = oobElement.cloneNode(true); - fragment = getDocument().createDocumentFragment(); - fragment.appendChild(oobElementClone); - if (!isInlineSwap(swapStyle, target)) { - fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself - } - - var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment }; - if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return; - - target = beforeSwapDetails.target; // allow re-targeting - if (beforeSwapDetails['shouldSwap']){ - swap(swapStyle, target, target, fragment, settleInfo); - } - forEach(settleInfo.elts, function (elt) { - triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails); - }); - } - ); - oobElement.parentNode.removeChild(oobElement); - } else { - oobElement.parentNode.removeChild(oobElement); - triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}); - } - return oobValue; - } - - function handleOutOfBandSwaps(elt, fragment, settleInfo) { - var oobSelects = getClosestAttributeValue(elt, "hx-select-oob"); - if (oobSelects) { - var oobSelectValues = oobSelects.split(","); - for (var i = 0; i < oobSelectValues.length; i++) { - var oobSelectValue = oobSelectValues[i].split(":", 2); - var id = oobSelectValue[0].trim(); - if (id.indexOf("#") === 0) { - id = id.substring(1); - } - var oobValue = oobSelectValue[1] || "true"; - var oobElement = fragment.querySelector("#" + id); - if (oobElement) { - oobSwap(oobValue, oobElement, settleInfo); - } - } - } - forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) { - var oobValue = getAttributeValue(oobElement, "hx-swap-oob"); - if (oobValue != null) { - oobSwap(oobValue, oobElement, settleInfo); - } - }); - } - - function handlePreservedElements(fragment) { - forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function (preservedElt) { - var id = getAttributeValue(preservedElt, "id"); - var oldElt = getDocument().getElementById(id); - if (oldElt != null) { - preservedElt.parentNode.replaceChild(oldElt, preservedElt); - } - }); - } - - function handleAttributes(parentNode, fragment, settleInfo) { - forEach(fragment.querySelectorAll("[id]"), function (newNode) { - var id = getRawAttribute(newNode, "id") - if (id && id.length > 0) { - var normalizedId = id.replace("'", "\\'"); - var normalizedTag = newNode.tagName.replace(':', '\\:'); - var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']"); - if (oldNode && oldNode !== parentNode) { - var newAttributes = newNode.cloneNode(); - cloneAttributes(newNode, oldNode); - settleInfo.tasks.push(function () { - cloneAttributes(newNode, newAttributes); - }); - } - } - }); - } - - function makeAjaxLoadTask(child) { - return function () { - removeClassFromElement(child, htmx.config.addedClass); - processNode(child); - processScripts(child); - processFocus(child) - triggerEvent(child, 'htmx:load'); - }; - } - - function processFocus(child) { - var autofocus = "[autofocus]"; - var autoFocusedElt = matches(child, autofocus) ? child : child.querySelector(autofocus) - if (autoFocusedElt != null) { - autoFocusedElt.focus(); - } - } - - function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) { - handleAttributes(parentNode, fragment, settleInfo); - while(fragment.childNodes.length > 0){ - var child = fragment.firstChild; - addClassToElement(child, htmx.config.addedClass); - parentNode.insertBefore(child, insertBefore); - if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { - settleInfo.tasks.push(makeAjaxLoadTask(child)); - } - } - } - - // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, - // derived from Java's string hashcode implementation - function stringHash(string, hash) { - var char = 0; - while (char < string.length){ - hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int - } - return hash; - } - - function attributeHash(elt) { - var hash = 0; - // IE fix - if (elt.attributes) { - for (var i = 0; i < elt.attributes.length; i++) { - var attribute = elt.attributes[i]; - if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent) - hash = stringHash(attribute.name, hash); - hash = stringHash(attribute.value, hash); - } - } - } - return hash; - } - - function deInitOnHandlers(elt) { - var internalData = getInternalData(elt); - if (internalData.onHandlers) { - for (var i = 0; i < internalData.onHandlers.length; i++) { - const handlerInfo = internalData.onHandlers[i]; - elt.removeEventListener(handlerInfo.event, handlerInfo.listener); - } - delete internalData.onHandlers - } - } - - function deInitNode(element) { - var internalData = getInternalData(element); - if (internalData.timeout) { - clearTimeout(internalData.timeout); - } - if (internalData.webSocket) { - internalData.webSocket.close(); - } - if (internalData.sseEventSource) { - internalData.sseEventSource.close(); - } - if (internalData.listenerInfos) { - forEach(internalData.listenerInfos, function (info) { - if (info.on) { - info.on.removeEventListener(info.trigger, info.listener); - } - }); - } - deInitOnHandlers(element); - forEach(Object.keys(internalData), function(key) { delete internalData[key] }); - } - - function cleanUpElement(element) { - triggerEvent(element, "htmx:beforeCleanupElement") - deInitNode(element); - if (element.children) { // IE - forEach(element.children, function(child) { cleanUpElement(child) }); - } - } - - function swapOuterHTML(target, fragment, settleInfo) { - if (target.tagName === "BODY") { - return swapInnerHTML(target, fragment, settleInfo); - } else { - // @type {HTMLElement} - var newElt - var eltBeforeNewContent = target.previousSibling; - insertNodesBefore(parentElt(target), target, fragment, settleInfo); - if (eltBeforeNewContent == null) { - newElt = parentElt(target).firstChild; - } else { - newElt = eltBeforeNewContent.nextSibling; - } - settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target }); - while(newElt && newElt !== target) { - if (newElt.nodeType === Node.ELEMENT_NODE) { - settleInfo.elts.push(newElt); - } - newElt = newElt.nextElementSibling; - } - cleanUpElement(target); - parentElt(target).removeChild(target); - } - } - - function swapAfterBegin(target, fragment, settleInfo) { - return insertNodesBefore(target, target.firstChild, fragment, settleInfo); - } - - function swapBeforeBegin(target, fragment, settleInfo) { - return insertNodesBefore(parentElt(target), target, fragment, settleInfo); - } - - function swapBeforeEnd(target, fragment, settleInfo) { - return insertNodesBefore(target, null, fragment, settleInfo); - } - - function swapAfterEnd(target, fragment, settleInfo) { - return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo); - } - function swapDelete(target, fragment, settleInfo) { - cleanUpElement(target); - return parentElt(target).removeChild(target); - } - - function swapInnerHTML(target, fragment, settleInfo) { - var firstChild = target.firstChild; - insertNodesBefore(target, firstChild, fragment, settleInfo); - if (firstChild) { - while (firstChild.nextSibling) { - cleanUpElement(firstChild.nextSibling) - target.removeChild(firstChild.nextSibling); - } - cleanUpElement(firstChild) - target.removeChild(firstChild); - } - } - - function maybeSelectFromResponse(elt, fragment, selectOverride) { - var selector = selectOverride || getClosestAttributeValue(elt, "hx-select"); - if (selector) { - var newFragment = getDocument().createDocumentFragment(); - forEach(fragment.querySelectorAll(selector), function (node) { - newFragment.appendChild(node); - }); - fragment = newFragment; - } - return fragment; - } - - function swap(swapStyle, elt, target, fragment, settleInfo) { - switch (swapStyle) { - case "none": - return; - case "outerHTML": - swapOuterHTML(target, fragment, settleInfo); - return; - case "afterbegin": - swapAfterBegin(target, fragment, settleInfo); - return; - case "beforebegin": - swapBeforeBegin(target, fragment, settleInfo); - return; - case "beforeend": - swapBeforeEnd(target, fragment, settleInfo); - return; - case "afterend": - swapAfterEnd(target, fragment, settleInfo); - return; - case "delete": - swapDelete(target, fragment, settleInfo); - return; - default: - var extensions = getExtensions(elt); - for (var i = 0; i < extensions.length; i++) { - var ext = extensions[i]; - try { - var newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo); - if (newElements) { - if (typeof newElements.length !== 'undefined') { - // if handleSwap returns an array (like) of elements, we handle them - for (var j = 0; j < newElements.length; j++) { - var child = newElements[j]; - if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { - settleInfo.tasks.push(makeAjaxLoadTask(child)); - } - } - } - return; - } - } catch (e) { - logError(e); - } - } - if (swapStyle === "innerHTML") { - swapInnerHTML(target, fragment, settleInfo); - } else { - swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo); - } - } - } - - function findTitle(content) { - if (content.indexOf('<title') > -1) { - var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, ''); - var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX); - if (result) { - return result[2]; - } - } - } - - function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) { - settleInfo.title = findTitle(responseText); - var fragment = makeFragment(responseText); - if (fragment) { - handleOutOfBandSwaps(elt, fragment, settleInfo); - fragment = maybeSelectFromResponse(elt, fragment, selectOverride); - handlePreservedElements(fragment); - return swap(swapStyle, elt, target, fragment, settleInfo); - } - } - - function handleTrigger(xhr, header, elt) { - var triggerBody = xhr.getResponseHeader(header); - if (triggerBody.indexOf("{") === 0) { - var triggers = parseJSON(triggerBody); - for (var eventName in triggers) { - if (triggers.hasOwnProperty(eventName)) { - var detail = triggers[eventName]; - if (!isRawObject(detail)) { - detail = {"value": detail} - } - triggerEvent(elt, eventName, detail); - } - } - } else { - var eventNames = triggerBody.split(",") - for (var i = 0; i < eventNames.length; i++) { - triggerEvent(elt, eventNames[i].trim(), []); - } - } - } - - var WHITESPACE = /\s/; - var WHITESPACE_OR_COMMA = /[\s,]/; - var SYMBOL_START = /[_$a-zA-Z]/; - var SYMBOL_CONT = /[_$a-zA-Z0-9]/; - var STRINGISH_START = ['"', "'", "/"]; - var NOT_WHITESPACE = /[^\s]/; - var COMBINED_SELECTOR_START = /[{(]/; - var COMBINED_SELECTOR_END = /[})]/; - function tokenizeString(str) { - var tokens = []; - var position = 0; - while (position < str.length) { - if(SYMBOL_START.exec(str.charAt(position))) { - var startPosition = position; - while (SYMBOL_CONT.exec(str.charAt(position + 1))) { - position++; - } - tokens.push(str.substr(startPosition, position - startPosition + 1)); - } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) { - var startChar = str.charAt(position); - var startPosition = position; - position++; - while (position < str.length && str.charAt(position) !== startChar ) { - if (str.charAt(position) === "\\") { - position++; - } - position++; - } - tokens.push(str.substr(startPosition, position - startPosition + 1)); - } else { - var symbol = str.charAt(position); - tokens.push(symbol); - } - position++; - } - return tokens; - } - - function isPossibleRelativeReference(token, last, paramName) { - return SYMBOL_START.exec(token.charAt(0)) && - token !== "true" && - token !== "false" && - token !== "this" && - token !== paramName && - last !== "."; - } - - function maybeGenerateConditional(elt, tokens, paramName) { - if (tokens[0] === '[') { - tokens.shift(); - var bracketCount = 1; - var conditionalSource = " return (function(" + paramName + "){ return ("; - var last = null; - while (tokens.length > 0) { - var token = tokens[0]; - if (token === "]") { - bracketCount--; - if (bracketCount === 0) { - if (last === null) { - conditionalSource = conditionalSource + "true"; - } - tokens.shift(); - conditionalSource += ")})"; - try { - var conditionFunction = maybeEval(elt,function () { - return Function(conditionalSource)(); - }, - function(){return true}) - conditionFunction.source = conditionalSource; - return conditionFunction; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:syntax:error", {error:e, source:conditionalSource}) - return null; - } - } - } else if (token === "[") { - bracketCount++; - } - if (isPossibleRelativeReference(token, last, paramName)) { - conditionalSource += "((" + paramName + "." + token + ") ? (" + paramName + "." + token + ") : (window." + token + "))"; - } else { - conditionalSource = conditionalSource + token; - } - last = tokens.shift(); - } - } - } - - function consumeUntil(tokens, match) { - var result = ""; - while (tokens.length > 0 && !match.test(tokens[0])) { - result += tokens.shift(); - } - return result; - } - - function consumeCSSSelector(tokens) { - var result; - if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { - tokens.shift(); - result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim(); - tokens.shift(); - } else { - result = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } - return result; - } - - var INPUT_SELECTOR = 'input, textarea, select'; - - /** - * @param {HTMLElement} elt - * @param {string} explicitTrigger - * @param {cache} cache for trigger specs - * @returns {import("./htmx").HtmxTriggerSpecification[]} - */ - function parseAndCacheTrigger(elt, explicitTrigger, cache) { - var triggerSpecs = []; - var tokens = tokenizeString(explicitTrigger); - do { - consumeUntil(tokens, NOT_WHITESPACE); - var initialLength = tokens.length; - var trigger = consumeUntil(tokens, /[,\[\s]/); - if (trigger !== "") { - if (trigger === "every") { - var every = {trigger: 'every'}; - consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); - consumeUntil(tokens, NOT_WHITESPACE); - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - every.eventFilter = eventFilter; - } - triggerSpecs.push(every); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); - } else { - var triggerSpec = {trigger: trigger}; - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - triggerSpec.eventFilter = eventFilter; - } - while (tokens.length > 0 && tokens[0] !== ",") { - consumeUntil(tokens, NOT_WHITESPACE) - var token = tokens.shift(); - if (token === "changed") { - triggerSpec.changed = true; - } else if (token === "once") { - triggerSpec.once = true; - } else if (token === "consume") { - triggerSpec.consume = true; - } else if (token === "delay" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "from" && tokens[0] === ":") { - tokens.shift(); - if (COMBINED_SELECTOR_START.test(tokens[0])) { - var from_arg = consumeCSSSelector(tokens); - } else { - var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); - if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") { - tokens.shift(); - var selector = consumeCSSSelector(tokens); - // `next` and `previous` allow a selector-less syntax - if (selector.length > 0) { - from_arg += " " + selector; - } - } - } - triggerSpec.from = from_arg; - } else if (token === "target" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.target = consumeCSSSelector(tokens); - } else if (token === "throttle" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "queue" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if (token === "root" && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeCSSSelector(tokens); - } else if (token === "threshold" && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - } - triggerSpecs.push(triggerSpec); - } - } - if (tokens.length === initialLength) { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - consumeUntil(tokens, NOT_WHITESPACE); - } while (tokens[0] === "," && tokens.shift()) - if (cache) { - cache[explicitTrigger] = triggerSpecs - } - return triggerSpecs - } - - /** - * @param {HTMLElement} elt - * @returns {import("./htmx").HtmxTriggerSpecification[]} - */ - function getTriggerSpecs(elt) { - var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); - var triggerSpecs = []; - if (explicitTrigger) { - var cache = htmx.config.triggerSpecsCache - triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) - } - - if (triggerSpecs.length > 0) { - return triggerSpecs; - } else if (matches(elt, 'form')) { - return [{trigger: 'submit'}]; - } else if (matches(elt, 'input[type="button"], input[type="submit"]')){ - return [{trigger: 'click'}]; - } else if (matches(elt, INPUT_SELECTOR)) { - return [{trigger: 'change'}]; - } else { - return [{trigger: 'click'}]; - } - } - - function cancelPolling(elt) { - getInternalData(elt).cancelled = true; - } - - function processPolling(elt, handler, spec) { - var nodeData = getInternalData(elt); - nodeData.timeout = setTimeout(function () { - if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { - triggerSpec: spec, - target: elt - }))) { - handler(elt); - } - processPolling(elt, handler, spec); - } - }, spec.pollInterval); - } - - function isLocalLink(elt) { - return location.hostname === elt.hostname && - getRawAttribute(elt,'href') && - getRawAttribute(elt,'href').indexOf("#") !== 0; - } - - function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || 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"; - if (verb === "get") { - } - path = getRawAttribute(elt, 'action'); - } - triggerSpecs.forEach(function(triggerSpec) { - addEventListener(elt, function(elt, evt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return - } - issueAjaxRequest(verb, path, elt, evt) - }, nodeData, triggerSpec, true); - }); - } - } - - /** - * - * @param {Event} evt - * @param {HTMLElement} elt - * @returns - */ - function shouldCancel(evt, elt) { - if (evt.type === "submit" || evt.type === "click") { - if (elt.tagName === "FORM") { - return true; - } - if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { - return true; - } - if (elt.tagName === "A" && elt.href && - (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) { - return true; - } - } - return false; - } - - function ignoreBoostedAnchorCtrlClick(elt, evt) { - return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); - } - - function maybeFilterEvent(triggerSpec, elt, evt) { - var eventFilter = triggerSpec.eventFilter; - if(eventFilter){ - try { - return eventFilter.call(elt, evt) !== true; - } catch(e) { - triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); - return true; - } - } - return false; - } - - function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { - var elementData = getInternalData(elt); - var eltsToListenOn; - if (triggerSpec.from) { - eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); - } else { - eltsToListenOn = [elt]; - } - // store the initial values of the elements, so we can tell if they change - if (triggerSpec.changed) { - eltsToListenOn.forEach(function (eltToListenOn) { - var eltToListenOnData = getInternalData(eltToListenOn); - eltToListenOnData.lastValue = eltToListenOn.value; - }) - } - forEach(eltsToListenOn, function (eltToListenOn) { - var eventListener = function (evt) { - if (!bodyContains(elt)) { - eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); - return; - } - if (ignoreBoostedAnchorCtrlClick(elt, evt)) { - return; - } - if (explicitCancel || shouldCancel(evt, elt)) { - evt.preventDefault(); - } - if (maybeFilterEvent(triggerSpec, elt, evt)) { - return; - } - var eventData = getInternalData(evt); - eventData.triggerSpec = triggerSpec; - if (eventData.handledFor == null) { - eventData.handledFor = []; - } - if (eventData.handledFor.indexOf(elt) < 0) { - eventData.handledFor.push(elt); - if (triggerSpec.consume) { - evt.stopPropagation(); - } - if (triggerSpec.target && evt.target) { - if (!matches(evt.target, triggerSpec.target)) { - return; - } - } - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } - } - if (triggerSpec.changed) { - var eltToListenOnData = getInternalData(eltToListenOn) - if (eltToListenOnData.lastValue === eltToListenOn.value) { - return; - } - eltToListenOnData.lastValue = eltToListenOn.value - } - if (elementData.delayed) { - clearTimeout(elementData.delayed); - } - if (elementData.throttle) { - return; - } - - if (triggerSpec.throttle > 0) { - if (!elementData.throttle) { - handler(elt, evt); - elementData.throttle = setTimeout(function () { - elementData.throttle = null; - }, triggerSpec.throttle); - } - } else if (triggerSpec.delay > 0) { - elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); - } else { - triggerEvent(elt, 'htmx:trigger') - handler(elt, evt); - } - } - }; - if (nodeData.listenerInfos == null) { - nodeData.listenerInfos = []; - } - nodeData.listenerInfos.push({ - trigger: triggerSpec.trigger, - listener: eventListener, - on: eltToListenOn - }) - eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); - }); - } - - var windowIsScrolling = false // used by initScrollHandler - var scrollHandler = null; - function initScrollHandler() { - if (!scrollHandler) { - scrollHandler = function() { - windowIsScrolling = true - }; - window.addEventListener("scroll", scrollHandler) - setInterval(function() { - if (windowIsScrolling) { - windowIsScrolling = false; - forEach(getDocument().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"), function (elt) { - maybeReveal(elt); - }) - } - }, 200); - } - } - - function maybeReveal(elt) { - if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { - elt.setAttribute('data-hx-revealed', 'true'); - var nodeData = getInternalData(elt); - if (nodeData.initHash) { - triggerEvent(elt, 'revealed'); - } else { - // if the node isn't initialized, wait for it before triggering the request - elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true}); - } - } - } - - //==================================================================== - // Web Sockets - //==================================================================== - - function processWebSocketInfo(elt, nodeData, info) { - var values = splitOnWhitespace(info); - for (var i = 0; i < values.length; i++) { - var value = values[i].split(/:(.+)/); - if (value[0] === "connect") { - ensureWebSocket(elt, value[1], 0); - } - if (value[0] === "send") { - processWebSocketSend(elt); - } - } - } - - function ensureWebSocket(elt, wssSource, retryCount) { - if (!bodyContains(elt)) { - return; // stop ensuring websocket connection when socket bearing element ceases to exist - } - - if (wssSource.indexOf("/") == 0) { // complete absolute paths only - var base_part = location.hostname + (location.port ? ':'+location.port: ''); - if (location.protocol == 'https:') { - wssSource = "wss://" + base_part + wssSource; - } else if (location.protocol == 'http:') { - wssSource = "ws://" + base_part + wssSource; - } - } - var socket = htmx.createWebSocket(wssSource); - socket.onerror = function (e) { - triggerErrorEvent(elt, "htmx:wsError", {error:e, socket:socket}); - maybeCloseWebSocketSource(elt); - }; - - socket.onclose = function (e) { - if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later - var delay = getWebSocketReconnectDelay(retryCount); - setTimeout(function() { - ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout - }, delay); - } - }; - socket.onopen = function (e) { - retryCount = 0; - } - - getInternalData(elt).webSocket = socket; - socket.addEventListener('message', function (event) { - if (maybeCloseWebSocketSource(elt)) { - return; - } - - var response = event.data; - withExtensions(elt, function(extension){ - response = extension.transformResponse(response, null, elt); - }); - - var settleInfo = makeSettleInfo(elt); - var fragment = makeFragment(response); - var children = toArray(fragment.children); - for (var i = 0; i < children.length; i++) { - var child = children[i]; - oobSwap(getAttributeValue(child, "hx-swap-oob") || "true", child, settleInfo); - } - - settleImmediately(settleInfo.tasks); - }); - } - - function maybeCloseWebSocketSource(elt) { - if (!bodyContains(elt)) { - getInternalData(elt).webSocket.close(); - return true; - } - } - - function processWebSocketSend(elt) { - var webSocketSourceElt = getClosestMatch(elt, function (parent) { - return getInternalData(parent).webSocket != null; - }); - if (webSocketSourceElt) { - elt.addEventListener(getTriggerSpecs(elt)[0].trigger, function (evt) { - var webSocket = getInternalData(webSocketSourceElt).webSocket; - var headers = getHeaders(elt, webSocketSourceElt); - var results = getInputValues(elt, 'post'); - var errors = results.errors; - var rawParameters = results.values; - var expressionVars = getExpressionVars(elt); - var allParameters = mergeObjects(rawParameters, expressionVars); - var filteredParameters = filterValues(allParameters, elt); - filteredParameters['HEADERS'] = headers; - if (errors && errors.length > 0) { - triggerEvent(elt, 'htmx:validation:halted', errors); - return; - } - webSocket.send(JSON.stringify(filteredParameters)); - if(shouldCancel(evt, elt)){ - evt.preventDefault(); - } - }); - } else { - triggerErrorEvent(elt, "htmx:noWebSocketSourceError"); - } - } - - function getWebSocketReconnectDelay(retryCount) { - var delay = htmx.config.wsReconnectDelay; - if (typeof delay === 'function') { - // @ts-ignore - return delay(retryCount); - } - if (delay === 'full-jitter') { - var exp = Math.min(retryCount, 6); - var maxDelay = 1000 * Math.pow(2, exp); - return maxDelay * Math.random(); - } - logError('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"'); - } - - //==================================================================== - // Server Sent Events - //==================================================================== - - function processSSEInfo(elt, nodeData, info) { - var values = splitOnWhitespace(info); - for (var i = 0; i < values.length; i++) { - var value = values[i].split(/:(.+)/); - if (value[0] === "connect") { - processSSESource(elt, value[1]); - } - - if ((value[0] === "swap")) { - processSSESwap(elt, value[1]) - } - } - } - - function processSSESource(elt, sseSrc) { - var source = htmx.createEventSource(sseSrc); - source.onerror = function (e) { - triggerErrorEvent(elt, "htmx:sseError", {error:e, source:source}); - maybeCloseSSESource(elt); - }; - getInternalData(elt).sseEventSource = source; - } - - function processSSESwap(elt, sseEventName) { - var sseSourceElt = getClosestMatch(elt, hasEventSource); - if (sseSourceElt) { - var sseEventSource = getInternalData(sseSourceElt).sseEventSource; - var sseListener = function (event) { - if (maybeCloseSSESource(sseSourceElt)) { - return; - } - if (!bodyContains(elt)) { - sseEventSource.removeEventListener(sseEventName, sseListener); - return; - } - - /////////////////////////// - // TODO: merge this code with AJAX and WebSockets code in the future. - - var response = event.data; - withExtensions(elt, function(extension){ - response = extension.transformResponse(response, null, elt); - }); - - var swapSpec = getSwapSpecification(elt) - var target = getTarget(elt) - var settleInfo = makeSettleInfo(elt); - - selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) - settleImmediately(settleInfo.tasks) - triggerEvent(elt, "htmx:sseMessage", event) - }; - - getInternalData(elt).sseListener = sseListener; - sseEventSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "htmx:noSSESourceError"); - } - } - - function processSSETrigger(elt, handler, sseEventName) { - var sseSourceElt = getClosestMatch(elt, hasEventSource); - if (sseSourceElt) { - var sseEventSource = getInternalData(sseSourceElt).sseEventSource; - var sseListener = function () { - if (!maybeCloseSSESource(sseSourceElt)) { - if (bodyContains(elt)) { - handler(elt); - } else { - sseEventSource.removeEventListener(sseEventName, sseListener); - } - } - }; - getInternalData(elt).sseListener = sseListener; - sseEventSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "htmx:noSSESourceError"); - } - } - - function maybeCloseSSESource(elt) { - if (!bodyContains(elt)) { - getInternalData(elt).sseEventSource.close(); - return true; - } - } - - function hasEventSource(node) { - return getInternalData(node).sseEventSource != null; - } - - //==================================================================== - - function loadImmediately(elt, handler, nodeData, delay) { - var load = function(){ - if (!nodeData.loaded) { - nodeData.loaded = true; - handler(elt); - } - } - if (delay > 0) { - setTimeout(load, delay); - } else { - load(); - } - } - - function processVerbs(elt, nodeData, triggerSpecs) { - var explicitAction = false; - forEach(VERBS, function (verb) { - if (hasAttribute(elt,'hx-' + verb)) { - var path = getAttributeValue(elt, 'hx-' + verb); - explicitAction = true; - nodeData.path = path; - nodeData.verb = verb; - triggerSpecs.forEach(function(triggerSpec) { - addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return - } - issueAjaxRequest(verb, path, elt, evt) - }) - }); - } - }); - return explicitAction; - } - - function addTriggerHandler(elt, triggerSpec, nodeData, handler) { - if (triggerSpec.sseEvent) { - processSSETrigger(elt, handler, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - addEventListener(elt, handler, nodeData, triggerSpec); - maybeReveal(elt); - } else if (triggerSpec.trigger === "intersect") { - var observerOptions = {}; - if (triggerSpec.root) { - observerOptions.root = querySelectorExt(elt, triggerSpec.root) - } - if (triggerSpec.threshold) { - observerOptions.threshold = parseFloat(triggerSpec.threshold); - } - var observer = new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - if (entry.isIntersecting) { - triggerEvent(elt, "intersect"); - break; - } - } - }, observerOptions); - observer.observe(elt); - addEventListener(elt, handler, nodeData, triggerSpec); - } else if (triggerSpec.trigger === "load") { - if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { - loadImmediately(elt, handler, nodeData, triggerSpec.delay); - } - } else if (triggerSpec.pollInterval > 0) { - nodeData.polling = true; - processPolling(elt, handler, triggerSpec); - } else { - addEventListener(elt, handler, nodeData, triggerSpec); - } - } - - function evalScript(script) { - if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) { - var newScript = getDocument().createElement("script"); - forEach(script.attributes, function (attr) { - newScript.setAttribute(attr.name, attr.value); - }); - newScript.textContent = script.textContent; - newScript.async = false; - if (htmx.config.inlineScriptNonce) { - newScript.nonce = htmx.config.inlineScriptNonce; - } - var parent = script.parentElement; - - try { - parent.insertBefore(newScript, script); - } catch (e) { - logError(e); - } finally { - // remove old script element, but only if it is still in DOM - if (script.parentElement) { - script.parentElement.removeChild(script); - } - } - } - } - - function processScripts(elt) { - if (matches(elt, "script")) { - evalScript(elt); - } - forEach(findAll(elt, "script"), function (script) { - evalScript(script); - }); - } - - function shouldProcessHxOn(elt) { - var attributes = elt.attributes - for (var j = 0; j < attributes.length; j++) { - var attrName = attributes[j].name - if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") || - startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) { - return true - } - } - return false - } - - function findHxOnWildcardElements(elt) { - var node = null - var elements = [] - - if (shouldProcessHxOn(elt)) { - elements.push(elt) - } - - if (document.evaluate) { - var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + - ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt) - while (node = iter.iterateNext()) elements.push(node) - } else { - var allElements = elt.getElementsByTagName("*") - for (var i = 0; i < allElements.length; i++) { - if (shouldProcessHxOn(allElements[i])) { - elements.push(allElements[i]) - } - } - } - - return elements - } - - function findElementsToProcess(elt) { - if (elt.querySelectorAll) { - var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; - var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]"); - return results; - } else { - return []; - } - } - - // Handle submit buttons/inputs that have the form attribute set - // see https://developer.mozilla.org/docs/Web/HTML/Element/button - function maybeSetLastButtonClicked(evt) { - var elt = closest(evt.target, "button, input[type='submit']"); - var internalData = getRelatedFormData(evt) - if (internalData) { - internalData.lastButtonClicked = elt; - } - }; - function maybeUnsetLastButtonClicked(evt){ - var internalData = getRelatedFormData(evt) - if (internalData) { - internalData.lastButtonClicked = null; - } - } - function getRelatedFormData(evt) { - var elt = closest(evt.target, "button, input[type='submit']"); - if (!elt) { - return; - } - var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form'); - if (!form) { - return; - } - return getInternalData(form); - } - function initButtonTracking(elt) { - // need to handle both click and focus in: - // focusin - in case someone tabs in to a button and hits the space bar - // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 - elt.addEventListener('click', maybeSetLastButtonClicked) - elt.addEventListener('focusin', maybeSetLastButtonClicked) - elt.addEventListener('focusout', maybeUnsetLastButtonClicked) - } - - function countCurlies(line) { - var tokens = tokenizeString(line); - var netCurlies = 0; - for (var i = 0; i < tokens.length; i++) { - const token = tokens[i]; - if (token === "{") { - netCurlies++; - } else if (token === "}") { - netCurlies--; - } - } - return netCurlies; - } - - function addHxOnEventHandler(elt, eventName, code) { - var nodeData = getInternalData(elt); - if (!Array.isArray(nodeData.onHandlers)) { - nodeData.onHandlers = []; - } - var func; - var listener = function (e) { - return maybeEval(elt, function() { - if (!func) { - func = new Function("event", code); - } - func.call(elt, e); - }); - }; - elt.addEventListener(eventName, listener); - nodeData.onHandlers.push({event:eventName, listener:listener}); - } - - function processHxOn(elt) { - var hxOnValue = getAttributeValue(elt, 'hx-on'); - if (hxOnValue) { - var handlers = {} - var lines = hxOnValue.split("\n"); - var currentEvent = null; - var curlyCount = 0; - while (lines.length > 0) { - var line = lines.shift(); - var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/); - if (curlyCount === 0 && match) { - line.split(":") - currentEvent = match[1].slice(0, -1); // strip last colon - handlers[currentEvent] = match[2]; - } else { - handlers[currentEvent] += line; - } - curlyCount += countCurlies(line); - } - - for (var eventName in handlers) { - addHxOnEventHandler(elt, eventName, handlers[eventName]); - } - } - } - - function processHxOnWildcard(elt) { - // wipe any previous on handlers so that this function takes precedence - deInitOnHandlers(elt) - - for (var i = 0; i < elt.attributes.length; i++) { - var name = elt.attributes[i].name - var value = elt.attributes[i].value - if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) { - var afterOnPosition = name.indexOf("-on") + 3; - var nextChar = name.slice(afterOnPosition, afterOnPosition + 1); - if (nextChar === "-" || nextChar === ":") { - var eventName = name.slice(afterOnPosition + 1); - // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support - if (startsWith(eventName, ":")) { - eventName = "htmx" + eventName - } else if (startsWith(eventName, "-")) { - eventName = "htmx:" + eventName.slice(1); - } else if (startsWith(eventName, "htmx-")) { - eventName = "htmx:" + eventName.slice(5); - } - - addHxOnEventHandler(elt, eventName, value) - } - } - } - } - - function initNode(elt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return; - } - var nodeData = getInternalData(elt); - if (nodeData.initHash !== attributeHash(elt)) { - // clean up any previously processed info - deInitNode(elt); - - nodeData.initHash = attributeHash(elt); - - processHxOn(elt); - - triggerEvent(elt, "htmx:beforeProcessNode") - - if (elt.value) { - nodeData.lastValue = elt.value; - } - - var triggerSpecs = getTriggerSpecs(elt); - var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs); - - if (!hasExplicitHttpAction) { - if (getClosestAttributeValue(elt, "hx-boost") === "true") { - boostElement(elt, nodeData, triggerSpecs); - } else if (hasAttribute(elt, 'hx-trigger')) { - triggerSpecs.forEach(function (triggerSpec) { - // For "naked" triggers, don't do anything at all - addTriggerHandler(elt, triggerSpec, nodeData, function () { - }) - }) - } - } - - // Handle submit buttons/inputs that have the form attribute set - // see https://developer.mozilla.org/docs/Web/HTML/Element/button - if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) { - initButtonTracking(elt) - } - - var sseInfo = getAttributeValue(elt, 'hx-sse'); - if (sseInfo) { - processSSEInfo(elt, nodeData, sseInfo); - } - - var wsInfo = getAttributeValue(elt, 'hx-ws'); - if (wsInfo) { - processWebSocketInfo(elt, nodeData, wsInfo); - } - triggerEvent(elt, "htmx:afterProcessNode"); - } - } - - function processNode(elt) { - elt = resolveTarget(elt); - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return; - } - initNode(elt); - forEach(findElementsToProcess(elt), function(child) { initNode(child) }); - // Because it happens second, the new way of adding onHandlers superseeds the old one - // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored - forEach(findHxOnWildcardElements(elt), processHxOnWildcard); - } - - //==================================================================== - // Event/Log Support - //==================================================================== - - function kebabEventName(str) { - return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase(); - } - - 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({error:eventName}, detail)); - } - - function ignoreEventForLogging(eventName) { - return eventName === "htmx:afterProcessNode" - } - - /** - * `withExtensions` locates all active extensions for a provided element, then - * executes the provided function using each of the active extensions. It should - * be called internally at every extendable execution point in htmx. - * - * @param {HTMLElement} elt - * @param {(extension:import("./htmx").HtmxExtension) => void} toDo - * @returns void - */ - function withExtensions(elt, toDo) { - forEach(getExtensions(elt), function(extension){ - try { - toDo(extension); - } catch (e) { - logError(e); - } - }); - } - - function logError(msg) { - if(console.error) { - console.error(msg); - } else if (console.log) { - console.log("ERROR: ", msg); - } - } - - function triggerEvent(elt, eventName, detail) { - elt = resolveTarget(elt); - if (detail == null) { - detail = {}; - } - detail["elt"] = elt; - var event = makeEvent(eventName, detail); - if (htmx.logger && !ignoreEventForLogging(eventName)) { - htmx.logger(elt, eventName, detail); - } - if (detail.error) { - logError(detail.error); - triggerEvent(elt, "htmx:error", {errorInfo:detail}) - } - var eventResult = elt.dispatchEvent(event); - var kebabName = kebabEventName(eventName); - if (eventResult && kebabName !== eventName) { - var kebabedEvent = makeEvent(kebabName, event.detail); - eventResult = eventResult && elt.dispatchEvent(kebabedEvent) - } - withExtensions(elt, function (extension) { - eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) - }); - return eventResult; - } - - //==================================================================== - // History Support - //==================================================================== - var currentPathForHistory = location.pathname+location.search; - - function getHistoryElement() { - var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]'); - return historyElt || getDocument().body; - } - - function saveToHistoryCache(url, content, title, scroll) { - if (!canAccessLocalStorage()) { - return; - } - - if (htmx.config.historyCacheSize <= 0) { - // make sure that an eventually already existing cache is purged - localStorage.removeItem("htmx-history-cache"); - return; - } - - url = normalizePath(url); - - var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - historyCache.splice(i, 1); - break; - } - } - var newHistoryItem = {url:url, content: content, title:title, scroll:scroll}; - triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache}) - historyCache.push(newHistoryItem) - while (historyCache.length > htmx.config.historyCacheSize) { - historyCache.shift(); - } - while(historyCache.length > 0){ - try { - localStorage.setItem("htmx-history-cache", JSON.stringify(historyCache)); - break; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:historyCacheError", {cause:e, cache: historyCache}) - historyCache.shift(); // shrink the cache and retry - } - } - } - - function getCachedHistory(url) { - if (!canAccessLocalStorage()) { - return null; - } - - url = normalizePath(url); - - var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - return historyCache[i]; - } - } - return null; - } - - function cleanInnerHtmlForHistory(elt) { - var className = htmx.config.requestClass; - var clone = elt.cloneNode(true); - forEach(findAll(clone, "." + className), function(child){ - removeClassFromElement(child, className); - }); - return clone.innerHTML; - } - - function saveCurrentPageToHistory() { - var elt = getHistoryElement(); - var path = currentPathForHistory || location.pathname+location.search; - - // Allow history snapshot feature to be disabled where hx-history="false" - // is present *anywhere* in the current document we're about to save, - // so we can prevent privileged data entering the cache. - // The page will still be reachable as a history entry, but htmx will fetch it - // live from the server onpopstate rather than look in the localStorage cache - var disableHistoryCache - try { - disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') - } catch (e) { - // IE11: insensitive modifier not supported so fallback to case sensitive selector - disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') - } - if (!disableHistoryCache) { - triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt}); - saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); - } - - if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href); - } - - function pushUrlIntoHistory(path) { - // remove the cache buster parameter, if any - if (htmx.config.getCacheBusterParam) { - path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') - if (endsWith(path, '&') || endsWith(path, "?")) { - path = path.slice(0, -1); - } - } - if(htmx.config.historyEnabled) { - history.pushState({htmx:true}, "", path); - } - currentPathForHistory = path; - } - - function replaceUrlInHistory(path) { - if(htmx.config.historyEnabled) history.replaceState({htmx:true}, "", path); - currentPathForHistory = path; - } - - function settleImmediately(tasks) { - forEach(tasks, function (task) { - task.call(); - }); - } - - function loadHistoryFromServer(path) { - var request = new XMLHttpRequest(); - var details = {path: path, xhr:request}; - triggerEvent(getDocument().body, "htmx:historyCacheMiss", details); - request.open('GET', path, true); - request.setRequestHeader("HX-Request", "true"); - request.setRequestHeader("HX-History-Restore-Request", "true"); - request.setRequestHeader("HX-Current-URL", getDocument().location.href); - request.onload = function () { - if (this.status >= 200 && this.status < 400) { - triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); - var fragment = makeFragment(this.response); - // @ts-ignore - fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; - var historyElement = getHistoryElement(); - var settleInfo = makeSettleInfo(historyElement); - var title = findTitle(this.response); - if (title) { - var titleElt = find("title"); - if (titleElt) { - titleElt.innerHTML = title; - } else { - window.document.title = title; - } - } - // @ts-ignore - swapInnerHTML(historyElement, fragment, settleInfo) - settleImmediately(settleInfo.tasks); - currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response}); - } else { - triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details); - } - }; - request.send(); - } - - function restoreHistory(path) { - saveCurrentPageToHistory(); - path = path || location.pathname+location.search; - var cached = getCachedHistory(path); - if (cached) { - var fragment = makeFragment(cached.content); - var historyElement = getHistoryElement(); - var settleInfo = makeSettleInfo(historyElement); - swapInnerHTML(historyElement, fragment, settleInfo) - settleImmediately(settleInfo.tasks); - document.title = cached.title; - setTimeout(function () { - window.scrollTo(0, cached.scroll); - }, 0); // next 'tick', so browser has time to render layout - currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); - } else { - if (htmx.config.refreshOnHistoryMiss) { - - // @ts-ignore: optional parameter in reload() function throws error - window.location.reload(true); - } else { - loadHistoryFromServer(path); - } - } - } - - function addRequestIndicatorClasses(elt) { - var indicators = findAttributeTargets(elt, 'hx-indicator'); - if (indicators == null) { - indicators = [elt]; - } - forEach(indicators, function (ic) { - var internalData = getInternalData(ic); - internalData.requestCount = (internalData.requestCount || 0) + 1; - ic.classList["add"].call(ic.classList, htmx.config.requestClass); - }); - return indicators; - } - - function disableElements(elt) { - var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt'); - if (disabledElts == null) { - disabledElts = []; - } - forEach(disabledElts, function (disabledElement) { - var internalData = getInternalData(disabledElement); - internalData.requestCount = (internalData.requestCount || 0) + 1; - disabledElement.setAttribute("disabled", ""); - }); - return disabledElts; - } - - function removeRequestIndicators(indicators, disabled) { - forEach(indicators, function (ic) { - var internalData = getInternalData(ic); - internalData.requestCount = (internalData.requestCount || 0) - 1; - if (internalData.requestCount === 0) { - ic.classList["remove"].call(ic.classList, htmx.config.requestClass); - } - }); - forEach(disabled, function (disabledElement) { - var internalData = getInternalData(disabledElement); - internalData.requestCount = (internalData.requestCount || 0) - 1; - if (internalData.requestCount === 0) { - disabledElement.removeAttribute('disabled'); - } - }); - } - - //==================================================================== - // 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 || closest(elt, "fieldset[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 addValueToValues(name, value, values) { - // This is a little ugly because both the current value of the named value in the form - // and the new value could be arrays, so we have to handle all four cases :/ - if (name != null && value != null) { - var current = values[name]; - if (current === undefined) { - values[name] = value; - } else if (Array.isArray(current)) { - if (Array.isArray(value)) { - values[name] = current.concat(value); - } else { - current.push(value); - } - } else { - if (Array.isArray(value)) { - values[name] = [current].concat(value); - } else { - values[name] = [current, value]; - } - } - } - } - - function processInputValue(processed, values, errors, elt, validate) { - if (elt == null || haveSeenNode(processed, elt)) { - return; - } else { - processed.push(elt); - } - if (shouldInclude(elt)) { - var name = getRawAttribute(elt,"name"); - var value = elt.value; - if (elt.multiple && elt.tagName === "SELECT") { - value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value }); - } - // include file inputs - if (elt.files) { - value = toArray(elt.files); - } - addValueToValues(name, value, values); - if (validate) { - validateElement(elt, errors); - } - } - if (matches(elt, 'form')) { - var inputs = elt.elements; - forEach(inputs, function(input) { - processInputValue(processed, values, errors, input, validate); - }); - } - } - - function validateElement(element, errors) { - if (element.willValidate) { - triggerEvent(element, "htmx:validation:validate") - if (!element.checkValidity()) { - errors.push({elt: element, message:element.validationMessage, validity:element.validity}); - triggerEvent(element, "htmx:validation:failed", {message:element.validationMessage, validity:element.validity}) - } - } - } - - /** - * @param {HTMLElement} elt - * @param {string} verb - */ - function getInputValues(elt, verb) { - var processed = []; - var values = {}; - var formValues = {}; - var errors = []; - var internalData = getInternalData(elt); - if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { - internalData.lastButtonClicked = null - } - - // only validate when form is directly submitted and novalidate or formnovalidate are not set - // or if the element has an explicit hx-validate="true" on it - var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true"; - if (internalData.lastButtonClicked) { - validate = validate && internalData.lastButtonClicked.formNoValidate !== true; - } - - // for a non-GET include the closest form - if (verb !== 'get') { - processInputValue(processed, formValues, errors, closest(elt, 'form'), validate); - } - - // include the element itself - processInputValue(processed, values, errors, elt, validate); - - // if a button or submit was clicked last, include its value - if (internalData.lastButtonClicked || elt.tagName === "BUTTON" || - (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) { - var button = internalData.lastButtonClicked || elt - var name = getRawAttribute(button, "name") - addValueToValues(name, button.value, formValues) - } - - // include any explicit includes - var includes = findAttributeTargets(elt, "hx-include"); - forEach(includes, function(node) { - processInputValue(processed, values, errors, node, validate); - // if a non-form is included, include any input values within it - if (!matches(node, 'form')) { - forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { - processInputValue(processed, values, errors, descendant, validate); - }) - } - }); - - // form values take precedence, overriding the regular values - values = mergeObjects(values, formValues); - - return {errors:errors, values:values}; - } - - function appendParam(returnStr, name, realValue) { - if (returnStr !== "") { - returnStr += "&"; - } - if (String(realValue) === "[object Object]") { - realValue = JSON.stringify(realValue); - } - var s = encodeURIComponent(realValue); - returnStr += encodeURIComponent(name) + "=" + s; - 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; - } - - function makeFormData(values) { - var formData = new FormData(); - for (var name in values) { - if (values.hasOwnProperty(name)) { - var value = values[name]; - if (Array.isArray(value)) { - forEach(value, function(v) { - formData.append(name, v); - }); - } else { - formData.append(name, value); - } - } - } - return formData; - } - - //==================================================================== - // Ajax - //==================================================================== - - /** - * @param {HTMLElement} elt - * @param {HTMLElement} target - * @param {string} prompt - * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification - */ - function getHeaders(elt, target, prompt) { - var headers = { - "HX-Request" : "true", - "HX-Trigger" : getRawAttribute(elt, "id"), - "HX-Trigger-Name" : getRawAttribute(elt, "name"), - "HX-Target" : getAttributeValue(target, "id"), - "HX-Current-URL" : getDocument().location.href, - } - getValuesForElement(elt, "hx-headers", false, headers) - if (prompt !== undefined) { - headers["HX-Prompt"] = prompt; - } - if (getInternalData(elt).boosted) { - headers["HX-Boosted"] = "true"; - } - return headers; - } - - /** - * filterValues takes an object containing form input values - * and returns a new object that only contains keys that are - * specified by the closest "hx-params" attribute - * @param {Object} inputValues - * @param {HTMLElement} elt - * @returns {Object} - */ - function filterValues(inputValues, elt) { - var paramsValue = getClosestAttributeValue(elt, "hx-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 isAnchorLink(elt) { - return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0 - } - - /** - * - * @param {HTMLElement} elt - * @param {string} swapInfoOverride - * @returns {import("./htmx").HtmxSwapSpecification} - */ - function getSwapSpecification(elt, swapInfoOverride) { - var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap"); - var swapSpec = { - "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, - "swapDelay" : htmx.config.defaultSwapDelay, - "settleDelay" : htmx.config.defaultSettleDelay - } - if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { - swapSpec["show"] = "top" - } - if (swapInfo) { - var split = splitOnWhitespace(swapInfo); - if (split.length > 0) { - for (var i = 0; i < split.length; i++) { - var value = split[i]; - if (value.indexOf("swap:") === 0) { - swapSpec["swapDelay"] = parseInterval(value.substr(5)); - } else if (value.indexOf("settle:") === 0) { - swapSpec["settleDelay"] = parseInterval(value.substr(7)); - } else if (value.indexOf("transition:") === 0) { - swapSpec["transition"] = value.substr(11) === "true"; - } else if (value.indexOf("ignoreTitle:") === 0) { - swapSpec["ignoreTitle"] = value.substr(12) === "true"; - } else if (value.indexOf("scroll:") === 0) { - var scrollSpec = value.substr(7); - var splitSpec = scrollSpec.split(":"); - var scrollVal = splitSpec.pop(); - var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; - swapSpec["scroll"] = scrollVal; - swapSpec["scrollTarget"] = selectorVal; - } else if (value.indexOf("show:") === 0) { - var showSpec = value.substr(5); - var splitSpec = showSpec.split(":"); - var showVal = splitSpec.pop(); - var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; - swapSpec["show"] = showVal; - swapSpec["showTarget"] = selectorVal; - } else if (value.indexOf("focus-scroll:") === 0) { - var focusScrollVal = value.substr("focus-scroll:".length); - swapSpec["focusScroll"] = focusScrollVal == "true"; - } else if (i == 0) { - swapSpec["swapStyle"] = value; - } else { - logError('Unknown modifier in hx-swap: ' + value); - } - } - } - } - return swapSpec; - } - - function usesFormData(elt) { - return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || - (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data"); - } - - function encodeParamsForBody(xhr, elt, filteredParameters) { - var encodedParameters = null; - withExtensions(elt, function (extension) { - if (encodedParameters == null) { - encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt); - } - }); - if (encodedParameters != null) { - return encodedParameters; - } else { - if (usesFormData(elt)) { - return makeFormData(filteredParameters); - } else { - return urlEncode(filteredParameters); - } - } - } - - /** - * - * @param {Element} target - * @returns {import("./htmx").HtmxSettleInfo} - */ - function makeSettleInfo(target) { - return {tasks: [], elts: [target]}; - } - - function updateScrollState(content, swapSpec) { - var first = content[0]; - var last = content[content.length - 1]; - if (swapSpec.scroll) { - var target = null; - if (swapSpec.scrollTarget) { - target = querySelectorExt(first, swapSpec.scrollTarget); - } - if (swapSpec.scroll === "top" && (first || target)) { - target = target || first; - target.scrollTop = 0; - } - if (swapSpec.scroll === "bottom" && (last || target)) { - target = target || last; - target.scrollTop = target.scrollHeight; - } - } - if (swapSpec.show) { - var target = null; - if (swapSpec.showTarget) { - var targetStr = swapSpec.showTarget; - if (swapSpec.showTarget === "window") { - targetStr = "body"; - } - target = querySelectorExt(first, targetStr); - } - if (swapSpec.show === "top" && (first || target)) { - target = target || first; - target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior}); - } - if (swapSpec.show === "bottom" && (last || target)) { - target = target || last; - target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior}); - } - } - } - - /** - * @param {HTMLElement} elt - * @param {string} attr - * @param {boolean=} evalAsDefault - * @param {Object=} values - * @returns {Object} - */ - function getValuesForElement(elt, attr, evalAsDefault, values) { - if (values == null) { - values = {}; - } - if (elt == null) { - return values; - } - var attributeValue = getAttributeValue(elt, attr); - if (attributeValue) { - var str = attributeValue.trim(); - var evaluateValue = evalAsDefault; - if (str === "unset") { - return null; - } - if (str.indexOf("javascript:") === 0) { - str = str.substr(11); - evaluateValue = true; - } else if (str.indexOf("js:") === 0) { - str = str.substr(3); - evaluateValue = true; - } - if (str.indexOf('{') !== 0) { - str = "{" + str + "}"; - } - var varsValues; - if (evaluateValue) { - varsValues = maybeEval(elt,function () {return Function("return (" + str + ")")();}, {}); - } else { - varsValues = parseJSON(str); - } - for (var key in varsValues) { - if (varsValues.hasOwnProperty(key)) { - if (values[key] == null) { - values[key] = varsValues[key]; - } - } - } - } - return getValuesForElement(parentElt(elt), attr, evalAsDefault, values); - } - - function maybeEval(elt, toEval, defaultVal) { - if (htmx.config.allowEval) { - return toEval(); - } else { - triggerErrorEvent(elt, 'htmx:evalDisallowedError'); - return defaultVal; - } - } - - /** - * @param {HTMLElement} elt - * @param {*} expressionVars - * @returns - */ - function getHXVarsForElement(elt, expressionVars) { - return getValuesForElement(elt, "hx-vars", true, expressionVars); - } - - /** - * @param {HTMLElement} elt - * @param {*} expressionVars - * @returns - */ - function getHXValsForElement(elt, expressionVars) { - return getValuesForElement(elt, "hx-vals", false, expressionVars); - } - - /** - * @param {HTMLElement} elt - * @returns {Object} - */ - function getExpressionVars(elt) { - return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)); - } - - function safelySetHeaderValue(xhr, header, headerValue) { - if (headerValue !== null) { - try { - xhr.setRequestHeader(header, headerValue); - } catch (e) { - // On an exception, try to set the header URI encoded instead - xhr.setRequestHeader(header, encodeURIComponent(headerValue)); - xhr.setRequestHeader(header + "-URI-AutoEncoded", "true"); - } - } - } - - function getPathFromResponse(xhr) { - // NB: IE11 does not support this stuff - if (xhr.responseURL && typeof(URL) !== "undefined") { - try { - var url = new URL(xhr.responseURL); - return url.pathname + url.search; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:badResponseUrl", {url: xhr.responseURL}); - } - } - } - - function hasHeader(xhr, regexp) { - return regexp.test(xhr.getAllResponseHeaders()) - } - - function ajaxHelper(verb, path, context) { - verb = verb.toLowerCase(); - if (context) { - if (context instanceof Element || isType(context, 'String')) { - return issueAjaxRequest(verb, path, null, null, { - targetOverride: resolveTarget(context), - returnPromise: true - }); - } else { - return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, - { - handler : context.handler, - headers : context.headers, - values : context.values, - targetOverride: resolveTarget(context.target), - swapOverride: context.swap, - select: context.select, - returnPromise: true - }); - } - } else { - return issueAjaxRequest(verb, path, null, null, { - returnPromise: true - }); - } - } - - function hierarchyForElt(elt) { - var arr = []; - while (elt) { - arr.push(elt); - elt = elt.parentElement; - } - return arr; - } - - function verifyPath(elt, path, requestConfig) { - var sameHost - var url - if (typeof URL === "function") { - url = new URL(path, document.location.href); - var origin = document.location.origin; - sameHost = origin === url.origin; - } else { - // IE11 doesn't support URL - url = path - sameHost = startsWith(path, document.location.origin) - } - - if (htmx.config.selfRequestsOnly) { - if (!sameHost) { - return false; - } - } - return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig)); - } - - function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { - var resolve = null; - var reject = null; - etc = etc != null ? etc : {}; - if(etc.returnPromise && typeof Promise !== "undefined"){ - var promise = new Promise(function (_resolve, _reject) { - resolve = _resolve; - reject = _reject; - }); - } - if(elt == null) { - elt = getDocument().body; - } - var responseHandler = etc.handler || handleAjaxResponse; - var select = etc.select || null; - - if (!bodyContains(elt)) { - // do not issue requests for elements removed from the DOM - maybeCall(resolve); - return promise; - } - var target = etc.targetOverride || getTarget(elt); - if (target == null || target == DUMMY_ELT) { - triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); - maybeCall(reject); - return promise; - } - - var eltData = getInternalData(elt); - var submitter = eltData.lastButtonClicked; - - if (submitter) { - var buttonPath = getRawAttribute(submitter, "formaction"); - if (buttonPath != null) { - path = buttonPath; - } - - var buttonVerb = getRawAttribute(submitter, "formmethod") - if (buttonVerb != null) { - // ignore buttons with formmethod="dialog" - if (buttonVerb.toLowerCase() !== "dialog") { - verb = buttonVerb; - } - } - } - - var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); - // allow event-based confirmation w/ a callback - if (confirmed === undefined) { - var issueRequest = function(skipConfirmation) { - return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation); - } - var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion}; - if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { - maybeCall(resolve); - return promise; - } - } - - var syncElt = elt; - var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); - var queueStrategy = null; - var abortable = false; - if (syncStrategy) { - var syncStrings = syncStrategy.split(":"); - var selector = syncStrings[0].trim(); - if (selector === "this") { - syncElt = findThisElement(elt, 'hx-sync'); - } else { - syncElt = querySelectorExt(elt, selector); - } - // default to the drop strategy - syncStrategy = (syncStrings[1] || 'drop').trim(); - eltData = getInternalData(syncElt); - if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { - maybeCall(resolve); - return promise; - } else if (syncStrategy === "abort") { - if (eltData.xhr) { - maybeCall(resolve); - return promise; - } else { - abortable = true; - } - } else if (syncStrategy === "replace") { - triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue - } else if (syncStrategy.indexOf("queue") === 0) { - var queueStrArray = syncStrategy.split(" "); - queueStrategy = (queueStrArray[1] || "last").trim(); - } - } - - if (eltData.xhr) { - if (eltData.abortable) { - triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue - } else { - if(queueStrategy == null){ - if (event) { - var eventData = getInternalData(event); - if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { - queueStrategy = eventData.triggerSpec.queue; - } - } - if (queueStrategy == null) { - queueStrategy = "last"; - } - } - if (eltData.queuedRequests == null) { - eltData.queuedRequests = []; - } - if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } else if (queueStrategy === "all") { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } else if (queueStrategy === "last") { - eltData.queuedRequests = []; // dump existing queue - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } - maybeCall(resolve); - return promise; - } - } - - var xhr = new XMLHttpRequest(); - eltData.xhr = xhr; - eltData.abortable = abortable; - var endRequestLock = function(){ - eltData.xhr = null; - eltData.abortable = false; - if (eltData.queuedRequests != null && - eltData.queuedRequests.length > 0) { - var queuedRequest = eltData.queuedRequests.shift(); - queuedRequest(); - } - } - var promptQuestion = getClosestAttributeValue(elt, "hx-prompt"); - if (promptQuestion) { - var promptResponse = prompt(promptQuestion); - // prompt returns null if cancelled and empty string if accepted with no entry - if (promptResponse === null || - !triggerEvent(elt, 'htmx:prompt', {prompt: promptResponse, target:target})) { - maybeCall(resolve); - endRequestLock(); - return promise; - } + triggerErrorEvent(getDocument().body, 'htmx:syntax:error', { error: e, source: conditionalSource }) + return null } + } + } else if (token === '[') { + bracketCount++ + } + if (isPossibleRelativeReference(token, last, paramName)) { + conditionalSource += '((' + paramName + '.' + token + ') ? (' + paramName + '.' + token + ') : (window.' + token + '))' + } else { + conditionalSource = conditionalSource + token + } + last = tokens.shift() + } + } + } + + /** + * @param {string[]} tokens + * @param {RegExp} match + * @returns {string} + */ + function consumeUntil(tokens, match) { + let result = '' + while (tokens.length > 0 && !match.test(tokens[0])) { + result += tokens.shift() + } + return result + } + + /** + * @param {string[]} tokens + * @returns {string} + */ + function consumeCSSSelector(tokens) { + let result + if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { + tokens.shift() + result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim() + tokens.shift() + } else { + result = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } + return result + } + + const INPUT_SELECTOR = 'input, textarea, select' + + /** + * @param {Element} elt + * @param {string} explicitTrigger + * @param {Object} cache for trigger specs + * @returns {HtmxTriggerSpecification[]} + */ + function parseAndCacheTrigger(elt, explicitTrigger, cache) { + /** @type HtmxTriggerSpecification[] */ + const triggerSpecs = [] + const tokens = tokenizeString(explicitTrigger) + do { + consumeUntil(tokens, NOT_WHITESPACE) + const initialLength = tokens.length + const trigger = consumeUntil(tokens, /[,\[\s]/) + if (trigger !== '') { + if (trigger === 'every') { + /** @type HtmxTriggerSpecification */ + const every = { trigger: 'every' } + consumeUntil(tokens, NOT_WHITESPACE) + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)) + consumeUntil(tokens, NOT_WHITESPACE) + var eventFilter = maybeGenerateConditional(elt, tokens, 'event') + if (eventFilter) { + every.eventFilter = eventFilter + } + triggerSpecs.push(every) + } else { + /** @type HtmxTriggerSpecification */ + const triggerSpec = { trigger } + var eventFilter = maybeGenerateConditional(elt, tokens, 'event') + if (eventFilter) { + triggerSpec.eventFilter = eventFilter + } + while (tokens.length > 0 && tokens[0] !== ',') { + consumeUntil(tokens, NOT_WHITESPACE) + const token = tokens.shift() + if (token === 'changed') { + triggerSpec.changed = true + } else if (token === 'once') { + triggerSpec.once = true + } else if (token === 'consume') { + triggerSpec.consume = true + } else if (token === 'delay' && tokens[0] === ':') { + tokens.shift() + triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)) + } else if (token === 'from' && tokens[0] === ':') { + tokens.shift() + if (COMBINED_SELECTOR_START.test(tokens[0])) { + var from_arg = consumeCSSSelector(tokens) + } else { + var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA) + if (from_arg === 'closest' || from_arg === 'find' || from_arg === 'next' || from_arg === 'previous') { + tokens.shift() + const selector = consumeCSSSelector(tokens) + // `next` and `previous` allow a selector-less syntax + if (selector.length > 0) { + from_arg += ' ' + selector + } + } + } + triggerSpec.from = from_arg + } else if (token === 'target' && tokens[0] === ':') { + tokens.shift() + triggerSpec.target = consumeCSSSelector(tokens) + } else if (token === 'throttle' && tokens[0] === ':') { + tokens.shift() + triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)) + } else if (token === 'queue' && tokens[0] === ':') { + tokens.shift() + triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } else if (token === 'root' && tokens[0] === ':') { + tokens.shift() + triggerSpec[token] = consumeCSSSelector(tokens) + } else if (token === 'threshold' && tokens[0] === ':') { + tokens.shift() + triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } else { + triggerErrorEvent(elt, 'htmx:syntax:error', { token: tokens.shift() }) + } + } + triggerSpecs.push(triggerSpec) + } + } + if (tokens.length === initialLength) { + triggerErrorEvent(elt, 'htmx:syntax:error', { token: tokens.shift() }) + } + consumeUntil(tokens, NOT_WHITESPACE) + } while (tokens[0] === ',' && tokens.shift()) + if (cache) { + cache[explicitTrigger] = triggerSpecs + } + return triggerSpecs + } + + /** + * @param {Element} elt + * @returns {HtmxTriggerSpecification[]} + */ + function getTriggerSpecs(elt) { + const explicitTrigger = getAttributeValue(elt, 'hx-trigger') + let triggerSpecs = [] + if (explicitTrigger) { + const cache = htmx.config.triggerSpecsCache + triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) + } - if (confirmQuestion && !confirmed) { - if(!confirm(confirmQuestion)) { - maybeCall(resolve); - endRequestLock() - return promise; - } + if (triggerSpecs.length > 0) { + return triggerSpecs + } else if (matches(elt, 'form')) { + return [{ trigger: 'submit' }] + } else if (matches(elt, 'input[type="button"], input[type="submit"]')) { + return [{ trigger: 'click' }] + } else if (matches(elt, INPUT_SELECTOR)) { + return [{ trigger: 'change' }] + } else { + return [{ trigger: 'click' }] + } + } + + /** + * @param {Element} elt + */ + function cancelPolling(elt) { + getInternalData(elt).cancelled = true + } + + /** + * @param {Element} elt + * @param {TriggerHandler} handler + * @param {HtmxTriggerSpecification} spec + */ + function processPolling(elt, handler, spec) { + const nodeData = getInternalData(elt) + nodeData.timeout = getWindow().setTimeout(function() { + if (bodyContains(elt) && nodeData.cancelled !== true) { + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { + handler(elt) + } + processPolling(elt, handler, spec) + } + }, spec.pollInterval) + } + + /** + * @param {HTMLAnchorElement} elt + * @returns {boolean} + */ + function isLocalLink(elt) { + return location.hostname === elt.hostname && + getRawAttribute(elt, 'href') && + getRawAttribute(elt, 'href').indexOf('#') !== 0 + } + + /** + * @param {Element} elt + */ + function eltIsDisabled(elt) { + return closest(elt, htmx.config.disableSelector) + } + + /** + * @param {Element} elt + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification[]} triggerSpecs + */ + function boostElement(elt, nodeData, triggerSpecs) { + if ((elt instanceof HTMLAnchorElement && isLocalLink(elt) && (elt.target === '' || elt.target === '_self')) || elt.tagName === 'FORM') { + nodeData.boosted = true + let verb, path + if (elt.tagName === 'A') { + verb = 'get' + path = getRawAttribute(elt, 'href') + } else { + const rawAttribute = getRawAttribute(elt, 'method') + verb = rawAttribute ? rawAttribute.toLowerCase() : 'get' + if (verb === 'get') { + } + path = getRawAttribute(elt, 'action') + } + triggerSpecs.forEach(function(triggerSpec) { + addEventListener(elt, function(node, evt) { + const elt = asElement(node) + if (eltIsDisabled(elt)) { + cleanUpElement(elt) + return + } + issueAjaxRequest(verb, path, elt, evt) + }, nodeData, triggerSpec, true) + }) + } + } + + /** + * @param {Event} evt + * @param {Node} node + * @returns {boolean} + */ + function shouldCancel(evt, node) { + const elt = asElement(node) + if (!elt) { + return false + } + if (evt.type === 'submit' || evt.type === 'click') { + if (elt.tagName === 'FORM') { + return true + } + if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { + return true + } + if (elt instanceof HTMLAnchorElement && elt.href && + (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf('#') !== 0)) { + return true + } + } + return false + } + + /** + * @param {Node} elt + * @param {Event|MouseEvent|KeyboardEvent|TouchEvent} evt + * @returns {boolean} + */ + function ignoreBoostedAnchorCtrlClick(elt, evt) { + return getInternalData(elt).boosted && elt instanceof HTMLAnchorElement && evt.type === 'click' && + // @ts-ignore this will resolve to undefined for events that don't define those properties, which is fine + (evt.ctrlKey || evt.metaKey) + } + + /** + * @param {HtmxTriggerSpecification} triggerSpec + * @param {Node} elt + * @param {Event} evt + * @returns {boolean} + */ + function maybeFilterEvent(triggerSpec, elt, evt) { + const eventFilter = triggerSpec.eventFilter + if (eventFilter) { + try { + return eventFilter.call(elt, evt) !== true + } catch (e) { + const source = eventFilter.source + triggerErrorEvent(getDocument().body, 'htmx:eventFilter:error', { error: e, source }) + return true + } + } + return false + } + + /** + * @param {Node} elt + * @param {TriggerHandler} handler + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification} triggerSpec + * @param {boolean} [explicitCancel] + */ + function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { + const elementData = getInternalData(elt) + /** @type {(Node|Window)[]} */ + let eltsToListenOn + if (triggerSpec.from) { + eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from) + } else { + eltsToListenOn = [elt] + } + // store the initial values of the elements, so we can tell if they change + if (triggerSpec.changed) { + eltsToListenOn.forEach(function(eltToListenOn) { + const eltToListenOnData = getInternalData(eltToListenOn) + // @ts-ignore value will be undefined for non-input elements, which is fine + eltToListenOnData.lastValue = eltToListenOn.value + }) + } + forEach(eltsToListenOn, function(eltToListenOn) { + /** @type EventListener */ + const eventListener = function(evt) { + if (!bodyContains(elt)) { + eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener) + return + } + if (ignoreBoostedAnchorCtrlClick(elt, evt)) { + return + } + if (explicitCancel || shouldCancel(evt, elt)) { + evt.preventDefault() + } + if (maybeFilterEvent(triggerSpec, elt, evt)) { + return + } + const eventData = getInternalData(evt) + eventData.triggerSpec = triggerSpec + if (eventData.handledFor == null) { + eventData.handledFor = [] + } + if (eventData.handledFor.indexOf(elt) < 0) { + eventData.handledFor.push(elt) + if (triggerSpec.consume) { + evt.stopPropagation() + } + if (triggerSpec.target && evt.target) { + if (!matches(asElement(evt.target), triggerSpec.target)) { + return + } + } + if (triggerSpec.once) { + if (elementData.triggeredOnce) { + return + } else { + elementData.triggeredOnce = true + } + } + if (triggerSpec.changed) { + const eltToListenOnData = getInternalData(eltToListenOn) + // @ts-ignore value will be undefined for non-input elements, which is fine + const value = eltToListenOn.value + if (eltToListenOnData.lastValue === value) { + return + } + eltToListenOnData.lastValue = value + } + if (elementData.delayed) { + clearTimeout(elementData.delayed) + } + if (elementData.throttle) { + return + } + + if (triggerSpec.throttle > 0) { + if (!elementData.throttle) { + handler(elt, evt) + elementData.throttle = getWindow().setTimeout(function() { + elementData.throttle = null + }, triggerSpec.throttle) + } + } else if (triggerSpec.delay > 0) { + elementData.delayed = getWindow().setTimeout(function() { handler(elt, evt) }, triggerSpec.delay) + } else { + triggerEvent(elt, 'htmx:trigger') + handler(elt, evt) + } + } + } + if (nodeData.listenerInfos == null) { + nodeData.listenerInfos = [] + } + nodeData.listenerInfos.push({ + trigger: triggerSpec.trigger, + listener: eventListener, + on: eltToListenOn + }) + eltToListenOn.addEventListener(triggerSpec.trigger, eventListener) + }) + } + + let windowIsScrolling = false // used by initScrollHandler + let scrollHandler = null + function initScrollHandler() { + if (!scrollHandler) { + scrollHandler = function() { + windowIsScrolling = true + } + window.addEventListener('scroll', scrollHandler) + setInterval(function() { + if (windowIsScrolling) { + windowIsScrolling = false + forEach(getDocument().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"), function(elt) { + maybeReveal(elt) + }) + } + }, 200) + } + } + + /** + * @param {Element} elt + */ + function maybeReveal(elt) { + if (!hasAttribute(elt, 'data-hx-revealed') && isScrolledIntoView(elt)) { + elt.setAttribute('data-hx-revealed', 'true') + const nodeData = getInternalData(elt) + if (nodeData.initHash) { + triggerEvent(elt, 'revealed') + } else { + // if the node isn't initialized, wait for it before triggering the request + elt.addEventListener('htmx:afterProcessNode', function() { triggerEvent(elt, 'revealed') }, { once: true }) + } + } + } + + //= =================================================================== + + /** + * @param {Element} elt + * @param {TriggerHandler} handler + * @param {HtmxNodeInternalData} nodeData + * @param {number} delay + */ + function loadImmediately(elt, handler, nodeData, delay) { + const load = function() { + if (!nodeData.loaded) { + nodeData.loaded = true + handler(elt) + } + } + if (delay > 0) { + getWindow().setTimeout(load, delay) + } else { + load() + } + } + + /** + * @param {Element} elt + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification[]} triggerSpecs + * @returns {boolean} + */ + function processVerbs(elt, nodeData, triggerSpecs) { + let explicitAction = false + forEach(VERBS, function(verb) { + if (hasAttribute(elt, 'hx-' + verb)) { + const path = getAttributeValue(elt, 'hx-' + verb) + explicitAction = true + nodeData.path = path + nodeData.verb = verb + triggerSpecs.forEach(function(triggerSpec) { + addTriggerHandler(elt, triggerSpec, nodeData, function(node, evt) { + const elt = asElement(node) + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return } + issueAjaxRequest(verb, path, elt, evt) + }) + }) + } + }) + return explicitAction + } + + /** + * @callback TriggerHandler + * @param {Node} elt + * @param {Event} [evt] + */ + + /** + * @param {Node} elt + * @param {HtmxTriggerSpecification} triggerSpec + * @param {HtmxNodeInternalData} nodeData + * @param {TriggerHandler} handler + */ + function addTriggerHandler(elt, triggerSpec, nodeData, handler) { + if (triggerSpec.trigger === 'revealed') { + initScrollHandler() + addEventListener(elt, handler, nodeData, triggerSpec) + maybeReveal(asElement(elt)) + } else if (triggerSpec.trigger === 'intersect') { + const observerOptions = {} + if (triggerSpec.root) { + observerOptions.root = querySelectorExt(elt, triggerSpec.root) + } + if (triggerSpec.threshold) { + observerOptions.threshold = parseFloat(triggerSpec.threshold) + } + const observer = new IntersectionObserver(function(entries) { + for (let i = 0; i < entries.length; i++) { + const entry = entries[i] + if (entry.isIntersecting) { + triggerEvent(elt, 'intersect') + break + } + } + }, observerOptions) + observer.observe(asElement(elt)) + addEventListener(asElement(elt), handler, nodeData, triggerSpec) + } else if (triggerSpec.trigger === 'load') { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent('load', { elt }))) { + loadImmediately(asElement(elt), handler, nodeData, triggerSpec.delay) + } + } else if (triggerSpec.pollInterval > 0) { + nodeData.polling = true + processPolling(asElement(elt), handler, triggerSpec) + } else { + addEventListener(elt, handler, nodeData, triggerSpec) + } + } + + /** + * @param {Node} node + * @returns {boolean} + */ + function shouldProcessHxOn(node) { + const elt = asElement(node) + if (!elt) { + return false + } + const attributes = elt.attributes + for (let j = 0; j < attributes.length; j++) { + const attrName = attributes[j].name + if (startsWith(attrName, 'hx-on:') || startsWith(attrName, 'data-hx-on:') || + startsWith(attrName, 'hx-on-') || startsWith(attrName, 'data-hx-on-')) { + return true + } + } + return false + } + + /** + * @param {Node} elt + * @returns {Element[]} + */ + const HX_ON_QUERY = new XPathEvaluator() + .createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + + ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]') + + function processHXOnRoot(elt, elements) { + if (shouldProcessHxOn(elt)) { + elements.push(asElement(elt)) + } + const iter = HX_ON_QUERY.evaluate(elt) + let node = null + while (node = iter.iterateNext()) elements.push(asElement(node)) + } + + function findHxOnWildcardElements(elt) { + /** @type {Element[]} */ + const elements = [] + if (elt instanceof DocumentFragment) { + for (const child of elt.childNodes) { + processHXOnRoot(child, elements) + } + } else { + processHXOnRoot(elt, elements) + } + return elements + } + + /** + * @param {Element} elt + * @returns {NodeListOf<Element>|[]} + */ + function findElementsToProcess(elt) { + if (elt.querySelectorAll) { + const boostedSelector = ', [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]' + + const extensionSelectors = [] + for (const e in extensions) { + const extension = extensions[e] + if (extension.getSelectors) { + var selectors = extension.getSelectors() + if (selectors) { + extensionSelectors.push(selectors) + } + } + } + + const results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit']," + + ' [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]' + extensionSelectors.flat().map(s => ', ' + s).join('')) + + return results + } else { + return [] + } + } + + /** + * Handle submit buttons/inputs that have the form attribute set + * see https://developer.mozilla.org/docs/Web/HTML/Element/button + * @param {Event} evt + */ + function maybeSetLastButtonClicked(evt) { + const elt = /** @type {HTMLButtonElement|HTMLInputElement} */ (closest(asElement(evt.target), "button, input[type='submit']")) + const internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = elt + } + } + + /** + * @param {Event} evt + */ + function maybeUnsetLastButtonClicked(evt) { + const internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = null + } + } + + /** + * @param {Event} evt + * @returns {HtmxNodeInternalData|undefined} + */ + function getRelatedFormData(evt) { + const elt = closest(asElement(evt.target), "button, input[type='submit']") + if (!elt) { + return + } + const form = resolveTarget('#' + getRawAttribute(elt, 'form'), elt.getRootNode()) || closest(elt, 'form') + if (!form) { + return + } + return getInternalData(form) + } + + /** + * @param {EventTarget} elt + */ + function initButtonTracking(elt) { + // need to handle both click and focus in: + // focusin - in case someone tabs in to a button and hits the space bar + // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + elt.addEventListener('click', maybeSetLastButtonClicked) + elt.addEventListener('focusin', maybeSetLastButtonClicked) + elt.addEventListener('focusout', maybeUnsetLastButtonClicked) + } + + /** + * @param {Element} elt + * @param {string} eventName + * @param {string} code + */ + function addHxOnEventHandler(elt, eventName, code) { + const nodeData = getInternalData(elt) + if (!Array.isArray(nodeData.onHandlers)) { + nodeData.onHandlers = [] + } + let func + /** @type EventListener */ + const listener = function(e) { + maybeEval(elt, function() { + if (eltIsDisabled(elt)) { + return + } + if (!func) { + func = new Function('event', code) + } + func.call(elt, e) + }) + } + elt.addEventListener(eventName, listener) + nodeData.onHandlers.push({ event: eventName, listener }) + } + + /** + * @param {Element} elt + */ + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (let i = 0; i < elt.attributes.length; i++) { + const name = elt.attributes[i].name + const value = elt.attributes[i].value + if (startsWith(name, 'hx-on') || startsWith(name, 'data-hx-on')) { + const afterOnPosition = name.indexOf('-on') + 3 + const nextChar = name.slice(afterOnPosition, afterOnPosition + 1) + if (nextChar === '-' || nextChar === ':') { + let eventName = name.slice(afterOnPosition + 1) + // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support + if (startsWith(eventName, ':')) { + eventName = 'htmx' + eventName + } else if (startsWith(eventName, '-')) { + eventName = 'htmx:' + eventName.slice(1) + } else if (startsWith(eventName, 'htmx-')) { + eventName = 'htmx:' + eventName.slice(5) + } + + addHxOnEventHandler(elt, eventName, value) + } + } + } + } + + /** + * @param {Element|HTMLInputElement} elt + */ + function initNode(elt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + const nodeData = getInternalData(elt) + if (nodeData.initHash !== attributeHash(elt)) { + // clean up any previously processed info + deInitNode(elt) + + nodeData.initHash = attributeHash(elt) + + triggerEvent(elt, 'htmx:beforeProcessNode') + + // @ts-ignore value will be undefined for non-input elements, which is fine + if (elt.value) { + // @ts-ignore + nodeData.lastValue = elt.value + } + + const triggerSpecs = getTriggerSpecs(elt) + const hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs) + + if (!hasExplicitHttpAction) { + if (getClosestAttributeValue(elt, 'hx-boost') === 'true') { + boostElement(elt, nodeData, triggerSpecs) + } else if (hasAttribute(elt, 'hx-trigger')) { + triggerSpecs.forEach(function(triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function() { + }) + }) + } + } + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + if (elt.tagName === 'FORM' || (getRawAttribute(elt, 'type') === 'submit' && hasAttribute(elt, 'form'))) { + initButtonTracking(elt) + } - var headers = getHeaders(elt, target, promptResponse); - - if (verb !== 'get' && !usesFormData(elt)) { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; - } + triggerEvent(elt, 'htmx:afterProcessNode') + } + } + + /** + * Processes new content, enabling htmx behavior. This can be useful if you have content that is added to the DOM outside of the normal htmx request cycle but still want htmx attributes to work. + * + * @see https://htmx.org/api/#process + * + * @param {Element|string} elt element to process + */ + function processNode(elt) { + elt = resolveTarget(elt) + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + initNode(elt) + forEach(findElementsToProcess(elt), function(child) { initNode(child) }) + forEach(findHxOnWildcardElements(elt), processHxOnWildcard) + } + + //= =================================================================== + // Event/Log Support + //= =================================================================== + + /** + * @param {string} str + * @returns {string} + */ + function kebabEventName(str) { + return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase() + } + + /** + * @param {string} eventName + * @param {any} detail + * @returns {CustomEvent} + */ + function makeEvent(eventName, detail) { + let evt + if (window.CustomEvent && typeof window.CustomEvent === 'function') { + // TODO: `composed: true` here is a hack to make global event handlers work with events in shadow DOM + // This breaks expected encapsulation but needs to be here until decided otherwise by core devs + evt = new CustomEvent(eventName, { bubbles: true, cancelable: true, composed: true, detail }) + } else { + evt = getDocument().createEvent('CustomEvent') + evt.initCustomEvent(eventName, true, true, detail) + } + return evt + } + + /** + * @param {EventTarget|string} elt + * @param {string} eventName + * @param {any=} detail + */ + function triggerErrorEvent(elt, eventName, detail) { + triggerEvent(elt, eventName, mergeObjects({ error: eventName }, detail)) + } + + /** + * @param {string} eventName + * @returns {boolean} + */ + function ignoreEventForLogging(eventName) { + return eventName === 'htmx:afterProcessNode' + } + + /** + * `withExtensions` locates all active extensions for a provided element, then + * executes the provided function using each of the active extensions. It should + * be called internally at every extendable execution point in htmx. + * + * @param {Element} elt + * @param {(extension:HtmxExtension) => void} toDo + * @returns void + */ + function withExtensions(elt, toDo) { + forEach(getExtensions(elt), function(extension) { + try { + toDo(extension) + } catch (e) { + logError(e) + } + }) + } + + function logError(msg) { + if (console.error) { + console.error(msg) + } else if (console.log) { + console.log('ERROR: ', msg) + } + } + + /** + * Triggers a given event on an element + * + * @see https://htmx.org/api/#trigger + * + * @param {EventTarget|string} elt the element to trigger the event on + * @param {string} eventName the name of the event to trigger + * @param {any=} detail details for the event + * @returns {boolean} + */ + function triggerEvent(elt, eventName, detail) { + elt = resolveTarget(elt) + if (detail == null) { + detail = {} + } + detail.elt = elt + const event = makeEvent(eventName, detail) + if (htmx.logger && !ignoreEventForLogging(eventName)) { + htmx.logger(elt, eventName, detail) + } + if (detail.error) { + logError(detail.error) + triggerEvent(elt, 'htmx:error', { errorInfo: detail }) + } + let eventResult = elt.dispatchEvent(event) + const kebabName = kebabEventName(eventName) + if (eventResult && kebabName !== eventName) { + const kebabedEvent = makeEvent(kebabName, event.detail) + eventResult = eventResult && elt.dispatchEvent(kebabedEvent) + } + withExtensions(asElement(elt), function(extension) { + eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) + }) + return eventResult + } + + //= =================================================================== + // History Support + //= =================================================================== + let currentPathForHistory = location.pathname + location.search + + /** + * @returns {Element} + */ + function getHistoryElement() { + const historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]') + return historyElt || getDocument().body + } + + /** + * @param {string} url + * @param {Element} rootElt + */ + function saveToHistoryCache(url, rootElt) { + if (!canAccessLocalStorage()) { + return + } - if (etc.headers) { - headers = mergeObjects(headers, etc.headers); - } - var results = getInputValues(elt, verb); - var errors = results.errors; - var rawParameters = results.values; - if (etc.values) { - rawParameters = mergeObjects(rawParameters, etc.values); - } - var expressionVars = getExpressionVars(elt); - var allParameters = mergeObjects(rawParameters, expressionVars); - var filteredParameters = filterValues(allParameters, elt); + // get state to save + const innerHTML = cleanInnerHtmlForHistory(rootElt) + const title = getDocument().title + const scroll = window.scrollY - if (htmx.config.getCacheBusterParam && verb === 'get') { - filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true"; - } + if (htmx.config.historyCacheSize <= 0) { + // make sure that an eventually already existing cache is purged + localStorage.removeItem('htmx-history-cache') + return + } - // behavior of anchors w/ empty href is to use the current URL - if (path == null || path === "") { - path = getDocument().location.href; - } + url = normalizePath(url) + const historyCache = parseJSON(localStorage.getItem('htmx-history-cache')) || [] + for (let i = 0; i < historyCache.length; i++) { + if (historyCache[i].url === url) { + historyCache.splice(i, 1) + break + } + } - var requestAttrValues = getValuesForElement(elt, 'hx-request'); + /** @type HtmxHistoryItem */ + const newHistoryItem = { url, content: innerHTML, title, scroll } - var eltIsBoosted = getInternalData(elt).boosted; + triggerEvent(getDocument().body, 'htmx:historyItemCreated', { item: newHistoryItem, cache: historyCache }) - var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + historyCache.push(newHistoryItem) + while (historyCache.length > htmx.config.historyCacheSize) { + historyCache.shift() + } - var requestConfig = { - boosted: eltIsBoosted, - useUrlParams: useUrlParams, - parameters: filteredParameters, - unfilteredParameters: allParameters, - headers:headers, - target:target, - verb:verb, - errors:errors, - withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, - timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, - path:path, - triggeringEvent:event - }; + // keep trying to save the cache until it succeeds or is empty + while (historyCache.length > 0) { + try { + localStorage.setItem('htmx-history-cache', JSON.stringify(historyCache)) + break + } catch (e) { + triggerErrorEvent(getDocument().body, 'htmx:historyCacheError', { cause: e, cache: historyCache }) + historyCache.shift() // shrink the cache and retry + } + } + } + + /** + * @typedef {Object} HtmxHistoryItem + * @property {string} url + * @property {string} content + * @property {string} title + * @property {number} scroll + */ + + /** + * @param {string} url + * @returns {HtmxHistoryItem|null} + */ + function getCachedHistory(url) { + if (!canAccessLocalStorage()) { + return null + } - if(!triggerEvent(elt, 'htmx:configRequest', requestConfig)){ - maybeCall(resolve); - endRequestLock(); - return promise; - } + url = normalizePath(url) - // copy out in case the object was overwritten - path = requestConfig.path; - verb = requestConfig.verb; - headers = requestConfig.headers; - filteredParameters = requestConfig.parameters; - errors = requestConfig.errors; - useUrlParams = requestConfig.useUrlParams; - - if(errors && errors.length > 0){ - triggerEvent(elt, 'htmx:validation:halted', requestConfig) - maybeCall(resolve); - endRequestLock(); - return promise; - } + const historyCache = parseJSON(localStorage.getItem('htmx-history-cache')) || [] + for (let i = 0; i < historyCache.length; i++) { + if (historyCache[i].url === url) { + return historyCache[i] + } + } + return null + } + + /** + * @param {Element} elt + * @returns {string} + */ + function cleanInnerHtmlForHistory(elt) { + const className = htmx.config.requestClass + const clone = /** @type Element */ (elt.cloneNode(true)) + forEach(findAll(clone, '.' + className), function(child) { + removeClassFromElement(child, className) + }) + return clone.innerHTML + } + + function saveCurrentPageToHistory() { + const elt = getHistoryElement() + const path = currentPathForHistory || location.pathname + location.search + + // Allow history snapshot feature to be disabled where hx-history="false" + // is present *anywhere* in the current document we're about to save, + // so we can prevent privileged data entering the cache. + // The page will still be reachable as a history entry, but htmx will fetch it + // live from the server onpopstate rather than look in the localStorage cache + let disableHistoryCache + try { + disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') + } catch (e) { + // IE11: insensitive modifier not supported so fallback to case sensitive selector + disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') + } + if (!disableHistoryCache) { + triggerEvent(getDocument().body, 'htmx:beforeHistorySave', { path, historyElt: elt }) + saveToHistoryCache(path, elt) + } - var splitPath = path.split("#"); - var pathNoAnchor = splitPath[0]; - var anchor = splitPath[1]; - - var finalPath = path - if (useUrlParams) { - finalPath = pathNoAnchor; - var values = Object.keys(filteredParameters).length !== 0; - if (values) { - if (finalPath.indexOf("?") < 0) { - finalPath += "?"; - } else { - finalPath += "&"; - } - finalPath += urlEncode(filteredParameters); - if (anchor) { - finalPath += "#" + anchor; - } - } - } + if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, getDocument().title, window.location.href) + } + + /** + * @param {string} path + */ + function pushUrlIntoHistory(path) { + // remove the cache buster parameter, if any + if (htmx.config.getCacheBusterParam) { + path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') + if (endsWith(path, '&') || endsWith(path, '?')) { + path = path.slice(0, -1) + } + } + if (htmx.config.historyEnabled) { + history.pushState({ htmx: true }, '', path) + } + currentPathForHistory = path + } + + /** + * @param {string} path + */ + function replaceUrlInHistory(path) { + if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, '', path) + currentPathForHistory = path + } + + /** + * @param {HtmxSettleTask[]} tasks + */ + function settleImmediately(tasks) { + forEach(tasks, function(task) { + task.call(undefined) + }) + } + + /** + * @param {string} path + */ + function loadHistoryFromServer(path) { + const request = new XMLHttpRequest() + const details = { path, xhr: request } + triggerEvent(getDocument().body, 'htmx:historyCacheMiss', details) + request.open('GET', path, true) + request.setRequestHeader('HX-Request', 'true') + request.setRequestHeader('HX-History-Restore-Request', 'true') + request.setRequestHeader('HX-Current-URL', getDocument().location.href) + request.onload = function() { + if (this.status >= 200 && this.status < 400) { + triggerEvent(getDocument().body, 'htmx:historyCacheMissLoad', details) + const fragment = makeFragment(this.response) + /** @type ParentNode */ + const content = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment + const historyElement = getHistoryElement() + const settleInfo = makeSettleInfo(historyElement) + handleTitle(fragment.title) + + swapInnerHTML(historyElement, content, settleInfo) + settleImmediately(settleInfo.tasks) + currentPathForHistory = path + triggerEvent(getDocument().body, 'htmx:historyRestore', { path, cacheMiss: true, serverResponse: this.response }) + } else { + triggerErrorEvent(getDocument().body, 'htmx:historyCacheMissLoadError', details) + } + } + request.send() + } + + /** + * @param {string} [path] + */ + function restoreHistory(path) { + saveCurrentPageToHistory() + path = path || location.pathname + location.search + const cached = getCachedHistory(path) + if (cached) { + const fragment = makeFragment(cached.content) + const historyElement = getHistoryElement() + const settleInfo = makeSettleInfo(historyElement) + handleTitle(fragment.title) + swapInnerHTML(historyElement, fragment, settleInfo) + settleImmediately(settleInfo.tasks) + getWindow().setTimeout(function() { + window.scrollTo(0, cached.scroll) + }, 0) // next 'tick', so browser has time to render layout + currentPathForHistory = path + triggerEvent(getDocument().body, 'htmx:historyRestore', { path, item: cached }) + } else { + if (htmx.config.refreshOnHistoryMiss) { + // @ts-ignore: optional parameter in reload() function throws error + // noinspection JSUnresolvedReference + window.location.reload(true) + } else { + loadHistoryFromServer(path) + } + } + } + + /** + * @param {Element} elt + * @returns {Element[]} + */ + function addRequestIndicatorClasses(elt) { + let indicators = /** @type Element[] */ (findAttributeTargets(elt, 'hx-indicator')) + if (indicators == null) { + indicators = [elt] + } + forEach(indicators, function(ic) { + const internalData = getInternalData(ic) + internalData.requestCount = (internalData.requestCount || 0) + 1 + ic.classList.add.call(ic.classList, htmx.config.requestClass) + }) + return indicators + } + + /** + * @param {Element} elt + * @returns {Element[]} + */ + function disableElements(elt) { + let disabledElts = /** @type Element[] */ (findAttributeTargets(elt, 'hx-disabled-elt')) + if (disabledElts == null) { + disabledElts = [] + } + forEach(disabledElts, function(disabledElement) { + const internalData = getInternalData(disabledElement) + internalData.requestCount = (internalData.requestCount || 0) + 1 + disabledElement.setAttribute('disabled', '') + }) + return disabledElts + } + + /** + * @param {Element[]} indicators + * @param {Element[]} disabled + */ + function removeRequestIndicators(indicators, disabled) { + forEach(indicators, function(ic) { + const internalData = getInternalData(ic) + internalData.requestCount = (internalData.requestCount || 0) - 1 + if (internalData.requestCount === 0) { + ic.classList.remove.call(ic.classList, htmx.config.requestClass) + } + }) + forEach(disabled, function(disabledElement) { + const internalData = getInternalData(disabledElement) + internalData.requestCount = (internalData.requestCount || 0) - 1 + if (internalData.requestCount === 0) { + disabledElement.removeAttribute('disabled') + } + }) + } + + //= =================================================================== + // Input Value Processing + //= =================================================================== + + /** + * @param {Element[]} processed + * @param {Element} elt + * @returns {boolean} + */ + function haveSeenNode(processed, elt) { + for (let i = 0; i < processed.length; i++) { + const node = processed[i] + if (node.isSameNode(elt)) { + return true + } + } + return false + } + + /** + * @param {Element} element + * @return {boolean} + */ + function shouldInclude(element) { + // Cast to trick tsc, undefined values will work fine here + const elt = /** @type {HTMLInputElement} */ (element) + if (elt.name === '' || elt.name == null || elt.disabled || closest(elt, 'fieldset[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 + } + + /** @param {string} name + * @param {string|Array|FormDataEntryValue} value + * @param {FormData} formData */ + function addValueToFormData(name, value, formData) { + if (name != null && value != null) { + if (Array.isArray(value)) { + value.forEach(function(v) { formData.append(name, v) }) + } else { + formData.append(name, value) + } + } + } + + /** @param {string} name + * @param {string|Array} value + * @param {FormData} formData */ + function removeValueFromFormData(name, value, formData) { + if (name != null && value != null) { + let values = formData.getAll(name) + if (Array.isArray(value)) { + values = values.filter(v => value.indexOf(v) < 0) + } else { + values = values.filter(v => v !== value) + } + formData.delete(name) + forEach(values, v => formData.append(name, v)) + } + } + + /** + * @param {Element[]} processed + * @param {FormData} formData + * @param {HtmxElementValidationError[]} errors + * @param {Element|HTMLInputElement|HTMLSelectElement|HTMLFormElement} elt + * @param {boolean} validate + */ + function processInputValue(processed, formData, errors, elt, validate) { + if (elt == null || haveSeenNode(processed, elt)) { + return + } else { + processed.push(elt) + } + if (shouldInclude(elt)) { + const name = getRawAttribute(elt, 'name') + // @ts-ignore value will be undefined for non-input elements, which is fine + let value = elt.value + if (elt instanceof HTMLSelectElement && elt.multiple) { + value = toArray(elt.querySelectorAll('option:checked')).map(function(e) { return (/** @type HTMLOptionElement */(e)).value }) + } + // include file inputs + if (elt instanceof HTMLInputElement && elt.files) { + value = toArray(elt.files) + } + addValueToFormData(name, value, formData) + if (validate) { + validateElement(elt, errors) + } + } + if (elt instanceof HTMLFormElement) { + forEach(elt.elements, function(input) { + if (processed.indexOf(input) >= 0) { + // The input has already been processed and added to the values, but the FormData that will be + // constructed right after on the form, will include it once again. So remove that input's value + // now to avoid duplicates + removeValueFromFormData(input.name, input.value, formData) + } else { + processed.push(input) + } + if (validate) { + validateElement(input, errors) + } + }) + new FormData(elt).forEach(function(value, name) { + if (value instanceof File && value.name === '') { + return // ignore no-name files + } + addValueToFormData(name, value, formData) + }) + } + } + + /** + * + * @param {Element} elt + * @param {HtmxElementValidationError[]} errors + */ + function validateElement(elt, errors) { + const element = /** @type {HTMLElement & ElementInternals} */ (elt) + if (element.willValidate) { + triggerEvent(element, 'htmx:validation:validate') + if (!element.checkValidity()) { + errors.push({ elt: element, message: element.validationMessage, validity: element.validity }) + triggerEvent(element, 'htmx:validation:failed', { message: element.validationMessage, validity: element.validity }) + } + } + } + + /** + * Override values in the one FormData with those from another. + * @param {FormData} receiver the formdata that will be mutated + * @param {FormData} donor the formdata that will provide the overriding values + * @returns {FormData} the {@linkcode receiver} + */ + function overrideFormData(receiver, donor) { + for (const key of donor.keys()) { + receiver.delete(key) + donor.getAll(key).forEach(function(value) { + receiver.append(key, value) + }) + } + return receiver + } + + /** + * @param {Element|HTMLFormElement} elt + * @param {HttpVerb} verb + * @returns {{errors: HtmxElementValidationError[], formData: FormData, values: Object}} + */ + function getInputValues(elt, verb) { + /** @type Element[] */ + const processed = [] + const formData = new FormData() + const priorityFormData = new FormData() + /** @type HtmxElementValidationError[] */ + const errors = [] + const internalData = getInternalData(elt) + if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { + internalData.lastButtonClicked = null + } - if (!verifyPath(elt, finalPath, requestConfig)) { - triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) - maybeCall(reject); - return promise; - }; + // only validate when form is directly submitted and novalidate or formnovalidate are not set + // or if the element has an explicit hx-validate="true" on it + let validate = (elt instanceof HTMLFormElement && elt.noValidate !== true) || getAttributeValue(elt, 'hx-validate') === 'true' + if (internalData.lastButtonClicked) { + validate = validate && internalData.lastButtonClicked.formNoValidate !== true + } - xhr.open(verb.toUpperCase(), finalPath, true); - xhr.overrideMimeType("text/html"); - xhr.withCredentials = requestConfig.withCredentials; - xhr.timeout = requestConfig.timeout; + // for a non-GET include the closest form + if (verb !== 'get') { + processInputValue(processed, priorityFormData, errors, closest(elt, 'form'), validate) + } - // request headers - if (requestAttrValues.noHeaders) { - // ignore all headers - } else { - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - var headerValue = headers[header]; - safelySetHeaderValue(xhr, header, headerValue); - } - } - } + // include the element itself + processInputValue(processed, formData, errors, elt, validate) - var responseInfo = { - xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select, - pathInfo: { - requestPath: path, - finalRequestPath: finalPath, - anchor: anchor - } - }; - - xhr.onload = function () { - try { - var hierarchy = hierarchyForElt(elt); - responseInfo.pathInfo.responsePath = getPathFromResponse(xhr); - responseHandler(elt, responseInfo); - removeRequestIndicators(indicators, disableElts); - triggerEvent(elt, 'htmx:afterRequest', responseInfo); - triggerEvent(elt, 'htmx:afterOnLoad', responseInfo); - // if the body no longer contains the element, trigger the event on the closest parent - // remaining in the DOM - if (!bodyContains(elt)) { - var secondaryTriggerElt = null; - while (hierarchy.length > 0 && secondaryTriggerElt == null) { - var parentEltInHierarchy = hierarchy.shift(); - if (bodyContains(parentEltInHierarchy)) { - secondaryTriggerElt = parentEltInHierarchy; - } - } - if (secondaryTriggerElt) { - triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo); - triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo); - } - } - maybeCall(resolve); - endRequestLock(); - } catch (e) { - triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({error:e}, responseInfo)); - throw e; - } - } - xhr.onerror = function () { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:sendError', responseInfo); - maybeCall(reject); - endRequestLock(); - } - xhr.onabort = function() { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo); - maybeCall(reject); - endRequestLock(); - } - xhr.ontimeout = function() { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:timeout', responseInfo); - maybeCall(reject); - endRequestLock(); - } - if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){ - maybeCall(resolve); - endRequestLock() - return promise - } - var indicators = addRequestIndicatorClasses(elt); - var disableElts = disableElements(elt); - - forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { - forEach([xhr, xhr.upload], function (target) { - target.addEventListener(eventName, function(event){ - triggerEvent(elt, "htmx:xhr:" + eventName, { - lengthComputable:event.lengthComputable, - loaded:event.loaded, - total:event.total - }); - }) - }); - }); - triggerEvent(elt, 'htmx:beforeSend', responseInfo); - var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) - xhr.send(params); - return promise; - } - - function determineHistoryUpdates(elt, responseInfo) { - - var xhr = responseInfo.xhr; - - //=========================================== - // First consult response headers - //=========================================== - var pathFromHeaders = null; - var typeFromHeaders = null; - if (hasHeader(xhr,/HX-Push:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Push"); - typeFromHeaders = "push"; - } else if (hasHeader(xhr,/HX-Push-Url:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Push-Url"); - typeFromHeaders = "push"; - } else if (hasHeader(xhr,/HX-Replace-Url:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url"); - typeFromHeaders = "replace"; - } + // if a button or submit was clicked last, include its value + if (internalData.lastButtonClicked || elt.tagName === 'BUTTON' || + (elt.tagName === 'INPUT' && getRawAttribute(elt, 'type') === 'submit')) { + const button = internalData.lastButtonClicked || (/** @type HTMLInputElement|HTMLButtonElement */(elt)) + const name = getRawAttribute(button, 'name') + addValueToFormData(name, button.value, priorityFormData) + } - // if there was a response header, that has priority - if (pathFromHeaders) { - if (pathFromHeaders === "false") { - return {} - } else { - return { - type: typeFromHeaders, - path : pathFromHeaders - } - } - } + // include any explicit includes + const includes = findAttributeTargets(elt, 'hx-include') + forEach(includes, function(node) { + processInputValue(processed, formData, errors, asElement(node), validate) + // if a non-form is included, include any input values within it + if (!matches(node, 'form')) { + forEach(asParentNode(node).querySelectorAll(INPUT_SELECTOR), function(descendant) { + processInputValue(processed, formData, errors, descendant, validate) + }) + } + }) + + // values from a <form> take precedence, overriding the regular values + overrideFormData(formData, priorityFormData) + + return { errors, formData, values: formDataProxy(formData) } + } + + /** + * @param {string} returnStr + * @param {string} name + * @param {any} realValue + * @returns {string} + */ + function appendParam(returnStr, name, realValue) { + if (returnStr !== '') { + returnStr += '&' + } + if (String(realValue) === '[object Object]') { + realValue = JSON.stringify(realValue) + } + const s = encodeURIComponent(realValue) + returnStr += encodeURIComponent(name) + '=' + s + return returnStr + } + + /** + * @param {FormData|Object} values + * @returns string + */ + function urlEncode(values) { + values = formDataFromObject(values) + let returnStr = '' + values.forEach(function(value, key) { + returnStr = appendParam(returnStr, key, value) + }) + return returnStr + } + + //= =================================================================== + // Ajax + //= =================================================================== + + /** + * @param {Element} elt + * @param {Element} target + * @param {string} prompt + * @returns {HtmxHeaderSpecification} + */ + function getHeaders(elt, target, prompt) { + /** @type HtmxHeaderSpecification */ + const headers = { + 'HX-Request': 'true', + 'HX-Trigger': getRawAttribute(elt, 'id'), + 'HX-Trigger-Name': getRawAttribute(elt, 'name'), + 'HX-Target': getAttributeValue(target, 'id'), + 'HX-Current-URL': getDocument().location.href + } + getValuesForElement(elt, 'hx-headers', false, headers) + if (prompt !== undefined) { + headers['HX-Prompt'] = prompt + } + if (getInternalData(elt).boosted) { + headers['HX-Boosted'] = 'true' + } + return headers + } + + /** + * filterValues takes an object containing form input values + * and returns a new object that only contains keys that are + * specified by the closest "hx-params" attribute + * @param {FormData} inputValues + * @param {Element} elt + * @returns {FormData} + */ + function filterValues(inputValues, elt) { + const paramsValue = getClosestAttributeValue(elt, 'hx-params') + if (paramsValue) { + if (paramsValue === 'none') { + return new FormData() + } else if (paramsValue === '*') { + return inputValues + } else if (paramsValue.indexOf('not ') === 0) { + forEach(paramsValue.substr(4).split(','), function(name) { + name = name.trim() + inputValues.delete(name) + }) + return inputValues + } else { + const newValues = new FormData() + forEach(paramsValue.split(','), function(name) { + name = name.trim() + if (inputValues.has(name)) { + inputValues.getAll(name).forEach(function(value) { newValues.append(name, value) }) + } + }) + return newValues + } + } else { + return inputValues + } + } + + /** + * @param {Element} elt + * @return {boolean} + */ + function isAnchorLink(elt) { + return !!getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf('#') >= 0 + } + + /** + * @param {Element} elt + * @param {HtmxSwapStyle} [swapInfoOverride] + * @returns {HtmxSwapSpecification} + */ + function getSwapSpecification(elt, swapInfoOverride) { + const swapInfo = swapInfoOverride || getClosestAttributeValue(elt, 'hx-swap') + /** @type HtmxSwapSpecification */ + const swapSpec = { + swapStyle: getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, + swapDelay: htmx.config.defaultSwapDelay, + settleDelay: htmx.config.defaultSettleDelay + } + if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { + swapSpec.show = 'top' + } + if (swapInfo) { + const split = splitOnWhitespace(swapInfo) + if (split.length > 0) { + for (let i = 0; i < split.length; i++) { + const value = split[i] + if (value.indexOf('swap:') === 0) { + swapSpec.swapDelay = parseInterval(value.substr(5)) + } else if (value.indexOf('settle:') === 0) { + swapSpec.settleDelay = parseInterval(value.substr(7)) + } else if (value.indexOf('transition:') === 0) { + swapSpec.transition = value.substr(11) === 'true' + } else if (value.indexOf('ignoreTitle:') === 0) { + swapSpec.ignoreTitle = value.substr(12) === 'true' + } else if (value.indexOf('scroll:') === 0) { + const scrollSpec = value.substr(7) + var splitSpec = scrollSpec.split(':') + const scrollVal = splitSpec.pop() + var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null + // @ts-ignore + swapSpec.scroll = scrollVal + swapSpec.scrollTarget = selectorVal + } else if (value.indexOf('show:') === 0) { + const showSpec = value.substr(5) + var splitSpec = showSpec.split(':') + const showVal = splitSpec.pop() + var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null + swapSpec.show = showVal + swapSpec.showTarget = selectorVal + } else if (value.indexOf('focus-scroll:') === 0) { + const focusScrollVal = value.substr('focus-scroll:'.length) + swapSpec.focusScroll = focusScrollVal == 'true' + } else if (i == 0) { + swapSpec.swapStyle = value + } else { + logError('Unknown modifier in hx-swap: ' + value) + } + } + } + } + return swapSpec + } + + /** + * @param {Element} elt + * @return {boolean} + */ + function usesFormData(elt) { + return getClosestAttributeValue(elt, 'hx-encoding') === 'multipart/form-data' || + (matches(elt, 'form') && getRawAttribute(elt, 'enctype') === 'multipart/form-data') + } + + /** + * @param {XMLHttpRequest} xhr + * @param {Element} elt + * @param {FormData} filteredParameters + * @returns {*|string|null} + */ + function encodeParamsForBody(xhr, elt, filteredParameters) { + let encodedParameters = null + withExtensions(elt, function(extension) { + if (encodedParameters == null) { + encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt) + } + }) + if (encodedParameters != null) { + return encodedParameters + } else { + if (usesFormData(elt)) { + // Force conversion to an actual FormData object in case filteredParameters is a formDataProxy + // See https://github.com/bigskysoftware/htmx/issues/2317 + return overrideFormData(new FormData(), formDataFromObject(filteredParameters)) + } else { + return urlEncode(filteredParameters) + } + } + } + + /** + * + * @param {Element} target + * @returns {HtmxSettleInfo} + */ + function makeSettleInfo(target) { + return { tasks: [], elts: [target] } + } + + /** + * @param {Element[]} content + * @param {HtmxSwapSpecification} swapSpec + */ + function updateScrollState(content, swapSpec) { + const first = content[0] + const last = content[content.length - 1] + if (swapSpec.scroll) { + var target = null + if (swapSpec.scrollTarget) { + target = asElement(querySelectorExt(first, swapSpec.scrollTarget)) + } + if (swapSpec.scroll === 'top' && (first || target)) { + target = target || first + target.scrollTop = 0 + } + if (swapSpec.scroll === 'bottom' && (last || target)) { + target = target || last + target.scrollTop = target.scrollHeight + } + } + if (swapSpec.show) { + var target = null + if (swapSpec.showTarget) { + let targetStr = swapSpec.showTarget + if (swapSpec.showTarget === 'window') { + targetStr = 'body' + } + target = asElement(querySelectorExt(first, targetStr)) + } + if (swapSpec.show === 'top' && (first || target)) { + target = target || first + // @ts-ignore For some reason tsc doesn't recognize "instant" as a valid option for now + target.scrollIntoView({ block: 'start', behavior: htmx.config.scrollBehavior }) + } + if (swapSpec.show === 'bottom' && (last || target)) { + target = target || last + // @ts-ignore For some reason tsc doesn't recognize "instant" as a valid option for now + target.scrollIntoView({ block: 'end', behavior: htmx.config.scrollBehavior }) + } + } + } + + /** + * @param {Element} elt + * @param {string} attr + * @param {boolean=} evalAsDefault + * @param {Object=} values + * @returns {Object} + */ + function getValuesForElement(elt, attr, evalAsDefault, values) { + if (values == null) { + values = {} + } + if (elt == null) { + return values + } + const attributeValue = getAttributeValue(elt, attr) + if (attributeValue) { + let str = attributeValue.trim() + let evaluateValue = evalAsDefault + if (str === 'unset') { + return null + } + if (str.indexOf('javascript:') === 0) { + str = str.substr(11) + evaluateValue = true + } else if (str.indexOf('js:') === 0) { + str = str.substr(3) + evaluateValue = true + } + if (str.indexOf('{') !== 0) { + str = '{' + str + '}' + } + let varsValues + if (evaluateValue) { + varsValues = maybeEval(elt, function() { return Function('return (' + str + ')')() }, {}) + } else { + varsValues = parseJSON(str) + } + for (const key in varsValues) { + if (varsValues.hasOwnProperty(key)) { + if (values[key] == null) { + values[key] = varsValues[key] + } + } + } + } + return getValuesForElement(asElement(parentElt(elt)), attr, evalAsDefault, values) + } + + /** + * @param {EventTarget|string} elt + * @param {() => any} toEval + * @param {any=} defaultVal + * @returns {any} + */ + function maybeEval(elt, toEval, defaultVal) { + if (htmx.config.allowEval) { + return toEval() + } else { + triggerErrorEvent(elt, 'htmx:evalDisallowedError') + return defaultVal + } + } + + /** + * @param {Element} elt + * @param {*?} expressionVars + * @returns + */ + function getHXVarsForElement(elt, expressionVars) { + return getValuesForElement(elt, 'hx-vars', true, expressionVars) + } + + /** + * @param {Element} elt + * @param {*?} expressionVars + * @returns + */ + function getHXValsForElement(elt, expressionVars) { + return getValuesForElement(elt, 'hx-vals', false, expressionVars) + } + + /** + * @param {Element} elt + * @returns {FormData} + */ + function getExpressionVars(elt) { + return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)) + } + + /** + * @param {XMLHttpRequest} xhr + * @param {string} header + * @param {string|null} headerValue + */ + function safelySetHeaderValue(xhr, header, headerValue) { + if (headerValue !== null) { + try { + xhr.setRequestHeader(header, headerValue) + } catch (e) { + // On an exception, try to set the header URI encoded instead + xhr.setRequestHeader(header, encodeURIComponent(headerValue)) + xhr.setRequestHeader(header + '-URI-AutoEncoded', 'true') + } + } + } + + /** + * @param {XMLHttpRequest} xhr + * @return {string} + */ + function getPathFromResponse(xhr) { + // NB: IE11 does not support this stuff + if (xhr.responseURL && typeof (URL) !== 'undefined') { + try { + const url = new URL(xhr.responseURL) + return url.pathname + url.search + } catch (e) { + triggerErrorEvent(getDocument().body, 'htmx:badResponseUrl', { url: xhr.responseURL }) + } + } + } + + /** + * @param {XMLHttpRequest} xhr + * @param {RegExp} regexp + * @return {boolean} + */ + function hasHeader(xhr, regexp) { + return regexp.test(xhr.getAllResponseHeaders()) + } + + /** + * Issues an htmx-style AJAX request + * + * @see https://htmx.org/api/#ajax + * + * @param {HttpVerb} verb + * @param {string} path the URL path to make the AJAX + * @param {Element|string|HtmxAjaxHelperContext} context the element to target (defaults to the **body**) | a selector for the target | a context object that contains any of the following + * @return {Promise<void>} Promise that resolves immediately if no request is sent, or when the request is complete + */ + function ajaxHelper(verb, path, context) { + verb = (/** @type HttpVerb */(verb.toLowerCase())) + if (context) { + if (context instanceof Element || typeof context === 'string') { + return issueAjaxRequest(verb, path, null, null, { + targetOverride: resolveTarget(context), + returnPromise: true + }) + } else { + return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, + { + handler: context.handler, + headers: context.headers, + values: context.values, + targetOverride: resolveTarget(context.target), + swapOverride: context.swap, + select: context.select, + returnPromise: true + }) + } + } else { + return issueAjaxRequest(verb, path, null, null, { + returnPromise: true + }) + } + } + + /** + * @param {Element} elt + * @return {Element[]} + */ + function hierarchyForElt(elt) { + const arr = [] + while (elt) { + arr.push(elt) + elt = elt.parentElement + } + return arr + } + + /** + * @param {Element} elt + * @param {string} path + * @param {HtmxRequestConfig} requestConfig + * @return {boolean} + */ + function verifyPath(elt, path, requestConfig) { + let sameHost + let url + if (typeof URL === 'function') { + url = new URL(path, document.location.href) + const origin = document.location.origin + sameHost = origin === url.origin + } else { + // IE11 doesn't support URL + url = path + sameHost = startsWith(path, document.location.origin) + } - //=========================================== - // Next resolve via DOM values - //=========================================== - var requestPath = responseInfo.pathInfo.finalRequestPath; - var responsePath = responseInfo.pathInfo.responsePath; - - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url"); - var elementIsBoosted = getInternalData(elt).boosted; - - var saveType = null; - var path = null; - - if (pushUrl) { - saveType = "push"; - path = pushUrl; - } else if (replaceUrl) { - saveType = "replace"; - path = replaceUrl; - } else if (elementIsBoosted) { - saveType = "push"; - path = responsePath || requestPath; // if there is no response path, go with the original request path - } + if (htmx.config.selfRequestsOnly) { + if (!sameHost) { + return false + } + } + return triggerEvent(elt, 'htmx:validateUrl', mergeObjects({ url, sameHost }, requestConfig)) + } + + /** + * @param {Object|FormData} obj + * @return {FormData} + */ + function formDataFromObject(obj) { + if (obj instanceof FormData) return obj + const formData = new FormData() + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + if (typeof obj[key].forEach === 'function') { + obj[key].forEach(function(v) { formData.append(key, v) }) + } else if (typeof obj[key] === 'object') { + formData.append(key, JSON.stringify(obj[key])) + } else { + formData.append(key, obj[key]) + } + } + } + return formData + } + + /** + * @param {FormData} formData + * @param {string} name + * @param {Array} array + * @returns {Array} + */ + function formDataArrayProxy(formData, name, array) { + // mutating the array should mutate the underlying form data + return new Proxy(array, { + get: function(target, key) { + if (typeof key === 'number') return target[key] + if (key === 'length') return target.length + if (key === 'push') { + return function(value) { + target.push(value) + formData.append(name, value) + } + } + if (typeof target[key] === 'function') { + return function() { + target[key].apply(target, arguments) + formData.delete(name) + target.forEach(function(v) { formData.append(name, v) }) + } + } + + if (target[key] && target[key].length === 1) { + return target[key][0] + } else { + return target[key] + } + }, + set: function(target, index, value) { + target[index] = value + formData.delete(name) + target.forEach(function(v) { formData.append(name, v) }) + return true + } + }) + } + + /** + * @param {FormData} formData + * @returns {Object} + */ + function formDataProxy(formData) { + return new Proxy(formData, { + get: function(target, name) { + if (typeof name === 'symbol') { + // Forward symbol calls to the FormData itself directly + return Reflect.get(target, name) + } + if (name === 'toJSON') { + // Support JSON.stringify call on proxy + return () => Object.fromEntries(formData) + } + if (name in target) { + // Wrap in function with apply to correctly bind the FormData context, as a direct call would result in an illegal invocation error + if (typeof target[name] === 'function') { + return function() { + return formData[name].apply(formData, arguments) + } + } else { + return target[name] + } + } + const array = formData.getAll(name) + // Those 2 undefined & single value returns are for retro-compatibility as we weren't using FormData before + if (array.length === 0) { + return undefined + } else if (array.length === 1) { + return array[0] + } else { + return formDataArrayProxy(target, name, array) + } + }, + set: function(target, name, value) { + if (typeof name !== 'string') { + return false + } + target.delete(name) + if (typeof value.forEach === 'function') { + value.forEach(function(v) { target.append(name, v) }) + } else { + target.append(name, value) + } + return true + }, + deleteProperty: function(target, name) { + if (typeof name === 'string') { + target.delete(name) + } + return true + }, + // Support Object.assign call from proxy + ownKeys: function(target) { + return Reflect.ownKeys(Object.fromEntries(target)) + }, + getOwnPropertyDescriptor: function(target, prop) { + return Reflect.getOwnPropertyDescriptor(Object.fromEntries(target), prop) + } + }) + } + + /** + * @param {HttpVerb} verb + * @param {string} path + * @param {Element} elt + * @param {Event} event + * @param {HtmxAjaxEtc} [etc] + * @param {boolean} [confirmed] + * @return {Promise<void>} + */ + function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { + let resolve = null + let reject = null + etc = etc != null ? etc : {} + if (etc.returnPromise && typeof Promise !== 'undefined') { + var promise = new Promise(function(_resolve, _reject) { + resolve = _resolve + reject = _reject + }) + } + if (elt == null) { + elt = getDocument().body + } + const responseHandler = etc.handler || handleAjaxResponse + const select = etc.select || null - if (path) { - // false indicates no push, return empty object - if (path === "false") { - return {}; - } + if (!bodyContains(elt)) { + // do not issue requests for elements removed from the DOM + maybeCall(resolve) + return promise + } + const target = etc.targetOverride || asElement(getTarget(elt)) + if (target == null || target == DUMMY_ELT) { + triggerErrorEvent(elt, 'htmx:targetError', { target: getAttributeValue(elt, 'hx-target') }) + maybeCall(reject) + return promise + } - // true indicates we want to follow wherever the server ended up sending us - if (path === "true") { - path = responsePath || requestPath; // if there is no response path, go with the original request path - } + let eltData = getInternalData(elt) + const submitter = eltData.lastButtonClicked - // restore any anchor associated with the request - if (responseInfo.pathInfo.anchor && - path.indexOf("#") === -1) { - path = path + "#" + responseInfo.pathInfo.anchor; - } + if (submitter) { + const buttonPath = getRawAttribute(submitter, 'formaction') + if (buttonPath != null) { + path = buttonPath + } - return { - type:saveType, - path: path - } - } else { - return {}; - } + const buttonVerb = getRawAttribute(submitter, 'formmethod') + if (buttonVerb != null) { + // ignore buttons with formmethod="dialog" + if (buttonVerb.toLowerCase() !== 'dialog') { + verb = (/** @type HttpVerb */(buttonVerb)) } + } + } - function handleAjaxResponse(elt, responseInfo) { - var xhr = responseInfo.xhr; - var target = responseInfo.target; - var etc = responseInfo.etc; - var requestConfig = responseInfo.requestConfig; - var select = responseInfo.select; + const confirmQuestion = getClosestAttributeValue(elt, 'hx-confirm') + // allow event-based confirmation w/ a callback + if (confirmed === undefined) { + const issueRequest = function(skipConfirmation) { + return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation) + } + const confirmDetails = { target, elt, path, verb, triggeringEvent: event, etc, issueRequest, question: confirmQuestion } + if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { + maybeCall(resolve) + return promise + } + } - if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; + let syncElt = elt + let syncStrategy = getClosestAttributeValue(elt, 'hx-sync') + let queueStrategy = null + let abortable = false + if (syncStrategy) { + const syncStrings = syncStrategy.split(':') + const selector = syncStrings[0].trim() + if (selector === 'this') { + syncElt = findThisElement(elt, 'hx-sync') + } else { + syncElt = asElement(querySelectorExt(elt, selector)) + } + // default to the drop strategy + syncStrategy = (syncStrings[1] || 'drop').trim() + eltData = getInternalData(syncElt) + if (syncStrategy === 'drop' && eltData.xhr && eltData.abortable !== true) { + maybeCall(resolve) + return promise + } else if (syncStrategy === 'abort') { + if (eltData.xhr) { + maybeCall(resolve) + return promise + } else { + abortable = true + } + } else if (syncStrategy === 'replace') { + triggerEvent(syncElt, 'htmx:abort') // abort the current request and continue + } else if (syncStrategy.indexOf('queue') === 0) { + const queueStrArray = syncStrategy.split(' ') + queueStrategy = (queueStrArray[1] || 'last').trim() + } + } - if (hasHeader(xhr, /HX-Trigger:/i)) { - handleTrigger(xhr, "HX-Trigger", elt); - } + if (eltData.xhr) { + if (eltData.abortable) { + triggerEvent(syncElt, 'htmx:abort') // abort the current request and continue + } else { + if (queueStrategy == null) { + if (event) { + const eventData = getInternalData(event) + if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { + queueStrategy = eventData.triggerSpec.queue + } + } + if (queueStrategy == null) { + queueStrategy = 'last' + } + } + if (eltData.queuedRequests == null) { + eltData.queuedRequests = [] + } + if (queueStrategy === 'first' && eltData.queuedRequests.length === 0) { + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } else if (queueStrategy === 'all') { + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } else if (queueStrategy === 'last') { + eltData.queuedRequests = [] // dump existing queue + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } + maybeCall(resolve) + return promise + } + } - if (hasHeader(xhr, /HX-Location:/i)) { - saveCurrentPageToHistory(); - var redirectPath = xhr.getResponseHeader("HX-Location"); - var swapSpec; - if (redirectPath.indexOf("{") === 0) { - swapSpec = parseJSON(redirectPath); - // what's the best way to throw an error if the user didn't include this - redirectPath = swapSpec['path']; - delete swapSpec['path']; - } - ajaxHelper('GET', redirectPath, swapSpec).then(function(){ - pushUrlIntoHistory(redirectPath); - }); - return; - } + const xhr = new XMLHttpRequest() + eltData.xhr = xhr + eltData.abortable = abortable + const endRequestLock = function() { + eltData.xhr = null + eltData.abortable = false + if (eltData.queuedRequests != null && + eltData.queuedRequests.length > 0) { + const queuedRequest = eltData.queuedRequests.shift() + queuedRequest() + } + } + const promptQuestion = getClosestAttributeValue(elt, 'hx-prompt') + if (promptQuestion) { + var promptResponse = prompt(promptQuestion) + // prompt returns null if cancelled and empty string if accepted with no entry + if (promptResponse === null || + !triggerEvent(elt, 'htmx:prompt', { prompt: promptResponse, target })) { + maybeCall(resolve) + endRequestLock() + return promise + } + } - var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh"); + if (confirmQuestion && !confirmed) { + if (!confirm(confirmQuestion)) { + maybeCall(resolve) + endRequestLock() + return promise + } + } - if (hasHeader(xhr, /HX-Redirect:/i)) { - location.href = xhr.getResponseHeader("HX-Redirect"); - shouldRefresh && location.reload(); - return; - } + let headers = getHeaders(elt, target, promptResponse) - if (shouldRefresh) { - location.reload(); - return; - } + if (verb !== 'get' && !usesFormData(elt)) { + headers['Content-Type'] = 'application/x-www-form-urlencoded' + } - if (hasHeader(xhr,/HX-Retarget:/i)) { - if (xhr.getResponseHeader("HX-Retarget") === "this") { - responseInfo.target = elt; - } else { - responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget")); - } - } + if (etc.headers) { + headers = mergeObjects(headers, etc.headers) + } + const results = getInputValues(elt, verb) + let errors = results.errors + const rawFormData = results.formData + if (etc.values) { + overrideFormData(rawFormData, formDataFromObject(etc.values)) + } + const expressionVars = formDataFromObject(getExpressionVars(elt)) + const allFormData = overrideFormData(rawFormData, expressionVars) + let filteredFormData = filterValues(allFormData, elt) - var historyUpdate = determineHistoryUpdates(elt, responseInfo); - - // by default htmx only swaps on 200 return codes and does not swap - // on 204 'No Content' - // this can be ovverriden by responding to the htmx:beforeSwap event and - // overriding the detail.shouldSwap property - var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; - var serverResponse = xhr.response; - var isError = xhr.status >= 400; - var ignoreTitle = htmx.config.ignoreTitle - var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo); - if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; - - target = beforeSwapDetails.target; // allow re-targeting - serverResponse = beforeSwapDetails.serverResponse; // allow updating content - isError = beforeSwapDetails.isError; // allow updating error - ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title - - responseInfo.target = target; // Make updated target available to response events - responseInfo.failed = isError; // Make failed property available to response events - responseInfo.successful = !isError; // Make successful property available to response events - - if (beforeSwapDetails.shouldSwap) { - if (xhr.status === 286) { - cancelPolling(elt); - } + if (htmx.config.getCacheBusterParam && verb === 'get') { + filteredFormData.set('org.htmx.cache-buster', getRawAttribute(target, 'id') || 'true') + } - withExtensions(elt, function (extension) { - serverResponse = extension.transformResponse(serverResponse, xhr, elt); - }); + // behavior of anchors w/ empty href is to use the current URL + if (path == null || path === '') { + path = getDocument().location.href + } - // Save current page if there will be a history update - if (historyUpdate.type) { - saveCurrentPageToHistory(); - } + /** + * @type {Object} + * @property {boolean} [credentials] + * @property {number} [timeout] + * @property {boolean} [noHeaders] + */ + const requestAttrValues = getValuesForElement(elt, 'hx-request') + + const eltIsBoosted = getInternalData(elt).boosted + + let useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + + /** @type HtmxRequestConfig */ + const requestConfig = { + boosted: eltIsBoosted, + useUrlParams, + formData: filteredFormData, + parameters: formDataProxy(filteredFormData), + unfilteredFormData: allFormData, + unfilteredParameters: formDataProxy(allFormData), + headers, + target, + verb, + errors, + withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, + timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, + path, + triggeringEvent: event + } - var swapOverride = etc.swapOverride; - if (hasHeader(xhr,/HX-Reswap:/i)) { - swapOverride = xhr.getResponseHeader("HX-Reswap"); - } - var swapSpec = getSwapSpecification(elt, swapOverride); + if (!triggerEvent(elt, 'htmx:configRequest', requestConfig)) { + maybeCall(resolve) + endRequestLock() + return promise + } - if (swapSpec.hasOwnProperty('ignoreTitle')) { - ignoreTitle = swapSpec.ignoreTitle; - } + // copy out in case the object was overwritten + path = requestConfig.path + verb = requestConfig.verb + headers = requestConfig.headers + filteredFormData = formDataFromObject(requestConfig.parameters) + errors = requestConfig.errors + useUrlParams = requestConfig.useUrlParams + + if (errors && errors.length > 0) { + triggerEvent(elt, 'htmx:validation:halted', requestConfig) + maybeCall(resolve) + endRequestLock() + return promise + } - target.classList.add(htmx.config.swappingClass); - - // optional transition API promise callbacks - var settleResolve = null; - var settleReject = null; - - var doSwap = function () { - try { - var activeElt = document.activeElement; - var selectionInfo = {}; - try { - selectionInfo = { - elt: activeElt, - // @ts-ignore - start: activeElt ? activeElt.selectionStart : null, - // @ts-ignore - end: activeElt ? activeElt.selectionEnd : null - }; - } catch (e) { - // safari issue - see https://github.com/microsoft/playwright/issues/5894 - } - - var selectOverride; - if (select) { - selectOverride = select; - } - - if (hasHeader(xhr, /HX-Reselect:/i)) { - selectOverride = xhr.getResponseHeader("HX-Reselect"); - } - - // if we need to save history, do so, before swapping so that relative resources have the correct base URL - if (historyUpdate.type) { - triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)); - if (historyUpdate.type === "push") { - pushUrlIntoHistory(historyUpdate.path); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path}); - } else { - replaceUrlInHistory(historyUpdate.path); - triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path}); - } - } - - var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride); - - if (selectionInfo.elt && - !bodyContains(selectionInfo.elt) && - getRawAttribute(selectionInfo.elt, "id")) { - var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id")); - var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; - if (newActiveElt) { - // @ts-ignore - if (selectionInfo.start && newActiveElt.setSelectionRange) { - // @ts-ignore - try { - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); - } catch (e) { - // the setSelectionRange method is present on fields that don't support it, so just let this fail - } - } - newActiveElt.focus(focusOptions); - } - } - - target.classList.remove(htmx.config.swappingClass); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.add(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSwap', responseInfo); - }); - - if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); - } - - var doSettle = function () { - forEach(settleInfo.tasks, function (task) { - task.call(); - }); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.remove(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSettle', responseInfo); - }); - - if (responseInfo.pathInfo.anchor) { - var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor); - if(anchorTarget) { - anchorTarget.scrollIntoView({block:'start', behavior: "auto"}); - } - } - - if(settleInfo.title && !ignoreTitle) { - var titleElt = find("title"); - if(titleElt) { - titleElt.innerHTML = settleInfo.title; - } else { - window.document.title = settleInfo.title; - } - } - - updateScrollState(settleInfo.elts, swapSpec); - - if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); - } - maybeCall(settleResolve); - } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'htmx:swapError', responseInfo); - maybeCall(settleReject); - throw e; - } - }; - - var shouldTransition = htmx.config.globalViewTransitions - if(swapSpec.hasOwnProperty('transition')){ - shouldTransition = swapSpec.transition; - } + const splitPath = path.split('#') + const pathNoAnchor = splitPath[0] + const anchor = splitPath[1] + + let finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor + const hasValues = !filteredFormData.keys().next().done + if (hasValues) { + if (finalPath.indexOf('?') < 0) { + finalPath += '?' + } else { + finalPath += '&' + } + finalPath += urlEncode(filteredFormData) + if (anchor) { + finalPath += '#' + anchor + } + } + } - if(shouldTransition && - triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && - typeof Promise !== "undefined" && document.startViewTransition){ - var settlePromise = new Promise(function (_resolve, _reject) { - settleResolve = _resolve; - settleReject = _reject; - }); - // wrap the original doSwap() in a call to startViewTransition() - var innerDoSwap = doSwap; - doSwap = function() { - document.startViewTransition(function () { - innerDoSwap(); - return settlePromise; - }); - } - } + if (!verifyPath(elt, finalPath, requestConfig)) { + triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) + maybeCall(reject) + return promise + } + xhr.open(verb.toUpperCase(), finalPath, true) + xhr.overrideMimeType('text/html') + xhr.withCredentials = requestConfig.withCredentials + xhr.timeout = requestConfig.timeout - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); - } - } - if (isError) { - triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo)); - } + // request headers + if (requestAttrValues.noHeaders) { + // ignore all headers + } else { + for (const header in headers) { + if (headers.hasOwnProperty(header)) { + const headerValue = headers[header] + safelySetHeaderValue(xhr, header, headerValue) } + } + } - //==================================================================== - // Extensions API - //==================================================================== - - /** @type {Object<string, import("./htmx").HtmxExtension>} */ - var extensions = {}; - - /** - * extensionBase defines the default functions for all extensions. - * @returns {import("./htmx").HtmxExtension} - */ - function extensionBase() { - return { - init: function(api) {return null;}, - onEvent : function(name, evt) {return true;}, - transformResponse : function(text, xhr, elt) {return text;}, - isInlineSwap : function(swapStyle) {return false;}, - handleSwap : function(swapStyle, target, fragment, settleInfo) {return false;}, - encodeParameters : function(xhr, parameters, elt) {return null;} - } - } + /** @type {HtmxResponseInfo} */ + const responseInfo = { + xhr, + target, + requestConfig, + etc, + boosted: eltIsBoosted, + select, + pathInfo: { + requestPath: path, + finalRequestPath: finalPath, + responsePath: null, + anchor + } + } - /** - * defineExtension initializes the extension and adds it to the htmx registry - * - * @param {string} name - * @param {import("./htmx").HtmxExtension} extension - */ - function defineExtension(name, extension) { - if(extension.init) { - extension.init(internalAPI) - } - extensions[name] = mergeObjects(extensionBase(), extension); - } + xhr.onload = function() { + try { + const hierarchy = hierarchyForElt(elt) + responseInfo.pathInfo.responsePath = getPathFromResponse(xhr) + responseHandler(elt, responseInfo) + removeRequestIndicators(indicators, disableElts) + triggerEvent(elt, 'htmx:afterRequest', responseInfo) + triggerEvent(elt, 'htmx:afterOnLoad', responseInfo) + // if the body no longer contains the element, trigger the event on the closest parent + // remaining in the DOM + if (!bodyContains(elt)) { + let secondaryTriggerElt = null + while (hierarchy.length > 0 && secondaryTriggerElt == null) { + const parentEltInHierarchy = hierarchy.shift() + if (bodyContains(parentEltInHierarchy)) { + secondaryTriggerElt = parentEltInHierarchy + } + } + if (secondaryTriggerElt) { + triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo) + triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo) + } + } + maybeCall(resolve) + endRequestLock() + } catch (e) { + triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({ error: e }, responseInfo)) + throw e + } + } + xhr.onerror = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:sendError', responseInfo) + maybeCall(reject) + endRequestLock() + } + xhr.onabort = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo) + maybeCall(reject) + endRequestLock() + } + xhr.ontimeout = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:timeout', responseInfo) + maybeCall(reject) + endRequestLock() + } + if (!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)) { + maybeCall(resolve) + endRequestLock() + return promise + } + var indicators = addRequestIndicatorClasses(elt) + var disableElts = disableElements(elt) + + forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { + forEach([xhr, xhr.upload], function(target) { + target.addEventListener(eventName, function(event) { + triggerEvent(elt, 'htmx:xhr:' + eventName, { + lengthComputable: event.lengthComputable, + loaded: event.loaded, + total: event.total + }) + }) + }) + }) + triggerEvent(elt, 'htmx:beforeSend', responseInfo) + const params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredFormData) + xhr.send(params) + return promise + } + + /** + * @typedef {Object} HtmxHistoryUpdate + * @property {string|null} [type] + * @property {string|null} [path] + */ + + /** + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + * @return {HtmxHistoryUpdate} + */ + function determineHistoryUpdates(elt, responseInfo) { + const xhr = responseInfo.xhr + + //= ========================================== + // First consult response headers + //= ========================================== + let pathFromHeaders = null + let typeFromHeaders = null + if (hasHeader(xhr, /HX-Push:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Push') + typeFromHeaders = 'push' + } else if (hasHeader(xhr, /HX-Push-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Push-Url') + typeFromHeaders = 'push' + } else if (hasHeader(xhr, /HX-Replace-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Replace-Url') + typeFromHeaders = 'replace' + } - /** - * removeExtension removes an extension from the htmx registry - * - * @param {string} name - */ - function removeExtension(name) { - delete extensions[name]; + // if there was a response header, that has priority + if (pathFromHeaders) { + if (pathFromHeaders === 'false') { + return {} + } else { + return { + type: typeFromHeaders, + path: pathFromHeaders } + } + } - /** - * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element - * - * @param {HTMLElement} elt - * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn - * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore - */ - function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + //= ========================================== + // Next resolve via DOM values + //= ========================================== + const requestPath = responseInfo.pathInfo.finalRequestPath + const responsePath = responseInfo.pathInfo.responsePath + + const pushUrl = getClosestAttributeValue(elt, 'hx-push-url') + const replaceUrl = getClosestAttributeValue(elt, 'hx-replace-url') + const elementIsBoosted = getInternalData(elt).boosted + + let saveType = null + let path = null + + if (pushUrl) { + saveType = 'push' + path = pushUrl + } else if (replaceUrl) { + saveType = 'replace' + path = replaceUrl + } else if (elementIsBoosted) { + saveType = 'push' + path = responsePath || requestPath // if there is no response path, go with the original request path + } - if (elt == undefined) { - return extensionsToReturn; - } - if (extensionsToReturn == undefined) { - extensionsToReturn = []; - } - if (extensionsToIgnore == undefined) { - extensionsToIgnore = []; - } - var extensionsForElement = getAttributeValue(elt, "hx-ext"); - if (extensionsForElement) { - forEach(extensionsForElement.split(","), function(extensionName){ - extensionName = extensionName.replace(/ /g, ''); - if (extensionName.slice(0, 7) == "ignore:") { - extensionsToIgnore.push(extensionName.slice(7)); - return; - } - if (extensionsToIgnore.indexOf(extensionName) < 0) { - var extension = extensions[extensionName]; - if (extension && extensionsToReturn.indexOf(extension) < 0) { - extensionsToReturn.push(extension); - } - } - }); - } - return getExtensions(parentElt(elt), extensionsToReturn, extensionsToIgnore); - } + if (path) { + // false indicates no push, return empty object + if (path === 'false') { + return {} + } + + // true indicates we want to follow wherever the server ended up sending us + if (path === 'true') { + path = responsePath || requestPath // if there is no response path, go with the original request path + } + + // restore any anchor associated with the request + if (responseInfo.pathInfo.anchor && path.indexOf('#') === -1) { + path = path + '#' + responseInfo.pathInfo.anchor + } + + return { + type: saveType, + path + } + } else { + return {} + } + } + + /** + * @param {HtmxResponseHandlingConfig} responseHandlingConfig + * @param {number} status + * @return {boolean} + */ + function codeMatches(responseHandlingConfig, status) { + var regExp = new RegExp(responseHandlingConfig.code) + return regExp.test(status.toString(10)) + } + + /** + * @param {XMLHttpRequest} xhr + * @return {HtmxResponseHandlingConfig} + */ + function resolveResponseHandling(xhr) { + for (var i = 0; i < htmx.config.responseHandling.length; i++) { + /** @type HtmxResponseHandlingConfig */ + var responseHandlingElement = htmx.config.responseHandling[i] + if (codeMatches(responseHandlingElement, xhr.status)) { + return responseHandlingElement + } + } + // no matches, return no swap + return { + swap: false + } + } + + /** + * @param {string} title + */ + function handleTitle(title) { + if (title) { + const titleElt = find('title') + if (titleElt) { + titleElt.innerHTML = title + } else { + window.document.title = title + } + } + } + + /** + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + */ + function handleAjaxResponse(elt, responseInfo) { + const xhr = responseInfo.xhr + let target = responseInfo.target + const etc = responseInfo.etc + const responseInfoSelect = responseInfo.select + + if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return + + if (hasHeader(xhr, /HX-Trigger:/i)) { + handleTriggerHeader(xhr, 'HX-Trigger', elt) + } - //==================================================================== - // Initialization - //==================================================================== - var isReady = false - getDocument().addEventListener('DOMContentLoaded', function() { - isReady = true - }) + if (hasHeader(xhr, /HX-Location:/i)) { + saveCurrentPageToHistory() + let redirectPath = xhr.getResponseHeader('HX-Location') + /** @type {HtmxAjaxHelperContext&{path:string}} */ + var redirectSwapSpec + if (redirectPath.indexOf('{') === 0) { + redirectSwapSpec = parseJSON(redirectPath) + // what's the best way to throw an error if the user didn't include this + redirectPath = redirectSwapSpec.path + delete redirectSwapSpec.path + } + ajaxHelper('get', redirectPath, redirectSwapSpec).then(function() { + pushUrlIntoHistory(redirectPath) + }) + return + } - /** - * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. - * - * This function uses isReady because there is no realiable way to ask the browswer whether - * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded - * firing and readystate=complete. - */ - function ready(fn) { - // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by - // some means other than the initial page load. - if (isReady || getDocument().readyState === 'complete') { - fn(); - } else { - getDocument().addEventListener('DOMContentLoaded', fn); - } - } + const shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && xhr.getResponseHeader('HX-Refresh') === 'true' - function insertIndicatorStyles() { - if (htmx.config.includeIndicatorStyles !== false) { - getDocument().head.insertAdjacentHTML("beforeend", - "<style>\ - ." + htmx.config.indicatorClass + "{opacity:0}\ - ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ - ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ - </style>"); - } - } + if (hasHeader(xhr, /HX-Redirect:/i)) { + location.href = xhr.getResponseHeader('HX-Redirect') + shouldRefresh && location.reload() + return + } - function getMetaConfig() { - var element = getDocument().querySelector('meta[name="htmx-config"]'); - if (element) { - // @ts-ignore - return parseJSON(element.content); - } else { - return null; - } - } + if (shouldRefresh) { + location.reload() + return + } - function mergeMetaConfig() { - var metaConfig = getMetaConfig(); - if (metaConfig) { - htmx.config = mergeObjects(htmx.config , metaConfig) - } - } + if (hasHeader(xhr, /HX-Retarget:/i)) { + if (xhr.getResponseHeader('HX-Retarget') === 'this') { + responseInfo.target = elt + } else { + responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget'))) + } + } - // initialize the document - ready(function () { - mergeMetaConfig(); - insertIndicatorStyles(); - var body = getDocument().body; - processNode(body); - var restoredElts = getDocument().querySelectorAll( - "[hx-trigger='restored'],[data-hx-trigger='restored']" - ); - body.addEventListener("htmx:abort", function (evt) { - var target = evt.target; - var internalData = getInternalData(target); - if (internalData && internalData.xhr) { - internalData.xhr.abort(); - } - }); - /** @type {(ev: PopStateEvent) => any} */ - const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null; - /** @type {(ev: PopStateEvent) => any} */ - window.onpopstate = function (event) { - if (event.state && event.state.htmx) { - restoreHistory(); - forEach(restoredElts, function(elt){ - triggerEvent(elt, 'htmx:restored', { - 'document': getDocument(), - 'triggerEvent': triggerEvent - }); - }); - } else { - if (originalPopstate) { - originalPopstate(event); - } - } - }; - setTimeout(function () { - triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event - body = null; // kill reference for gc - }, 0); + const historyUpdate = determineHistoryUpdates(elt, responseInfo) + + const responseHandling = resolveResponseHandling(xhr) + const shouldSwap = responseHandling.swap + let isError = !!responseHandling.error + let ignoreTitle = htmx.config.ignoreTitle || responseHandling.ignoreTitle + let selectOverride = responseHandling.select + if (responseHandling.target) { + responseInfo.target = asElement(querySelectorExt(elt, responseHandling.target)) + } + var swapOverride = etc.swapOverride + if (swapOverride == null && responseHandling.swapOverride) { + swapOverride = responseHandling.swapOverride + } + + // response headers override response handling config + if (hasHeader(xhr, /HX-Retarget:/i)) { + if (xhr.getResponseHeader('HX-Retarget') === 'this') { + responseInfo.target = elt + } else { + responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget'))) + } + } + if (hasHeader(xhr, /HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader('HX-Reswap') + } + + var serverResponse = xhr.response + /** @type HtmxBeforeSwapDetails */ + var beforeSwapDetails = mergeObjects({ + shouldSwap, + serverResponse, + isError, + ignoreTitle, + selectOverride + }, responseInfo) + + if (responseHandling.event && !triggerEvent(target, responseHandling.event, beforeSwapDetails)) return + + if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return + + target = beforeSwapDetails.target // allow re-targeting + serverResponse = beforeSwapDetails.serverResponse // allow updating content + isError = beforeSwapDetails.isError // allow updating error + ignoreTitle = beforeSwapDetails.ignoreTitle // allow updating ignoring title + selectOverride = beforeSwapDetails.selectOverride // allow updating select override + + responseInfo.target = target // Make updated target available to response events + responseInfo.failed = isError // Make failed property available to response events + responseInfo.successful = !isError // Make successful property available to response events + + if (beforeSwapDetails.shouldSwap) { + if (xhr.status === 286) { + cancelPolling(elt) + } + + withExtensions(elt, function(extension) { + serverResponse = extension.transformResponse(serverResponse, xhr, elt) + }) + + // Save current page if there will be a history update + if (historyUpdate.type) { + saveCurrentPageToHistory() + } + + if (hasHeader(xhr, /HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader('HX-Reswap') + } + var swapSpec = getSwapSpecification(elt, swapOverride) + + if (!swapSpec.hasOwnProperty('ignoreTitle')) { + swapSpec.ignoreTitle = ignoreTitle + } + + target.classList.add(htmx.config.swappingClass) + + // optional transition API promise callbacks + let settleResolve = null + let settleReject = null + + if (responseInfoSelect) { + selectOverride = responseInfoSelect + } + + if (hasHeader(xhr, /HX-Reselect:/i)) { + selectOverride = xhr.getResponseHeader('HX-Reselect') + } + + const selectOOB = getClosestAttributeValue(elt, 'hx-select-oob') + const select = getClosestAttributeValue(elt, 'hx-select') + + let doSwap = function() { + try { + // if we need to save history, do so, before swapping so that relative resources have the correct base URL + if (historyUpdate.type) { + triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)) + if (historyUpdate.type === 'push') { + pushUrlIntoHistory(historyUpdate.path) + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', { path: historyUpdate.path }) + } else { + replaceUrlInHistory(historyUpdate.path) + triggerEvent(getDocument().body, 'htmx:replacedInHistory', { path: historyUpdate.path }) + } + } + + swap(target, serverResponse, swapSpec, { + select: selectOverride || select, + selectOOB, + eventInfo: responseInfo, + anchor: responseInfo.pathInfo.anchor, + contextElement: elt, + afterSwapCallback: function() { + if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { + let finalElt = elt + if (!bodyContains(elt)) { + finalElt = getDocument().body + } + handleTriggerHeader(xhr, 'HX-Trigger-After-Swap', finalElt) + } + }, + afterSettleCallback: function() { + if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { + let finalElt = elt + if (!bodyContains(elt)) { + finalElt = getDocument().body + } + handleTriggerHeader(xhr, 'HX-Trigger-After-Settle', finalElt) + } + maybeCall(settleResolve) + } + }) + } catch (e) { + triggerErrorEvent(elt, 'htmx:swapError', responseInfo) + maybeCall(settleReject) + throw e + } + } + + let shouldTransition = htmx.config.globalViewTransitions + if (swapSpec.hasOwnProperty('transition')) { + shouldTransition = swapSpec.transition + } + + if (shouldTransition && + triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && + typeof Promise !== 'undefined' && + // @ts-ignore experimental feature atm + document.startViewTransition) { + const settlePromise = new Promise(function(_resolve, _reject) { + settleResolve = _resolve + settleReject = _reject }) + // wrap the original doSwap() in a call to startViewTransition() + const innerDoSwap = doSwap + doSwap = function() { + // @ts-ignore experimental feature atm + document.startViewTransition(function() { + innerDoSwap() + return settlePromise + }) + } + } + + if (swapSpec.swapDelay > 0) { + getWindow().setTimeout(doSwap, swapSpec.swapDelay) + } else { + doSwap() + } + } + if (isError) { + triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({ error: 'Response Status Error Code ' + xhr.status + ' from ' + responseInfo.pathInfo.requestPath }, responseInfo)) + } + } + + //= =================================================================== + // Extensions API + //= =================================================================== + + /** @type {Object<string, HtmxExtension>} */ + const extensions = {} + + /** + * extensionBase defines the default functions for all extensions. + * @returns {HtmxExtension} + */ + function extensionBase() { + return { + init: function(api) { return null }, + getSelectors: function() { return null }, + onEvent: function(name, evt) { return true }, + transformResponse: function(text, xhr, elt) { return text }, + isInlineSwap: function(swapStyle) { return false }, + handleSwap: function(swapStyle, target, fragment, settleInfo) { return false }, + encodeParameters: function(xhr, parameters, elt) { return null } + } + } + + /** + * defineExtension initializes the extension and adds it to the htmx registry + * + * @see https://htmx.org/api/#defineExtension + * + * @param {string} name the extension name + * @param {HtmxExtension} extension the extension definition + */ + function defineExtension(name, extension) { + if (extension.init) { + extension.init(internalAPI) + } + extensions[name] = mergeObjects(extensionBase(), extension) + } + + /** + * removeExtension removes an extension from the htmx registry + * + * @see https://htmx.org/api/#removeExtension + * + * @param {string} name + */ + function removeExtension(name) { + delete extensions[name] + } + + /** + * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element + * + * @param {Element} elt + * @param {HtmxExtension[]=} extensionsToReturn + * @param {string[]=} extensionsToIgnore + * @returns {HtmxExtension[]} + */ + function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + if (extensionsToReturn == undefined) { + extensionsToReturn = [] + } + if (elt == undefined) { + return extensionsToReturn + } + if (extensionsToIgnore == undefined) { + extensionsToIgnore = [] + } + const extensionsForElement = getAttributeValue(elt, 'hx-ext') + if (extensionsForElement) { + forEach(extensionsForElement.split(','), function(extensionName) { + extensionName = extensionName.replace(/ /g, '') + if (extensionName.slice(0, 7) == 'ignore:') { + extensionsToIgnore.push(extensionName.slice(7)) + return + } + if (extensionsToIgnore.indexOf(extensionName) < 0) { + const extension = extensions[extensionName] + if (extension && extensionsToReturn.indexOf(extension) < 0) { + extensionsToReturn.push(extension) + } + } + }) + } + return getExtensions(asElement(parentElt(elt)), extensionsToReturn, extensionsToIgnore) + } + + //= =================================================================== + // Initialization + //= =================================================================== + var isReady = false + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true + }) + + /** + * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. + * + * This function uses isReady because there is no reliable way to ask the browser whether + * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded + * firing and readystate=complete. + */ + function ready(fn) { + // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by + // some means other than the initial page load. + if (isReady || getDocument().readyState === 'complete') { + fn() + } else { + getDocument().addEventListener('DOMContentLoaded', fn) + } + } + + function insertIndicatorStyles() { + if (htmx.config.includeIndicatorStyles !== false) { + const nonceAttribute = htmx.config.inlineStyleNonce ? ` nonce="${htmx.config.inlineStyleNonce}"` : '' + getDocument().head.insertAdjacentHTML('beforeend', + '<style' + nonceAttribute + '>\ + .' + htmx.config.indicatorClass + '{opacity:0}\ + .' + htmx.config.requestClass + ' .' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\ + .' + htmx.config.requestClass + '.' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\ + </style>') + } + } + + function getMetaConfig() { + /** @type HTMLMetaElement */ + const element = getDocument().querySelector('meta[name="htmx-config"]') + if (element) { + return parseJSON(element.content) + } else { + return null + } + } - return htmx; + function mergeMetaConfig() { + const metaConfig = getMetaConfig() + if (metaConfig) { + htmx.config = mergeObjects(htmx.config, metaConfig) + } + } + + // initialize the document + ready(function() { + mergeMetaConfig() + insertIndicatorStyles() + let body = getDocument().body + processNode(body) + const restoredElts = getDocument().querySelectorAll( + "[hx-trigger='restored'],[data-hx-trigger='restored']" + ) + body.addEventListener('htmx:abort', function(evt) { + const target = evt.target + const internalData = getInternalData(target) + if (internalData && internalData.xhr) { + internalData.xhr.abort() + } + }) + /** @type {(ev: PopStateEvent) => any} */ + const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null + /** @type {(ev: PopStateEvent) => any} */ + window.onpopstate = function(event) { + if (event.state && event.state.htmx) { + restoreHistory() + forEach(restoredElts, function(elt) { + triggerEvent(elt, 'htmx:restored', { + document: getDocument(), + triggerEvent + }) + }) + } else { + if (originalPopstate) { + originalPopstate(event) + } + } } -)() -})); + getWindow().setTimeout(function() { + triggerEvent(body, 'htmx:load', {}) // give ready handlers a chance to load up before firing this event + body = null // kill reference for gc + }, 0) + }) + + return htmx +})() + +/** @typedef {'get'|'head'|'post'|'put'|'delete'|'connect'|'options'|'trace'|'patch'} HttpVerb */ + +/** + * @typedef {Object} SwapOptions + * @property {string} [select] + * @property {string} [selectOOB] + * @property {*} [eventInfo] + * @property {string} [anchor] + * @property {Element} [contextElement] + * @property {swapCallback} [afterSwapCallback] + * @property {swapCallback} [afterSettleCallback] + */ + +/** + * @callback swapCallback + */ + +/** + * @typedef {'innerHTML' | 'outerHTML' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'delete' | 'none' | string} HtmxSwapStyle + */ + +/** + * @typedef HtmxSwapSpecification + * @property {HtmxSwapStyle} swapStyle + * @property {number} swapDelay + * @property {number} settleDelay + * @property {boolean} [transition] + * @property {boolean} [ignoreTitle] + * @property {string} [head] + * @property {'top' | 'bottom'} [scroll] + * @property {string} [scrollTarget] + * @property {string} [show] + * @property {string} [showTarget] + * @property {boolean} [focusScroll] + */ + +/** + * @typedef {((this:Node, evt:Event) => boolean) & {source: string}} ConditionalFunction + */ + +/** + * @typedef {Object} HtmxTriggerSpecification + * @property {string} trigger + * @property {number} [pollInterval] + * @property {ConditionalFunction} [eventFilter] + * @property {boolean} [changed] + * @property {boolean} [once] + * @property {boolean} [consume] + * @property {number} [delay] + * @property {string} [from] + * @property {string} [target] + * @property {number} [throttle] + * @property {string} [queue] + * @property {string} [root] + * @property {string} [threshold] + */ + +/** + * @typedef {{elt: Element, message: string, validity: ValidityState}} HtmxElementValidationError + */ + +/** + * @typedef {Record<string, string>} HtmxHeaderSpecification + * @property {'true'} HX-Request + * @property {string|null} HX-Trigger + * @property {string|null} HX-Trigger-Name + * @property {string|null} HX-Target + * @property {string} HX-Current-URL + * @property {string} [HX-Prompt] + * @property {'true'} [HX-Boosted] + * @property {string} [Content-Type] + * @property {'true'} [HX-History-Restore-Request] + */ + +/** @typedef HtmxAjaxHelperContext + * @property {Element|string} [source] + * @property {Event} [event] + * @property {HtmxAjaxHandler} [handler] + * @property {Element|string} target + * @property {HtmxSwapStyle} [swap] + * @property {Object|FormData} [values] + * @property {Record<string,string>} [headers] + * @property {string} [select] + */ + +/** + * @typedef {Object} HtmxRequestConfig + * @property {boolean} boosted + * @property {boolean} useUrlParams + * @property {FormData} formData + * @property {Object} parameters formData proxy + * @property {FormData} unfilteredFormData + * @property {Object} unfilteredParameters unfilteredFormData proxy + * @property {HtmxHeaderSpecification} headers + * @property {Element} target + * @property {HttpVerb} verb + * @property {HtmxElementValidationError[]} errors + * @property {boolean} withCredentials + * @property {number} timeout + * @property {string} path + * @property {Event} triggeringEvent + */ + +/** + * @typedef {Object} HtmxResponseInfo + * @property {XMLHttpRequest} xhr + * @property {Element} target + * @property {HtmxRequestConfig} requestConfig + * @property {HtmxAjaxEtc} etc + * @property {boolean} boosted + * @property {string} select + * @property {{requestPath: string, finalRequestPath: string, responsePath: string|null, anchor: string}} pathInfo + * @property {boolean} [failed] + * @property {boolean} [successful] + */ + +/** + * @typedef {Object} HtmxAjaxEtc + * @property {boolean} [returnPromise] + * @property {HtmxAjaxHandler} [handler] + * @property {string} [select] + * @property {Element} [targetOverride] + * @property {HtmxSwapStyle} [swapOverride] + * @property {Record<string,string>} [headers] + * @property {Object|FormData} [values] + * @property {boolean} [credentials] + * @property {number} [timeout] + */ + +/** + * @typedef {Object} HtmxResponseHandlingConfig + * @property {string} [code] + * @property {boolean} swap + * @property {boolean} [error] + * @property {boolean} [ignoreTitle] + * @property {string} [select] + * @property {string} [target] + * @property {string} [swapOverride] + * @property {string} [event] + */ + +/** + * @typedef {HtmxResponseInfo & {shouldSwap: boolean, serverResponse: any, isError: boolean, ignoreTitle: boolean, selectOverride:string}} HtmxBeforeSwapDetails + */ + +/** + * @callback HtmxAjaxHandler + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + */ + +/** + * @typedef {(() => void)} HtmxSettleTask + */ + +/** + * @typedef {Object} HtmxSettleInfo + * @property {HtmxSettleTask[]} tasks + * @property {Element[]} elts + * @property {string} [title] + */ + +/** + * @typedef {Object} HtmxExtension + * @see https://htmx.org/extensions/#defining + * @property {(api: any) => void} init + * @property {(name: string, event: Event|CustomEvent) => boolean} onEvent + * @property {(text: string, xhr: XMLHttpRequest, elt: Element) => string} transformResponse + * @property {(swapStyle: HtmxSwapStyle) => boolean} isInlineSwap + * @property {(swapStyle: HtmxSwapStyle, target: Element, fragment: Node, settleInfo: HtmxSettleInfo) => boolean} handleSwap + * @property {(xhr: XMLHttpRequest, parameters: FormData, elt: Element) => *|string|null} encodeParameters + */ diff --git a/code/ch4_app/ch4_starter_video_collector/static/js/htmx.min.js b/code/ch4_app/ch4_starter_video_collector/static/js/htmx.min.js index 53bbdf6..d66acce 100644 --- a/code/ch4_app/ch4_starter_video_collector/static/js/htmx.min.js +++ b/code/ch4_app/ch4_starter_video_collector/static/js/htmx.min.js @@ -1,4 +1,2 @@ -// /////////////////////////////////////////////////////////////////// -// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js -// -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(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 a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/<body/.test(e)}function l(e){var t=!N(e);var r=A(e);var n=e;if(r==="head"){n=n.replace(S,"")}if(Q.config.useTemplateFragments&&t){var i=a("<body><template>"+n+"</template></body>",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a("<table>"+n+"</table>",1);case"col":return a("<table><colgroup>"+n+"</colgroup></table>",2);case"tr":return a("<table><tbody>"+n+"</tbody></table>",2);case"td":case"th":return a("<table><tbody><tr>"+n+"</tr></tbody></table>",3);case"script":case"style":return a("<div>"+n+"</div>",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function oe(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function X(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var Y=function(e,t){var r=re().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function we(t,r){oe(t.attributes,function(e){if(!r.hasAttribute(e.name)&&be(e.name)){t.removeAttribute(e.name)}});oe(r.attributes,function(e){if(be(e.name)){t.setAttribute(e.name,e.value)}})}function Se(e,t){var r=Fr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){b(e)}}return e==="outerHTML"}function Ee(e,i,a){var t="#"+ee(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a<i.length;a++){var o=i[a].split(":",2);var s=o[0].trim();if(s.indexOf("#")===0){s=s.substring(1)}var l=o[1]||"true";var u=t.querySelector("#"+s);if(u){Ee(l,u,r)}}}oe(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=te(e,"hx-swap-oob");if(t!=null){Ee(t,e,r)}})}function Re(e){oe(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=te(e,"id");var r=re().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function Te(o,e,s){oe(e.querySelectorAll("[id]"),function(e){var t=ee(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Le(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=He(n.name,t);t=He(n.value,t)}}}return t}function Ae(e){var t=ae(e);if(t.onHandlers){for(var r=0;r<t.onHandlers.length;r++){const n=t.onHandlers[r];e.removeEventListener(n.event,n.listener)}delete t.onHandlers}}function Ne(e){var t=ae(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){oe(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}Ae(e);oe(Object.keys(t),function(e){delete t[e]})}function p(e){ce(e,"htmx:beforeCleanupElement");Ne(e);if(e.children){oe(e.children,function(e){p(e)})}}function Ie(t,e,r){if(t.tagName==="BODY"){return Ue(t,e,r)}else{var n;var i=t.previousSibling;m(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}p(t);u(t).removeChild(t)}}function ke(e,t,r){return m(e,e.firstChild,t,r)}function Pe(e,t,r){return m(u(e),e,t,r)}function Me(e,t,r){return m(e,null,t,r)}function Xe(e,t,r){return m(u(e),e.nextSibling,t,r)}function De(e,t,r){p(e);return u(e).removeChild(e)}function Ue(e,t,r){var n=e.firstChild;m(e,n,t,r);if(n){while(n.nextSibling){p(n.nextSibling);e.removeChild(n.nextSibling)}p(n);e.removeChild(n)}}function Be(e,t,r){var n=r||ne(e,"hx-select");if(n){var i=re().createDocumentFragment();oe(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function Fe(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Ie(r,n,i);return;case"afterbegin":ke(r,n,i);return;case"beforebegin":Pe(r,n,i);return;case"beforeend":Me(r,n,i);return;case"afterend":Xe(r,n,i);return;case"delete":De(r,n,i);return;default:var a=Fr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Oe(f))}}}return}}catch(e){b(e)}}if(e==="innerHTML"){Ue(r,n,i)}else{Fe(Q.config.defaultSwapStyle,t,r,n,i)}}}function Ve(e){if(e.indexOf("<title")>-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){ce(r,s[l].trim(),[])}}}var ze=/\s/;var x=/[\s,]/;var $e=/[_$a-zA-Z]/;var We=/[_$a-zA-Z0-9]/;var Ge=['"',"'","/"];var Je=/[^\s]/;var Ze=/[{(]/;var Ke=/[})]/;function Ye(e){var t=[];var r=0;while(r<e.length){if($e.exec(e.charAt(r))){var n=r;while(We.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ge.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function Qe(e,t,r){return $e.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function et(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){xt(e,a[1],0)}if(a[0]==="send"){bt(e)}}}function xt(s,r,n){if(!se(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=Q.createWebSocket(r);t.onerror=function(e){fe(s,"htmx:wsError",{error:e,socket:t});yt(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a<i.length;a++){var o=i[a];Ee(te(o,"hx-swap-oob")||"true",o,r)}nr(r.tasks)})}function yt(e){if(!se(e)){ae(e).webSocket.close();return true}}function bt(u){var f=c(u,function(e){return ae(e).webSocket!=null});if(f){u.addEventListener(it(u)[0].trigger,function(e){var t=ae(f).webSocket;var r=xr(u,f);var n=dr(u,"post");var i=n.errors;var a=n.values;var o=Hr(u);var s=le(a,o);var l=yr(s,u);l["HEADERS"]=r;if(i&&i.length>0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){Et(e,a[1])}if(a[0]==="swap"){Ct(e,a[1])}}}function Et(t,e){var r=Q.createEventSource(e);r.onerror=function(e){fe(t,"htmx:sseError",{error:e,source:r});Tt(t)};ae(t).sseEventSource=r}function Ct(a,o){var s=c(a,Ot);if(s){var l=ae(s).sseEventSource;var u=function(e){if(Tt(s)){return}if(!se(a)){l.removeEventListener(o,u);return}var t=e.data;R(a,function(e){t=e.transformResponse(t,null,a)});var r=wr(a);var n=ye(a);var i=T(a);je(r.swapStyle,n,a,t,i);nr(i.tasks);ce(a,"htmx:sseMessage",e)};ae(a).sseListener=u;l.addEventListener(o,u)}else{fe(a,"htmx:noSSESourceError")}}function Rt(e,t,r){var n=c(e,Ot);if(n){var i=ae(n).sseEventSource;var a=function(){if(!Tt(n)){if(se(e)){t(e)}else{i.removeEventListener(r,a)}}};ae(e).sseListener=a;i.addEventListener(r,a)}else{fe(e,"htmx:noSSESourceError")}}function Tt(e){if(!se(e)){ae(e).sseEventSource.close();return true}}function Ot(e){return ae(e).sseEventSource!=null}function qt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n>0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){ce(n,"intersect");break}}},i);a.observe(n);ht(n,r,t,e)}else if(e.trigger==="load"){if(!ct(e,n,Wt("load",{elt:n}))){qt(n,r,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r<t.length;r++){var n=t[r].name;if(s(n,"hx-on:")||s(n,"data-hx-on:")||s(n,"hx-on-")||s(n,"data-hx-on-")){return true}}return false}function kt(e){var t=null;var r=[];if(It(e)){r.push(e)}if(document.evaluate){var n=document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]',e);while(t=n.iterateNext())r.push(t)}else{var i=e.getElementsByTagName("*");for(var a=0;a<i.length;a++){if(It(i[a])){r.push(i[a])}}}return r}function Pt(e){if(e.querySelectorAll){var t=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";var r=e.querySelectorAll(i+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Mt(e){var t=v(e.target,"button, input[type='submit']");var r=Dt(e);if(r){r.lastButtonClicked=t}}function Xt(e){var t=Dt(e);if(t){t.lastButtonClicked=null}}function Dt(e){var t=v(e.target,"button, input[type='submit']");if(!t){return}var r=g("#"+ee(t,"form"))||v(t,"form");if(!r){return}return ae(r)}function Ut(e){e.addEventListener("click",Mt);e.addEventListener("focusin",Mt);e.addEventListener("focusout",Xt)}function Bt(e){var t=Ye(e);var r=0;for(var n=0;n<t.length;n++){const i=t[n];if(i==="{"){r++}else if(i==="}"){r--}}return r}function Ft(t,e,r){var n=ae(t);if(!Array.isArray(n.onHandlers)){n.onHandlers=[]}var i;var a=function(e){return Tr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Vt(e){var t=te(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;t<e.attributes.length;t++){var r=e.attributes[t].name;var n=e.attributes[t].value;if(s(r,"hx-on")||s(r,"data-hx-on")){var i=r.indexOf("-on")+3;var a=r.slice(i,i+1);if(a==="-"||a===":"){var o=r.slice(i+1);if(s(o,":")){o="htmx"+o}else if(s(o,"-")){o="htmx:"+o.slice(1)}else if(s(o,"htmx-")){o="htmx:"+o.slice(5)}Ft(e,o,n)}}}}function _t(t){if(v(t,Q.config.disableSelector)){p(t);return}var r=ae(t);if(r.initHash!==Le(t)){Ne(t);r.initHash=Le(t);Vt(t);ce(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=it(t);var n=Ht(t,r,e);if(!n){if(ne(t,"hx-boost")==="true"){lt(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){Lt(t,e,r,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&o(t,"form")){Ut(t)}var i=te(t,"hx-sse");if(i){St(t,r,i)}var a=te(t,"hx-ws");if(a){pt(t,r,a)}ce(t,"htmx:afterProcessNode")}}function zt(e){e=g(e);if(v(e,Q.config.disableSelector)){p(e);return}_t(e);oe(Pt(e),function(e){_t(e)});oe(kt(e),jt)}function $t(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=re().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function fe(e,t,r){ce(e,t,le({error:t},r))}function Gt(e){return e==="htmx:afterProcessNode"}function R(e,t){oe(Fr(e),function(e){try{t(e)}catch(e){b(e)}})}function b(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ce(e,t,r){e=g(e);if(r==null){r={}}r["elt"]=e;var n=Wt(t,r);if(Q.logger&&!Gt(t)){Q.logger(e,t,r)}if(r.error){b(r.error);ce(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=$t(t);if(i&&a!==t){var o=Wt(a,n.detail);i=i&&e.dispatchEvent(o)}R(e,function(e){i=i&&(e.onEvent(t,n)!==false&&!n.defaultPrevented)});return i}var Jt=location.pathname+location.search;function Zt(){var e=re().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||re().body}function Kt(e,t,r,n){if(!U()){return}if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}e=B(e);var i=E(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};ce(re().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Qt(e){var t=Q.config.requestClass;var r=e.cloneNode(true);oe(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function er(){var e=Zt();var t=Jt||location.pathname+location.search;var r;try{r=re().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){r=re().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!r){ce(re().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Kt(t,Qt(e),re().title,window.scrollY)}if(Q.config.historyEnabled)history.replaceState({htmx:true},re().title,window.location.href)}function tr(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(G(e,"&")||G(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Jt=e}function rr(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Jt=e}function nr(e){oe(e,function(e){e.call()})}function ir(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};ce(re().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",re().location.href);e.onload=function(){if(this.status>=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function fr(e){if(e.name===""||e.name==null||e.disabled||v(e,"fieldset[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 cr(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function hr(t,r,n,e,i){if(e==null||ur(t,e)){return}else{t.push(e)}if(fr(e)){var a=ee(e,"name");var o=e.value;if(e.multiple&&e.tagName==="SELECT"){o=M(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=M(e.files)}cr(a,o,r);if(i){vr(e,n)}}if(h(e,"form")){var s=e.elements;oe(s,function(e){hr(t,r,n,e,i)})}}function vr(e,t){if(e.willValidate){ce(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});ce(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function dr(e,t){var r=[];var n={};var i={};var a=[];var o=ae(e);if(o.lastButtonClicked&&!se(o.lastButtonClicked)){o.lastButtonClicked=null}var s=h(e,"form")&&e.noValidate!==true||te(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){hr(r,i,a,v(e,"form"),s)}hr(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=ee(l,"name");cr(u,l.value,i)}var f=pe(e,"hx-include");oe(f,function(e){hr(r,n,a,e,s);if(!h(e,"form")){oe(e.querySelectorAll(rt),function(e){hr(r,n,a,e,s)})}});n=le(n,i);return{errors:a,values:n}}function gr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function mr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t=gr(t,r,e)})}else{t=gr(t,r,n)}}}return t}function pr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function xr(e,t,r){var n={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":re().location.href};Rr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ae(e).boosted){n["HX-Boosted"]="true"}return n}function yr(t,e){var r=ne(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){oe(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};oe(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function br(e){return ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=d(o.substr(5))}else if(o.indexOf("settle:")===0){n["settleDelay"]=d(o.substr(7))}else if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}else if(o.indexOf("ignoreTitle:")===0){n["ignoreTitle"]=o.substr(12)==="true"}else if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","<style> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file +// v2.0.0 from https://github.com/bigskysoftware/htmx/releases +var htmx=function(){"use strict";const Q={onLoad:null,process:null,on:null,off:null,trigger:null,ajax:null,find:null,findAll:null,closest:null,values:function(e,t){const n=cn(e,t||"post");return n.values},remove:null,addClass:null,removeClass:null,toggleClass:null,takeClass:null,swap:null,defineExtension:null,removeExtension:null,logAll:null,logNone:null,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",inlineStyleNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",scrollBehavior:"instant",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get","delete"],selfRequestsOnly:true,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null,disableInheritance:false,responseHandling:[{code:"204",swap:false},{code:"[23]..",swap:true},{code:"[45]..",swap:false,error:true}],allowNestedOobSwaps:true},parseInterval:null,_:null,version:"2.0.0"};Q.onLoad=$;Q.process=Dt;Q.on=be;Q.off=we;Q.trigger=he;Q.ajax=Hn;Q.find=r;Q.findAll=p;Q.closest=g;Q.remove=K;Q.addClass=W;Q.removeClass=o;Q.toggleClass=Y;Q.takeClass=ge;Q.swap=ze;Q.defineExtension=Un;Q.removeExtension=Bn;Q.logAll=z;Q.logNone=J;Q.parseInterval=d;Q._=_;const n={addTriggerHandler:Et,bodyContains:le,canAccessLocalStorage:j,findThisElement:Ee,filterValues:dn,swap:ze,hasAttribute:s,getAttributeValue:te,getClosestAttributeValue:re,getClosestMatch:T,getExpressionVars:Cn,getHeaders:hn,getInputValues:cn,getInternalData:ie,getSwapSpecification:pn,getTriggerSpecs:lt,getTarget:Ce,makeFragment:D,mergeObjects:ue,makeSettleInfo:xn,oobSwap:Te,querySelectorExt:fe,settleImmediately:Gt,shouldCancel:dt,triggerEvent:he,triggerErrorEvent:ae,withExtensions:Ut};const v=["get","post","put","delete","patch"];const R=v.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");const O=e("head");function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e instanceof Element&&e.getAttribute(t)}function s(e,t){return!!e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){const t=e.parentElement;if(!t&&e.parentNode instanceof ShadowRoot)return e.parentNode;return t}function ne(){return document}function H(e,t){return e.getRootNode?e.getRootNode({composed:t}):ne()}function T(e,t){while(e&&!t(e)){e=u(e)}return e||null}function q(e,t,n){const r=te(t,n);const o=te(t,"hx-disinherit");var i=te(t,"hx-inherit");if(e!==t){if(Q.config.disableInheritance){if(i&&(i==="*"||i.split(" ").indexOf(n)>=0)){return r}else{return null}}if(o&&(o==="*"||o.split(" ").indexOf(n)>=0)){return"unset"}}return r}function re(t,n){let r=null;T(t,function(e){return!!(r=q(t,ce(e),n))});if(r!=="unset"){return r}}function a(e,t){const n=e instanceof Element&&(e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector);return!!n&&n.call(e,t)}function L(e){const t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;const n=t.exec(e);if(n){return n[1].toLowerCase()}else{return""}}function N(e){const t=new DOMParser;return t.parseFromString(e,"text/html")}function A(e,t){while(t.childNodes.length>0){e.append(t.childNodes[0])}}function I(e){const t=ne().createElement("script");se(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}return t}function P(e){return e.matches("script")&&(e.type==="text/javascript"||e.type==="module"||e.type==="")}function k(e){Array.from(e.querySelectorAll("script")).forEach(e=>{if(P(e)){const t=I(e);const n=e.parentNode;try{n.insertBefore(t,e)}catch(e){w(e)}finally{e.remove()}}})}function D(e){const t=e.replace(O,"");const n=L(t);let r;if(n==="html"){r=new DocumentFragment;const i=N(e);A(r,i.body);r.title=i.title}else if(n==="body"){r=new DocumentFragment;const i=N(t);A(r,i.body);r.title=i.title}else{const i=N('<body><template class="internal-htmx-wrapper">'+t+"</template></body>");r=i.querySelector("template").content;r.title=i.title;var o=r.querySelector("title");if(o&&o.parentNode===r){o.remove();r.title=o.innerText}}if(r){if(Q.config.allowScriptTags){k(r)}else{r.querySelectorAll("script").forEach(e=>e.remove())}}return r}function oe(e){if(e){e()}}function t(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function M(e){return typeof e==="function"}function X(e){return t(e,"Object")}function ie(e){const t="htmx-internal-data";let n=e[t];if(!n){n=e[t]={}}return n}function F(t){const n=[];if(t){for(let e=0;e<t.length;e++){n.push(t[e])}}return n}function se(t,n){if(t){for(let e=0;e<t.length;e++){n(t[e])}}}function U(e){const t=e.getBoundingClientRect();const n=t.top;const r=t.bottom;return n<window.innerHeight&&r>=0}function le(e){const t=e.getRootNode&&e.getRootNode();if(t&&t instanceof window.ShadowRoot){return ne().body.contains(t.host)}else{return ne().body.contains(e)}}function B(e){return e.trim().split(/\s+/)}function ue(e,t){for(const n in t){if(t.hasOwnProperty(n)){e[n]=t[n]}}return e}function S(e){try{return JSON.parse(e)}catch(e){w(e);return null}}function j(){const e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function V(t){try{const e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function _(e){return vn(ne().body,function(){return eval(e)})}function $(t){const e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function z(){Q.logger=function(e,t,n){if(console){console.log(t,e,n)}}}function J(){Q.logger=null}function r(e,t){if(typeof e!=="string"){return e.querySelector(t)}else{return r(ne(),e)}}function p(e,t){if(typeof e!=="string"){return e.querySelectorAll(t)}else{return p(ne(),e)}}function E(){return window}function K(e,t){e=y(e);if(t){E().setTimeout(function(){K(e);e=null},t)}else{u(e).removeChild(e)}}function ce(e){return e instanceof Element?e:null}function G(e){return e instanceof HTMLElement?e:null}function Z(e){return typeof e==="string"?e:null}function h(e){return e instanceof Element||e instanceof Document||e instanceof DocumentFragment?e:null}function W(e,t,n){e=ce(y(e));if(!e){return}if(n){E().setTimeout(function(){W(e,t);e=null},n)}else{e.classList&&e.classList.add(t)}}function o(e,t,n){let r=ce(y(e));if(!r){return}if(n){E().setTimeout(function(){o(r,t);r=null},n)}else{if(r.classList){r.classList.remove(t);if(r.classList.length===0){r.removeAttribute("class")}}}}function Y(e,t){e=y(e);e.classList.toggle(t)}function ge(e,t){e=y(e);se(e.parentElement.children,function(e){o(e,t)});W(ce(e),t)}function g(e,t){e=ce(y(e));if(e&&e.closest){return e.closest(t)}else{do{if(e==null||a(e,t)){return e}}while(e=e&&ce(u(e)));return null}}function l(e,t){return e.substring(0,t.length)===t}function pe(e,t){return e.substring(e.length-t.length)===t}function i(e){const t=e.trim();if(l(t,"<")&&pe(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function m(e,t,n){e=y(e);if(t.indexOf("closest ")===0){return[g(ce(e),i(t.substr(8)))]}else if(t.indexOf("find ")===0){return[r(h(e),i(t.substr(5)))]}else if(t==="next"){return[ce(e).nextElementSibling]}else if(t.indexOf("next ")===0){return[me(e,i(t.substr(5)),!!n)]}else if(t==="previous"){return[ce(e).previousElementSibling]}else if(t.indexOf("previous ")===0){return[ye(e,i(t.substr(9)),!!n)]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else if(t==="root"){return[H(e,!!n)]}else if(t.indexOf("global ")===0){return m(e,t.slice(7),true)}else{return F(h(H(e,!!n)).querySelectorAll(i(t)))}}var me=function(t,e,n){const r=h(H(t,n)).querySelectorAll(e);for(let e=0;e<r.length;e++){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_PRECEDING){return o}}};var ye=function(t,e,n){const r=h(H(t,n)).querySelectorAll(e);for(let e=r.length-1;e>=0;e--){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_FOLLOWING){return o}}};function fe(e,t){if(typeof e!=="string"){return m(e,t)[0]}else{return m(ne().body,e)[0]}}function y(e,t){if(typeof e==="string"){return r(h(t)||document,e)}else{return e}}function xe(e,t,n){if(M(t)){return{target:ne().body,event:Z(e),listener:t}}else{return{target:y(e),event:Z(t),listener:n}}}function be(t,n,r){_n(function(){const e=xe(t,n,r);e.target.addEventListener(e.event,e.listener)});const e=M(n);return e?n:r}function we(t,n,r){_n(function(){const e=xe(t,n,r);e.target.removeEventListener(e.event,e.listener)});return M(n)?n:r}const ve=ne().createElement("output");function Se(e,t){const n=re(e,t);if(n){if(n==="this"){return[Ee(e,t)]}else{const r=m(e,n);if(r.length===0){w('The selector "'+n+'" on '+t+" returned no matches!");return[ve]}else{return r}}}}function Ee(e,t){return ce(T(e,function(e){return te(ce(e),t)!=null}))}function Ce(e){const t=re(e,"hx-target");if(t){if(t==="this"){return Ee(e,"hx-target")}else{return fe(e,t)}}else{const n=ie(e);if(n.boosted){return ne().body}else{return e}}}function Re(t){const n=Q.config.attributesToSettle;for(let e=0;e<n.length;e++){if(t===n[e]){return true}}return false}function Oe(t,n){se(t.attributes,function(e){if(!n.hasAttribute(e.name)&&Re(e.name)){t.removeAttribute(e.name)}});se(n.attributes,function(e){if(Re(e.name)){t.setAttribute(e.name,e.value)}})}function He(t,e){const n=jn(e);for(let e=0;e<n.length;e++){const r=n[e];try{if(r.isInlineSwap(t)){return true}}catch(e){w(e)}}return t==="outerHTML"}function Te(e,o,i){let t="#"+ee(o,"id");let s="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){s=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{s=e}const n=ne().querySelectorAll(t);if(n){se(n,function(e){let t;const n=o.cloneNode(true);t=ne().createDocumentFragment();t.appendChild(n);if(!He(s,e)){t=h(n)}const r={shouldSwap:true,target:e,fragment:t};if(!he(e,"htmx:oobBeforeSwap",r))return;e=r.target;if(r.shouldSwap){_e(s,e,e,t,i)}se(i.elts,function(e){he(e,"htmx:oobAfterSwap",r)})});o.parentNode.removeChild(o)}else{o.parentNode.removeChild(o);ae(ne().body,"htmx:oobErrorNoTarget",{content:o})}return e}function qe(e){se(p(e,"[hx-preserve], [data-hx-preserve]"),function(e){const t=te(e,"id");const n=ne().getElementById(t);if(n!=null){e.parentNode.replaceChild(n,e)}})}function Le(l,e,u){se(e.querySelectorAll("[id]"),function(t){const n=ee(t,"id");if(n&&n.length>0){const r=n.replace("'","\\'");const o=t.tagName.replace(":","\\:");const e=h(l);const i=e&&e.querySelector(o+"[id='"+r+"']");if(i&&i!==e){const s=t.cloneNode();Oe(t,i);u.tasks.push(function(){Oe(t,s)})}}})}function Ne(e){return function(){o(e,Q.config.addedClass);Dt(ce(e));Ae(h(e));he(e,"htmx:load")}}function Ae(e){const t="[autofocus]";const n=G(a(e,t)?e:e.querySelector(t));if(n!=null){n.focus()}}function c(e,t,n,r){Le(e,n,r);while(n.childNodes.length>0){const o=n.firstChild;W(ce(o),Q.config.addedClass);e.insertBefore(o,t);if(o.nodeType!==Node.TEXT_NODE&&o.nodeType!==Node.COMMENT_NODE){r.tasks.push(Ne(o))}}}function Ie(e,t){let n=0;while(n<e.length){t=(t<<5)-t+e.charCodeAt(n++)|0}return t}function Pe(t){let n=0;if(t.attributes){for(let e=0;e<t.attributes.length;e++){const r=t.attributes[e];if(r.value){n=Ie(r.name,n);n=Ie(r.value,n)}}}return n}function ke(t){const n=ie(t);if(n.onHandlers){for(let e=0;e<n.onHandlers.length;e++){const r=n.onHandlers[e];we(t,r.event,r.listener)}delete n.onHandlers}}function De(e){const t=ie(e);if(t.timeout){clearTimeout(t.timeout)}if(t.listenerInfos){se(t.listenerInfos,function(e){if(e.on){we(e.on,e.trigger,e.listener)}})}ke(e);se(Object.keys(t),function(e){delete t[e]})}function f(e){he(e,"htmx:beforeCleanupElement");De(e);if(e.children){se(e.children,function(e){f(e)})}}function Me(t,e,n){let r;const o=t.previousSibling;c(u(t),t,e,n);if(o==null){r=u(t).firstChild}else{r=o.nextSibling}n.elts=n.elts.filter(function(e){return e!==t});while(r&&r!==t){if(r instanceof Element){n.elts.push(r);r=r.nextElementSibling}else{r=null}}f(t);if(t instanceof Element){t.remove()}else{t.parentNode.removeChild(t)}}function Xe(e,t,n){return c(e,e.firstChild,t,n)}function Fe(e,t,n){return c(u(e),e,t,n)}function Ue(e,t,n){return c(e,null,t,n)}function Be(e,t,n){return c(u(e),e.nextSibling,t,n)}function je(e){f(e);return u(e).removeChild(e)}function Ve(e,t,n){const r=e.firstChild;c(e,r,t,n);if(r){while(r.nextSibling){f(r.nextSibling);e.removeChild(r.nextSibling)}f(r);e.removeChild(r)}}function _e(t,e,n,r,o){switch(t){case"none":return;case"outerHTML":Me(n,r,o);return;case"afterbegin":Xe(n,r,o);return;case"beforebegin":Fe(n,r,o);return;case"beforeend":Ue(n,r,o);return;case"afterend":Be(n,r,o);return;case"delete":je(n);return;default:var i=jn(e);for(let e=0;e<i.length;e++){const s=i[e];try{const l=s.handleSwap(t,n,r,o);if(l){if(typeof l.length!=="undefined"){for(let e=0;e<l.length;e++){const u=l[e];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){o.tasks.push(Ne(u))}}}return}}catch(e){w(e)}}if(t==="innerHTML"){Ve(n,r,o)}else{_e(Q.config.defaultSwapStyle,e,n,r,o)}}}function $e(e,n){se(p(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){if(Q.config.allowNestedOobSwaps||e.parentElement===null){const t=te(e,"hx-swap-oob");if(t!=null){Te(t,e,n)}}else{e.removeAttribute("hx-swap-oob");e.removeAttribute("data-hx-swap-oob")}})}function ze(e,t,r,o){if(!o){o={}}e=y(e);const n=document.activeElement;let i={};try{i={elt:n,start:n?n.selectionStart:null,end:n?n.selectionEnd:null}}catch(e){}const s=xn(e);if(r.swapStyle==="textContent"){e.textContent=t}else{let n=D(t);s.title=n.title;if(o.selectOOB){const u=o.selectOOB.split(",");for(let t=0;t<u.length;t++){const c=u[t].split(":",2);let e=c[0].trim();if(e.indexOf("#")===0){e=e.substring(1)}const f=c[1]||"true";const a=n.querySelector("#"+e);if(a){Te(f,a,s)}}}$e(n,s);se(p(n,"template"),function(e){$e(e.content,s);if(e.content.childElementCount===0){e.remove()}});if(o.select){const h=ne().createDocumentFragment();se(n.querySelectorAll(o.select),function(e){h.appendChild(e)});n=h}qe(n);_e(r.swapStyle,o.contextElement,e,n,s)}if(i.elt&&!le(i.elt)&&ee(i.elt,"id")){const d=document.getElementById(ee(i.elt,"id"));const g={preventScroll:r.focusScroll!==undefined?!r.focusScroll:!Q.config.defaultFocusScroll};if(d){if(i.start&&d.setSelectionRange){try{d.setSelectionRange(i.start,i.end)}catch(e){}}d.focus(g)}}e.classList.remove(Q.config.swappingClass);se(s.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}he(e,"htmx:afterSwap",o.eventInfo)});if(o.afterSwapCallback){o.afterSwapCallback()}if(!r.ignoreTitle){Dn(s.title)}const l=function(){se(s.tasks,function(e){e.call()});se(s.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}he(e,"htmx:afterSettle",o.eventInfo)});if(o.anchor){const e=ce(y("#"+o.anchor));if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}bn(s.elts,r);if(o.afterSettleCallback){o.afterSettleCallback()}};if(r.settleDelay>0){E().setTimeout(l,r.settleDelay)}else{l()}}function Je(e,t,n){const r=e.getResponseHeader(t);if(r.indexOf("{")===0){const o=S(r);for(const i in o){if(o.hasOwnProperty(i)){let e=o[i];if(!X(e)){e={value:e}}he(n,i,e)}}}else{const s=r.split(",");for(let e=0;e<s.length;e++){he(n,s[e].trim(),[])}}}const Ke=/\s/;const x=/[\s,]/;const Ge=/[_$a-zA-Z]/;const Ze=/[_$a-zA-Z0-9]/;const We=['"',"'","/"];const Ye=/[^\s]/;const Qe=/[{(]/;const et=/[})]/;function tt(e){const t=[];let n=0;while(n<e.length){if(Ge.exec(e.charAt(n))){var r=n;while(Ze.exec(e.charAt(n+1))){n++}t.push(e.substr(r,n-r+1))}else if(We.indexOf(e.charAt(n))!==-1){const o=e.charAt(n);var r=n;n++;while(n<e.length&&e.charAt(n)!==o){if(e.charAt(n)==="\\"){n++}n++}t.push(e.substr(r,n-r+1))}else{const i=e.charAt(n);t.push(i)}n++}return t}function nt(e,t,n){return Ge.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==n&&t!=="."}function rt(r,o,i){if(o[0]==="["){o.shift();let e=1;let t=" return (function("+i+"){ return (";let n=null;while(o.length>0){const s=o[0];if(s==="]"){e--;if(e===0){if(n===null){t=t+"true"}o.shift();t+=")})";try{const l=vn(r,function(){return Function(t)()},function(){return true});l.source=t;return l}catch(e){ae(ne().body,"htmx:syntax:error",{error:e,source:t});return null}}}else if(s==="["){e++}if(nt(s,n,i)){t+="(("+i+"."+s+") ? ("+i+"."+s+") : (window."+s+"))"}else{t=t+s}n=o.shift()}}}function b(e,t){let n="";while(e.length>0&&!t.test(e[0])){n+=e.shift()}return n}function ot(e){let t;if(e.length>0&&Qe.test(e[0])){e.shift();t=b(e,et).trim();e.shift()}else{t=b(e,x)}return t}const it="input, textarea, select";function st(e,t,n){const r=[];const o=tt(t);do{b(o,Ye);const l=o.length;const u=b(o,/[,\[\s]/);if(u!==""){if(u==="every"){const c={trigger:"every"};b(o,Ye);c.pollInterval=d(b(o,/[,\[\s]/));b(o,Ye);var i=rt(e,o,"event");if(i){c.eventFilter=i}r.push(c)}else{const f={trigger:u};var i=rt(e,o,"event");if(i){f.eventFilter=i}while(o.length>0&&o[0]!==","){b(o,Ye);const a=o.shift();if(a==="changed"){f.changed=true}else if(a==="once"){f.once=true}else if(a==="consume"){f.consume=true}else if(a==="delay"&&o[0]===":"){o.shift();f.delay=d(b(o,x))}else if(a==="from"&&o[0]===":"){o.shift();if(Qe.test(o[0])){var s=ot(o)}else{var s=b(o,x);if(s==="closest"||s==="find"||s==="next"||s==="previous"){o.shift();const h=ot(o);if(h.length>0){s+=" "+h}}}f.from=s}else if(a==="target"&&o[0]===":"){o.shift();f.target=ot(o)}else if(a==="throttle"&&o[0]===":"){o.shift();f.throttle=d(b(o,x))}else if(a==="queue"&&o[0]===":"){o.shift();f.queue=b(o,x)}else if(a==="root"&&o[0]===":"){o.shift();f[a]=ot(o)}else if(a==="threshold"&&o[0]===":"){o.shift();f[a]=b(o,x)}else{ae(e,"htmx:syntax:error",{token:o.shift()})}}r.push(f)}}if(o.length===l){ae(e,"htmx:syntax:error",{token:o.shift()})}b(o,Ye)}while(o[0]===","&&o.shift());if(n){n[t]=r}return r}function lt(e){const t=te(e,"hx-trigger");let n=[];if(t){const r=Q.config.triggerSpecsCache;n=r&&r[t]||st(e,t,r)}if(n.length>0){return n}else if(a(e,"form")){return[{trigger:"submit"}]}else if(a(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(a(e,it)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function ut(e){ie(e).cancelled=true}function ct(e,t,n){const r=ie(e);r.timeout=E().setTimeout(function(){if(le(e)&&r.cancelled!==true){if(!pt(n,e,Xt("hx:poll:trigger",{triggerSpec:n,target:e}))){t(e)}ct(e,t,n)}},n.pollInterval)}function ft(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function at(e){return g(e,Q.config.disableSelector)}function ht(t,n,e){if(t instanceof HTMLAnchorElement&&ft(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){n.boosted=true;let r,o;if(t.tagName==="A"){r="get";o=ee(t,"href")}else{const i=ee(t,"method");r=i?i.toLowerCase():"get";if(r==="get"){}o=ee(t,"action")}e.forEach(function(e){mt(t,function(e,t){const n=ce(e);if(at(n)){f(n);return}de(r,o,n,t)},n,e,true)})}}function dt(e,t){const n=ce(t);if(!n){return false}if(e.type==="submit"||e.type==="click"){if(n.tagName==="FORM"){return true}if(a(n,'input[type="submit"], button')&&g(n,"form")!==null){return true}if(n instanceof HTMLAnchorElement&&n.href&&(n.getAttribute("href")==="#"||n.getAttribute("href").indexOf("#")!==0)){return true}}return false}function gt(e,t){return ie(e).boosted&&e instanceof HTMLAnchorElement&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function pt(e,t,n){const r=e.eventFilter;if(r){try{return r.call(t,n)!==true}catch(e){const o=r.source;ae(ne().body,"htmx:eventFilter:error",{error:e,source:o});return true}}return false}function mt(s,l,e,u,c){const f=ie(s);let t;if(u.from){t=m(s,u.from)}else{t=[s]}if(u.changed){t.forEach(function(e){const t=ie(e);t.lastValue=e.value})}se(t,function(o){const i=function(e){if(!le(s)){o.removeEventListener(u.trigger,i);return}if(gt(s,e)){return}if(c||dt(e,s)){e.preventDefault()}if(pt(u,s,e)){return}const t=ie(e);t.triggerSpec=u;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(s)<0){t.handledFor.push(s);if(u.consume){e.stopPropagation()}if(u.target&&e.target){if(!a(ce(e.target),u.target)){return}}if(u.once){if(f.triggeredOnce){return}else{f.triggeredOnce=true}}if(u.changed){const n=ie(o);const r=o.value;if(n.lastValue===r){return}n.lastValue=r}if(f.delayed){clearTimeout(f.delayed)}if(f.throttle){return}if(u.throttle>0){if(!f.throttle){l(s,e);f.throttle=E().setTimeout(function(){f.throttle=null},u.throttle)}}else if(u.delay>0){f.delayed=E().setTimeout(function(){l(s,e)},u.delay)}else{he(s,"htmx:trigger");l(s,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:u.trigger,listener:i,on:o});o.addEventListener(u.trigger,i)})}let yt=false;let xt=null;function bt(){if(!xt){xt=function(){yt=true};window.addEventListener("scroll",xt);setInterval(function(){if(yt){yt=false;se(ne().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"),function(e){wt(e)})}},200)}}function wt(e){if(!s(e,"data-hx-revealed")&&U(e)){e.setAttribute("data-hx-revealed","true");const t=ie(e);if(t.initHash){he(e,"revealed")}else{e.addEventListener("htmx:afterProcessNode",function(){he(e,"revealed")},{once:true})}}}function vt(e,t,n,r){const o=function(){if(!n.loaded){n.loaded=true;t(e)}};if(r>0){E().setTimeout(o,r)}else{o()}}function St(t,n,e){let i=false;se(v,function(r){if(s(t,"hx-"+r)){const o=te(t,"hx-"+r);i=true;n.path=o;n.verb=r;e.forEach(function(e){Et(t,e,n,function(e,t){const n=ce(e);if(g(n,Q.config.disableSelector)){f(n);return}de(r,o,n,t)})})}});return i}function Et(r,e,t,n){if(e.trigger==="revealed"){bt();mt(r,n,t,e);wt(ce(r))}else if(e.trigger==="intersect"){const o={};if(e.root){o.root=fe(r,e.root)}if(e.threshold){o.threshold=parseFloat(e.threshold)}const i=new IntersectionObserver(function(t){for(let e=0;e<t.length;e++){const n=t[e];if(n.isIntersecting){he(r,"intersect");break}}},o);i.observe(ce(r));mt(ce(r),n,t,e)}else if(e.trigger==="load"){if(!pt(e,r,Xt("load",{elt:r}))){vt(ce(r),n,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ct(ce(r),n,e)}else{mt(r,n,t,e)}}function Ct(e){const t=ce(e);if(!t){return false}const n=t.attributes;for(let e=0;e<n.length;e++){const r=n[e].name;if(l(r,"hx-on:")||l(r,"data-hx-on:")||l(r,"hx-on-")||l(r,"data-hx-on-")){return true}}return false}const Rt=(new XPathEvaluator).createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]');function Ot(e,t){if(Ct(e)){t.push(ce(e))}const n=Rt.evaluate(e);let r=null;while(r=n.iterateNext())t.push(ce(r))}function Ht(e){const t=[];if(e instanceof DocumentFragment){for(const n of e.childNodes){Ot(n,t)}}else{Ot(e,t)}return t}function Tt(e){if(e.querySelectorAll){const n=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";const r=[];for(const i in Xn){const s=Xn[i];if(s.getSelectors){var t=s.getSelectors();if(t){r.push(t)}}}const o=e.querySelectorAll(R+n+", form, [type='submit'],"+" [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]"+r.flat().map(e=>", "+e).join(""));return o}else{return[]}}function qt(e){const t=g(ce(e.target),"button, input[type='submit']");const n=Nt(e);if(n){n.lastButtonClicked=t}}function Lt(e){const t=Nt(e);if(t){t.lastButtonClicked=null}}function Nt(e){const t=g(ce(e.target),"button, input[type='submit']");if(!t){return}const n=y("#"+ee(t,"form"),t.getRootNode())||g(t,"form");if(!n){return}return ie(n)}function At(e){e.addEventListener("click",qt);e.addEventListener("focusin",qt);e.addEventListener("focusout",Lt)}function It(t,e,n){const r=ie(t);if(!Array.isArray(r.onHandlers)){r.onHandlers=[]}let o;const i=function(e){vn(t,function(){if(at(t)){return}if(!o){o=new Function("event",n)}o.call(t,e)})};t.addEventListener(e,i);r.onHandlers.push({event:e,listener:i})}function Pt(t){ke(t);for(let e=0;e<t.attributes.length;e++){const n=t.attributes[e].name;const r=t.attributes[e].value;if(l(n,"hx-on")||l(n,"data-hx-on")){const o=n.indexOf("-on")+3;const i=n.slice(o,o+1);if(i==="-"||i===":"){let e=n.slice(o+1);if(l(e,":")){e="htmx"+e}else if(l(e,"-")){e="htmx:"+e.slice(1)}else if(l(e,"htmx-")){e="htmx:"+e.slice(5)}It(t,e,r)}}}}function kt(t){if(g(t,Q.config.disableSelector)){f(t);return}const n=ie(t);if(n.initHash!==Pe(t)){De(t);n.initHash=Pe(t);he(t,"htmx:beforeProcessNode");if(t.value){n.lastValue=t.value}const e=lt(t);const r=St(t,n,e);if(!r){if(re(t,"hx-boost")==="true"){ht(t,n,e)}else if(s(t,"hx-trigger")){e.forEach(function(e){Et(t,e,n,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&s(t,"form")){At(t)}he(t,"htmx:afterProcessNode")}}function Dt(e){e=y(e);if(g(e,Q.config.disableSelector)){f(e);return}kt(e);se(Tt(e),function(e){kt(e)});se(Ht(e),Pt)}function Mt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Xt(e,t){let n;if(window.CustomEvent&&typeof window.CustomEvent==="function"){n=new CustomEvent(e,{bubbles:true,cancelable:true,composed:true,detail:t})}else{n=ne().createEvent("CustomEvent");n.initCustomEvent(e,true,true,t)}return n}function ae(e,t,n){he(e,t,ue({error:t},n))}function Ft(e){return e==="htmx:afterProcessNode"}function Ut(e,t){se(jn(e),function(e){try{t(e)}catch(e){w(e)}})}function w(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function he(e,t,n){e=y(e);if(n==null){n={}}n.elt=e;const r=Xt(t,n);if(Q.logger&&!Ft(t)){Q.logger(e,t,n)}if(n.error){w(n.error);he(e,"htmx:error",{errorInfo:n})}let o=e.dispatchEvent(r);const i=Mt(t);if(o&&i!==t){const s=Xt(i,r.detail);o=o&&e.dispatchEvent(s)}Ut(ce(e),function(e){o=o&&(e.onEvent(t,r)!==false&&!r.defaultPrevented)});return o}let Bt=location.pathname+location.search;function jt(){const e=ne().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||ne().body}function Vt(t,e){if(!j()){return}const n=$t(e);const r=ne().title;const o=window.scrollY;if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}t=V(t);const i=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e<i.length;e++){if(i[e].url===t){i.splice(e,1);break}}const s={url:t,content:n,title:r,scroll:o};he(ne().body,"htmx:historyItemCreated",{item:s,cache:i});i.push(s);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ae(ne().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function _t(t){if(!j()){return null}t=V(t);const n=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e<n.length;e++){if(n[e].url===t){return n[e]}}return null}function $t(e){const t=Q.config.requestClass;const n=e.cloneNode(true);se(p(n,"."+t),function(e){o(e,t)});return n.innerHTML}function zt(){const e=jt();const t=Bt||location.pathname+location.search;let n;try{n=ne().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){n=ne().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!n){he(ne().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Vt(t,e)}if(Q.config.historyEnabled)history.replaceState({htmx:true},ne().title,window.location.href)}function Jt(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(pe(e,"&")||pe(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Bt=e}function Kt(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Bt=e}function Gt(e){se(e,function(e){e.call(undefined)})}function Zt(o){const e=new XMLHttpRequest;const i={path:o,xhr:e};he(ne().body,"htmx:historyCacheMiss",i);e.open("GET",o,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",ne().location.href);e.onload=function(){if(this.status>=200&&this.status<400){he(ne().body,"htmx:historyCacheMissLoad",i);const e=D(this.response);const t=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;const n=jt();const r=xn(n);Dn(e.title);Ve(n,t,r);Gt(r.tasks);Bt=o;he(ne().body,"htmx:historyRestore",{path:o,cacheMiss:true,serverResponse:this.response})}else{ae(ne().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Wt(e){zt();e=e||location.pathname+location.search;const t=_t(e);if(t){const n=D(t.content);const r=jt();const o=xn(r);Dn(n.title);Ve(r,n,o);Gt(o.tasks);E().setTimeout(function(){window.scrollTo(0,t.scroll)},0);Bt=e;he(ne().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{Zt(e)}}}function Yt(e){let t=Se(e,"hx-indicator");if(t==null){t=[e]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.classList.add.call(e.classList,Q.config.requestClass)});return t}function Qt(e){let t=Se(e,"hx-disabled-elt");if(t==null){t=[]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function en(e,t){se(e,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList.remove.call(e.classList,Q.config.requestClass)}});se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function tn(t,n){for(let e=0;e<t.length;e++){const r=t[e];if(r.isSameNode(n)){return true}}return false}function nn(e){const t=e;if(t.name===""||t.name==null||t.disabled||g(t,"fieldset[disabled]")){return false}if(t.type==="button"||t.type==="submit"||t.tagName==="image"||t.tagName==="reset"||t.tagName==="file"){return false}if(t.type==="checkbox"||t.type==="radio"){return t.checked}return true}function rn(t,e,n){if(t!=null&&e!=null){if(Array.isArray(e)){e.forEach(function(e){n.append(t,e)})}else{n.append(t,e)}}}function on(t,n,r){if(t!=null&&n!=null){let e=r.getAll(t);if(Array.isArray(n)){e=e.filter(e=>n.indexOf(e)<0)}else{e=e.filter(e=>e!==n)}r.delete(t);se(e,e=>r.append(t,e))}}function sn(t,n,r,o,i){if(o==null||tn(t,o)){return}else{t.push(o)}if(nn(o)){const s=ee(o,"name");let e=o.value;if(o instanceof HTMLSelectElement&&o.multiple){e=F(o.querySelectorAll("option:checked")).map(function(e){return e.value})}if(o instanceof HTMLInputElement&&o.files){e=F(o.files)}rn(s,e,n);if(i){ln(o,r)}}if(o instanceof HTMLFormElement){se(o.elements,function(e){if(t.indexOf(e)>=0){on(e.name,e.value,n)}else{t.push(e)}if(i){ln(e,r)}});new FormData(o).forEach(function(e,t){if(e instanceof File&&e.name===""){return}rn(t,e,n)})}}function ln(e,t){const n=e;if(n.willValidate){he(n,"htmx:validation:validate");if(!n.checkValidity()){t.push({elt:n,message:n.validationMessage,validity:n.validity});he(n,"htmx:validation:failed",{message:n.validationMessage,validity:n.validity})}}}function un(t,e){for(const n of e.keys()){t.delete(n);e.getAll(n).forEach(function(e){t.append(n,e)})}return t}function cn(e,t){const n=[];const r=new FormData;const o=new FormData;const i=[];const s=ie(e);if(s.lastButtonClicked&&!le(s.lastButtonClicked)){s.lastButtonClicked=null}let l=e instanceof HTMLFormElement&&e.noValidate!==true||te(e,"hx-validate")==="true";if(s.lastButtonClicked){l=l&&s.lastButtonClicked.formNoValidate!==true}if(t!=="get"){sn(n,o,i,g(e,"form"),l)}sn(n,r,i,e,l);if(s.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){const c=s.lastButtonClicked||e;const f=ee(c,"name");rn(f,c.value,o)}const u=Se(e,"hx-include");se(u,function(e){sn(n,r,i,ce(e),l);if(!a(e,"form")){se(h(e).querySelectorAll(it),function(e){sn(n,r,i,e,l)})}});un(r,o);return{errors:i,formData:r,values:An(r)}}function fn(e,t,n){if(e!==""){e+="&"}if(String(n)==="[object Object]"){n=JSON.stringify(n)}const r=encodeURIComponent(n);e+=encodeURIComponent(t)+"="+r;return e}function an(e){e=Ln(e);let n="";e.forEach(function(e,t){n=fn(n,t,e)});return n}function hn(e,t,n){const r={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":ne().location.href};wn(e,"hx-headers",false,r);if(n!==undefined){r["HX-Prompt"]=n}if(ie(e).boosted){r["HX-Boosted"]="true"}return r}function dn(n,e){const t=re(e,"hx-params");if(t){if(t==="none"){return new FormData}else if(t==="*"){return n}else if(t.indexOf("not ")===0){se(t.substr(4).split(","),function(e){e=e.trim();n.delete(e)});return n}else{const r=new FormData;se(t.split(","),function(t){t=t.trim();if(n.has(t)){n.getAll(t).forEach(function(e){r.append(t,e)})}});return r}}else{return n}}function gn(e){return!!ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function pn(e,t){const n=t||re(e,"hx-swap");const r={swapStyle:ie(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ie(e).boosted&&!gn(e)){r.show="top"}if(n){const s=B(n);if(s.length>0){for(let e=0;e<s.length;e++){const l=s[e];if(l.indexOf("swap:")===0){r.swapDelay=d(l.substr(5))}else if(l.indexOf("settle:")===0){r.settleDelay=d(l.substr(7))}else if(l.indexOf("transition:")===0){r.transition=l.substr(11)==="true"}else if(l.indexOf("ignoreTitle:")===0){r.ignoreTitle=l.substr(12)==="true"}else if(l.indexOf("scroll:")===0){const u=l.substr(7);var o=u.split(":");const c=o.pop();var i=o.length>0?o.join(":"):null;r.scroll=c;r.scrollTarget=i}else if(l.indexOf("show:")===0){const f=l.substr(5);var o=f.split(":");const a=o.pop();var i=o.length>0?o.join(":"):null;r.show=a;r.showTarget=i}else if(l.indexOf("focus-scroll:")===0){const h=l.substr("focus-scroll:".length);r.focusScroll=h=="true"}else if(e==0){r.swapStyle=l}else{w("Unknown modifier in hx-swap: "+l)}}}}return r}function mn(e){return re(e,"hx-encoding")==="multipart/form-data"||a(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function yn(t,n,r){let o=null;Ut(n,function(e){if(o==null){o=e.encodeParameters(t,r,n)}});if(o!=null){return o}else{if(mn(n)){return un(new FormData,Ln(r))}else{return an(r)}}}function xn(e){return{tasks:[],elts:[e]}}function bn(e,t){const n=e[0];const r=e[e.length-1];if(t.scroll){var o=null;if(t.scrollTarget){o=ce(fe(n,t.scrollTarget))}if(t.scroll==="top"&&(n||o)){o=o||n;o.scrollTop=0}if(t.scroll==="bottom"&&(r||o)){o=o||r;o.scrollTop=o.scrollHeight}}if(t.show){var o=null;if(t.showTarget){let e=t.showTarget;if(t.showTarget==="window"){e="body"}o=ce(fe(n,e))}if(t.show==="top"&&(n||o)){o=o||n;o.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(r||o)){o=o||r;o.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function wn(r,e,o,i){if(i==null){i={}}if(r==null){return i}const s=te(r,e);if(s){let e=s.trim();let t=o;if(e==="unset"){return null}if(e.indexOf("javascript:")===0){e=e.substr(11);t=true}else if(e.indexOf("js:")===0){e=e.substr(3);t=true}if(e.indexOf("{")!==0){e="{"+e+"}"}let n;if(t){n=vn(r,function(){return Function("return ("+e+")")()},{})}else{n=S(e)}for(const l in n){if(n.hasOwnProperty(l)){if(i[l]==null){i[l]=n[l]}}}}return wn(ce(u(r)),e,o,i)}function vn(e,t,n){if(Q.config.allowEval){return t()}else{ae(e,"htmx:evalDisallowedError");return n}}function Sn(e,t){return wn(e,"hx-vars",true,t)}function En(e,t){return wn(e,"hx-vals",false,t)}function Cn(e){return ue(Sn(e),En(e))}function Rn(t,n,r){if(r!==null){try{t.setRequestHeader(n,r)}catch(e){t.setRequestHeader(n,encodeURIComponent(r));t.setRequestHeader(n+"-URI-AutoEncoded","true")}}}function On(t){if(t.responseURL&&typeof URL!=="undefined"){try{const e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ae(ne().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function C(e,t){return t.test(e.getAllResponseHeaders())}function Hn(e,t,n){e=e.toLowerCase();if(n){if(n instanceof Element||typeof n==="string"){return de(e,t,null,null,{targetOverride:y(n),returnPromise:true})}else{return de(e,t,y(n.source),n.event,{handler:n.handler,headers:n.headers,values:n.values,targetOverride:y(n.target),swapOverride:n.swap,select:n.select,returnPromise:true})}}else{return de(e,t,null,null,{returnPromise:true})}}function Tn(e){const t=[];while(e){t.push(e);e=e.parentElement}return t}function qn(e,t,n){let r;let o;if(typeof URL==="function"){o=new URL(t,document.location.href);const i=document.location.origin;r=i===o.origin}else{o=t;r=l(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!r){return false}}return he(e,"htmx:validateUrl",ue({url:o,sameHost:r},n))}function Ln(e){if(e instanceof FormData)return e;const t=new FormData;for(const n in e){if(e.hasOwnProperty(n)){if(typeof e[n].forEach==="function"){e[n].forEach(function(e){t.append(n,e)})}else if(typeof e[n]==="object"){t.append(n,JSON.stringify(e[n]))}else{t.append(n,e[n])}}}return t}function Nn(r,o,e){return new Proxy(e,{get:function(t,e){if(typeof e==="number")return t[e];if(e==="length")return t.length;if(e==="push"){return function(e){t.push(e);r.append(o,e)}}if(typeof t[e]==="function"){return function(){t[e].apply(t,arguments);r.delete(o);t.forEach(function(e){r.append(o,e)})}}if(t[e]&&t[e].length===1){return t[e][0]}else{return t[e]}},set:function(e,t,n){e[t]=n;r.delete(o);e.forEach(function(e){r.append(o,e)});return true}})}function An(r){return new Proxy(r,{get:function(e,t){if(typeof t==="symbol"){return Reflect.get(e,t)}if(t==="toJSON"){return()=>Object.fromEntries(r)}if(t in e){if(typeof e[t]==="function"){return function(){return r[t].apply(r,arguments)}}else{return e[t]}}const n=r.getAll(t);if(n.length===0){return undefined}else if(n.length===1){return n[0]}else{return Nn(e,t,n)}},set:function(t,n,e){if(typeof n!=="string"){return false}t.delete(n);if(typeof e.forEach==="function"){e.forEach(function(e){t.append(n,e)})}else{t.append(n,e)}return true},deleteProperty:function(e,t){if(typeof t==="string"){e.delete(t)}return true},ownKeys:function(e){return Reflect.ownKeys(Object.fromEntries(e))},getOwnPropertyDescriptor:function(e,t){return Reflect.getOwnPropertyDescriptor(Object.fromEntries(e),t)}})}function de(t,n,r,o,i,D){let s=null;let l=null;i=i!=null?i:{};if(i.returnPromise&&typeof Promise!=="undefined"){var e=new Promise(function(e,t){s=e;l=t})}if(r==null){r=ne().body}const M=i.handler||Mn;const X=i.select||null;if(!le(r)){oe(s);return e}const u=i.targetOverride||ce(Ce(r));if(u==null||u==ve){ae(r,"htmx:targetError",{target:te(r,"hx-target")});oe(l);return e}let c=ie(r);const f=c.lastButtonClicked;if(f){const L=ee(f,"formaction");if(L!=null){n=L}const N=ee(f,"formmethod");if(N!=null){if(N.toLowerCase()!=="dialog"){t=N}}}const a=re(r,"hx-confirm");if(D===undefined){const K=function(e){return de(t,n,r,o,i,!!e)};const G={target:u,elt:r,path:n,verb:t,triggeringEvent:o,etc:i,issueRequest:K,question:a};if(he(r,"htmx:confirm",G)===false){oe(s);return e}}let h=r;let d=re(r,"hx-sync");let g=null;let F=false;if(d){const A=d.split(":");const I=A[0].trim();if(I==="this"){h=Ee(r,"hx-sync")}else{h=ce(fe(r,I))}d=(A[1]||"drop").trim();c=ie(h);if(d==="drop"&&c.xhr&&c.abortable!==true){oe(s);return e}else if(d==="abort"){if(c.xhr){oe(s);return e}else{F=true}}else if(d==="replace"){he(h,"htmx:abort")}else if(d.indexOf("queue")===0){const Z=d.split(" ");g=(Z[1]||"last").trim()}}if(c.xhr){if(c.abortable){he(h,"htmx:abort")}else{if(g==null){if(o){const P=ie(o);if(P&&P.triggerSpec&&P.triggerSpec.queue){g=P.triggerSpec.queue}}if(g==null){g="last"}}if(c.queuedRequests==null){c.queuedRequests=[]}if(g==="first"&&c.queuedRequests.length===0){c.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="all"){c.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="last"){c.queuedRequests=[];c.queuedRequests.push(function(){de(t,n,r,o,i)})}oe(s);return e}}const p=new XMLHttpRequest;c.xhr=p;c.abortable=F;const m=function(){c.xhr=null;c.abortable=false;if(c.queuedRequests!=null&&c.queuedRequests.length>0){const e=c.queuedRequests.shift();e()}};const U=re(r,"hx-prompt");if(U){var y=prompt(U);if(y===null||!he(r,"htmx:prompt",{prompt:y,target:u})){oe(s);m();return e}}if(a&&!D){if(!confirm(a)){oe(s);m();return e}}let x=hn(r,u,y);if(t!=="get"&&!mn(r)){x["Content-Type"]="application/x-www-form-urlencoded"}if(i.headers){x=ue(x,i.headers)}const B=cn(r,t);let b=B.errors;const j=B.formData;if(i.values){un(j,Ln(i.values))}const V=Ln(Cn(r));const w=un(j,V);let v=dn(w,r);if(Q.config.getCacheBusterParam&&t==="get"){v.set("org.htmx.cache-buster",ee(u,"id")||"true")}if(n==null||n===""){n=ne().location.href}const S=wn(r,"hx-request");const _=ie(r).boosted;let E=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;const C={boosted:_,useUrlParams:E,formData:v,parameters:An(v),unfilteredFormData:w,unfilteredParameters:An(w),headers:x,target:u,verb:t,errors:b,withCredentials:i.credentials||S.credentials||Q.config.withCredentials,timeout:i.timeout||S.timeout||Q.config.timeout,path:n,triggeringEvent:o};if(!he(r,"htmx:configRequest",C)){oe(s);m();return e}n=C.path;t=C.verb;x=C.headers;v=Ln(C.parameters);b=C.errors;E=C.useUrlParams;if(b&&b.length>0){he(r,"htmx:validation:halted",C);oe(s);m();return e}const $=n.split("#");const z=$[0];const R=$[1];let O=n;if(E){O=z;const W=!v.keys().next().done;if(W){if(O.indexOf("?")<0){O+="?"}else{O+="&"}O+=an(v);if(R){O+="#"+R}}}if(!qn(r,O,C)){ae(r,"htmx:invalidPath",C);oe(l);return e}p.open(t.toUpperCase(),O,true);p.overrideMimeType("text/html");p.withCredentials=C.withCredentials;p.timeout=C.timeout;if(S.noHeaders){}else{for(const k in x){if(x.hasOwnProperty(k)){const Y=x[k];Rn(p,k,Y)}}}const H={xhr:p,target:u,requestConfig:C,etc:i,boosted:_,select:X,pathInfo:{requestPath:n,finalRequestPath:O,responsePath:null,anchor:R}};p.onload=function(){try{const t=Tn(r);H.pathInfo.responsePath=On(p);M(r,H);en(T,q);he(r,"htmx:afterRequest",H);he(r,"htmx:afterOnLoad",H);if(!le(r)){let e=null;while(t.length>0&&e==null){const n=t.shift();if(le(n)){e=n}}if(e){he(e,"htmx:afterRequest",H);he(e,"htmx:afterOnLoad",H)}}oe(s);m()}catch(e){ae(r,"htmx:onLoadError",ue({error:e},H));throw e}};p.onerror=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:sendError",H);oe(l);m()};p.onabort=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:sendAbort",H);oe(l);m()};p.ontimeout=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:timeout",H);oe(l);m()};if(!he(r,"htmx:beforeRequest",H)){oe(s);m();return e}var T=Yt(r);var q=Qt(r);se(["loadstart","loadend","progress","abort"],function(t){se([p,p.upload],function(e){e.addEventListener(t,function(e){he(r,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});he(r,"htmx:beforeSend",H);const J=E?null:yn(p,r,v);p.send(J);return e}function In(e,t){const n=t.xhr;let r=null;let o=null;if(C(n,/HX-Push:/i)){r=n.getResponseHeader("HX-Push");o="push"}else if(C(n,/HX-Push-Url:/i)){r=n.getResponseHeader("HX-Push-Url");o="push"}else if(C(n,/HX-Replace-Url:/i)){r=n.getResponseHeader("HX-Replace-Url");o="replace"}if(r){if(r==="false"){return{}}else{return{type:o,path:r}}}const i=t.pathInfo.finalRequestPath;const s=t.pathInfo.responsePath;const l=re(e,"hx-push-url");const u=re(e,"hx-replace-url");const c=ie(e).boosted;let f=null;let a=null;if(l){f="push";a=l}else if(u){f="replace";a=u}else if(c){f="push";a=s||i}if(a){if(a==="false"){return{}}if(a==="true"){a=s||i}if(t.pathInfo.anchor&&a.indexOf("#")===-1){a=a+"#"+t.pathInfo.anchor}return{type:f,path:a}}else{return{}}}function Pn(e,t){var n=new RegExp(e.code);return n.test(t.toString(10))}function kn(e){for(var t=0;t<Q.config.responseHandling.length;t++){var n=Q.config.responseHandling[t];if(Pn(n,e.status)){return n}}return{swap:false}}function Dn(e){if(e){const t=r("title");if(t){t.innerHTML=e}else{window.document.title=e}}}function Mn(o,i){const s=i.xhr;let l=i.target;const e=i.etc;const u=i.select;if(!he(o,"htmx:beforeOnLoad",i))return;if(C(s,/HX-Trigger:/i)){Je(s,"HX-Trigger",o)}if(C(s,/HX-Location:/i)){zt();let e=s.getResponseHeader("HX-Location");var t;if(e.indexOf("{")===0){t=S(e);e=t.path;delete t.path}Hn("get",e,t).then(function(){Jt(e)});return}const n=C(s,/HX-Refresh:/i)&&s.getResponseHeader("HX-Refresh")==="true";if(C(s,/HX-Redirect:/i)){location.href=s.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(C(s,/HX-Retarget:/i)){if(s.getResponseHeader("HX-Retarget")==="this"){i.target=o}else{i.target=ce(fe(o,s.getResponseHeader("HX-Retarget")))}}const c=In(o,i);const r=kn(s);const f=r.swap;let a=!!r.error;let h=Q.config.ignoreTitle||r.ignoreTitle;let d=r.select;if(r.target){i.target=ce(fe(o,r.target))}var g=e.swapOverride;if(g==null&&r.swapOverride){g=r.swapOverride}if(C(s,/HX-Retarget:/i)){if(s.getResponseHeader("HX-Retarget")==="this"){i.target=o}else{i.target=ce(fe(o,s.getResponseHeader("HX-Retarget")))}}if(C(s,/HX-Reswap:/i)){g=s.getResponseHeader("HX-Reswap")}var p=s.response;var m=ue({shouldSwap:f,serverResponse:p,isError:a,ignoreTitle:h,selectOverride:d},i);if(r.event&&!he(l,r.event,m))return;if(!he(l,"htmx:beforeSwap",m))return;l=m.target;p=m.serverResponse;a=m.isError;h=m.ignoreTitle;d=m.selectOverride;i.target=l;i.failed=a;i.successful=!a;if(m.shouldSwap){if(s.status===286){ut(o)}Ut(o,function(e){p=e.transformResponse(p,s,o)});if(c.type){zt()}if(C(s,/HX-Reswap:/i)){g=s.getResponseHeader("HX-Reswap")}var y=pn(o,g);if(!y.hasOwnProperty("ignoreTitle")){y.ignoreTitle=h}l.classList.add(Q.config.swappingClass);let n=null;let r=null;if(u){d=u}if(C(s,/HX-Reselect:/i)){d=s.getResponseHeader("HX-Reselect")}const x=re(o,"hx-select-oob");const b=re(o,"hx-select");let e=function(){try{if(c.type){he(ne().body,"htmx:beforeHistoryUpdate",ue({history:c},i));if(c.type==="push"){Jt(c.path);he(ne().body,"htmx:pushedIntoHistory",{path:c.path})}else{Kt(c.path);he(ne().body,"htmx:replacedInHistory",{path:c.path})}}ze(l,p,y,{select:d||b,selectOOB:x,eventInfo:i,anchor:i.pathInfo.anchor,contextElement:o,afterSwapCallback:function(){if(C(s,/HX-Trigger-After-Swap:/i)){let e=o;if(!le(o)){e=ne().body}Je(s,"HX-Trigger-After-Swap",e)}},afterSettleCallback:function(){if(C(s,/HX-Trigger-After-Settle:/i)){let e=o;if(!le(o)){e=ne().body}Je(s,"HX-Trigger-After-Settle",e)}oe(n)}})}catch(e){ae(o,"htmx:swapError",i);oe(r);throw e}};let t=Q.config.globalViewTransitions;if(y.hasOwnProperty("transition")){t=y.transition}if(t&&he(o,"htmx:beforeTransition",i)&&typeof Promise!=="undefined"&&document.startViewTransition){const w=new Promise(function(e,t){n=e;r=t});const v=e;e=function(){document.startViewTransition(function(){v();return w})}}if(y.swapDelay>0){E().setTimeout(e,y.swapDelay)}else{e()}}if(a){ae(o,"htmx:responseError",ue({error:"Response Status Error Code "+s.status+" from "+i.pathInfo.requestPath},i))}}const Xn={};function Fn(){return{init:function(e){return null},getSelectors:function(){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,n){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,n,r){return false},encodeParameters:function(e,t,n){return null}}}function Un(e,t){if(t.init){t.init(n)}Xn[e]=ue(Fn(),t)}function Bn(e){delete Xn[e]}function jn(e,n,r){if(n==undefined){n=[]}if(e==undefined){return n}if(r==undefined){r=[]}const t=te(e,"hx-ext");if(t){se(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){r.push(e.slice(7));return}if(r.indexOf(e)<0){const t=Xn[e];if(t&&n.indexOf(t)<0){n.push(t)}}})}return jn(ce(u(e)),n,r)}var Vn=false;ne().addEventListener("DOMContentLoaded",function(){Vn=true});function _n(e){if(Vn||ne().readyState==="complete"){e()}else{ne().addEventListener("DOMContentLoaded",e)}}function $n(){if(Q.config.includeIndicatorStyles!==false){const e=Q.config.inlineStyleNonce?` nonce="${Q.config.inlineStyleNonce}"`:"";ne().head.insertAdjacentHTML("beforeend","<style"+e+"> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zn(){const e=ne().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function Jn(){const e=zn();if(e){Q.config=ue(Q.config,e)}}_n(function(){Jn();$n();let e=ne().body;Dt(e);const t=ne().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){const t=e.target;const n=ie(t);if(n&&n.xhr){n.xhr.abort()}});const n=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){Wt();se(t,function(e){he(e,"htmx:restored",{document:ne(),triggerEvent:he})})}else{if(n){n(e)}}};E().setTimeout(function(){he(e,"htmx:load",{});e=null},0)});return Q}(); \ No newline at end of file diff --git a/code/ch5_partials/ch5_final_video_collector/static/js/htmx.d.ts b/code/ch5_partials/ch5_final_video_collector/static/js/htmx.d.ts new file mode 100644 index 0000000..3775459 --- /dev/null +++ b/code/ch5_partials/ch5_final_video_collector/static/js/htmx.d.ts @@ -0,0 +1,195 @@ +declare namespace htmx { + const onLoad: (callback: (elt: Node) => void) => EventListener; + const process: (elt: string | Element) => void; + const on: (arg1: string | EventTarget, arg2: string | EventListener, arg3?: EventListener) => EventListener; + const off: (arg1: string | EventTarget, arg2: string | EventListener, arg3?: EventListener) => EventListener; + const trigger: (elt: string | EventTarget, eventName: string, detail?: any) => boolean; + const ajax: (verb: HttpVerb, path: string, context: string | Element | HtmxAjaxHelperContext) => Promise<void>; + const find: (eltOrSelector: string | ParentNode, selector?: string) => Element; + const findAll: (eltOrSelector: string | ParentNode, selector?: string) => NodeListOf<Element>; + const closest: (elt: string | Element, selector: string) => Element; + function values(elt: Element, type: HttpVerb): any; + const remove: (elt: Node, delay?: number) => void; + const addClass: (elt: string | Element, clazz: string, delay?: number) => void; + const removeClass: (node: string | Node, clazz: string, delay?: number) => void; + const toggleClass: (elt: string | Element, clazz: string) => void; + const takeClass: (elt: string | Node, clazz: string) => void; + const swap: (target: string | Element, content: string, swapSpec: HtmxSwapSpecification, swapOptions?: SwapOptions) => void; + const defineExtension: (name: string, extension: any) => void; + const removeExtension: (name: string) => void; + const logAll: () => void; + const logNone: () => void; + const logger: any; + namespace config { + const historyEnabled: boolean; + const historyCacheSize: number; + const refreshOnHistoryMiss: boolean; + const defaultSwapStyle: HtmxSwapStyle; + const defaultSwapDelay: number; + const defaultSettleDelay: number; + const includeIndicatorStyles: boolean; + const indicatorClass: string; + const requestClass: string; + const addedClass: string; + const settlingClass: string; + const swappingClass: string; + const allowEval: boolean; + const allowScriptTags: boolean; + const inlineScriptNonce: string; + const inlineStyleNonce: string; + const attributesToSettle: string[]; + const withCredentials: boolean; + const timeout: number; + const wsReconnectDelay: "full-jitter" | ((retryCount: number) => number); + const wsBinaryType: BinaryType; + const disableSelector: string; + const scrollBehavior: 'auto' | 'instant' | 'smooth'; + const defaultFocusScroll: boolean; + const getCacheBusterParam: boolean; + const globalViewTransitions: boolean; + const methodsThatUseUrlParams: (HttpVerb)[]; + const selfRequestsOnly: boolean; + const ignoreTitle: boolean; + const scrollIntoViewOnBoost: boolean; + const triggerSpecsCache: any | null; + const disableInheritance: boolean; + const responseHandling: HtmxResponseHandlingConfig[]; + const allowNestedOobSwaps: boolean; + } + const parseInterval: (str: string) => number; + const _: (str: string) => any; + const version: string; +} +type HttpVerb = 'get' | 'head' | 'post' | 'put' | 'delete' | 'connect' | 'options' | 'trace' | 'patch'; +type SwapOptions = { + select?: string; + selectOOB?: string; + eventInfo?: any; + anchor?: string; + contextElement?: Element; + afterSwapCallback?: swapCallback; + afterSettleCallback?: swapCallback; +}; +type swapCallback = () => any; +type HtmxSwapStyle = 'innerHTML' | 'outerHTML' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'delete' | 'none' | string; +type HtmxSwapSpecification = { + swapStyle: HtmxSwapStyle; + swapDelay: number; + settleDelay: number; + transition?: boolean; + ignoreTitle?: boolean; + head?: string; + scroll?: 'top' | 'bottom'; + scrollTarget?: string; + show?: string; + showTarget?: string; + focusScroll?: boolean; +}; +type ConditionalFunction = ((this: Node, evt: Event) => boolean) & { + source: string; +}; +type HtmxTriggerSpecification = { + trigger: string; + pollInterval?: number; + eventFilter?: ConditionalFunction; + changed?: boolean; + once?: boolean; + consume?: boolean; + delay?: number; + from?: string; + target?: string; + throttle?: number; + queue?: string; + root?: string; + threshold?: string; +}; +type HtmxElementValidationError = { + elt: Element; + message: string; + validity: ValidityState; +}; +type HtmxHeaderSpecification = Record<string, string>; +type HtmxAjaxHelperContext = { + source?: Element | string; + event?: Event; + handler?: HtmxAjaxHandler; + target: Element | string; + swap?: HtmxSwapStyle; + values?: any | FormData; + headers?: Record<string, string>; + select?: string; +}; +type HtmxRequestConfig = { + boosted: boolean; + useUrlParams: boolean; + formData: FormData; + /** + * formData proxy + */ + parameters: any; + unfilteredFormData: FormData; + /** + * unfilteredFormData proxy + */ + unfilteredParameters: any; + headers: HtmxHeaderSpecification; + target: Element; + verb: HttpVerb; + errors: HtmxElementValidationError[]; + withCredentials: boolean; + timeout: number; + path: string; + triggeringEvent: Event; +}; +type HtmxResponseInfo = { + xhr: XMLHttpRequest; + target: Element; + requestConfig: HtmxRequestConfig; + etc: HtmxAjaxEtc; + boosted: boolean; + select: string; + pathInfo: { + requestPath: string; + finalRequestPath: string; + responsePath: string | null; + anchor: string; + }; + failed?: boolean; + successful?: boolean; +}; +type HtmxAjaxEtc = { + returnPromise?: boolean; + handler?: HtmxAjaxHandler; + select?: string; + targetOverride?: Element; + swapOverride?: HtmxSwapStyle; + headers?: Record<string, string>; + values?: any | FormData; + credentials?: boolean; + timeout?: number; +}; +type HtmxResponseHandlingConfig = { + code?: string; + swap: boolean; + error?: boolean; + ignoreTitle?: boolean; + select?: string; + target?: string; + swapOverride?: string; + event?: string; +}; +type HtmxBeforeSwapDetails = HtmxResponseInfo & { + shouldSwap: boolean; + serverResponse: any; + isError: boolean; + ignoreTitle: boolean; + selectOverride: string; +}; +type HtmxAjaxHandler = (elt: Element, responseInfo: HtmxResponseInfo) => any; +type HtmxSettleTask = (() => void); +type HtmxSettleInfo = { + tasks: HtmxSettleTask[]; + elts: Element[]; + title?: string; +}; +type HtmxExtension = any; diff --git a/code/ch5_partials/ch5_final_video_collector/static/js/htmx.js b/code/ch5_partials/ch5_final_video_collector/static/js/htmx.js index 86e7668..c57bcd7 100644 --- a/code/ch5_partials/ch5_final_video_collector/static/js/htmx.js +++ b/code/ch5_partials/ch5_final_video_collector/static/js/htmx.js @@ -1,3909 +1,5131 @@ -// /////////////////////////////////////////////////////////////////// -// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.js -// - -// UMD insanity -// This code sets up support for (in order) AMD, ES6 modules, and globals. -(function (root, factory) { - //@ts-ignore - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - //@ts-ignore - define([], factory); - } else if (typeof module === 'object' && module.exports) { - // Node. Does not work with strict CommonJS, but - // only CommonJS-like environments that support module.exports, - // like Node. - module.exports = factory(); - } else { - // Browser globals - root.htmx = root.htmx || factory(); - } -}(typeof self !== 'undefined' ? self : this, function () { -return (function () { - 'use strict'; - - // Public API - //** @type {import("./htmx").HtmxApi} */ - // TODO: list all methods in public API - var htmx = { - onLoad: onLoadHelper, - process: processNode, - on: addEventListenerImpl, - off: removeEventListenerImpl, - trigger : triggerEvent, - ajax : ajaxHelper, - find : find, - findAll : findAll, - closest : closest, - values : function(elt, type){ - var inputValues = getInputValues(elt, type || "post"); - return inputValues.values; - }, - remove : removeElement, - addClass : addClassToElement, - removeClass : removeClassFromElement, - toggleClass : toggleClassOnElement, - takeClass : takeClassForElement, - defineExtension : defineExtension, - removeExtension : removeExtension, - logAll : logAll, - logNone : logNone, - logger : null, - config : { - historyEnabled:true, - historyCacheSize:10, - refreshOnHistoryMiss:false, - defaultSwapStyle:'innerHTML', - defaultSwapDelay:0, - defaultSettleDelay:20, - includeIndicatorStyles:true, - indicatorClass:'htmx-indicator', - requestClass:'htmx-request', - addedClass:'htmx-added', - settlingClass:'htmx-settling', - swappingClass:'htmx-swapping', - allowEval:true, - allowScriptTags:true, - inlineScriptNonce:'', - attributesToSettle:["class", "style", "width", "height"], - withCredentials:false, - timeout:0, - wsReconnectDelay: 'full-jitter', - wsBinaryType: 'blob', - disableSelector: "[hx-disable], [data-hx-disable]", - useTemplateFragments: false, - scrollBehavior: 'smooth', - defaultFocusScroll: false, - getCacheBusterParam: false, - globalViewTransitions: false, - methodsThatUseUrlParams: ["get"], - selfRequestsOnly: false, - ignoreTitle: false, - scrollIntoViewOnBoost: true, - triggerSpecsCache: null, - }, - parseInterval:parseInterval, - _:internalEval, - createEventSource: function(url){ - return new EventSource(url, {withCredentials:true}) - }, - createWebSocket: function(url){ - var sock = new WebSocket(url, []); - sock.binaryType = htmx.config.wsBinaryType; - return sock; - }, - version: "1.9.10" - }; - - /** @type {import("./htmx").HtmxInternalApi} */ - var internalAPI = { - addTriggerHandler: addTriggerHandler, - bodyContains: bodyContains, - canAccessLocalStorage: canAccessLocalStorage, - findThisElement: findThisElement, - filterValues: filterValues, - hasAttribute: hasAttribute, - getAttributeValue: getAttributeValue, - getClosestAttributeValue: getClosestAttributeValue, - getClosestMatch: getClosestMatch, - getExpressionVars: getExpressionVars, - getHeaders: getHeaders, - getInputValues: getInputValues, - getInternalData: getInternalData, - getSwapSpecification: getSwapSpecification, - getTriggerSpecs: getTriggerSpecs, - getTarget: getTarget, - makeFragment: makeFragment, - mergeObjects: mergeObjects, - makeSettleInfo: makeSettleInfo, - oobSwap: oobSwap, - querySelectorExt: querySelectorExt, - selectAndSwap: selectAndSwap, - settleImmediately: settleImmediately, - shouldCancel: shouldCancel, - triggerEvent: triggerEvent, - triggerErrorEvent: triggerErrorEvent, - withExtensions: withExtensions, - } - - var VERBS = ['get', 'post', 'put', 'delete', 'patch']; - var VERB_SELECTOR = VERBS.map(function(verb){ - return "[hx-" + verb + "], [data-hx-" + verb + "]" - }).join(", "); - - var HEAD_TAG_REGEX = makeTagRegEx('head'), - TITLE_TAG_REGEX = makeTagRegEx('title'), - SVG_TAGS_REGEX = makeTagRegEx('svg', true); - - //==================================================================== - // Utilities - //==================================================================== - - /** - * @param {string} tag - * @param {boolean} global - * @returns {RegExp} - */ - function makeTagRegEx(tag, global = false) { - return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, - global ? 'gim' : 'im'); - } - - function parseInterval(str) { - if (str == undefined) { - return undefined; - } - - let interval = NaN; - if (str.slice(-2) == "ms") { - interval = parseFloat(str.slice(0, -2)); - } else if (str.slice(-1) == "s") { - interval = parseFloat(str.slice(0, -1)) * 1000; - } else if (str.slice(-1) == "m") { - interval = parseFloat(str.slice(0, -1)) * 1000 * 60; - } else { - interval = parseFloat(str); - } - return isNaN(interval) ? undefined : interval; - } - - /** - * @param {HTMLElement} elt - * @param {string} name - * @returns {(string | null)} - */ - function getRawAttribute(elt, name) { - return elt.getAttribute && elt.getAttribute(name); - } - - // resolve with both hx and data-hx prefixes - function hasAttribute(elt, qualifiedName) { - return elt.hasAttribute && (elt.hasAttribute(qualifiedName) || - elt.hasAttribute("data-" + qualifiedName)); - } - - /** - * - * @param {HTMLElement} elt - * @param {string} qualifiedName - * @returns {(string | null)} - */ - function getAttributeValue(elt, qualifiedName) { - return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); - } - - /** - * @param {HTMLElement} elt - * @returns {HTMLElement | null} - */ - function parentElt(elt) { - return elt.parentElement; - } - - /** - * @returns {Document} - */ - function getDocument() { - return document; - } - - /** - * @param {HTMLElement} elt - * @param {(e:HTMLElement) => boolean} condition - * @returns {HTMLElement | null} - */ - function getClosestMatch(elt, condition) { - while (elt && !condition(elt)) { - elt = parentElt(elt); - } - - return elt ? elt : null; - } - - function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ - var attributeValue = getAttributeValue(ancestor, attributeName); - var disinherit = getAttributeValue(ancestor, "hx-disinherit"); - if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) { - return "unset"; - } else { - return attributeValue - } - } - - /** - * @param {HTMLElement} elt - * @param {string} attributeName - * @returns {string | null} - */ - function getClosestAttributeValue(elt, attributeName) { - var closestAttr = null; - getClosestMatch(elt, function (e) { - return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName); - }); - if (closestAttr !== "unset") { - return closestAttr; - } - } - - /** - * @param {HTMLElement} elt - * @param {string} selector - * @returns {boolean} - */ - function matches(elt, selector) { - // @ts-ignore: non-standard properties for browser compatibility - // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; - return matchesFunction && matchesFunction.call(elt, selector); - } - - /** - * @param {string} str - * @returns {string} - */ - 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 ""; - } - } - - /** - * - * @param {string} resp - * @param {number} depth - * @returns {Element} - */ - function parseHTML(resp, depth) { - var parser = new DOMParser(); - var responseDoc = parser.parseFromString(resp, "text/html"); - - /** @type {Element} */ - var responseNode = responseDoc.body; - while (depth > 0) { - depth--; - // @ts-ignore - responseNode = responseNode.firstChild; - } - if (responseNode == null) { - // @ts-ignore - responseNode = getDocument().createDocumentFragment(); - } - return responseNode; - } - - function aFullPageResponse(resp) { - return /<body/.test(resp) - } +// v2.0.0 from https://github.com/bigskysoftware/htmx/releases + +var htmx = (function() { + 'use strict' + + // Public API + const htmx = { + // Tsc madness here, assigning the functions directly results in an invalid TypeScript output, but reassigning is fine + /* Event processing */ + /** @type {typeof onLoadHelper} */ + onLoad: null, + /** @type {typeof processNode} */ + process: null, + /** @type {typeof addEventListenerImpl} */ + on: null, + /** @type {typeof removeEventListenerImpl} */ + off: null, + /** @type {typeof triggerEvent} */ + trigger: null, + /** @type {typeof ajaxHelper} */ + ajax: null, + /* DOM querying helpers */ + /** @type {typeof find} */ + find: null, + /** @type {typeof findAll} */ + findAll: null, + /** @type {typeof closest} */ + closest: null, + /** + * Returns the input values that would resolve for a given element via the htmx value resolution mechanism + * + * @see https://htmx.org/api/#values + * + * @param {Element} elt the element to resolve values on + * @param {HttpVerb} type the request type (e.g. **get** or **post**) non-GET's will include the enclosing form of the element. Defaults to **post** + * @returns {Object} + */ + values: function(elt, type) { + const inputValues = getInputValues(elt, type || 'post') + return inputValues.values + }, + /* DOM manipulation helpers */ + /** @type {typeof removeElement} */ + remove: null, + /** @type {typeof addClassToElement} */ + addClass: null, + /** @type {typeof removeClassFromElement} */ + removeClass: null, + /** @type {typeof toggleClassOnElement} */ + toggleClass: null, + /** @type {typeof takeClassForElement} */ + takeClass: null, + /** @type {typeof swap} */ + swap: null, + /* Extension entrypoints */ + /** @type {typeof defineExtension} */ + defineExtension: null, + /** @type {typeof removeExtension} */ + removeExtension: null, + /* Debugging */ + /** @type {typeof logAll} */ + logAll: null, + /** @type {typeof logNone} */ + logNone: null, + /* Debugging */ + /** + * The logger htmx uses to log with + * + * @see https://htmx.org/api/#logger + */ + logger: null, + /** + * A property holding the configuration htmx uses at runtime. + * + * Note that using a [meta tag](https://htmx.org/docs/#config) is the preferred mechanism for setting these properties. + * + * @see https://htmx.org/api/#config + */ + config: { + /** + * Whether to use history. + * @type boolean + * @default true + */ + historyEnabled: true, + /** + * The number of pages to keep in **localStorage** for history support. + * @type number + * @default 10 + */ + historyCacheSize: 10, + /** + * @type boolean + * @default false + */ + refreshOnHistoryMiss: false, + /** + * The default swap style to use if **[hx-swap](https://htmx.org/attributes/hx-swap)** is omitted. + * @type HtmxSwapStyle + * @default 'innerHTML' + */ + defaultSwapStyle: 'innerHTML', + /** + * The default delay between receiving a response from the server and doing the swap. + * @type number + * @default 0 + */ + defaultSwapDelay: 0, + /** + * The default delay between completing the content swap and settling attributes. + * @type number + * @default 20 + */ + defaultSettleDelay: 20, + /** + * If true, htmx will inject a small amount of CSS into the page to make indicators invisible unless the **htmx-indicator** class is present. + * @type boolean + * @default true + */ + includeIndicatorStyles: true, + /** + * The class to place on indicators when a request is in flight. + * @type string + * @default 'htmx-indicator' + */ + indicatorClass: 'htmx-indicator', + /** + * The class to place on triggering elements when a request is in flight. + * @type string + * @default 'htmx-request' + */ + requestClass: 'htmx-request', + /** + * The class to temporarily place on elements that htmx has added to the DOM. + * @type string + * @default 'htmx-added' + */ + addedClass: 'htmx-added', + /** + * The class to place on target elements when htmx is in the settling phase. + * @type string + * @default 'htmx-settling' + */ + settlingClass: 'htmx-settling', + /** + * The class to place on target elements when htmx is in the swapping phase. + * @type string + * @default 'htmx-swapping' + */ + swappingClass: 'htmx-swapping', + /** + * Allows the use of eval-like functionality in htmx, to enable **hx-vars**, trigger conditions & script tag evaluation. Can be set to **false** for CSP compatibility. + * @type boolean + * @default true + */ + allowEval: true, + /** + * If set to false, disables the interpretation of script tags. + * @type boolean + * @default true + */ + allowScriptTags: true, + /** + * If set, the nonce will be added to inline scripts. + * @type string + * @default '' + */ + inlineScriptNonce: '', + /** + * If set, the nonce will be added to inline styles. + * @type string + * @default '' + */ + inlineStyleNonce: '', + /** + * The attributes to settle during the settling phase. + * @type string[] + * @default ['class', 'style', 'width', 'height'] + */ + attributesToSettle: ['class', 'style', 'width', 'height'], + /** + * Allow cross-site Access-Control requests using credentials such as cookies, authorization headers or TLS client certificates. + * @type boolean + * @default false + */ + withCredentials: false, + /** + * @type number + * @default 0 + */ + timeout: 0, + /** + * The default implementation of **getWebSocketReconnectDelay** for reconnecting after unexpected connection loss by the event code **Abnormal Closure**, **Service Restart** or **Try Again Later**. + * @type {'full-jitter' | ((retryCount:number) => number)} + * @default "full-jitter" + */ + wsReconnectDelay: 'full-jitter', + /** + * The type of binary data being received over the WebSocket connection + * @type BinaryType + * @default 'blob' + */ + wsBinaryType: 'blob', + /** + * @type string + * @default '[hx-disable], [data-hx-disable]' + */ + disableSelector: '[hx-disable], [data-hx-disable]', + /** + * @type {'auto' | 'instant' | 'smooth'} + * @default 'smooth' + */ + scrollBehavior: 'instant', + /** + * If the focused element should be scrolled into view. + * @type boolean + * @default false + */ + defaultFocusScroll: false, + /** + * If set to true htmx will include a cache-busting parameter in GET requests to avoid caching partial responses by the browser + * @type boolean + * @default false + */ + getCacheBusterParam: false, + /** + * If set to true, htmx will use the View Transition API when swapping in new content. + * @type boolean + * @default false + */ + globalViewTransitions: false, + /** + * htmx will format requests with these methods by encoding their parameters in the URL, not the request body + * @type {(HttpVerb)[]} + * @default ['get', 'delete'] + */ + methodsThatUseUrlParams: ['get', 'delete'], + /** + * If set to true, disables htmx-based requests to non-origin hosts. + * @type boolean + * @default false + */ + selfRequestsOnly: true, + /** + * If set to true htmx will not update the title of the document when a title tag is found in new content + * @type boolean + * @default false + */ + ignoreTitle: false, + /** + * Whether the target of a boosted element is scrolled into the viewport. + * @type boolean + * @default true + */ + scrollIntoViewOnBoost: true, + /** + * The cache to store evaluated trigger specifications into. + * You may define a simple object to use a never-clearing cache, or implement your own system using a [proxy object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Proxy) + * @type {Object|null} + * @default null + */ + triggerSpecsCache: null, + /** @type boolean */ + disableInheritance: false, + /** @type HtmxResponseHandlingConfig[] */ + responseHandling: [ + { code: '204', swap: false }, + { code: '[23]..', swap: true }, + { code: '[45]..', swap: false, error: true } + ], + /** + * Whether to process OOB swaps on elements that are nested within the main response element. + * @type boolean + * @default true + */ + allowNestedOobSwaps: true + }, + /** @type {typeof parseInterval} */ + parseInterval: null, + /** @type {typeof internalEval} */ + _: null, + version: '2.0.0' + } + // Tsc madness part 2 + htmx.onLoad = onLoadHelper + htmx.process = processNode + htmx.on = addEventListenerImpl + htmx.off = removeEventListenerImpl + htmx.trigger = triggerEvent + htmx.ajax = ajaxHelper + htmx.find = find + htmx.findAll = findAll + htmx.closest = closest + htmx.remove = removeElement + htmx.addClass = addClassToElement + htmx.removeClass = removeClassFromElement + htmx.toggleClass = toggleClassOnElement + htmx.takeClass = takeClassForElement + htmx.swap = swap + htmx.defineExtension = defineExtension + htmx.removeExtension = removeExtension + htmx.logAll = logAll + htmx.logNone = logNone + htmx.parseInterval = parseInterval + htmx._ = internalEval + + const internalAPI = { + addTriggerHandler, + bodyContains, + canAccessLocalStorage, + findThisElement, + filterValues, + swap, + hasAttribute, + getAttributeValue, + getClosestAttributeValue, + getClosestMatch, + getExpressionVars, + getHeaders, + getInputValues, + getInternalData, + getSwapSpecification, + getTriggerSpecs, + getTarget, + makeFragment, + mergeObjects, + makeSettleInfo, + oobSwap, + querySelectorExt, + settleImmediately, + shouldCancel, + triggerEvent, + triggerErrorEvent, + withExtensions + } + + const VERBS = ['get', 'post', 'put', 'delete', 'patch'] + const VERB_SELECTOR = VERBS.map(function(verb) { + return '[hx-' + verb + '], [data-hx-' + verb + ']' + }).join(', ') + + const HEAD_TAG_REGEX = makeTagRegEx('head') + + //= =================================================================== + // Utilities + //= =================================================================== + + /** + * @param {string} tag + * @param {boolean} global + * @returns {RegExp} + */ + function makeTagRegEx(tag, global = false) { + return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, + global ? 'gim' : 'im') + } + + /** + * Parses an interval string consistent with the way htmx does. Useful for plugins that have timing-related attributes. + * + * Caution: Accepts an int followed by either **s** or **ms**. All other values use **parseFloat** + * + * @see https://htmx.org/api/#parseInterval + * + * @param {string} str timing string + * @returns {number|undefined} + */ + function parseInterval(str) { + if (str == undefined) { + return undefined + } - /** - * - * @param {string} response - * @returns {Element} - */ - function makeFragment(response) { - var partialResponse = !aFullPageResponse(response); - var startTag = getStartTag(response); - var content = response; - if (startTag === 'head') { - content = content.replace(HEAD_TAG_REGEX, ''); - } - if (htmx.config.useTemplateFragments && partialResponse) { - var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0); - // @ts-ignore type mismatch between DocumentFragment and Element. - // TODO: Are these close enough for htmx to use interchangeably? - return documentFragment.querySelector('template').content; - } - switch (startTag) { - case "thead": - case "tbody": - case "tfoot": - case "colgroup": - case "caption": - return parseHTML("<table>" + content + "</table>", 1); - case "col": - return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2); - case "tr": - return parseHTML("<table><tbody>" + content + "</tbody></table>", 2); - case "td": - case "th": - return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3); - case "script": - case "style": - return parseHTML("<div>" + content + "</div>", 1); - default: - return parseHTML(content, 0); - } - } + let interval = NaN + if (str.slice(-2) == 'ms') { + interval = parseFloat(str.slice(0, -2)) + } else if (str.slice(-1) == 's') { + interval = parseFloat(str.slice(0, -1)) * 1000 + } else if (str.slice(-1) == 'm') { + interval = parseFloat(str.slice(0, -1)) * 1000 * 60 + } else { + interval = parseFloat(str) + } + return isNaN(interval) ? undefined : interval + } + + /** + * @param {Node} elt + * @param {string} name + * @returns {(string | null)} + */ + function getRawAttribute(elt, name) { + return elt instanceof Element && elt.getAttribute(name) + } + + /** + * @param {Element} elt + * @param {string} qualifiedName + * @returns {boolean} + */ + // resolve with both hx and data-hx prefixes + function hasAttribute(elt, qualifiedName) { + return !!elt.hasAttribute && (elt.hasAttribute(qualifiedName) || + elt.hasAttribute('data-' + qualifiedName)) + } + + /** + * + * @param {Node} elt + * @param {string} qualifiedName + * @returns {(string | null)} + */ + function getAttributeValue(elt, qualifiedName) { + return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, 'data-' + qualifiedName) + } + + /** + * @param {Node} elt + * @returns {Node | null} + */ + function parentElt(elt) { + const parent = elt.parentElement + if (!parent && elt.parentNode instanceof ShadowRoot) return elt.parentNode + return parent + } + + /** + * @returns {Document} + */ + function getDocument() { + return document + } + + /** + * @param {Node} elt + * @param {boolean} global + * @returns {Node|Document} + */ + function getRootNode(elt, global) { + return elt.getRootNode ? elt.getRootNode({ composed: global }) : getDocument() + } + + /** + * @param {Node} elt + * @param {(e:Node) => boolean} condition + * @returns {Node | null} + */ + function getClosestMatch(elt, condition) { + while (elt && !condition(elt)) { + elt = parentElt(elt) + } - /** - * @param {Function} func - */ - function maybeCall(func){ - if(func) { - func(); - } + return elt || null + } + + /** + * @param {Element} initialElement + * @param {Element} ancestor + * @param {string} attributeName + * @returns {string|null} + */ + function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName) { + const attributeValue = getAttributeValue(ancestor, attributeName) + const disinherit = getAttributeValue(ancestor, 'hx-disinherit') + var inherit = getAttributeValue(ancestor, 'hx-inherit') + if (initialElement !== ancestor) { + if (htmx.config.disableInheritance) { + if (inherit && (inherit === '*' || inherit.split(' ').indexOf(attributeName) >= 0)) { + return attributeValue + } else { + return null + } + } + if (disinherit && (disinherit === '*' || disinherit.split(' ').indexOf(attributeName) >= 0)) { + return 'unset' + } + } + return attributeValue + } + + /** + * @param {Element} elt + * @param {string} attributeName + * @returns {string | null} + */ + function getClosestAttributeValue(elt, attributeName) { + let closestAttr = null + getClosestMatch(elt, function(e) { + return !!(closestAttr = getAttributeValueWithDisinheritance(elt, asElement(e), attributeName)) + }) + if (closestAttr !== 'unset') { + return closestAttr + } + } + + /** + * @param {Node} elt + * @param {string} selector + * @returns {boolean} + */ + function matches(elt, selector) { + // @ts-ignore: non-standard properties for browser compatibility + // noinspection JSUnresolvedVariable + const matchesFunction = elt instanceof Element && (elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector) + return !!matchesFunction && matchesFunction.call(elt, selector) + } + + /** + * @param {string} str + * @returns {string} + */ + function getStartTag(str) { + const tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i + const match = tagMatcher.exec(str) + if (match) { + return match[1].toLowerCase() + } else { + return '' + } + } + + /** + * @param {string} resp + * @returns {Document} + */ + function parseHTML(resp) { + const parser = new DOMParser() + return parser.parseFromString(resp, 'text/html') + } + + /** + * @param {DocumentFragment} fragment + * @param {Node} elt + */ + function takeChildrenFor(fragment, elt) { + while (elt.childNodes.length > 0) { + fragment.append(elt.childNodes[0]) + } + } + + /** + * @param {HTMLScriptElement} script + * @returns {HTMLScriptElement} + */ + function duplicateScript(script) { + const newScript = getDocument().createElement('script') + forEach(script.attributes, function(attr) { + newScript.setAttribute(attr.name, attr.value) + }) + newScript.textContent = script.textContent + newScript.async = false + if (htmx.config.inlineScriptNonce) { + newScript.nonce = htmx.config.inlineScriptNonce + } + return newScript + } + + /** + * @param {HTMLScriptElement} script + * @returns {boolean} + */ + function isJavaScriptScriptNode(script) { + return script.matches('script') && (script.type === 'text/javascript' || script.type === 'module' || script.type === '') + } + + /** + * we have to make new copies of script tags that we are going to insert because + * SOME browsers (not saying who, but it involves an element and an animal) don't + * execute scripts created in <template> tags when they are inserted into the DOM + * and all the others do lmao + * @param {DocumentFragment} fragment + */ + function normalizeScriptTags(fragment) { + Array.from(fragment.querySelectorAll('script')).forEach(/** @param {HTMLScriptElement} script */ (script) => { + if (isJavaScriptScriptNode(script)) { + const newScript = duplicateScript(script) + const parent = script.parentNode + try { + parent.insertBefore(newScript, script) + } catch (e) { + logError(e) + } finally { + script.remove() + } + } + }) + } + + /** + * @typedef {DocumentFragment & {title?: string}} DocumentFragmentWithTitle + * @description a document fragment representing the response HTML, including + * a `title` property for any title information found + */ + + /** + * @param {string} response HTML + * @returns {DocumentFragmentWithTitle} + */ + function makeFragment(response) { + // strip head tag to determine shape of response we are dealing with + const responseWithNoHead = response.replace(HEAD_TAG_REGEX, '') + const startTag = getStartTag(responseWithNoHead) + /** @type DocumentFragmentWithTitle */ + let fragment + if (startTag === 'html') { + // if it is a full document, parse it and return the body + fragment = /** @type DocumentFragmentWithTitle */ (new DocumentFragment()) + const doc = parseHTML(response) + takeChildrenFor(fragment, doc.body) + fragment.title = doc.title + } else if (startTag === 'body') { + // parse body w/o wrapping in template + fragment = /** @type DocumentFragmentWithTitle */ (new DocumentFragment()) + const doc = parseHTML(responseWithNoHead) + takeChildrenFor(fragment, doc.body) + fragment.title = doc.title + } else { + // otherwise we have non-body partial HTML content, so wrap it in a template to maximize parsing flexibility + const doc = parseHTML('<body><template class="internal-htmx-wrapper">' + responseWithNoHead + '</template></body>') + fragment = /** @type DocumentFragmentWithTitle */ (doc.querySelector('template').content) + // extract title into fragment for later processing + fragment.title = doc.title + + // for legacy reasons we support a title tag at the root level of non-body responses, so we need to handle it + var titleElement = fragment.querySelector('title') + if (titleElement && titleElement.parentNode === fragment) { + titleElement.remove() + fragment.title = titleElement.innerText + } + } + if (fragment) { + if (htmx.config.allowScriptTags) { + normalizeScriptTags(fragment) + } else { + // remove all script tags if scripts are disabled + fragment.querySelectorAll('script').forEach((script) => script.remove()) + } + } + return fragment + } + + /** + * @param {Function} func + */ + function maybeCall(func) { + if (func) { + func() + } + } + + /** + * @param {any} o + * @param {string} type + * @returns + */ + function isType(o, type) { + return Object.prototype.toString.call(o) === '[object ' + type + ']' + } + + /** + * @param {*} o + * @returns {o is Function} + */ + function isFunction(o) { + return typeof o === 'function' + } + + /** + * @param {*} o + * @returns {o is Object} + */ + function isRawObject(o) { + return isType(o, 'Object') + } + + /** + * @typedef {Object} OnHandler + * @property {(keyof HTMLElementEventMap)|string} event + * @property {EventListener} listener + */ + + /** + * @typedef {Object} ListenerInfo + * @property {string} trigger + * @property {EventListener} listener + * @property {EventTarget} on + */ + + /** + * @typedef {Object} HtmxNodeInternalData + * Element data + * @property {number} [initHash] + * @property {boolean} [boosted] + * @property {OnHandler[]} [onHandlers] + * @property {number} [timeout] + * @property {ListenerInfo[]} [listenerInfos] + * @property {boolean} [cancelled] + * @property {boolean} [triggeredOnce] + * @property {number} [delayed] + * @property {number|null} [throttle] + * @property {string} [lastValue] + * @property {boolean} [loaded] + * @property {string} [path] + * @property {string} [verb] + * @property {boolean} [polling] + * @property {HTMLButtonElement|HTMLInputElement|null} [lastButtonClicked] + * @property {number} [requestCount] + * @property {XMLHttpRequest} [xhr] + * @property {(() => void)[]} [queuedRequests] + * @property {boolean} [abortable] + * + * Event data + * @property {HtmxTriggerSpecification} [triggerSpec] + * @property {EventTarget[]} [handledFor] + */ + + /** + * getInternalData retrieves "private" data stored by htmx within an element + * @param {EventTarget|Event} elt + * @returns {HtmxNodeInternalData} + */ + function getInternalData(elt) { + const dataProp = 'htmx-internal-data' + let data = elt[dataProp] + if (!data) { + data = elt[dataProp] = {} + } + return data + } + + /** + * toArray converts an ArrayLike object into a real array. + * @template T + * @param {ArrayLike<T>} arr + * @returns {T[]} + */ + function toArray(arr) { + const returnArr = [] + if (arr) { + for (let i = 0; i < arr.length; i++) { + returnArr.push(arr[i]) + } + } + return returnArr + } + + /** + * @template T + * @param {T[]|NamedNodeMap|HTMLCollection|HTMLFormControlsCollection|ArrayLike<T>} arr + * @param {(T) => void} func + */ + function forEach(arr, func) { + if (arr) { + for (let i = 0; i < arr.length; i++) { + func(arr[i]) + } + } + } + + /** + * @param {Element} el + * @returns {boolean} + */ + function isScrolledIntoView(el) { + const rect = el.getBoundingClientRect() + const elemTop = rect.top + const elemBottom = rect.bottom + return elemTop < window.innerHeight && elemBottom >= 0 + } + + /** + * @param {Node} elt + * @returns {boolean} + */ + function bodyContains(elt) { + // IE Fix + const rootNode = elt.getRootNode && elt.getRootNode() + if (rootNode && rootNode instanceof window.ShadowRoot) { + return getDocument().body.contains(rootNode.host) + } else { + return getDocument().body.contains(elt) + } + } + + /** + * @param {string} trigger + * @returns {string[]} + */ + function splitOnWhitespace(trigger) { + return trigger.trim().split(/\s+/) + } + + /** + * mergeObjects takes all the keys from + * obj2 and duplicates them into obj1 + * @template T1 + * @template T2 + * @param {T1} obj1 + * @param {T2} obj2 + * @returns {T1 & T2} + */ + function mergeObjects(obj1, obj2) { + for (const key in obj2) { + if (obj2.hasOwnProperty(key)) { + // @ts-ignore tsc doesn't seem to properly handle types merging + obj1[key] = obj2[key] + } + } + // @ts-ignore tsc doesn't seem to properly handle types merging + return obj1 + } + + /** + * @param {string} jString + * @returns {any|null} + */ + function parseJSON(jString) { + try { + return JSON.parse(jString) + } catch (error) { + logError(error) + return null + } + } + + /** + * @returns {boolean} + */ + function canAccessLocalStorage() { + const test = 'htmx:localStorageTest' + try { + localStorage.setItem(test, test) + localStorage.removeItem(test) + return true + } catch (e) { + return false + } + } + + /** + * @param {string} path + * @returns {string} + */ + function normalizePath(path) { + try { + const url = new URL(path) + if (url) { + path = url.pathname + url.search + } + // remove trailing slash, unless index page + if (!(/^\/$/.test(path))) { + path = path.replace(/\/+$/, '') + } + return path + } catch (e) { + // be kind to IE11, which doesn't support URL() + return path + } + } + + //= ========================================================================================= + // public API + //= ========================================================================================= + + /** + * @param {string} str + * @returns {any} + */ + function internalEval(str) { + return maybeEval(getDocument().body, function() { + return eval(str) + }) + } + + /** + * Adds a callback for the **htmx:load** event. This can be used to process new content, for example initializing the content with a javascript library + * + * @see https://htmx.org/api/#onLoad + * + * @param {(elt: Node) => void} callback the callback to call on newly loaded content + * @returns {EventListener} + */ + function onLoadHelper(callback) { + const value = htmx.on('htmx:load', /** @param {CustomEvent} evt */ function(evt) { + callback(evt.detail.elt) + }) + return value + } + + /** + * Log all htmx events, useful for debugging. + * + * @see https://htmx.org/api/#logAll + */ + function logAll() { + htmx.logger = function(elt, event, data) { + if (console) { + console.log(event, elt, data) + } + } + } + + function logNone() { + htmx.logger = null + } + + /** + * Finds an element matching the selector + * + * @see https://htmx.org/api/#find + * + * @param {ParentNode|string} eltOrSelector the root element to find the matching element in, inclusive | the selector to match + * @param {string} [selector] the selector to match + * @returns {Element|null} + */ + function find(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return eltOrSelector.querySelector(selector) + } else { + return find(getDocument(), eltOrSelector) + } + } + + /** + * Finds all elements matching the selector + * + * @see https://htmx.org/api/#findAll + * + * @param {ParentNode|string} eltOrSelector the root element to find the matching elements in, inclusive | the selector to match + * @param {string} [selector] the selector to match + * @returns {NodeListOf<Element>} + */ + function findAll(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return eltOrSelector.querySelectorAll(selector) + } else { + return findAll(getDocument(), eltOrSelector) + } + } + + /** + * @returns Window + */ + function getWindow() { + return window + } + + /** + * Removes an element from the DOM + * + * @see https://htmx.org/api/#remove + * + * @param {Node} elt + * @param {number} [delay] + */ + function removeElement(elt, delay) { + elt = resolveTarget(elt) + if (delay) { + getWindow().setTimeout(function() { + removeElement(elt) + elt = null + }, delay) + } else { + parentElt(elt).removeChild(elt) + } + } + + /** + * @param {any} elt + * @return {Element|null} + */ + function asElement(elt) { + return elt instanceof Element ? elt : null + } + + /** + * @param {any} elt + * @return {HTMLElement|null} + */ + function asHtmlElement(elt) { + return elt instanceof HTMLElement ? elt : null + } + + /** + * @param {any} value + * @return {string|null} + */ + function asString(value) { + return typeof value === 'string' ? value : null + } + + /** + * @param {EventTarget} elt + * @return {ParentNode|null} + */ + function asParentNode(elt) { + return elt instanceof Element || elt instanceof Document || elt instanceof DocumentFragment ? elt : null + } + + /** + * This method adds a class to the given element. + * + * @see https://htmx.org/api/#addClass + * + * @param {Element|string} elt the element to add the class to + * @param {string} clazz the class to add + * @param {number} [delay] the delay (in milliseconds) before class is added + */ + function addClassToElement(elt, clazz, delay) { + elt = asElement(resolveTarget(elt)) + if (!elt) { + return + } + if (delay) { + getWindow().setTimeout(function() { + addClassToElement(elt, clazz) + elt = null + }, delay) + } else { + elt.classList && elt.classList.add(clazz) + } + } + + /** + * Removes a class from the given element + * + * @see https://htmx.org/api/#removeClass + * + * @param {Node|string} node element to remove the class from + * @param {string} clazz the class to remove + * @param {number} [delay] the delay (in milliseconds before class is removed) + */ + function removeClassFromElement(node, clazz, delay) { + let elt = asElement(resolveTarget(node)) + if (!elt) { + return + } + if (delay) { + getWindow().setTimeout(function() { + removeClassFromElement(elt, clazz) + elt = null + }, delay) + } else { + if (elt.classList) { + elt.classList.remove(clazz) + // if there are no classes left, remove the class attribute + if (elt.classList.length === 0) { + elt.removeAttribute('class') } + } + } + } + + /** + * Toggles the given class on an element + * + * @see https://htmx.org/api/#toggleClass + * + * @param {Element|string} elt the element to toggle the class on + * @param {string} clazz the class to toggle + */ + function toggleClassOnElement(elt, clazz) { + elt = resolveTarget(elt) + elt.classList.toggle(clazz) + } + + /** + * Takes the given class from its siblings, so that among its siblings, only the given element will have the class. + * + * @see https://htmx.org/api/#takeClass + * + * @param {Node|string} elt the element that will take the class + * @param {string} clazz the class to take + */ + function takeClassForElement(elt, clazz) { + elt = resolveTarget(elt) + forEach(elt.parentElement.children, function(child) { + removeClassFromElement(child, clazz) + }) + addClassToElement(asElement(elt), clazz) + } + + /** + * Finds the closest matching element in the given elements parentage, inclusive of the element + * + * @see https://htmx.org/api/#closest + * + * @param {Element|string} elt the element to find the selector from + * @param {string} selector the selector to find + * @returns {Element|null} + */ + function closest(elt, selector) { + elt = asElement(resolveTarget(elt)) + if (elt && elt.closest) { + return elt.closest(selector) + } else { + // TODO remove when IE goes away + do { + if (elt == null || matches(elt, selector)) { + return elt + } + } + while (elt = elt && asElement(parentElt(elt))) + return null + } + } + + /** + * @param {string} str + * @param {string} prefix + * @returns {boolean} + */ + function startsWith(str, prefix) { + return str.substring(0, prefix.length) === prefix + } + + /** + * @param {string} str + * @param {string} suffix + * @returns {boolean} + */ + function endsWith(str, suffix) { + return str.substring(str.length - suffix.length) === suffix + } + + /** + * @param {string} selector + * @returns {string} + */ + function normalizeSelector(selector) { + const trimmedSelector = selector.trim() + if (startsWith(trimmedSelector, '<') && endsWith(trimmedSelector, '/>')) { + return trimmedSelector.substring(1, trimmedSelector.length - 2) + } else { + return trimmedSelector + } + } + + /** + * @param {Node|Element|Document|string} elt + * @param {string} selector + * @param {boolean=} global + * @returns {(Node|Window)[]} + */ + function querySelectorAllExt(elt, selector, global) { + elt = resolveTarget(elt) + if (selector.indexOf('closest ') === 0) { + return [closest(asElement(elt), normalizeSelector(selector.substr(8)))] + } else if (selector.indexOf('find ') === 0) { + return [find(asParentNode(elt), normalizeSelector(selector.substr(5)))] + } else if (selector === 'next') { + return [asElement(elt).nextElementSibling] + } else if (selector.indexOf('next ') === 0) { + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)), !!global)] + } else if (selector === 'previous') { + return [asElement(elt).previousElementSibling] + } else if (selector.indexOf('previous ') === 0) { + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)), !!global)] + } else if (selector === 'document') { + return [document] + } else if (selector === 'window') { + return [window] + } else if (selector === 'body') { + return [document.body] + } else if (selector === 'root') { + return [getRootNode(elt, !!global)] + } else if (selector.indexOf('global ') === 0) { + return querySelectorAllExt(elt, selector.slice(7), true) + } else { + return toArray(asParentNode(getRootNode(elt, !!global)).querySelectorAll(normalizeSelector(selector))) + } + } + + /** + * @param {Node} start + * @param {string} match + * @param {boolean} global + * @returns {Element} + */ + var scanForwardQuery = function(start, match, global) { + const results = asParentNode(getRootNode(start, global)).querySelectorAll(match) + for (let i = 0; i < results.length; i++) { + const elt = results[i] + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { + return elt + } + } + } + + /** + * @param {Node} start + * @param {string} match + * @param {boolean} global + * @returns {Element} + */ + var scanBackwardsQuery = function(start, match, global) { + const results = asParentNode(getRootNode(start, global)).querySelectorAll(match) + for (let i = results.length - 1; i >= 0; i--) { + const elt = results[i] + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { + return elt + } + } + } + + /** + * @param {Node|string} eltOrSelector + * @param {string=} selector + * @returns {Node|Window} + */ + function querySelectorExt(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return querySelectorAllExt(eltOrSelector, selector)[0] + } else { + return querySelectorAllExt(getDocument().body, eltOrSelector)[0] + } + } + + /** + * @template {EventTarget} T + * @param {T|string} eltOrSelector + * @param {T} [context] + * @returns {Element|T|null} + */ + function resolveTarget(eltOrSelector, context) { + if (typeof eltOrSelector === 'string') { + return find(asParentNode(context) || document, eltOrSelector) + } else { + return eltOrSelector + } + } + + /** + * @typedef {keyof HTMLElementEventMap|string} AnyEventName + */ + + /** + * @typedef {Object} EventArgs + * @property {EventTarget} target + * @property {AnyEventName} event + * @property {EventListener} listener + */ + + /** + * @param {EventTarget|AnyEventName} arg1 + * @param {AnyEventName|EventListener} arg2 + * @param {EventListener} [arg3] + * @returns {EventArgs} + */ + function processEventArgs(arg1, arg2, arg3) { + if (isFunction(arg2)) { + return { + target: getDocument().body, + event: asString(arg1), + listener: arg2 + } + } else { + return { + target: resolveTarget(arg1), + event: asString(arg2), + listener: arg3 + } + } + } + + /** + * Adds an event listener to an element + * + * @see https://htmx.org/api/#on + * + * @param {EventTarget|string} arg1 the element to add the listener to | the event name to add the listener for + * @param {string|EventListener} arg2 the event name to add the listener for | the listener to add + * @param {EventListener} [arg3] the listener to add + * @returns {EventListener} + */ + function addEventListenerImpl(arg1, arg2, arg3) { + ready(function() { + const eventArgs = processEventArgs(arg1, arg2, arg3) + eventArgs.target.addEventListener(eventArgs.event, eventArgs.listener) + }) + const b = isFunction(arg2) + return b ? arg2 : arg3 + } + + /** + * Removes an event listener from an element + * + * @see https://htmx.org/api/#off + * + * @param {EventTarget|string} arg1 the element to remove the listener from | the event name to remove the listener from + * @param {string|EventListener} arg2 the event name to remove the listener from | the listener to remove + * @param {EventListener} [arg3] the listener to remove + * @returns {EventListener} + */ + function removeEventListenerImpl(arg1, arg2, arg3) { + ready(function() { + const eventArgs = processEventArgs(arg1, arg2, arg3) + eventArgs.target.removeEventListener(eventArgs.event, eventArgs.listener) + }) + return isFunction(arg2) ? arg2 : arg3 + } + + //= =================================================================== + // Node processing + //= =================================================================== + + const DUMMY_ELT = getDocument().createElement('output') // dummy element for bad selectors + /** + * @param {Element} elt + * @param {string} attrName + * @returns {(Node|Window)[]} + */ + function findAttributeTargets(elt, attrName) { + const attrTarget = getClosestAttributeValue(elt, attrName) + if (attrTarget) { + if (attrTarget === 'this') { + return [findThisElement(elt, attrName)] + } else { + const result = querySelectorAllExt(elt, attrTarget) + if (result.length === 0) { + logError('The selector "' + attrTarget + '" on ' + attrName + ' returned no matches!') + return [DUMMY_ELT] + } else { + return result + } + } + } + } + + /** + * @param {Element} elt + * @param {string} attribute + * @returns {Element|null} + */ + function findThisElement(elt, attribute) { + return asElement(getClosestMatch(elt, function(elt) { + return getAttributeValue(asElement(elt), attribute) != null + })) + } + + /** + * @param {Element} elt + * @returns {Node|Window|null} + */ + function getTarget(elt) { + const targetStr = getClosestAttributeValue(elt, 'hx-target') + if (targetStr) { + if (targetStr === 'this') { + return findThisElement(elt, 'hx-target') + } else { + return querySelectorExt(elt, targetStr) + } + } else { + const data = getInternalData(elt) + if (data.boosted) { + return getDocument().body + } else { + return elt + } + } + } + + /** + * @param {string} name + * @returns {boolean} + */ + function shouldSettleAttribute(name) { + const attributesToSettle = htmx.config.attributesToSettle + for (let i = 0; i < attributesToSettle.length; i++) { + if (name === attributesToSettle[i]) { + return true + } + } + return false + } + + /** + * @param {Element} mergeTo + * @param {Element} mergeFrom + */ + function cloneAttributes(mergeTo, mergeFrom) { + forEach(mergeTo.attributes, function(attr) { + if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) { + mergeTo.removeAttribute(attr.name) + } + }) + forEach(mergeFrom.attributes, function(attr) { + if (shouldSettleAttribute(attr.name)) { + mergeTo.setAttribute(attr.name, attr.value) + } + }) + } + + /** + * @param {HtmxSwapStyle} swapStyle + * @param {Element} target + * @returns {boolean} + */ + function isInlineSwap(swapStyle, target) { + const extensions = getExtensions(target) + for (let i = 0; i < extensions.length; i++) { + const extension = extensions[i] + try { + if (extension.isInlineSwap(swapStyle)) { + return true + } + } catch (e) { + logError(e) + } + } + return swapStyle === 'outerHTML' + } + + /** + * @param {string} oobValue + * @param {Element} oobElement + * @param {HtmxSettleInfo} settleInfo + * @returns + */ + function oobSwap(oobValue, oobElement, settleInfo) { + let selector = '#' + getRawAttribute(oobElement, 'id') + /** @type HtmxSwapStyle */ + let swapStyle = 'outerHTML' + if (oobValue === 'true') { + // do nothing + } else if (oobValue.indexOf(':') > 0) { + swapStyle = oobValue.substr(0, oobValue.indexOf(':')) + selector = oobValue.substr(oobValue.indexOf(':') + 1, oobValue.length) + } else { + swapStyle = oobValue + } - /** - * @param {any} o - * @param {string} type - * @returns - */ - function isType(o, type) { - return Object.prototype.toString.call(o) === "[object " + type + "]"; - } - - /** - * @param {*} o - * @returns {o is Function} - */ - function isFunction(o) { - return isType(o, "Function"); - } - - /** - * @param {*} o - * @returns {o is Object} - */ - function isRawObject(o) { - return isType(o, "Object"); - } - - /** - * getInternalData retrieves "private" data stored by htmx within an element - * @param {HTMLElement} elt - * @returns {*} - */ - function getInternalData(elt) { - var dataProp = 'htmx-internal-data'; - var data = elt[dataProp]; - if (!data) { - data = elt[dataProp] = {}; - } - return data; - } - - /** - * toArray converts an ArrayLike object into a real array. - * @param {ArrayLike} arr - * @returns {any[]} - */ - function toArray(arr) { - var returnArr = []; - if (arr) { - for (var i = 0; i < arr.length; i++) { - returnArr.push(arr[i]); - } - } - return returnArr + const targets = getDocument().querySelectorAll(selector) + if (targets) { + forEach( + targets, + function(target) { + let fragment + const oobElementClone = oobElement.cloneNode(true) + fragment = getDocument().createDocumentFragment() + fragment.appendChild(oobElementClone) + if (!isInlineSwap(swapStyle, target)) { + fragment = asParentNode(oobElementClone) // if this is not an inline swap, we use the content of the node, not the node itself + } + + const beforeSwapDetails = { shouldSwap: true, target, fragment } + if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return + + target = beforeSwapDetails.target // allow re-targeting + if (beforeSwapDetails.shouldSwap) { + swapWithStyle(swapStyle, target, target, fragment, settleInfo) + } + forEach(settleInfo.elts, function(elt) { + triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails) + }) + } + ) + oobElement.parentNode.removeChild(oobElement) + } else { + oobElement.parentNode.removeChild(oobElement) + triggerErrorEvent(getDocument().body, 'htmx:oobErrorNoTarget', { content: oobElement }) + } + return oobValue + } + + /** + * @param {DocumentFragment} fragment + */ + function handlePreservedElements(fragment) { + forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function(preservedElt) { + const id = getAttributeValue(preservedElt, 'id') + const oldElt = getDocument().getElementById(id) + if (oldElt != null) { + preservedElt.parentNode.replaceChild(oldElt, preservedElt) + } + }) + } + + /** + * @param {Node} parentNode + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function handleAttributes(parentNode, fragment, settleInfo) { + forEach(fragment.querySelectorAll('[id]'), function(newNode) { + const id = getRawAttribute(newNode, 'id') + if (id && id.length > 0) { + const normalizedId = id.replace("'", "\\'") + const normalizedTag = newNode.tagName.replace(':', '\\:') + const parentElt = asParentNode(parentNode) + const oldNode = parentElt && parentElt.querySelector(normalizedTag + "[id='" + normalizedId + "']") + if (oldNode && oldNode !== parentElt) { + const newAttributes = newNode.cloneNode() + cloneAttributes(newNode, oldNode) + settleInfo.tasks.push(function() { + cloneAttributes(newNode, newAttributes) + }) + } + } + }) + } + + /** + * @param {Node} child + * @returns {HtmxSettleTask} + */ + function makeAjaxLoadTask(child) { + return function() { + removeClassFromElement(child, htmx.config.addedClass) + processNode(asElement(child)) + processFocus(asParentNode(child)) + triggerEvent(child, 'htmx:load') + } + } + + /** + * @param {ParentNode} child + */ + function processFocus(child) { + const autofocus = '[autofocus]' + const autoFocusedElt = asHtmlElement(matches(child, autofocus) ? child : child.querySelector(autofocus)) + if (autoFocusedElt != null) { + autoFocusedElt.focus() + } + } + + /** + * @param {Node} parentNode + * @param {Node} insertBefore + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) { + handleAttributes(parentNode, fragment, settleInfo) + while (fragment.childNodes.length > 0) { + const child = fragment.firstChild + addClassToElement(asElement(child), htmx.config.addedClass) + parentNode.insertBefore(child, insertBefore) + if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { + settleInfo.tasks.push(makeAjaxLoadTask(child)) + } + } + } + + /** + * based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, + * derived from Java's string hashcode implementation + * @param {string} string + * @param {number} hash + * @returns {number} + */ + function stringHash(string, hash) { + let char = 0 + while (char < string.length) { + hash = (hash << 5) - hash + string.charCodeAt(char++) | 0 // bitwise or ensures we have a 32-bit int + } + return hash + } + + /** + * @param {Element} elt + * @returns {number} + */ + function attributeHash(elt) { + let hash = 0 + // IE fix + if (elt.attributes) { + for (let i = 0; i < elt.attributes.length; i++) { + const attribute = elt.attributes[i] + if (attribute.value) { // only include attributes w/ actual values (empty is same as non-existent) + hash = stringHash(attribute.name, hash) + hash = stringHash(attribute.value, hash) + } + } + } + return hash + } + + /** + * @param {EventTarget} elt + */ + function deInitOnHandlers(elt) { + const internalData = getInternalData(elt) + if (internalData.onHandlers) { + for (let i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i] + removeEventListenerImpl(elt, handlerInfo.event, handlerInfo.listener) + } + delete internalData.onHandlers + } + } + + /** + * @param {Node} element + */ + function deInitNode(element) { + const internalData = getInternalData(element) + if (internalData.timeout) { + clearTimeout(internalData.timeout) + } + if (internalData.listenerInfos) { + forEach(internalData.listenerInfos, function(info) { + if (info.on) { + removeEventListenerImpl(info.on, info.trigger, info.listener) } - - function forEach(arr, func) { - if (arr) { - for (var i = 0; i < arr.length; i++) { - func(arr[i]); - } - } + }) + } + deInitOnHandlers(element) + forEach(Object.keys(internalData), function(key) { delete internalData[key] }) + } + + /** + * @param {Node} element + */ + function cleanUpElement(element) { + triggerEvent(element, 'htmx:beforeCleanupElement') + deInitNode(element) + // @ts-ignore IE11 code + // noinspection JSUnresolvedReference + if (element.children) { // IE + // @ts-ignore + forEach(element.children, function(child) { cleanUpElement(child) }) + } + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapOuterHTML(target, fragment, settleInfo) { + /** @type {Node} */ + let newElt + const eltBeforeNewContent = target.previousSibling + insertNodesBefore(parentElt(target), target, fragment, settleInfo) + if (eltBeforeNewContent == null) { + newElt = parentElt(target).firstChild + } else { + newElt = eltBeforeNewContent.nextSibling + } + settleInfo.elts = settleInfo.elts.filter(function(e) { return e !== target }) + while (newElt && newElt !== target) { + if (newElt instanceof Element) { + settleInfo.elts.push(newElt) + newElt = newElt.nextElementSibling + } else { + newElt = null + } + } + cleanUpElement(target) + if (target instanceof Element) { + target.remove() + } else { + target.parentNode.removeChild(target) + } + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapAfterBegin(target, fragment, settleInfo) { + return insertNodesBefore(target, target.firstChild, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapBeforeBegin(target, fragment, settleInfo) { + return insertNodesBefore(parentElt(target), target, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapBeforeEnd(target, fragment, settleInfo) { + return insertNodesBefore(target, null, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapAfterEnd(target, fragment, settleInfo) { + return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo) + } + + /** + * @param {Node} target + */ + function swapDelete(target) { + cleanUpElement(target) + return parentElt(target).removeChild(target) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapInnerHTML(target, fragment, settleInfo) { + const firstChild = target.firstChild + insertNodesBefore(target, firstChild, fragment, settleInfo) + if (firstChild) { + while (firstChild.nextSibling) { + cleanUpElement(firstChild.nextSibling) + target.removeChild(firstChild.nextSibling) + } + cleanUpElement(firstChild) + target.removeChild(firstChild) + } + } + + /** + * @param {HtmxSwapStyle} swapStyle + * @param {Element} elt + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapWithStyle(swapStyle, elt, target, fragment, settleInfo) { + switch (swapStyle) { + case 'none': + return + case 'outerHTML': + swapOuterHTML(target, fragment, settleInfo) + return + case 'afterbegin': + swapAfterBegin(target, fragment, settleInfo) + return + case 'beforebegin': + swapBeforeBegin(target, fragment, settleInfo) + return + case 'beforeend': + swapBeforeEnd(target, fragment, settleInfo) + return + case 'afterend': + swapAfterEnd(target, fragment, settleInfo) + return + case 'delete': + swapDelete(target) + return + default: + var extensions = getExtensions(elt) + for (let i = 0; i < extensions.length; i++) { + const ext = extensions[i] + try { + const newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo) + if (newElements) { + if (typeof newElements.length !== 'undefined') { + // if handleSwap returns an array (like) of elements, we handle them + for (let j = 0; j < newElements.length; j++) { + const child = newElements[j] + if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { + settleInfo.tasks.push(makeAjaxLoadTask(child)) + } + } + } + return + } + } catch (e) { + logError(e) + } + } + if (swapStyle === 'innerHTML') { + swapInnerHTML(target, fragment, settleInfo) + } else { + swapWithStyle(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo) } + } + } + + /** + * @param {DocumentFragment} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function findAndSwapOobElements(fragment, settleInfo) { + forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function(oobElement) { + if (htmx.config.allowNestedOobSwaps || oobElement.parentElement === null) { + const oobValue = getAttributeValue(oobElement, 'hx-swap-oob') + if (oobValue != null) { + oobSwap(oobValue, oobElement, settleInfo) + } + } else { + oobElement.removeAttribute('hx-swap-oob') + oobElement.removeAttribute('data-hx-swap-oob') + } + }) + } + + /** + * Implements complete swapping pipeline, including: focus and selection preservation, + * title updates, scroll, OOB swapping, normal swapping and settling + * @param {string|Element} target + * @param {string} content + * @param {HtmxSwapSpecification} swapSpec + * @param {SwapOptions} [swapOptions] + */ + function swap(target, content, swapSpec, swapOptions) { + if (!swapOptions) { + swapOptions = {} + } - function isScrolledIntoView(el) { - var rect = el.getBoundingClientRect(); - var elemTop = rect.top; - var elemBottom = rect.bottom; - return elemTop < window.innerHeight && elemBottom >= 0; - } + target = resolveTarget(target) + + // preserve focus and selection + const activeElt = document.activeElement + let selectionInfo = {} + try { + selectionInfo = { + elt: activeElt, + // @ts-ignore + start: activeElt ? activeElt.selectionStart : null, + // @ts-ignore + end: activeElt ? activeElt.selectionEnd : null + } + } catch (e) { + // safari issue - see https://github.com/microsoft/playwright/issues/5894 + } + const settleInfo = makeSettleInfo(target) - function bodyContains(elt) { - // IE Fix - if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) { - return getDocument().body.contains(elt.getRootNode().host); - } else { - return getDocument().body.contains(elt); - } - } + // For text content swaps, don't parse the response as HTML, just insert it + if (swapSpec.swapStyle === 'textContent') { + target.textContent = content + // Otherwise, make the fragment and process it + } else { + let fragment = makeFragment(content) + + settleInfo.title = fragment.title + + // select-oob swaps + if (swapOptions.selectOOB) { + const oobSelectValues = swapOptions.selectOOB.split(',') + for (let i = 0; i < oobSelectValues.length; i++) { + const oobSelectValue = oobSelectValues[i].split(':', 2) + let id = oobSelectValue[0].trim() + if (id.indexOf('#') === 0) { + id = id.substring(1) + } + const oobValue = oobSelectValue[1] || 'true' + const oobElement = fragment.querySelector('#' + id) + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo) + } + } + } + // oob swaps + findAndSwapOobElements(fragment, settleInfo) + forEach(findAll(fragment, 'template'), /** @param {HTMLTemplateElement} template */function(template) { + findAndSwapOobElements(template.content, settleInfo) + if (template.content.childElementCount === 0) { + // Avoid polluting the DOM with empty templates that were only used to encapsulate oob swap + template.remove() + } + }) + + // normal swap + if (swapOptions.select) { + const newFragment = getDocument().createDocumentFragment() + forEach(fragment.querySelectorAll(swapOptions.select), function(node) { + newFragment.appendChild(node) + }) + fragment = newFragment + } + handlePreservedElements(fragment) + swapWithStyle(swapSpec.swapStyle, swapOptions.contextElement, target, fragment, settleInfo) + } - function splitOnWhitespace(trigger) { - return trigger.trim().split(/\s+/); - } + // apply saved focus and selection information to swapped content + if (selectionInfo.elt && + !bodyContains(selectionInfo.elt) && + getRawAttribute(selectionInfo.elt, 'id')) { + const newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, 'id')) + const focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll } + if (newActiveElt) { + // @ts-ignore + if (selectionInfo.start && newActiveElt.setSelectionRange) { + try { + // @ts-ignore + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end) + } catch (e) { + // the setSelectionRange method is present on fields that don't support it, so just let this fail + } + } + newActiveElt.focus(focusOptions) + } + } - /** - * mergeObjects takes all of the keys from - * obj2 and duplicates them into obj1 - * @param {Object} obj1 - * @param {Object} obj2 - * @returns {Object} - */ - function mergeObjects(obj1, obj2) { - for (var key in obj2) { - if (obj2.hasOwnProperty(key)) { - obj1[key] = obj2[key]; - } - } - return obj1; - } + target.classList.remove(htmx.config.swappingClass) + forEach(settleInfo.elts, function(elt) { + if (elt.classList) { + elt.classList.add(htmx.config.settlingClass) + } + triggerEvent(elt, 'htmx:afterSwap', swapOptions.eventInfo) + }) + if (swapOptions.afterSwapCallback) { + swapOptions.afterSwapCallback() + } - function parseJSON(jString) { - try { - return JSON.parse(jString); - } catch(error) { - logError(error); - return null; - } - } + // merge in new title after swap but before settle + if (!swapSpec.ignoreTitle) { + handleTitle(settleInfo.title) + } - function canAccessLocalStorage() { - var test = 'htmx:localStorageTest'; - try { - localStorage.setItem(test, test); - localStorage.removeItem(test); - return true; - } catch(e) { - return false; - } - } + // settle + const doSettle = function() { + forEach(settleInfo.tasks, function(task) { + task.call() + }) + forEach(settleInfo.elts, function(elt) { + if (elt.classList) { + elt.classList.remove(htmx.config.settlingClass) + } + triggerEvent(elt, 'htmx:afterSettle', swapOptions.eventInfo) + }) + + if (swapOptions.anchor) { + const anchorTarget = asElement(resolveTarget('#' + swapOptions.anchor)) + if (anchorTarget) { + anchorTarget.scrollIntoView({ block: 'start', behavior: 'auto' }) + } + } + + updateScrollState(settleInfo.elts, swapSpec) + if (swapOptions.afterSettleCallback) { + swapOptions.afterSettleCallback() + } + } - function normalizePath(path) { + if (swapSpec.settleDelay > 0) { + getWindow().setTimeout(doSettle, swapSpec.settleDelay) + } else { + doSettle() + } + } + + /** + * @param {XMLHttpRequest} xhr + * @param {string} header + * @param {EventTarget} elt + */ + function handleTriggerHeader(xhr, header, elt) { + const triggerBody = xhr.getResponseHeader(header) + if (triggerBody.indexOf('{') === 0) { + const triggers = parseJSON(triggerBody) + for (const eventName in triggers) { + if (triggers.hasOwnProperty(eventName)) { + let detail = triggers[eventName] + if (!isRawObject(detail)) { + detail = { value: detail } + } + triggerEvent(elt, eventName, detail) + } + } + } else { + const eventNames = triggerBody.split(',') + for (let i = 0; i < eventNames.length; i++) { + triggerEvent(elt, eventNames[i].trim(), []) + } + } + } + + const WHITESPACE = /\s/ + const WHITESPACE_OR_COMMA = /[\s,]/ + const SYMBOL_START = /[_$a-zA-Z]/ + const SYMBOL_CONT = /[_$a-zA-Z0-9]/ + const STRINGISH_START = ['"', "'", '/'] + const NOT_WHITESPACE = /[^\s]/ + const COMBINED_SELECTOR_START = /[{(]/ + const COMBINED_SELECTOR_END = /[})]/ + + /** + * @param {string} str + * @returns {string[]} + */ + function tokenizeString(str) { + /** @type string[] */ + const tokens = [] + let position = 0 + while (position < str.length) { + if (SYMBOL_START.exec(str.charAt(position))) { + var startPosition = position + while (SYMBOL_CONT.exec(str.charAt(position + 1))) { + position++ + } + tokens.push(str.substr(startPosition, position - startPosition + 1)) + } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) { + const startChar = str.charAt(position) + var startPosition = position + position++ + while (position < str.length && str.charAt(position) !== startChar) { + if (str.charAt(position) === '\\') { + position++ + } + position++ + } + tokens.push(str.substr(startPosition, position - startPosition + 1)) + } else { + const symbol = str.charAt(position) + tokens.push(symbol) + } + position++ + } + return tokens + } + + /** + * @param {string} token + * @param {string|null} last + * @param {string} paramName + * @returns {boolean} + */ + function isPossibleRelativeReference(token, last, paramName) { + return SYMBOL_START.exec(token.charAt(0)) && + token !== 'true' && + token !== 'false' && + token !== 'this' && + token !== paramName && + last !== '.' + } + + /** + * @param {EventTarget|string} elt + * @param {string[]} tokens + * @param {string} paramName + * @returns {ConditionalFunction|null} + */ + function maybeGenerateConditional(elt, tokens, paramName) { + if (tokens[0] === '[') { + tokens.shift() + let bracketCount = 1 + let conditionalSource = ' return (function(' + paramName + '){ return (' + let last = null + while (tokens.length > 0) { + const token = tokens[0] + // @ts-ignore For some reason tsc doesn't understand the shift call, and thinks we're comparing the same value here, i.e. '[' vs ']' + if (token === ']') { + bracketCount-- + if (bracketCount === 0) { + if (last === null) { + conditionalSource = conditionalSource + 'true' + } + tokens.shift() + conditionalSource += ')})' try { - var url = new URL(path); - if (url) { - path = url.pathname + url.search; - } - // remove trailing slash, unless index page - if (!(/^\/$/.test(path))) { - path = path.replace(/\/+$/, ''); - } - return path; + const conditionFunction = maybeEval(elt, function() { + return Function(conditionalSource)() + }, + function() { return true }) + conditionFunction.source = conditionalSource + return conditionFunction } catch (e) { - // be kind to IE11, which doesn't support URL() - return path; - } - } - - //========================================================================================== - // public API - //========================================================================================== - - function internalEval(str){ - return maybeEval(getDocument().body, function () { - return eval(str); - }); - } - - function onLoadHelper(callback) { - var value = htmx.on("htmx:load", function(evt) { - callback(evt.detail.elt); - }); - return value; - } - - function logAll(){ - htmx.logger = function(elt, event, data) { - if(console) { - console.log(event, elt, data); - } - } - } - - function logNone() { - htmx.logger = null - } - - function find(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelector(selector); - } else { - return find(getDocument(), eltOrSelector); - } - } - - function findAll(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelectorAll(selector); - } else { - return findAll(getDocument(), eltOrSelector); - } - } - - function removeElement(elt, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - removeElement(elt); - elt = null; - }, delay); - } else { - elt.parentElement.removeChild(elt); - } - } - - function addClassToElement(elt, clazz, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - addClassToElement(elt, clazz); - elt = null; - }, delay); - } else { - elt.classList && elt.classList.add(clazz); - } - } - - function removeClassFromElement(elt, clazz, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - removeClassFromElement(elt, clazz); - elt = null; - }, delay); - } else { - if (elt.classList) { - elt.classList.remove(clazz); - // if there are no classes left, remove the class attribute - if (elt.classList.length === 0) { - elt.removeAttribute("class"); - } - } - } - } - - function toggleClassOnElement(elt, clazz) { - elt = resolveTarget(elt); - elt.classList.toggle(clazz); - } - - function takeClassForElement(elt, clazz) { - elt = resolveTarget(elt); - forEach(elt.parentElement.children, function(child){ - removeClassFromElement(child, clazz); - }) - addClassToElement(elt, clazz); - } - - function closest(elt, selector) { - elt = resolveTarget(elt); - if (elt.closest) { - return elt.closest(selector); - } else { - // TODO remove when IE goes away - do{ - if (elt == null || matches(elt, selector)){ - return elt; - } - } - while (elt = elt && parentElt(elt)); - return null; - } - } - - function startsWith(str, prefix) { - return str.substring(0, prefix.length) === prefix - } - - function endsWith(str, suffix) { - return str.substring(str.length - suffix.length) === suffix - } - - function normalizeSelector(selector) { - var trimmedSelector = selector.trim(); - if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) { - return trimmedSelector.substring(1, trimmedSelector.length - 2); - } else { - return trimmedSelector; - } - } - - function querySelectorAllExt(elt, selector) { - if (selector.indexOf("closest ") === 0) { - return [closest(elt, normalizeSelector(selector.substr(8)))]; - } else if (selector.indexOf("find ") === 0) { - return [find(elt, normalizeSelector(selector.substr(5)))]; - } else if (selector === "next") { - return [elt.nextElementSibling] - } else if (selector.indexOf("next ") === 0) { - return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; - } else if (selector === "previous") { - return [elt.previousElementSibling] - } else if (selector.indexOf("previous ") === 0) { - return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; - } else if (selector === 'document') { - return [document]; - } else if (selector === 'window') { - return [window]; - } else if (selector === 'body') { - return [document.body]; - } else { - return getDocument().querySelectorAll(normalizeSelector(selector)); - } - } - - var scanForwardQuery = function(start, match) { - var results = getDocument().querySelectorAll(match); - for (var i = 0; i < results.length; i++) { - var elt = results[i]; - if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { - return elt; - } - } - } - - var scanBackwardsQuery = function(start, match) { - var results = getDocument().querySelectorAll(match); - for (var i = results.length - 1; i >= 0; i--) { - var elt = results[i]; - if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { - return elt; - } - } - } - - function querySelectorExt(eltOrSelector, selector) { - if (selector) { - return querySelectorAllExt(eltOrSelector, selector)[0]; - } else { - return querySelectorAllExt(getDocument().body, eltOrSelector)[0]; - } - } - - function resolveTarget(arg2) { - if (isType(arg2, 'String')) { - return find(arg2); - } else { - return arg2; - } - } - - function processEventArgs(arg1, arg2, arg3) { - if (isFunction(arg2)) { - return { - target: getDocument().body, - event: arg1, - listener: arg2 - } - } else { - return { - target: resolveTarget(arg1), - event: arg2, - listener: arg3 - } - } - - } - - function addEventListenerImpl(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 removeEventListenerImpl(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 - //==================================================================== - - var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors - function findAttributeTargets(elt, attrName) { - var attrTarget = getClosestAttributeValue(elt, attrName); - if (attrTarget) { - if (attrTarget === "this") { - return [findThisElement(elt, attrName)]; - } else { - var result = querySelectorAllExt(elt, attrTarget); - if (result.length === 0) { - logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!"); - return [DUMMY_ELT] - } else { - return result; - } - } - } - } - - function findThisElement(elt, attribute){ - return getClosestMatch(elt, function (elt) { - return getAttributeValue(elt, attribute) != null; - }) - } - - function getTarget(elt) { - var targetStr = getClosestAttributeValue(elt, "hx-target"); - if (targetStr) { - if (targetStr === "this") { - return findThisElement(elt,'hx-target'); - } else { - return querySelectorExt(elt, targetStr) - } - } else { - var data = getInternalData(elt); - if (data.boosted) { - return getDocument().body; - } else { - return elt; - } - } - } - - function shouldSettleAttribute(name) { - var attributesToSettle = htmx.config.attributesToSettle; - for (var i = 0; i < attributesToSettle.length; i++) { - if (name === attributesToSettle[i]) { - return true; - } - } - return false; - } - - function cloneAttributes(mergeTo, mergeFrom) { - forEach(mergeTo.attributes, function (attr) { - if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) { - mergeTo.removeAttribute(attr.name) - } - }); - forEach(mergeFrom.attributes, function (attr) { - if (shouldSettleAttribute(attr.name)) { - mergeTo.setAttribute(attr.name, attr.value); - } - }); - } - - function isInlineSwap(swapStyle, target) { - var extensions = getExtensions(target); - for (var i = 0; i < extensions.length; i++) { - var extension = extensions[i]; - try { - if (extension.isInlineSwap(swapStyle)) { - return true; - } - } catch(e) { - logError(e); - } - } - return swapStyle === "outerHTML"; - } - - /** - * - * @param {string} oobValue - * @param {HTMLElement} oobElement - * @param {*} settleInfo - * @returns - */ - function oobSwap(oobValue, oobElement, settleInfo) { - var selector = "#" + getRawAttribute(oobElement, "id"); - var swapStyle = "outerHTML"; - if (oobValue === "true") { - // do nothing - } else if (oobValue.indexOf(":") > 0) { - swapStyle = oobValue.substr(0, oobValue.indexOf(":")); - selector = oobValue.substr(oobValue.indexOf(":") + 1, oobValue.length); - } else { - swapStyle = oobValue; - } - - var targets = getDocument().querySelectorAll(selector); - if (targets) { - forEach( - targets, - function (target) { - var fragment; - var oobElementClone = oobElement.cloneNode(true); - fragment = getDocument().createDocumentFragment(); - fragment.appendChild(oobElementClone); - if (!isInlineSwap(swapStyle, target)) { - fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself - } - - var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment }; - if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return; - - target = beforeSwapDetails.target; // allow re-targeting - if (beforeSwapDetails['shouldSwap']){ - swap(swapStyle, target, target, fragment, settleInfo); - } - forEach(settleInfo.elts, function (elt) { - triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails); - }); - } - ); - oobElement.parentNode.removeChild(oobElement); - } else { - oobElement.parentNode.removeChild(oobElement); - triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}); - } - return oobValue; - } - - function handleOutOfBandSwaps(elt, fragment, settleInfo) { - var oobSelects = getClosestAttributeValue(elt, "hx-select-oob"); - if (oobSelects) { - var oobSelectValues = oobSelects.split(","); - for (var i = 0; i < oobSelectValues.length; i++) { - var oobSelectValue = oobSelectValues[i].split(":", 2); - var id = oobSelectValue[0].trim(); - if (id.indexOf("#") === 0) { - id = id.substring(1); - } - var oobValue = oobSelectValue[1] || "true"; - var oobElement = fragment.querySelector("#" + id); - if (oobElement) { - oobSwap(oobValue, oobElement, settleInfo); - } - } - } - forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) { - var oobValue = getAttributeValue(oobElement, "hx-swap-oob"); - if (oobValue != null) { - oobSwap(oobValue, oobElement, settleInfo); - } - }); - } - - function handlePreservedElements(fragment) { - forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function (preservedElt) { - var id = getAttributeValue(preservedElt, "id"); - var oldElt = getDocument().getElementById(id); - if (oldElt != null) { - preservedElt.parentNode.replaceChild(oldElt, preservedElt); - } - }); - } - - function handleAttributes(parentNode, fragment, settleInfo) { - forEach(fragment.querySelectorAll("[id]"), function (newNode) { - var id = getRawAttribute(newNode, "id") - if (id && id.length > 0) { - var normalizedId = id.replace("'", "\\'"); - var normalizedTag = newNode.tagName.replace(':', '\\:'); - var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']"); - if (oldNode && oldNode !== parentNode) { - var newAttributes = newNode.cloneNode(); - cloneAttributes(newNode, oldNode); - settleInfo.tasks.push(function () { - cloneAttributes(newNode, newAttributes); - }); - } - } - }); - } - - function makeAjaxLoadTask(child) { - return function () { - removeClassFromElement(child, htmx.config.addedClass); - processNode(child); - processScripts(child); - processFocus(child) - triggerEvent(child, 'htmx:load'); - }; - } - - function processFocus(child) { - var autofocus = "[autofocus]"; - var autoFocusedElt = matches(child, autofocus) ? child : child.querySelector(autofocus) - if (autoFocusedElt != null) { - autoFocusedElt.focus(); - } - } - - function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) { - handleAttributes(parentNode, fragment, settleInfo); - while(fragment.childNodes.length > 0){ - var child = fragment.firstChild; - addClassToElement(child, htmx.config.addedClass); - parentNode.insertBefore(child, insertBefore); - if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { - settleInfo.tasks.push(makeAjaxLoadTask(child)); - } - } - } - - // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, - // derived from Java's string hashcode implementation - function stringHash(string, hash) { - var char = 0; - while (char < string.length){ - hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int - } - return hash; - } - - function attributeHash(elt) { - var hash = 0; - // IE fix - if (elt.attributes) { - for (var i = 0; i < elt.attributes.length; i++) { - var attribute = elt.attributes[i]; - if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent) - hash = stringHash(attribute.name, hash); - hash = stringHash(attribute.value, hash); - } - } - } - return hash; - } - - function deInitOnHandlers(elt) { - var internalData = getInternalData(elt); - if (internalData.onHandlers) { - for (var i = 0; i < internalData.onHandlers.length; i++) { - const handlerInfo = internalData.onHandlers[i]; - elt.removeEventListener(handlerInfo.event, handlerInfo.listener); - } - delete internalData.onHandlers - } - } - - function deInitNode(element) { - var internalData = getInternalData(element); - if (internalData.timeout) { - clearTimeout(internalData.timeout); - } - if (internalData.webSocket) { - internalData.webSocket.close(); - } - if (internalData.sseEventSource) { - internalData.sseEventSource.close(); - } - if (internalData.listenerInfos) { - forEach(internalData.listenerInfos, function (info) { - if (info.on) { - info.on.removeEventListener(info.trigger, info.listener); - } - }); - } - deInitOnHandlers(element); - forEach(Object.keys(internalData), function(key) { delete internalData[key] }); - } - - function cleanUpElement(element) { - triggerEvent(element, "htmx:beforeCleanupElement") - deInitNode(element); - if (element.children) { // IE - forEach(element.children, function(child) { cleanUpElement(child) }); - } - } - - function swapOuterHTML(target, fragment, settleInfo) { - if (target.tagName === "BODY") { - return swapInnerHTML(target, fragment, settleInfo); - } else { - // @type {HTMLElement} - var newElt - var eltBeforeNewContent = target.previousSibling; - insertNodesBefore(parentElt(target), target, fragment, settleInfo); - if (eltBeforeNewContent == null) { - newElt = parentElt(target).firstChild; - } else { - newElt = eltBeforeNewContent.nextSibling; - } - settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target }); - while(newElt && newElt !== target) { - if (newElt.nodeType === Node.ELEMENT_NODE) { - settleInfo.elts.push(newElt); - } - newElt = newElt.nextElementSibling; - } - cleanUpElement(target); - parentElt(target).removeChild(target); - } - } - - function swapAfterBegin(target, fragment, settleInfo) { - return insertNodesBefore(target, target.firstChild, fragment, settleInfo); - } - - function swapBeforeBegin(target, fragment, settleInfo) { - return insertNodesBefore(parentElt(target), target, fragment, settleInfo); - } - - function swapBeforeEnd(target, fragment, settleInfo) { - return insertNodesBefore(target, null, fragment, settleInfo); - } - - function swapAfterEnd(target, fragment, settleInfo) { - return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo); - } - function swapDelete(target, fragment, settleInfo) { - cleanUpElement(target); - return parentElt(target).removeChild(target); - } - - function swapInnerHTML(target, fragment, settleInfo) { - var firstChild = target.firstChild; - insertNodesBefore(target, firstChild, fragment, settleInfo); - if (firstChild) { - while (firstChild.nextSibling) { - cleanUpElement(firstChild.nextSibling) - target.removeChild(firstChild.nextSibling); - } - cleanUpElement(firstChild) - target.removeChild(firstChild); - } - } - - function maybeSelectFromResponse(elt, fragment, selectOverride) { - var selector = selectOverride || getClosestAttributeValue(elt, "hx-select"); - if (selector) { - var newFragment = getDocument().createDocumentFragment(); - forEach(fragment.querySelectorAll(selector), function (node) { - newFragment.appendChild(node); - }); - fragment = newFragment; - } - return fragment; - } - - function swap(swapStyle, elt, target, fragment, settleInfo) { - switch (swapStyle) { - case "none": - return; - case "outerHTML": - swapOuterHTML(target, fragment, settleInfo); - return; - case "afterbegin": - swapAfterBegin(target, fragment, settleInfo); - return; - case "beforebegin": - swapBeforeBegin(target, fragment, settleInfo); - return; - case "beforeend": - swapBeforeEnd(target, fragment, settleInfo); - return; - case "afterend": - swapAfterEnd(target, fragment, settleInfo); - return; - case "delete": - swapDelete(target, fragment, settleInfo); - return; - default: - var extensions = getExtensions(elt); - for (var i = 0; i < extensions.length; i++) { - var ext = extensions[i]; - try { - var newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo); - if (newElements) { - if (typeof newElements.length !== 'undefined') { - // if handleSwap returns an array (like) of elements, we handle them - for (var j = 0; j < newElements.length; j++) { - var child = newElements[j]; - if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { - settleInfo.tasks.push(makeAjaxLoadTask(child)); - } - } - } - return; - } - } catch (e) { - logError(e); - } - } - if (swapStyle === "innerHTML") { - swapInnerHTML(target, fragment, settleInfo); - } else { - swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo); - } - } - } - - function findTitle(content) { - if (content.indexOf('<title') > -1) { - var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, ''); - var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX); - if (result) { - return result[2]; - } - } - } - - function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) { - settleInfo.title = findTitle(responseText); - var fragment = makeFragment(responseText); - if (fragment) { - handleOutOfBandSwaps(elt, fragment, settleInfo); - fragment = maybeSelectFromResponse(elt, fragment, selectOverride); - handlePreservedElements(fragment); - return swap(swapStyle, elt, target, fragment, settleInfo); - } - } - - function handleTrigger(xhr, header, elt) { - var triggerBody = xhr.getResponseHeader(header); - if (triggerBody.indexOf("{") === 0) { - var triggers = parseJSON(triggerBody); - for (var eventName in triggers) { - if (triggers.hasOwnProperty(eventName)) { - var detail = triggers[eventName]; - if (!isRawObject(detail)) { - detail = {"value": detail} - } - triggerEvent(elt, eventName, detail); - } - } - } else { - var eventNames = triggerBody.split(",") - for (var i = 0; i < eventNames.length; i++) { - triggerEvent(elt, eventNames[i].trim(), []); - } - } - } - - var WHITESPACE = /\s/; - var WHITESPACE_OR_COMMA = /[\s,]/; - var SYMBOL_START = /[_$a-zA-Z]/; - var SYMBOL_CONT = /[_$a-zA-Z0-9]/; - var STRINGISH_START = ['"', "'", "/"]; - var NOT_WHITESPACE = /[^\s]/; - var COMBINED_SELECTOR_START = /[{(]/; - var COMBINED_SELECTOR_END = /[})]/; - function tokenizeString(str) { - var tokens = []; - var position = 0; - while (position < str.length) { - if(SYMBOL_START.exec(str.charAt(position))) { - var startPosition = position; - while (SYMBOL_CONT.exec(str.charAt(position + 1))) { - position++; - } - tokens.push(str.substr(startPosition, position - startPosition + 1)); - } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) { - var startChar = str.charAt(position); - var startPosition = position; - position++; - while (position < str.length && str.charAt(position) !== startChar ) { - if (str.charAt(position) === "\\") { - position++; - } - position++; - } - tokens.push(str.substr(startPosition, position - startPosition + 1)); - } else { - var symbol = str.charAt(position); - tokens.push(symbol); - } - position++; - } - return tokens; - } - - function isPossibleRelativeReference(token, last, paramName) { - return SYMBOL_START.exec(token.charAt(0)) && - token !== "true" && - token !== "false" && - token !== "this" && - token !== paramName && - last !== "."; - } - - function maybeGenerateConditional(elt, tokens, paramName) { - if (tokens[0] === '[') { - tokens.shift(); - var bracketCount = 1; - var conditionalSource = " return (function(" + paramName + "){ return ("; - var last = null; - while (tokens.length > 0) { - var token = tokens[0]; - if (token === "]") { - bracketCount--; - if (bracketCount === 0) { - if (last === null) { - conditionalSource = conditionalSource + "true"; - } - tokens.shift(); - conditionalSource += ")})"; - try { - var conditionFunction = maybeEval(elt,function () { - return Function(conditionalSource)(); - }, - function(){return true}) - conditionFunction.source = conditionalSource; - return conditionFunction; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:syntax:error", {error:e, source:conditionalSource}) - return null; - } - } - } else if (token === "[") { - bracketCount++; - } - if (isPossibleRelativeReference(token, last, paramName)) { - conditionalSource += "((" + paramName + "." + token + ") ? (" + paramName + "." + token + ") : (window." + token + "))"; - } else { - conditionalSource = conditionalSource + token; - } - last = tokens.shift(); - } - } - } - - function consumeUntil(tokens, match) { - var result = ""; - while (tokens.length > 0 && !match.test(tokens[0])) { - result += tokens.shift(); - } - return result; - } - - function consumeCSSSelector(tokens) { - var result; - if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { - tokens.shift(); - result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim(); - tokens.shift(); - } else { - result = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } - return result; - } - - var INPUT_SELECTOR = 'input, textarea, select'; - - /** - * @param {HTMLElement} elt - * @param {string} explicitTrigger - * @param {cache} cache for trigger specs - * @returns {import("./htmx").HtmxTriggerSpecification[]} - */ - function parseAndCacheTrigger(elt, explicitTrigger, cache) { - var triggerSpecs = []; - var tokens = tokenizeString(explicitTrigger); - do { - consumeUntil(tokens, NOT_WHITESPACE); - var initialLength = tokens.length; - var trigger = consumeUntil(tokens, /[,\[\s]/); - if (trigger !== "") { - if (trigger === "every") { - var every = {trigger: 'every'}; - consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); - consumeUntil(tokens, NOT_WHITESPACE); - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - every.eventFilter = eventFilter; - } - triggerSpecs.push(every); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); - } else { - var triggerSpec = {trigger: trigger}; - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - triggerSpec.eventFilter = eventFilter; - } - while (tokens.length > 0 && tokens[0] !== ",") { - consumeUntil(tokens, NOT_WHITESPACE) - var token = tokens.shift(); - if (token === "changed") { - triggerSpec.changed = true; - } else if (token === "once") { - triggerSpec.once = true; - } else if (token === "consume") { - triggerSpec.consume = true; - } else if (token === "delay" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "from" && tokens[0] === ":") { - tokens.shift(); - if (COMBINED_SELECTOR_START.test(tokens[0])) { - var from_arg = consumeCSSSelector(tokens); - } else { - var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); - if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") { - tokens.shift(); - var selector = consumeCSSSelector(tokens); - // `next` and `previous` allow a selector-less syntax - if (selector.length > 0) { - from_arg += " " + selector; - } - } - } - triggerSpec.from = from_arg; - } else if (token === "target" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.target = consumeCSSSelector(tokens); - } else if (token === "throttle" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "queue" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if (token === "root" && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeCSSSelector(tokens); - } else if (token === "threshold" && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - } - triggerSpecs.push(triggerSpec); - } - } - if (tokens.length === initialLength) { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - consumeUntil(tokens, NOT_WHITESPACE); - } while (tokens[0] === "," && tokens.shift()) - if (cache) { - cache[explicitTrigger] = triggerSpecs - } - return triggerSpecs - } - - /** - * @param {HTMLElement} elt - * @returns {import("./htmx").HtmxTriggerSpecification[]} - */ - function getTriggerSpecs(elt) { - var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); - var triggerSpecs = []; - if (explicitTrigger) { - var cache = htmx.config.triggerSpecsCache - triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) - } - - if (triggerSpecs.length > 0) { - return triggerSpecs; - } else if (matches(elt, 'form')) { - return [{trigger: 'submit'}]; - } else if (matches(elt, 'input[type="button"], input[type="submit"]')){ - return [{trigger: 'click'}]; - } else if (matches(elt, INPUT_SELECTOR)) { - return [{trigger: 'change'}]; - } else { - return [{trigger: 'click'}]; - } - } - - function cancelPolling(elt) { - getInternalData(elt).cancelled = true; - } - - function processPolling(elt, handler, spec) { - var nodeData = getInternalData(elt); - nodeData.timeout = setTimeout(function () { - if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { - triggerSpec: spec, - target: elt - }))) { - handler(elt); - } - processPolling(elt, handler, spec); - } - }, spec.pollInterval); - } - - function isLocalLink(elt) { - return location.hostname === elt.hostname && - getRawAttribute(elt,'href') && - getRawAttribute(elt,'href').indexOf("#") !== 0; - } - - function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || 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"; - if (verb === "get") { - } - path = getRawAttribute(elt, 'action'); - } - triggerSpecs.forEach(function(triggerSpec) { - addEventListener(elt, function(elt, evt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return - } - issueAjaxRequest(verb, path, elt, evt) - }, nodeData, triggerSpec, true); - }); - } - } - - /** - * - * @param {Event} evt - * @param {HTMLElement} elt - * @returns - */ - function shouldCancel(evt, elt) { - if (evt.type === "submit" || evt.type === "click") { - if (elt.tagName === "FORM") { - return true; - } - if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { - return true; - } - if (elt.tagName === "A" && elt.href && - (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) { - return true; - } - } - return false; - } - - function ignoreBoostedAnchorCtrlClick(elt, evt) { - return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); - } - - function maybeFilterEvent(triggerSpec, elt, evt) { - var eventFilter = triggerSpec.eventFilter; - if(eventFilter){ - try { - return eventFilter.call(elt, evt) !== true; - } catch(e) { - triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); - return true; - } - } - return false; - } - - function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { - var elementData = getInternalData(elt); - var eltsToListenOn; - if (triggerSpec.from) { - eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); - } else { - eltsToListenOn = [elt]; - } - // store the initial values of the elements, so we can tell if they change - if (triggerSpec.changed) { - eltsToListenOn.forEach(function (eltToListenOn) { - var eltToListenOnData = getInternalData(eltToListenOn); - eltToListenOnData.lastValue = eltToListenOn.value; - }) - } - forEach(eltsToListenOn, function (eltToListenOn) { - var eventListener = function (evt) { - if (!bodyContains(elt)) { - eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); - return; - } - if (ignoreBoostedAnchorCtrlClick(elt, evt)) { - return; - } - if (explicitCancel || shouldCancel(evt, elt)) { - evt.preventDefault(); - } - if (maybeFilterEvent(triggerSpec, elt, evt)) { - return; - } - var eventData = getInternalData(evt); - eventData.triggerSpec = triggerSpec; - if (eventData.handledFor == null) { - eventData.handledFor = []; - } - if (eventData.handledFor.indexOf(elt) < 0) { - eventData.handledFor.push(elt); - if (triggerSpec.consume) { - evt.stopPropagation(); - } - if (triggerSpec.target && evt.target) { - if (!matches(evt.target, triggerSpec.target)) { - return; - } - } - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } - } - if (triggerSpec.changed) { - var eltToListenOnData = getInternalData(eltToListenOn) - if (eltToListenOnData.lastValue === eltToListenOn.value) { - return; - } - eltToListenOnData.lastValue = eltToListenOn.value - } - if (elementData.delayed) { - clearTimeout(elementData.delayed); - } - if (elementData.throttle) { - return; - } - - if (triggerSpec.throttle > 0) { - if (!elementData.throttle) { - handler(elt, evt); - elementData.throttle = setTimeout(function () { - elementData.throttle = null; - }, triggerSpec.throttle); - } - } else if (triggerSpec.delay > 0) { - elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); - } else { - triggerEvent(elt, 'htmx:trigger') - handler(elt, evt); - } - } - }; - if (nodeData.listenerInfos == null) { - nodeData.listenerInfos = []; - } - nodeData.listenerInfos.push({ - trigger: triggerSpec.trigger, - listener: eventListener, - on: eltToListenOn - }) - eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); - }); - } - - var windowIsScrolling = false // used by initScrollHandler - var scrollHandler = null; - function initScrollHandler() { - if (!scrollHandler) { - scrollHandler = function() { - windowIsScrolling = true - }; - window.addEventListener("scroll", scrollHandler) - setInterval(function() { - if (windowIsScrolling) { - windowIsScrolling = false; - forEach(getDocument().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"), function (elt) { - maybeReveal(elt); - }) - } - }, 200); - } - } - - function maybeReveal(elt) { - if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { - elt.setAttribute('data-hx-revealed', 'true'); - var nodeData = getInternalData(elt); - if (nodeData.initHash) { - triggerEvent(elt, 'revealed'); - } else { - // if the node isn't initialized, wait for it before triggering the request - elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true}); - } - } - } - - //==================================================================== - // Web Sockets - //==================================================================== - - function processWebSocketInfo(elt, nodeData, info) { - var values = splitOnWhitespace(info); - for (var i = 0; i < values.length; i++) { - var value = values[i].split(/:(.+)/); - if (value[0] === "connect") { - ensureWebSocket(elt, value[1], 0); - } - if (value[0] === "send") { - processWebSocketSend(elt); - } - } - } - - function ensureWebSocket(elt, wssSource, retryCount) { - if (!bodyContains(elt)) { - return; // stop ensuring websocket connection when socket bearing element ceases to exist - } - - if (wssSource.indexOf("/") == 0) { // complete absolute paths only - var base_part = location.hostname + (location.port ? ':'+location.port: ''); - if (location.protocol == 'https:') { - wssSource = "wss://" + base_part + wssSource; - } else if (location.protocol == 'http:') { - wssSource = "ws://" + base_part + wssSource; - } - } - var socket = htmx.createWebSocket(wssSource); - socket.onerror = function (e) { - triggerErrorEvent(elt, "htmx:wsError", {error:e, socket:socket}); - maybeCloseWebSocketSource(elt); - }; - - socket.onclose = function (e) { - if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later - var delay = getWebSocketReconnectDelay(retryCount); - setTimeout(function() { - ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout - }, delay); - } - }; - socket.onopen = function (e) { - retryCount = 0; - } - - getInternalData(elt).webSocket = socket; - socket.addEventListener('message', function (event) { - if (maybeCloseWebSocketSource(elt)) { - return; - } - - var response = event.data; - withExtensions(elt, function(extension){ - response = extension.transformResponse(response, null, elt); - }); - - var settleInfo = makeSettleInfo(elt); - var fragment = makeFragment(response); - var children = toArray(fragment.children); - for (var i = 0; i < children.length; i++) { - var child = children[i]; - oobSwap(getAttributeValue(child, "hx-swap-oob") || "true", child, settleInfo); - } - - settleImmediately(settleInfo.tasks); - }); - } - - function maybeCloseWebSocketSource(elt) { - if (!bodyContains(elt)) { - getInternalData(elt).webSocket.close(); - return true; - } - } - - function processWebSocketSend(elt) { - var webSocketSourceElt = getClosestMatch(elt, function (parent) { - return getInternalData(parent).webSocket != null; - }); - if (webSocketSourceElt) { - elt.addEventListener(getTriggerSpecs(elt)[0].trigger, function (evt) { - var webSocket = getInternalData(webSocketSourceElt).webSocket; - var headers = getHeaders(elt, webSocketSourceElt); - var results = getInputValues(elt, 'post'); - var errors = results.errors; - var rawParameters = results.values; - var expressionVars = getExpressionVars(elt); - var allParameters = mergeObjects(rawParameters, expressionVars); - var filteredParameters = filterValues(allParameters, elt); - filteredParameters['HEADERS'] = headers; - if (errors && errors.length > 0) { - triggerEvent(elt, 'htmx:validation:halted', errors); - return; - } - webSocket.send(JSON.stringify(filteredParameters)); - if(shouldCancel(evt, elt)){ - evt.preventDefault(); - } - }); - } else { - triggerErrorEvent(elt, "htmx:noWebSocketSourceError"); - } - } - - function getWebSocketReconnectDelay(retryCount) { - var delay = htmx.config.wsReconnectDelay; - if (typeof delay === 'function') { - // @ts-ignore - return delay(retryCount); - } - if (delay === 'full-jitter') { - var exp = Math.min(retryCount, 6); - var maxDelay = 1000 * Math.pow(2, exp); - return maxDelay * Math.random(); - } - logError('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"'); - } - - //==================================================================== - // Server Sent Events - //==================================================================== - - function processSSEInfo(elt, nodeData, info) { - var values = splitOnWhitespace(info); - for (var i = 0; i < values.length; i++) { - var value = values[i].split(/:(.+)/); - if (value[0] === "connect") { - processSSESource(elt, value[1]); - } - - if ((value[0] === "swap")) { - processSSESwap(elt, value[1]) - } - } - } - - function processSSESource(elt, sseSrc) { - var source = htmx.createEventSource(sseSrc); - source.onerror = function (e) { - triggerErrorEvent(elt, "htmx:sseError", {error:e, source:source}); - maybeCloseSSESource(elt); - }; - getInternalData(elt).sseEventSource = source; - } - - function processSSESwap(elt, sseEventName) { - var sseSourceElt = getClosestMatch(elt, hasEventSource); - if (sseSourceElt) { - var sseEventSource = getInternalData(sseSourceElt).sseEventSource; - var sseListener = function (event) { - if (maybeCloseSSESource(sseSourceElt)) { - return; - } - if (!bodyContains(elt)) { - sseEventSource.removeEventListener(sseEventName, sseListener); - return; - } - - /////////////////////////// - // TODO: merge this code with AJAX and WebSockets code in the future. - - var response = event.data; - withExtensions(elt, function(extension){ - response = extension.transformResponse(response, null, elt); - }); - - var swapSpec = getSwapSpecification(elt) - var target = getTarget(elt) - var settleInfo = makeSettleInfo(elt); - - selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) - settleImmediately(settleInfo.tasks) - triggerEvent(elt, "htmx:sseMessage", event) - }; - - getInternalData(elt).sseListener = sseListener; - sseEventSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "htmx:noSSESourceError"); - } - } - - function processSSETrigger(elt, handler, sseEventName) { - var sseSourceElt = getClosestMatch(elt, hasEventSource); - if (sseSourceElt) { - var sseEventSource = getInternalData(sseSourceElt).sseEventSource; - var sseListener = function () { - if (!maybeCloseSSESource(sseSourceElt)) { - if (bodyContains(elt)) { - handler(elt); - } else { - sseEventSource.removeEventListener(sseEventName, sseListener); - } - } - }; - getInternalData(elt).sseListener = sseListener; - sseEventSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "htmx:noSSESourceError"); - } - } - - function maybeCloseSSESource(elt) { - if (!bodyContains(elt)) { - getInternalData(elt).sseEventSource.close(); - return true; - } - } - - function hasEventSource(node) { - return getInternalData(node).sseEventSource != null; - } - - //==================================================================== - - function loadImmediately(elt, handler, nodeData, delay) { - var load = function(){ - if (!nodeData.loaded) { - nodeData.loaded = true; - handler(elt); - } - } - if (delay > 0) { - setTimeout(load, delay); - } else { - load(); - } - } - - function processVerbs(elt, nodeData, triggerSpecs) { - var explicitAction = false; - forEach(VERBS, function (verb) { - if (hasAttribute(elt,'hx-' + verb)) { - var path = getAttributeValue(elt, 'hx-' + verb); - explicitAction = true; - nodeData.path = path; - nodeData.verb = verb; - triggerSpecs.forEach(function(triggerSpec) { - addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return - } - issueAjaxRequest(verb, path, elt, evt) - }) - }); - } - }); - return explicitAction; - } - - function addTriggerHandler(elt, triggerSpec, nodeData, handler) { - if (triggerSpec.sseEvent) { - processSSETrigger(elt, handler, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - addEventListener(elt, handler, nodeData, triggerSpec); - maybeReveal(elt); - } else if (triggerSpec.trigger === "intersect") { - var observerOptions = {}; - if (triggerSpec.root) { - observerOptions.root = querySelectorExt(elt, triggerSpec.root) - } - if (triggerSpec.threshold) { - observerOptions.threshold = parseFloat(triggerSpec.threshold); - } - var observer = new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - if (entry.isIntersecting) { - triggerEvent(elt, "intersect"); - break; - } - } - }, observerOptions); - observer.observe(elt); - addEventListener(elt, handler, nodeData, triggerSpec); - } else if (triggerSpec.trigger === "load") { - if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { - loadImmediately(elt, handler, nodeData, triggerSpec.delay); - } - } else if (triggerSpec.pollInterval > 0) { - nodeData.polling = true; - processPolling(elt, handler, triggerSpec); - } else { - addEventListener(elt, handler, nodeData, triggerSpec); - } - } - - function evalScript(script) { - if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) { - var newScript = getDocument().createElement("script"); - forEach(script.attributes, function (attr) { - newScript.setAttribute(attr.name, attr.value); - }); - newScript.textContent = script.textContent; - newScript.async = false; - if (htmx.config.inlineScriptNonce) { - newScript.nonce = htmx.config.inlineScriptNonce; - } - var parent = script.parentElement; - - try { - parent.insertBefore(newScript, script); - } catch (e) { - logError(e); - } finally { - // remove old script element, but only if it is still in DOM - if (script.parentElement) { - script.parentElement.removeChild(script); - } - } - } - } - - function processScripts(elt) { - if (matches(elt, "script")) { - evalScript(elt); - } - forEach(findAll(elt, "script"), function (script) { - evalScript(script); - }); - } - - function shouldProcessHxOn(elt) { - var attributes = elt.attributes - for (var j = 0; j < attributes.length; j++) { - var attrName = attributes[j].name - if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") || - startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) { - return true - } - } - return false - } - - function findHxOnWildcardElements(elt) { - var node = null - var elements = [] - - if (shouldProcessHxOn(elt)) { - elements.push(elt) - } - - if (document.evaluate) { - var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + - ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt) - while (node = iter.iterateNext()) elements.push(node) - } else { - var allElements = elt.getElementsByTagName("*") - for (var i = 0; i < allElements.length; i++) { - if (shouldProcessHxOn(allElements[i])) { - elements.push(allElements[i]) - } - } - } - - return elements - } - - function findElementsToProcess(elt) { - if (elt.querySelectorAll) { - var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; - var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]"); - return results; - } else { - return []; - } - } - - // Handle submit buttons/inputs that have the form attribute set - // see https://developer.mozilla.org/docs/Web/HTML/Element/button - function maybeSetLastButtonClicked(evt) { - var elt = closest(evt.target, "button, input[type='submit']"); - var internalData = getRelatedFormData(evt) - if (internalData) { - internalData.lastButtonClicked = elt; - } - }; - function maybeUnsetLastButtonClicked(evt){ - var internalData = getRelatedFormData(evt) - if (internalData) { - internalData.lastButtonClicked = null; - } - } - function getRelatedFormData(evt) { - var elt = closest(evt.target, "button, input[type='submit']"); - if (!elt) { - return; - } - var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form'); - if (!form) { - return; - } - return getInternalData(form); - } - function initButtonTracking(elt) { - // need to handle both click and focus in: - // focusin - in case someone tabs in to a button and hits the space bar - // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 - elt.addEventListener('click', maybeSetLastButtonClicked) - elt.addEventListener('focusin', maybeSetLastButtonClicked) - elt.addEventListener('focusout', maybeUnsetLastButtonClicked) - } - - function countCurlies(line) { - var tokens = tokenizeString(line); - var netCurlies = 0; - for (var i = 0; i < tokens.length; i++) { - const token = tokens[i]; - if (token === "{") { - netCurlies++; - } else if (token === "}") { - netCurlies--; - } - } - return netCurlies; - } - - function addHxOnEventHandler(elt, eventName, code) { - var nodeData = getInternalData(elt); - if (!Array.isArray(nodeData.onHandlers)) { - nodeData.onHandlers = []; - } - var func; - var listener = function (e) { - return maybeEval(elt, function() { - if (!func) { - func = new Function("event", code); - } - func.call(elt, e); - }); - }; - elt.addEventListener(eventName, listener); - nodeData.onHandlers.push({event:eventName, listener:listener}); - } - - function processHxOn(elt) { - var hxOnValue = getAttributeValue(elt, 'hx-on'); - if (hxOnValue) { - var handlers = {} - var lines = hxOnValue.split("\n"); - var currentEvent = null; - var curlyCount = 0; - while (lines.length > 0) { - var line = lines.shift(); - var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/); - if (curlyCount === 0 && match) { - line.split(":") - currentEvent = match[1].slice(0, -1); // strip last colon - handlers[currentEvent] = match[2]; - } else { - handlers[currentEvent] += line; - } - curlyCount += countCurlies(line); - } - - for (var eventName in handlers) { - addHxOnEventHandler(elt, eventName, handlers[eventName]); - } - } - } - - function processHxOnWildcard(elt) { - // wipe any previous on handlers so that this function takes precedence - deInitOnHandlers(elt) - - for (var i = 0; i < elt.attributes.length; i++) { - var name = elt.attributes[i].name - var value = elt.attributes[i].value - if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) { - var afterOnPosition = name.indexOf("-on") + 3; - var nextChar = name.slice(afterOnPosition, afterOnPosition + 1); - if (nextChar === "-" || nextChar === ":") { - var eventName = name.slice(afterOnPosition + 1); - // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support - if (startsWith(eventName, ":")) { - eventName = "htmx" + eventName - } else if (startsWith(eventName, "-")) { - eventName = "htmx:" + eventName.slice(1); - } else if (startsWith(eventName, "htmx-")) { - eventName = "htmx:" + eventName.slice(5); - } - - addHxOnEventHandler(elt, eventName, value) - } - } - } - } - - function initNode(elt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return; - } - var nodeData = getInternalData(elt); - if (nodeData.initHash !== attributeHash(elt)) { - // clean up any previously processed info - deInitNode(elt); - - nodeData.initHash = attributeHash(elt); - - processHxOn(elt); - - triggerEvent(elt, "htmx:beforeProcessNode") - - if (elt.value) { - nodeData.lastValue = elt.value; - } - - var triggerSpecs = getTriggerSpecs(elt); - var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs); - - if (!hasExplicitHttpAction) { - if (getClosestAttributeValue(elt, "hx-boost") === "true") { - boostElement(elt, nodeData, triggerSpecs); - } else if (hasAttribute(elt, 'hx-trigger')) { - triggerSpecs.forEach(function (triggerSpec) { - // For "naked" triggers, don't do anything at all - addTriggerHandler(elt, triggerSpec, nodeData, function () { - }) - }) - } - } - - // Handle submit buttons/inputs that have the form attribute set - // see https://developer.mozilla.org/docs/Web/HTML/Element/button - if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) { - initButtonTracking(elt) - } - - var sseInfo = getAttributeValue(elt, 'hx-sse'); - if (sseInfo) { - processSSEInfo(elt, nodeData, sseInfo); - } - - var wsInfo = getAttributeValue(elt, 'hx-ws'); - if (wsInfo) { - processWebSocketInfo(elt, nodeData, wsInfo); - } - triggerEvent(elt, "htmx:afterProcessNode"); - } - } - - function processNode(elt) { - elt = resolveTarget(elt); - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return; - } - initNode(elt); - forEach(findElementsToProcess(elt), function(child) { initNode(child) }); - // Because it happens second, the new way of adding onHandlers superseeds the old one - // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored - forEach(findHxOnWildcardElements(elt), processHxOnWildcard); - } - - //==================================================================== - // Event/Log Support - //==================================================================== - - function kebabEventName(str) { - return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase(); - } - - 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({error:eventName}, detail)); - } - - function ignoreEventForLogging(eventName) { - return eventName === "htmx:afterProcessNode" - } - - /** - * `withExtensions` locates all active extensions for a provided element, then - * executes the provided function using each of the active extensions. It should - * be called internally at every extendable execution point in htmx. - * - * @param {HTMLElement} elt - * @param {(extension:import("./htmx").HtmxExtension) => void} toDo - * @returns void - */ - function withExtensions(elt, toDo) { - forEach(getExtensions(elt), function(extension){ - try { - toDo(extension); - } catch (e) { - logError(e); - } - }); - } - - function logError(msg) { - if(console.error) { - console.error(msg); - } else if (console.log) { - console.log("ERROR: ", msg); - } - } - - function triggerEvent(elt, eventName, detail) { - elt = resolveTarget(elt); - if (detail == null) { - detail = {}; - } - detail["elt"] = elt; - var event = makeEvent(eventName, detail); - if (htmx.logger && !ignoreEventForLogging(eventName)) { - htmx.logger(elt, eventName, detail); - } - if (detail.error) { - logError(detail.error); - triggerEvent(elt, "htmx:error", {errorInfo:detail}) - } - var eventResult = elt.dispatchEvent(event); - var kebabName = kebabEventName(eventName); - if (eventResult && kebabName !== eventName) { - var kebabedEvent = makeEvent(kebabName, event.detail); - eventResult = eventResult && elt.dispatchEvent(kebabedEvent) - } - withExtensions(elt, function (extension) { - eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) - }); - return eventResult; - } - - //==================================================================== - // History Support - //==================================================================== - var currentPathForHistory = location.pathname+location.search; - - function getHistoryElement() { - var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]'); - return historyElt || getDocument().body; - } - - function saveToHistoryCache(url, content, title, scroll) { - if (!canAccessLocalStorage()) { - return; - } - - if (htmx.config.historyCacheSize <= 0) { - // make sure that an eventually already existing cache is purged - localStorage.removeItem("htmx-history-cache"); - return; - } - - url = normalizePath(url); - - var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - historyCache.splice(i, 1); - break; - } - } - var newHistoryItem = {url:url, content: content, title:title, scroll:scroll}; - triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache}) - historyCache.push(newHistoryItem) - while (historyCache.length > htmx.config.historyCacheSize) { - historyCache.shift(); - } - while(historyCache.length > 0){ - try { - localStorage.setItem("htmx-history-cache", JSON.stringify(historyCache)); - break; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:historyCacheError", {cause:e, cache: historyCache}) - historyCache.shift(); // shrink the cache and retry - } - } - } - - function getCachedHistory(url) { - if (!canAccessLocalStorage()) { - return null; - } - - url = normalizePath(url); - - var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - return historyCache[i]; - } - } - return null; - } - - function cleanInnerHtmlForHistory(elt) { - var className = htmx.config.requestClass; - var clone = elt.cloneNode(true); - forEach(findAll(clone, "." + className), function(child){ - removeClassFromElement(child, className); - }); - return clone.innerHTML; - } - - function saveCurrentPageToHistory() { - var elt = getHistoryElement(); - var path = currentPathForHistory || location.pathname+location.search; - - // Allow history snapshot feature to be disabled where hx-history="false" - // is present *anywhere* in the current document we're about to save, - // so we can prevent privileged data entering the cache. - // The page will still be reachable as a history entry, but htmx will fetch it - // live from the server onpopstate rather than look in the localStorage cache - var disableHistoryCache - try { - disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') - } catch (e) { - // IE11: insensitive modifier not supported so fallback to case sensitive selector - disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') - } - if (!disableHistoryCache) { - triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt}); - saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); - } - - if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href); - } - - function pushUrlIntoHistory(path) { - // remove the cache buster parameter, if any - if (htmx.config.getCacheBusterParam) { - path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') - if (endsWith(path, '&') || endsWith(path, "?")) { - path = path.slice(0, -1); - } - } - if(htmx.config.historyEnabled) { - history.pushState({htmx:true}, "", path); - } - currentPathForHistory = path; - } - - function replaceUrlInHistory(path) { - if(htmx.config.historyEnabled) history.replaceState({htmx:true}, "", path); - currentPathForHistory = path; - } - - function settleImmediately(tasks) { - forEach(tasks, function (task) { - task.call(); - }); - } - - function loadHistoryFromServer(path) { - var request = new XMLHttpRequest(); - var details = {path: path, xhr:request}; - triggerEvent(getDocument().body, "htmx:historyCacheMiss", details); - request.open('GET', path, true); - request.setRequestHeader("HX-Request", "true"); - request.setRequestHeader("HX-History-Restore-Request", "true"); - request.setRequestHeader("HX-Current-URL", getDocument().location.href); - request.onload = function () { - if (this.status >= 200 && this.status < 400) { - triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); - var fragment = makeFragment(this.response); - // @ts-ignore - fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; - var historyElement = getHistoryElement(); - var settleInfo = makeSettleInfo(historyElement); - var title = findTitle(this.response); - if (title) { - var titleElt = find("title"); - if (titleElt) { - titleElt.innerHTML = title; - } else { - window.document.title = title; - } - } - // @ts-ignore - swapInnerHTML(historyElement, fragment, settleInfo) - settleImmediately(settleInfo.tasks); - currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response}); - } else { - triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details); - } - }; - request.send(); - } - - function restoreHistory(path) { - saveCurrentPageToHistory(); - path = path || location.pathname+location.search; - var cached = getCachedHistory(path); - if (cached) { - var fragment = makeFragment(cached.content); - var historyElement = getHistoryElement(); - var settleInfo = makeSettleInfo(historyElement); - swapInnerHTML(historyElement, fragment, settleInfo) - settleImmediately(settleInfo.tasks); - document.title = cached.title; - setTimeout(function () { - window.scrollTo(0, cached.scroll); - }, 0); // next 'tick', so browser has time to render layout - currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); - } else { - if (htmx.config.refreshOnHistoryMiss) { - - // @ts-ignore: optional parameter in reload() function throws error - window.location.reload(true); - } else { - loadHistoryFromServer(path); - } - } - } - - function addRequestIndicatorClasses(elt) { - var indicators = findAttributeTargets(elt, 'hx-indicator'); - if (indicators == null) { - indicators = [elt]; - } - forEach(indicators, function (ic) { - var internalData = getInternalData(ic); - internalData.requestCount = (internalData.requestCount || 0) + 1; - ic.classList["add"].call(ic.classList, htmx.config.requestClass); - }); - return indicators; - } - - function disableElements(elt) { - var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt'); - if (disabledElts == null) { - disabledElts = []; - } - forEach(disabledElts, function (disabledElement) { - var internalData = getInternalData(disabledElement); - internalData.requestCount = (internalData.requestCount || 0) + 1; - disabledElement.setAttribute("disabled", ""); - }); - return disabledElts; - } - - function removeRequestIndicators(indicators, disabled) { - forEach(indicators, function (ic) { - var internalData = getInternalData(ic); - internalData.requestCount = (internalData.requestCount || 0) - 1; - if (internalData.requestCount === 0) { - ic.classList["remove"].call(ic.classList, htmx.config.requestClass); - } - }); - forEach(disabled, function (disabledElement) { - var internalData = getInternalData(disabledElement); - internalData.requestCount = (internalData.requestCount || 0) - 1; - if (internalData.requestCount === 0) { - disabledElement.removeAttribute('disabled'); - } - }); - } - - //==================================================================== - // 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 || closest(elt, "fieldset[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 addValueToValues(name, value, values) { - // This is a little ugly because both the current value of the named value in the form - // and the new value could be arrays, so we have to handle all four cases :/ - if (name != null && value != null) { - var current = values[name]; - if (current === undefined) { - values[name] = value; - } else if (Array.isArray(current)) { - if (Array.isArray(value)) { - values[name] = current.concat(value); - } else { - current.push(value); - } - } else { - if (Array.isArray(value)) { - values[name] = [current].concat(value); - } else { - values[name] = [current, value]; - } - } - } - } - - function processInputValue(processed, values, errors, elt, validate) { - if (elt == null || haveSeenNode(processed, elt)) { - return; - } else { - processed.push(elt); - } - if (shouldInclude(elt)) { - var name = getRawAttribute(elt,"name"); - var value = elt.value; - if (elt.multiple && elt.tagName === "SELECT") { - value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value }); - } - // include file inputs - if (elt.files) { - value = toArray(elt.files); - } - addValueToValues(name, value, values); - if (validate) { - validateElement(elt, errors); - } - } - if (matches(elt, 'form')) { - var inputs = elt.elements; - forEach(inputs, function(input) { - processInputValue(processed, values, errors, input, validate); - }); - } - } - - function validateElement(element, errors) { - if (element.willValidate) { - triggerEvent(element, "htmx:validation:validate") - if (!element.checkValidity()) { - errors.push({elt: element, message:element.validationMessage, validity:element.validity}); - triggerEvent(element, "htmx:validation:failed", {message:element.validationMessage, validity:element.validity}) - } - } - } - - /** - * @param {HTMLElement} elt - * @param {string} verb - */ - function getInputValues(elt, verb) { - var processed = []; - var values = {}; - var formValues = {}; - var errors = []; - var internalData = getInternalData(elt); - if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { - internalData.lastButtonClicked = null - } - - // only validate when form is directly submitted and novalidate or formnovalidate are not set - // or if the element has an explicit hx-validate="true" on it - var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true"; - if (internalData.lastButtonClicked) { - validate = validate && internalData.lastButtonClicked.formNoValidate !== true; - } - - // for a non-GET include the closest form - if (verb !== 'get') { - processInputValue(processed, formValues, errors, closest(elt, 'form'), validate); - } - - // include the element itself - processInputValue(processed, values, errors, elt, validate); - - // if a button or submit was clicked last, include its value - if (internalData.lastButtonClicked || elt.tagName === "BUTTON" || - (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) { - var button = internalData.lastButtonClicked || elt - var name = getRawAttribute(button, "name") - addValueToValues(name, button.value, formValues) - } - - // include any explicit includes - var includes = findAttributeTargets(elt, "hx-include"); - forEach(includes, function(node) { - processInputValue(processed, values, errors, node, validate); - // if a non-form is included, include any input values within it - if (!matches(node, 'form')) { - forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { - processInputValue(processed, values, errors, descendant, validate); - }) - } - }); - - // form values take precedence, overriding the regular values - values = mergeObjects(values, formValues); - - return {errors:errors, values:values}; - } - - function appendParam(returnStr, name, realValue) { - if (returnStr !== "") { - returnStr += "&"; - } - if (String(realValue) === "[object Object]") { - realValue = JSON.stringify(realValue); - } - var s = encodeURIComponent(realValue); - returnStr += encodeURIComponent(name) + "=" + s; - 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; - } - - function makeFormData(values) { - var formData = new FormData(); - for (var name in values) { - if (values.hasOwnProperty(name)) { - var value = values[name]; - if (Array.isArray(value)) { - forEach(value, function(v) { - formData.append(name, v); - }); - } else { - formData.append(name, value); - } - } - } - return formData; - } - - //==================================================================== - // Ajax - //==================================================================== - - /** - * @param {HTMLElement} elt - * @param {HTMLElement} target - * @param {string} prompt - * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification - */ - function getHeaders(elt, target, prompt) { - var headers = { - "HX-Request" : "true", - "HX-Trigger" : getRawAttribute(elt, "id"), - "HX-Trigger-Name" : getRawAttribute(elt, "name"), - "HX-Target" : getAttributeValue(target, "id"), - "HX-Current-URL" : getDocument().location.href, - } - getValuesForElement(elt, "hx-headers", false, headers) - if (prompt !== undefined) { - headers["HX-Prompt"] = prompt; - } - if (getInternalData(elt).boosted) { - headers["HX-Boosted"] = "true"; - } - return headers; - } - - /** - * filterValues takes an object containing form input values - * and returns a new object that only contains keys that are - * specified by the closest "hx-params" attribute - * @param {Object} inputValues - * @param {HTMLElement} elt - * @returns {Object} - */ - function filterValues(inputValues, elt) { - var paramsValue = getClosestAttributeValue(elt, "hx-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 isAnchorLink(elt) { - return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0 - } - - /** - * - * @param {HTMLElement} elt - * @param {string} swapInfoOverride - * @returns {import("./htmx").HtmxSwapSpecification} - */ - function getSwapSpecification(elt, swapInfoOverride) { - var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap"); - var swapSpec = { - "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, - "swapDelay" : htmx.config.defaultSwapDelay, - "settleDelay" : htmx.config.defaultSettleDelay - } - if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { - swapSpec["show"] = "top" - } - if (swapInfo) { - var split = splitOnWhitespace(swapInfo); - if (split.length > 0) { - for (var i = 0; i < split.length; i++) { - var value = split[i]; - if (value.indexOf("swap:") === 0) { - swapSpec["swapDelay"] = parseInterval(value.substr(5)); - } else if (value.indexOf("settle:") === 0) { - swapSpec["settleDelay"] = parseInterval(value.substr(7)); - } else if (value.indexOf("transition:") === 0) { - swapSpec["transition"] = value.substr(11) === "true"; - } else if (value.indexOf("ignoreTitle:") === 0) { - swapSpec["ignoreTitle"] = value.substr(12) === "true"; - } else if (value.indexOf("scroll:") === 0) { - var scrollSpec = value.substr(7); - var splitSpec = scrollSpec.split(":"); - var scrollVal = splitSpec.pop(); - var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; - swapSpec["scroll"] = scrollVal; - swapSpec["scrollTarget"] = selectorVal; - } else if (value.indexOf("show:") === 0) { - var showSpec = value.substr(5); - var splitSpec = showSpec.split(":"); - var showVal = splitSpec.pop(); - var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; - swapSpec["show"] = showVal; - swapSpec["showTarget"] = selectorVal; - } else if (value.indexOf("focus-scroll:") === 0) { - var focusScrollVal = value.substr("focus-scroll:".length); - swapSpec["focusScroll"] = focusScrollVal == "true"; - } else if (i == 0) { - swapSpec["swapStyle"] = value; - } else { - logError('Unknown modifier in hx-swap: ' + value); - } - } - } - } - return swapSpec; - } - - function usesFormData(elt) { - return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || - (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data"); - } - - function encodeParamsForBody(xhr, elt, filteredParameters) { - var encodedParameters = null; - withExtensions(elt, function (extension) { - if (encodedParameters == null) { - encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt); - } - }); - if (encodedParameters != null) { - return encodedParameters; - } else { - if (usesFormData(elt)) { - return makeFormData(filteredParameters); - } else { - return urlEncode(filteredParameters); - } - } - } - - /** - * - * @param {Element} target - * @returns {import("./htmx").HtmxSettleInfo} - */ - function makeSettleInfo(target) { - return {tasks: [], elts: [target]}; - } - - function updateScrollState(content, swapSpec) { - var first = content[0]; - var last = content[content.length - 1]; - if (swapSpec.scroll) { - var target = null; - if (swapSpec.scrollTarget) { - target = querySelectorExt(first, swapSpec.scrollTarget); - } - if (swapSpec.scroll === "top" && (first || target)) { - target = target || first; - target.scrollTop = 0; - } - if (swapSpec.scroll === "bottom" && (last || target)) { - target = target || last; - target.scrollTop = target.scrollHeight; - } - } - if (swapSpec.show) { - var target = null; - if (swapSpec.showTarget) { - var targetStr = swapSpec.showTarget; - if (swapSpec.showTarget === "window") { - targetStr = "body"; - } - target = querySelectorExt(first, targetStr); - } - if (swapSpec.show === "top" && (first || target)) { - target = target || first; - target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior}); - } - if (swapSpec.show === "bottom" && (last || target)) { - target = target || last; - target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior}); - } - } - } - - /** - * @param {HTMLElement} elt - * @param {string} attr - * @param {boolean=} evalAsDefault - * @param {Object=} values - * @returns {Object} - */ - function getValuesForElement(elt, attr, evalAsDefault, values) { - if (values == null) { - values = {}; - } - if (elt == null) { - return values; - } - var attributeValue = getAttributeValue(elt, attr); - if (attributeValue) { - var str = attributeValue.trim(); - var evaluateValue = evalAsDefault; - if (str === "unset") { - return null; - } - if (str.indexOf("javascript:") === 0) { - str = str.substr(11); - evaluateValue = true; - } else if (str.indexOf("js:") === 0) { - str = str.substr(3); - evaluateValue = true; - } - if (str.indexOf('{') !== 0) { - str = "{" + str + "}"; - } - var varsValues; - if (evaluateValue) { - varsValues = maybeEval(elt,function () {return Function("return (" + str + ")")();}, {}); - } else { - varsValues = parseJSON(str); - } - for (var key in varsValues) { - if (varsValues.hasOwnProperty(key)) { - if (values[key] == null) { - values[key] = varsValues[key]; - } - } - } - } - return getValuesForElement(parentElt(elt), attr, evalAsDefault, values); - } - - function maybeEval(elt, toEval, defaultVal) { - if (htmx.config.allowEval) { - return toEval(); - } else { - triggerErrorEvent(elt, 'htmx:evalDisallowedError'); - return defaultVal; - } - } - - /** - * @param {HTMLElement} elt - * @param {*} expressionVars - * @returns - */ - function getHXVarsForElement(elt, expressionVars) { - return getValuesForElement(elt, "hx-vars", true, expressionVars); - } - - /** - * @param {HTMLElement} elt - * @param {*} expressionVars - * @returns - */ - function getHXValsForElement(elt, expressionVars) { - return getValuesForElement(elt, "hx-vals", false, expressionVars); - } - - /** - * @param {HTMLElement} elt - * @returns {Object} - */ - function getExpressionVars(elt) { - return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)); - } - - function safelySetHeaderValue(xhr, header, headerValue) { - if (headerValue !== null) { - try { - xhr.setRequestHeader(header, headerValue); - } catch (e) { - // On an exception, try to set the header URI encoded instead - xhr.setRequestHeader(header, encodeURIComponent(headerValue)); - xhr.setRequestHeader(header + "-URI-AutoEncoded", "true"); - } - } - } - - function getPathFromResponse(xhr) { - // NB: IE11 does not support this stuff - if (xhr.responseURL && typeof(URL) !== "undefined") { - try { - var url = new URL(xhr.responseURL); - return url.pathname + url.search; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:badResponseUrl", {url: xhr.responseURL}); - } - } - } - - function hasHeader(xhr, regexp) { - return regexp.test(xhr.getAllResponseHeaders()) - } - - function ajaxHelper(verb, path, context) { - verb = verb.toLowerCase(); - if (context) { - if (context instanceof Element || isType(context, 'String')) { - return issueAjaxRequest(verb, path, null, null, { - targetOverride: resolveTarget(context), - returnPromise: true - }); - } else { - return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, - { - handler : context.handler, - headers : context.headers, - values : context.values, - targetOverride: resolveTarget(context.target), - swapOverride: context.swap, - select: context.select, - returnPromise: true - }); - } - } else { - return issueAjaxRequest(verb, path, null, null, { - returnPromise: true - }); - } - } - - function hierarchyForElt(elt) { - var arr = []; - while (elt) { - arr.push(elt); - elt = elt.parentElement; - } - return arr; - } - - function verifyPath(elt, path, requestConfig) { - var sameHost - var url - if (typeof URL === "function") { - url = new URL(path, document.location.href); - var origin = document.location.origin; - sameHost = origin === url.origin; - } else { - // IE11 doesn't support URL - url = path - sameHost = startsWith(path, document.location.origin) - } - - if (htmx.config.selfRequestsOnly) { - if (!sameHost) { - return false; - } - } - return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig)); - } - - function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { - var resolve = null; - var reject = null; - etc = etc != null ? etc : {}; - if(etc.returnPromise && typeof Promise !== "undefined"){ - var promise = new Promise(function (_resolve, _reject) { - resolve = _resolve; - reject = _reject; - }); - } - if(elt == null) { - elt = getDocument().body; - } - var responseHandler = etc.handler || handleAjaxResponse; - var select = etc.select || null; - - if (!bodyContains(elt)) { - // do not issue requests for elements removed from the DOM - maybeCall(resolve); - return promise; - } - var target = etc.targetOverride || getTarget(elt); - if (target == null || target == DUMMY_ELT) { - triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); - maybeCall(reject); - return promise; - } - - var eltData = getInternalData(elt); - var submitter = eltData.lastButtonClicked; - - if (submitter) { - var buttonPath = getRawAttribute(submitter, "formaction"); - if (buttonPath != null) { - path = buttonPath; - } - - var buttonVerb = getRawAttribute(submitter, "formmethod") - if (buttonVerb != null) { - // ignore buttons with formmethod="dialog" - if (buttonVerb.toLowerCase() !== "dialog") { - verb = buttonVerb; - } - } - } - - var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); - // allow event-based confirmation w/ a callback - if (confirmed === undefined) { - var issueRequest = function(skipConfirmation) { - return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation); - } - var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion}; - if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { - maybeCall(resolve); - return promise; - } - } - - var syncElt = elt; - var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); - var queueStrategy = null; - var abortable = false; - if (syncStrategy) { - var syncStrings = syncStrategy.split(":"); - var selector = syncStrings[0].trim(); - if (selector === "this") { - syncElt = findThisElement(elt, 'hx-sync'); - } else { - syncElt = querySelectorExt(elt, selector); - } - // default to the drop strategy - syncStrategy = (syncStrings[1] || 'drop').trim(); - eltData = getInternalData(syncElt); - if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { - maybeCall(resolve); - return promise; - } else if (syncStrategy === "abort") { - if (eltData.xhr) { - maybeCall(resolve); - return promise; - } else { - abortable = true; - } - } else if (syncStrategy === "replace") { - triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue - } else if (syncStrategy.indexOf("queue") === 0) { - var queueStrArray = syncStrategy.split(" "); - queueStrategy = (queueStrArray[1] || "last").trim(); - } - } - - if (eltData.xhr) { - if (eltData.abortable) { - triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue - } else { - if(queueStrategy == null){ - if (event) { - var eventData = getInternalData(event); - if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { - queueStrategy = eventData.triggerSpec.queue; - } - } - if (queueStrategy == null) { - queueStrategy = "last"; - } - } - if (eltData.queuedRequests == null) { - eltData.queuedRequests = []; - } - if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } else if (queueStrategy === "all") { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } else if (queueStrategy === "last") { - eltData.queuedRequests = []; // dump existing queue - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } - maybeCall(resolve); - return promise; - } - } - - var xhr = new XMLHttpRequest(); - eltData.xhr = xhr; - eltData.abortable = abortable; - var endRequestLock = function(){ - eltData.xhr = null; - eltData.abortable = false; - if (eltData.queuedRequests != null && - eltData.queuedRequests.length > 0) { - var queuedRequest = eltData.queuedRequests.shift(); - queuedRequest(); - } - } - var promptQuestion = getClosestAttributeValue(elt, "hx-prompt"); - if (promptQuestion) { - var promptResponse = prompt(promptQuestion); - // prompt returns null if cancelled and empty string if accepted with no entry - if (promptResponse === null || - !triggerEvent(elt, 'htmx:prompt', {prompt: promptResponse, target:target})) { - maybeCall(resolve); - endRequestLock(); - return promise; - } + triggerErrorEvent(getDocument().body, 'htmx:syntax:error', { error: e, source: conditionalSource }) + return null } + } + } else if (token === '[') { + bracketCount++ + } + if (isPossibleRelativeReference(token, last, paramName)) { + conditionalSource += '((' + paramName + '.' + token + ') ? (' + paramName + '.' + token + ') : (window.' + token + '))' + } else { + conditionalSource = conditionalSource + token + } + last = tokens.shift() + } + } + } + + /** + * @param {string[]} tokens + * @param {RegExp} match + * @returns {string} + */ + function consumeUntil(tokens, match) { + let result = '' + while (tokens.length > 0 && !match.test(tokens[0])) { + result += tokens.shift() + } + return result + } + + /** + * @param {string[]} tokens + * @returns {string} + */ + function consumeCSSSelector(tokens) { + let result + if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { + tokens.shift() + result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim() + tokens.shift() + } else { + result = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } + return result + } + + const INPUT_SELECTOR = 'input, textarea, select' + + /** + * @param {Element} elt + * @param {string} explicitTrigger + * @param {Object} cache for trigger specs + * @returns {HtmxTriggerSpecification[]} + */ + function parseAndCacheTrigger(elt, explicitTrigger, cache) { + /** @type HtmxTriggerSpecification[] */ + const triggerSpecs = [] + const tokens = tokenizeString(explicitTrigger) + do { + consumeUntil(tokens, NOT_WHITESPACE) + const initialLength = tokens.length + const trigger = consumeUntil(tokens, /[,\[\s]/) + if (trigger !== '') { + if (trigger === 'every') { + /** @type HtmxTriggerSpecification */ + const every = { trigger: 'every' } + consumeUntil(tokens, NOT_WHITESPACE) + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)) + consumeUntil(tokens, NOT_WHITESPACE) + var eventFilter = maybeGenerateConditional(elt, tokens, 'event') + if (eventFilter) { + every.eventFilter = eventFilter + } + triggerSpecs.push(every) + } else { + /** @type HtmxTriggerSpecification */ + const triggerSpec = { trigger } + var eventFilter = maybeGenerateConditional(elt, tokens, 'event') + if (eventFilter) { + triggerSpec.eventFilter = eventFilter + } + while (tokens.length > 0 && tokens[0] !== ',') { + consumeUntil(tokens, NOT_WHITESPACE) + const token = tokens.shift() + if (token === 'changed') { + triggerSpec.changed = true + } else if (token === 'once') { + triggerSpec.once = true + } else if (token === 'consume') { + triggerSpec.consume = true + } else if (token === 'delay' && tokens[0] === ':') { + tokens.shift() + triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)) + } else if (token === 'from' && tokens[0] === ':') { + tokens.shift() + if (COMBINED_SELECTOR_START.test(tokens[0])) { + var from_arg = consumeCSSSelector(tokens) + } else { + var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA) + if (from_arg === 'closest' || from_arg === 'find' || from_arg === 'next' || from_arg === 'previous') { + tokens.shift() + const selector = consumeCSSSelector(tokens) + // `next` and `previous` allow a selector-less syntax + if (selector.length > 0) { + from_arg += ' ' + selector + } + } + } + triggerSpec.from = from_arg + } else if (token === 'target' && tokens[0] === ':') { + tokens.shift() + triggerSpec.target = consumeCSSSelector(tokens) + } else if (token === 'throttle' && tokens[0] === ':') { + tokens.shift() + triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)) + } else if (token === 'queue' && tokens[0] === ':') { + tokens.shift() + triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } else if (token === 'root' && tokens[0] === ':') { + tokens.shift() + triggerSpec[token] = consumeCSSSelector(tokens) + } else if (token === 'threshold' && tokens[0] === ':') { + tokens.shift() + triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } else { + triggerErrorEvent(elt, 'htmx:syntax:error', { token: tokens.shift() }) + } + } + triggerSpecs.push(triggerSpec) + } + } + if (tokens.length === initialLength) { + triggerErrorEvent(elt, 'htmx:syntax:error', { token: tokens.shift() }) + } + consumeUntil(tokens, NOT_WHITESPACE) + } while (tokens[0] === ',' && tokens.shift()) + if (cache) { + cache[explicitTrigger] = triggerSpecs + } + return triggerSpecs + } + + /** + * @param {Element} elt + * @returns {HtmxTriggerSpecification[]} + */ + function getTriggerSpecs(elt) { + const explicitTrigger = getAttributeValue(elt, 'hx-trigger') + let triggerSpecs = [] + if (explicitTrigger) { + const cache = htmx.config.triggerSpecsCache + triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) + } - if (confirmQuestion && !confirmed) { - if(!confirm(confirmQuestion)) { - maybeCall(resolve); - endRequestLock() - return promise; - } + if (triggerSpecs.length > 0) { + return triggerSpecs + } else if (matches(elt, 'form')) { + return [{ trigger: 'submit' }] + } else if (matches(elt, 'input[type="button"], input[type="submit"]')) { + return [{ trigger: 'click' }] + } else if (matches(elt, INPUT_SELECTOR)) { + return [{ trigger: 'change' }] + } else { + return [{ trigger: 'click' }] + } + } + + /** + * @param {Element} elt + */ + function cancelPolling(elt) { + getInternalData(elt).cancelled = true + } + + /** + * @param {Element} elt + * @param {TriggerHandler} handler + * @param {HtmxTriggerSpecification} spec + */ + function processPolling(elt, handler, spec) { + const nodeData = getInternalData(elt) + nodeData.timeout = getWindow().setTimeout(function() { + if (bodyContains(elt) && nodeData.cancelled !== true) { + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { + handler(elt) + } + processPolling(elt, handler, spec) + } + }, spec.pollInterval) + } + + /** + * @param {HTMLAnchorElement} elt + * @returns {boolean} + */ + function isLocalLink(elt) { + return location.hostname === elt.hostname && + getRawAttribute(elt, 'href') && + getRawAttribute(elt, 'href').indexOf('#') !== 0 + } + + /** + * @param {Element} elt + */ + function eltIsDisabled(elt) { + return closest(elt, htmx.config.disableSelector) + } + + /** + * @param {Element} elt + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification[]} triggerSpecs + */ + function boostElement(elt, nodeData, triggerSpecs) { + if ((elt instanceof HTMLAnchorElement && isLocalLink(elt) && (elt.target === '' || elt.target === '_self')) || elt.tagName === 'FORM') { + nodeData.boosted = true + let verb, path + if (elt.tagName === 'A') { + verb = 'get' + path = getRawAttribute(elt, 'href') + } else { + const rawAttribute = getRawAttribute(elt, 'method') + verb = rawAttribute ? rawAttribute.toLowerCase() : 'get' + if (verb === 'get') { + } + path = getRawAttribute(elt, 'action') + } + triggerSpecs.forEach(function(triggerSpec) { + addEventListener(elt, function(node, evt) { + const elt = asElement(node) + if (eltIsDisabled(elt)) { + cleanUpElement(elt) + return + } + issueAjaxRequest(verb, path, elt, evt) + }, nodeData, triggerSpec, true) + }) + } + } + + /** + * @param {Event} evt + * @param {Node} node + * @returns {boolean} + */ + function shouldCancel(evt, node) { + const elt = asElement(node) + if (!elt) { + return false + } + if (evt.type === 'submit' || evt.type === 'click') { + if (elt.tagName === 'FORM') { + return true + } + if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { + return true + } + if (elt instanceof HTMLAnchorElement && elt.href && + (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf('#') !== 0)) { + return true + } + } + return false + } + + /** + * @param {Node} elt + * @param {Event|MouseEvent|KeyboardEvent|TouchEvent} evt + * @returns {boolean} + */ + function ignoreBoostedAnchorCtrlClick(elt, evt) { + return getInternalData(elt).boosted && elt instanceof HTMLAnchorElement && evt.type === 'click' && + // @ts-ignore this will resolve to undefined for events that don't define those properties, which is fine + (evt.ctrlKey || evt.metaKey) + } + + /** + * @param {HtmxTriggerSpecification} triggerSpec + * @param {Node} elt + * @param {Event} evt + * @returns {boolean} + */ + function maybeFilterEvent(triggerSpec, elt, evt) { + const eventFilter = triggerSpec.eventFilter + if (eventFilter) { + try { + return eventFilter.call(elt, evt) !== true + } catch (e) { + const source = eventFilter.source + triggerErrorEvent(getDocument().body, 'htmx:eventFilter:error', { error: e, source }) + return true + } + } + return false + } + + /** + * @param {Node} elt + * @param {TriggerHandler} handler + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification} triggerSpec + * @param {boolean} [explicitCancel] + */ + function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { + const elementData = getInternalData(elt) + /** @type {(Node|Window)[]} */ + let eltsToListenOn + if (triggerSpec.from) { + eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from) + } else { + eltsToListenOn = [elt] + } + // store the initial values of the elements, so we can tell if they change + if (triggerSpec.changed) { + eltsToListenOn.forEach(function(eltToListenOn) { + const eltToListenOnData = getInternalData(eltToListenOn) + // @ts-ignore value will be undefined for non-input elements, which is fine + eltToListenOnData.lastValue = eltToListenOn.value + }) + } + forEach(eltsToListenOn, function(eltToListenOn) { + /** @type EventListener */ + const eventListener = function(evt) { + if (!bodyContains(elt)) { + eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener) + return + } + if (ignoreBoostedAnchorCtrlClick(elt, evt)) { + return + } + if (explicitCancel || shouldCancel(evt, elt)) { + evt.preventDefault() + } + if (maybeFilterEvent(triggerSpec, elt, evt)) { + return + } + const eventData = getInternalData(evt) + eventData.triggerSpec = triggerSpec + if (eventData.handledFor == null) { + eventData.handledFor = [] + } + if (eventData.handledFor.indexOf(elt) < 0) { + eventData.handledFor.push(elt) + if (triggerSpec.consume) { + evt.stopPropagation() + } + if (triggerSpec.target && evt.target) { + if (!matches(asElement(evt.target), triggerSpec.target)) { + return + } + } + if (triggerSpec.once) { + if (elementData.triggeredOnce) { + return + } else { + elementData.triggeredOnce = true + } + } + if (triggerSpec.changed) { + const eltToListenOnData = getInternalData(eltToListenOn) + // @ts-ignore value will be undefined for non-input elements, which is fine + const value = eltToListenOn.value + if (eltToListenOnData.lastValue === value) { + return + } + eltToListenOnData.lastValue = value + } + if (elementData.delayed) { + clearTimeout(elementData.delayed) + } + if (elementData.throttle) { + return + } + + if (triggerSpec.throttle > 0) { + if (!elementData.throttle) { + handler(elt, evt) + elementData.throttle = getWindow().setTimeout(function() { + elementData.throttle = null + }, triggerSpec.throttle) + } + } else if (triggerSpec.delay > 0) { + elementData.delayed = getWindow().setTimeout(function() { handler(elt, evt) }, triggerSpec.delay) + } else { + triggerEvent(elt, 'htmx:trigger') + handler(elt, evt) + } + } + } + if (nodeData.listenerInfos == null) { + nodeData.listenerInfos = [] + } + nodeData.listenerInfos.push({ + trigger: triggerSpec.trigger, + listener: eventListener, + on: eltToListenOn + }) + eltToListenOn.addEventListener(triggerSpec.trigger, eventListener) + }) + } + + let windowIsScrolling = false // used by initScrollHandler + let scrollHandler = null + function initScrollHandler() { + if (!scrollHandler) { + scrollHandler = function() { + windowIsScrolling = true + } + window.addEventListener('scroll', scrollHandler) + setInterval(function() { + if (windowIsScrolling) { + windowIsScrolling = false + forEach(getDocument().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"), function(elt) { + maybeReveal(elt) + }) + } + }, 200) + } + } + + /** + * @param {Element} elt + */ + function maybeReveal(elt) { + if (!hasAttribute(elt, 'data-hx-revealed') && isScrolledIntoView(elt)) { + elt.setAttribute('data-hx-revealed', 'true') + const nodeData = getInternalData(elt) + if (nodeData.initHash) { + triggerEvent(elt, 'revealed') + } else { + // if the node isn't initialized, wait for it before triggering the request + elt.addEventListener('htmx:afterProcessNode', function() { triggerEvent(elt, 'revealed') }, { once: true }) + } + } + } + + //= =================================================================== + + /** + * @param {Element} elt + * @param {TriggerHandler} handler + * @param {HtmxNodeInternalData} nodeData + * @param {number} delay + */ + function loadImmediately(elt, handler, nodeData, delay) { + const load = function() { + if (!nodeData.loaded) { + nodeData.loaded = true + handler(elt) + } + } + if (delay > 0) { + getWindow().setTimeout(load, delay) + } else { + load() + } + } + + /** + * @param {Element} elt + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification[]} triggerSpecs + * @returns {boolean} + */ + function processVerbs(elt, nodeData, triggerSpecs) { + let explicitAction = false + forEach(VERBS, function(verb) { + if (hasAttribute(elt, 'hx-' + verb)) { + const path = getAttributeValue(elt, 'hx-' + verb) + explicitAction = true + nodeData.path = path + nodeData.verb = verb + triggerSpecs.forEach(function(triggerSpec) { + addTriggerHandler(elt, triggerSpec, nodeData, function(node, evt) { + const elt = asElement(node) + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return } + issueAjaxRequest(verb, path, elt, evt) + }) + }) + } + }) + return explicitAction + } + + /** + * @callback TriggerHandler + * @param {Node} elt + * @param {Event} [evt] + */ + + /** + * @param {Node} elt + * @param {HtmxTriggerSpecification} triggerSpec + * @param {HtmxNodeInternalData} nodeData + * @param {TriggerHandler} handler + */ + function addTriggerHandler(elt, triggerSpec, nodeData, handler) { + if (triggerSpec.trigger === 'revealed') { + initScrollHandler() + addEventListener(elt, handler, nodeData, triggerSpec) + maybeReveal(asElement(elt)) + } else if (triggerSpec.trigger === 'intersect') { + const observerOptions = {} + if (triggerSpec.root) { + observerOptions.root = querySelectorExt(elt, triggerSpec.root) + } + if (triggerSpec.threshold) { + observerOptions.threshold = parseFloat(triggerSpec.threshold) + } + const observer = new IntersectionObserver(function(entries) { + for (let i = 0; i < entries.length; i++) { + const entry = entries[i] + if (entry.isIntersecting) { + triggerEvent(elt, 'intersect') + break + } + } + }, observerOptions) + observer.observe(asElement(elt)) + addEventListener(asElement(elt), handler, nodeData, triggerSpec) + } else if (triggerSpec.trigger === 'load') { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent('load', { elt }))) { + loadImmediately(asElement(elt), handler, nodeData, triggerSpec.delay) + } + } else if (triggerSpec.pollInterval > 0) { + nodeData.polling = true + processPolling(asElement(elt), handler, triggerSpec) + } else { + addEventListener(elt, handler, nodeData, triggerSpec) + } + } + + /** + * @param {Node} node + * @returns {boolean} + */ + function shouldProcessHxOn(node) { + const elt = asElement(node) + if (!elt) { + return false + } + const attributes = elt.attributes + for (let j = 0; j < attributes.length; j++) { + const attrName = attributes[j].name + if (startsWith(attrName, 'hx-on:') || startsWith(attrName, 'data-hx-on:') || + startsWith(attrName, 'hx-on-') || startsWith(attrName, 'data-hx-on-')) { + return true + } + } + return false + } + + /** + * @param {Node} elt + * @returns {Element[]} + */ + const HX_ON_QUERY = new XPathEvaluator() + .createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + + ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]') + + function processHXOnRoot(elt, elements) { + if (shouldProcessHxOn(elt)) { + elements.push(asElement(elt)) + } + const iter = HX_ON_QUERY.evaluate(elt) + let node = null + while (node = iter.iterateNext()) elements.push(asElement(node)) + } + + function findHxOnWildcardElements(elt) { + /** @type {Element[]} */ + const elements = [] + if (elt instanceof DocumentFragment) { + for (const child of elt.childNodes) { + processHXOnRoot(child, elements) + } + } else { + processHXOnRoot(elt, elements) + } + return elements + } + + /** + * @param {Element} elt + * @returns {NodeListOf<Element>|[]} + */ + function findElementsToProcess(elt) { + if (elt.querySelectorAll) { + const boostedSelector = ', [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]' + + const extensionSelectors = [] + for (const e in extensions) { + const extension = extensions[e] + if (extension.getSelectors) { + var selectors = extension.getSelectors() + if (selectors) { + extensionSelectors.push(selectors) + } + } + } + + const results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit']," + + ' [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]' + extensionSelectors.flat().map(s => ', ' + s).join('')) + + return results + } else { + return [] + } + } + + /** + * Handle submit buttons/inputs that have the form attribute set + * see https://developer.mozilla.org/docs/Web/HTML/Element/button + * @param {Event} evt + */ + function maybeSetLastButtonClicked(evt) { + const elt = /** @type {HTMLButtonElement|HTMLInputElement} */ (closest(asElement(evt.target), "button, input[type='submit']")) + const internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = elt + } + } + + /** + * @param {Event} evt + */ + function maybeUnsetLastButtonClicked(evt) { + const internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = null + } + } + + /** + * @param {Event} evt + * @returns {HtmxNodeInternalData|undefined} + */ + function getRelatedFormData(evt) { + const elt = closest(asElement(evt.target), "button, input[type='submit']") + if (!elt) { + return + } + const form = resolveTarget('#' + getRawAttribute(elt, 'form'), elt.getRootNode()) || closest(elt, 'form') + if (!form) { + return + } + return getInternalData(form) + } + + /** + * @param {EventTarget} elt + */ + function initButtonTracking(elt) { + // need to handle both click and focus in: + // focusin - in case someone tabs in to a button and hits the space bar + // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + elt.addEventListener('click', maybeSetLastButtonClicked) + elt.addEventListener('focusin', maybeSetLastButtonClicked) + elt.addEventListener('focusout', maybeUnsetLastButtonClicked) + } + + /** + * @param {Element} elt + * @param {string} eventName + * @param {string} code + */ + function addHxOnEventHandler(elt, eventName, code) { + const nodeData = getInternalData(elt) + if (!Array.isArray(nodeData.onHandlers)) { + nodeData.onHandlers = [] + } + let func + /** @type EventListener */ + const listener = function(e) { + maybeEval(elt, function() { + if (eltIsDisabled(elt)) { + return + } + if (!func) { + func = new Function('event', code) + } + func.call(elt, e) + }) + } + elt.addEventListener(eventName, listener) + nodeData.onHandlers.push({ event: eventName, listener }) + } + + /** + * @param {Element} elt + */ + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (let i = 0; i < elt.attributes.length; i++) { + const name = elt.attributes[i].name + const value = elt.attributes[i].value + if (startsWith(name, 'hx-on') || startsWith(name, 'data-hx-on')) { + const afterOnPosition = name.indexOf('-on') + 3 + const nextChar = name.slice(afterOnPosition, afterOnPosition + 1) + if (nextChar === '-' || nextChar === ':') { + let eventName = name.slice(afterOnPosition + 1) + // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support + if (startsWith(eventName, ':')) { + eventName = 'htmx' + eventName + } else if (startsWith(eventName, '-')) { + eventName = 'htmx:' + eventName.slice(1) + } else if (startsWith(eventName, 'htmx-')) { + eventName = 'htmx:' + eventName.slice(5) + } + + addHxOnEventHandler(elt, eventName, value) + } + } + } + } + + /** + * @param {Element|HTMLInputElement} elt + */ + function initNode(elt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + const nodeData = getInternalData(elt) + if (nodeData.initHash !== attributeHash(elt)) { + // clean up any previously processed info + deInitNode(elt) + + nodeData.initHash = attributeHash(elt) + + triggerEvent(elt, 'htmx:beforeProcessNode') + + // @ts-ignore value will be undefined for non-input elements, which is fine + if (elt.value) { + // @ts-ignore + nodeData.lastValue = elt.value + } + + const triggerSpecs = getTriggerSpecs(elt) + const hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs) + + if (!hasExplicitHttpAction) { + if (getClosestAttributeValue(elt, 'hx-boost') === 'true') { + boostElement(elt, nodeData, triggerSpecs) + } else if (hasAttribute(elt, 'hx-trigger')) { + triggerSpecs.forEach(function(triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function() { + }) + }) + } + } + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + if (elt.tagName === 'FORM' || (getRawAttribute(elt, 'type') === 'submit' && hasAttribute(elt, 'form'))) { + initButtonTracking(elt) + } - var headers = getHeaders(elt, target, promptResponse); - - if (verb !== 'get' && !usesFormData(elt)) { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; - } + triggerEvent(elt, 'htmx:afterProcessNode') + } + } + + /** + * Processes new content, enabling htmx behavior. This can be useful if you have content that is added to the DOM outside of the normal htmx request cycle but still want htmx attributes to work. + * + * @see https://htmx.org/api/#process + * + * @param {Element|string} elt element to process + */ + function processNode(elt) { + elt = resolveTarget(elt) + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + initNode(elt) + forEach(findElementsToProcess(elt), function(child) { initNode(child) }) + forEach(findHxOnWildcardElements(elt), processHxOnWildcard) + } + + //= =================================================================== + // Event/Log Support + //= =================================================================== + + /** + * @param {string} str + * @returns {string} + */ + function kebabEventName(str) { + return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase() + } + + /** + * @param {string} eventName + * @param {any} detail + * @returns {CustomEvent} + */ + function makeEvent(eventName, detail) { + let evt + if (window.CustomEvent && typeof window.CustomEvent === 'function') { + // TODO: `composed: true` here is a hack to make global event handlers work with events in shadow DOM + // This breaks expected encapsulation but needs to be here until decided otherwise by core devs + evt = new CustomEvent(eventName, { bubbles: true, cancelable: true, composed: true, detail }) + } else { + evt = getDocument().createEvent('CustomEvent') + evt.initCustomEvent(eventName, true, true, detail) + } + return evt + } + + /** + * @param {EventTarget|string} elt + * @param {string} eventName + * @param {any=} detail + */ + function triggerErrorEvent(elt, eventName, detail) { + triggerEvent(elt, eventName, mergeObjects({ error: eventName }, detail)) + } + + /** + * @param {string} eventName + * @returns {boolean} + */ + function ignoreEventForLogging(eventName) { + return eventName === 'htmx:afterProcessNode' + } + + /** + * `withExtensions` locates all active extensions for a provided element, then + * executes the provided function using each of the active extensions. It should + * be called internally at every extendable execution point in htmx. + * + * @param {Element} elt + * @param {(extension:HtmxExtension) => void} toDo + * @returns void + */ + function withExtensions(elt, toDo) { + forEach(getExtensions(elt), function(extension) { + try { + toDo(extension) + } catch (e) { + logError(e) + } + }) + } + + function logError(msg) { + if (console.error) { + console.error(msg) + } else if (console.log) { + console.log('ERROR: ', msg) + } + } + + /** + * Triggers a given event on an element + * + * @see https://htmx.org/api/#trigger + * + * @param {EventTarget|string} elt the element to trigger the event on + * @param {string} eventName the name of the event to trigger + * @param {any=} detail details for the event + * @returns {boolean} + */ + function triggerEvent(elt, eventName, detail) { + elt = resolveTarget(elt) + if (detail == null) { + detail = {} + } + detail.elt = elt + const event = makeEvent(eventName, detail) + if (htmx.logger && !ignoreEventForLogging(eventName)) { + htmx.logger(elt, eventName, detail) + } + if (detail.error) { + logError(detail.error) + triggerEvent(elt, 'htmx:error', { errorInfo: detail }) + } + let eventResult = elt.dispatchEvent(event) + const kebabName = kebabEventName(eventName) + if (eventResult && kebabName !== eventName) { + const kebabedEvent = makeEvent(kebabName, event.detail) + eventResult = eventResult && elt.dispatchEvent(kebabedEvent) + } + withExtensions(asElement(elt), function(extension) { + eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) + }) + return eventResult + } + + //= =================================================================== + // History Support + //= =================================================================== + let currentPathForHistory = location.pathname + location.search + + /** + * @returns {Element} + */ + function getHistoryElement() { + const historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]') + return historyElt || getDocument().body + } + + /** + * @param {string} url + * @param {Element} rootElt + */ + function saveToHistoryCache(url, rootElt) { + if (!canAccessLocalStorage()) { + return + } - if (etc.headers) { - headers = mergeObjects(headers, etc.headers); - } - var results = getInputValues(elt, verb); - var errors = results.errors; - var rawParameters = results.values; - if (etc.values) { - rawParameters = mergeObjects(rawParameters, etc.values); - } - var expressionVars = getExpressionVars(elt); - var allParameters = mergeObjects(rawParameters, expressionVars); - var filteredParameters = filterValues(allParameters, elt); + // get state to save + const innerHTML = cleanInnerHtmlForHistory(rootElt) + const title = getDocument().title + const scroll = window.scrollY - if (htmx.config.getCacheBusterParam && verb === 'get') { - filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true"; - } + if (htmx.config.historyCacheSize <= 0) { + // make sure that an eventually already existing cache is purged + localStorage.removeItem('htmx-history-cache') + return + } - // behavior of anchors w/ empty href is to use the current URL - if (path == null || path === "") { - path = getDocument().location.href; - } + url = normalizePath(url) + const historyCache = parseJSON(localStorage.getItem('htmx-history-cache')) || [] + for (let i = 0; i < historyCache.length; i++) { + if (historyCache[i].url === url) { + historyCache.splice(i, 1) + break + } + } - var requestAttrValues = getValuesForElement(elt, 'hx-request'); + /** @type HtmxHistoryItem */ + const newHistoryItem = { url, content: innerHTML, title, scroll } - var eltIsBoosted = getInternalData(elt).boosted; + triggerEvent(getDocument().body, 'htmx:historyItemCreated', { item: newHistoryItem, cache: historyCache }) - var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + historyCache.push(newHistoryItem) + while (historyCache.length > htmx.config.historyCacheSize) { + historyCache.shift() + } - var requestConfig = { - boosted: eltIsBoosted, - useUrlParams: useUrlParams, - parameters: filteredParameters, - unfilteredParameters: allParameters, - headers:headers, - target:target, - verb:verb, - errors:errors, - withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, - timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, - path:path, - triggeringEvent:event - }; + // keep trying to save the cache until it succeeds or is empty + while (historyCache.length > 0) { + try { + localStorage.setItem('htmx-history-cache', JSON.stringify(historyCache)) + break + } catch (e) { + triggerErrorEvent(getDocument().body, 'htmx:historyCacheError', { cause: e, cache: historyCache }) + historyCache.shift() // shrink the cache and retry + } + } + } + + /** + * @typedef {Object} HtmxHistoryItem + * @property {string} url + * @property {string} content + * @property {string} title + * @property {number} scroll + */ + + /** + * @param {string} url + * @returns {HtmxHistoryItem|null} + */ + function getCachedHistory(url) { + if (!canAccessLocalStorage()) { + return null + } - if(!triggerEvent(elt, 'htmx:configRequest', requestConfig)){ - maybeCall(resolve); - endRequestLock(); - return promise; - } + url = normalizePath(url) - // copy out in case the object was overwritten - path = requestConfig.path; - verb = requestConfig.verb; - headers = requestConfig.headers; - filteredParameters = requestConfig.parameters; - errors = requestConfig.errors; - useUrlParams = requestConfig.useUrlParams; - - if(errors && errors.length > 0){ - triggerEvent(elt, 'htmx:validation:halted', requestConfig) - maybeCall(resolve); - endRequestLock(); - return promise; - } + const historyCache = parseJSON(localStorage.getItem('htmx-history-cache')) || [] + for (let i = 0; i < historyCache.length; i++) { + if (historyCache[i].url === url) { + return historyCache[i] + } + } + return null + } + + /** + * @param {Element} elt + * @returns {string} + */ + function cleanInnerHtmlForHistory(elt) { + const className = htmx.config.requestClass + const clone = /** @type Element */ (elt.cloneNode(true)) + forEach(findAll(clone, '.' + className), function(child) { + removeClassFromElement(child, className) + }) + return clone.innerHTML + } + + function saveCurrentPageToHistory() { + const elt = getHistoryElement() + const path = currentPathForHistory || location.pathname + location.search + + // Allow history snapshot feature to be disabled where hx-history="false" + // is present *anywhere* in the current document we're about to save, + // so we can prevent privileged data entering the cache. + // The page will still be reachable as a history entry, but htmx will fetch it + // live from the server onpopstate rather than look in the localStorage cache + let disableHistoryCache + try { + disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') + } catch (e) { + // IE11: insensitive modifier not supported so fallback to case sensitive selector + disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') + } + if (!disableHistoryCache) { + triggerEvent(getDocument().body, 'htmx:beforeHistorySave', { path, historyElt: elt }) + saveToHistoryCache(path, elt) + } - var splitPath = path.split("#"); - var pathNoAnchor = splitPath[0]; - var anchor = splitPath[1]; - - var finalPath = path - if (useUrlParams) { - finalPath = pathNoAnchor; - var values = Object.keys(filteredParameters).length !== 0; - if (values) { - if (finalPath.indexOf("?") < 0) { - finalPath += "?"; - } else { - finalPath += "&"; - } - finalPath += urlEncode(filteredParameters); - if (anchor) { - finalPath += "#" + anchor; - } - } - } + if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, getDocument().title, window.location.href) + } + + /** + * @param {string} path + */ + function pushUrlIntoHistory(path) { + // remove the cache buster parameter, if any + if (htmx.config.getCacheBusterParam) { + path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') + if (endsWith(path, '&') || endsWith(path, '?')) { + path = path.slice(0, -1) + } + } + if (htmx.config.historyEnabled) { + history.pushState({ htmx: true }, '', path) + } + currentPathForHistory = path + } + + /** + * @param {string} path + */ + function replaceUrlInHistory(path) { + if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, '', path) + currentPathForHistory = path + } + + /** + * @param {HtmxSettleTask[]} tasks + */ + function settleImmediately(tasks) { + forEach(tasks, function(task) { + task.call(undefined) + }) + } + + /** + * @param {string} path + */ + function loadHistoryFromServer(path) { + const request = new XMLHttpRequest() + const details = { path, xhr: request } + triggerEvent(getDocument().body, 'htmx:historyCacheMiss', details) + request.open('GET', path, true) + request.setRequestHeader('HX-Request', 'true') + request.setRequestHeader('HX-History-Restore-Request', 'true') + request.setRequestHeader('HX-Current-URL', getDocument().location.href) + request.onload = function() { + if (this.status >= 200 && this.status < 400) { + triggerEvent(getDocument().body, 'htmx:historyCacheMissLoad', details) + const fragment = makeFragment(this.response) + /** @type ParentNode */ + const content = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment + const historyElement = getHistoryElement() + const settleInfo = makeSettleInfo(historyElement) + handleTitle(fragment.title) + + swapInnerHTML(historyElement, content, settleInfo) + settleImmediately(settleInfo.tasks) + currentPathForHistory = path + triggerEvent(getDocument().body, 'htmx:historyRestore', { path, cacheMiss: true, serverResponse: this.response }) + } else { + triggerErrorEvent(getDocument().body, 'htmx:historyCacheMissLoadError', details) + } + } + request.send() + } + + /** + * @param {string} [path] + */ + function restoreHistory(path) { + saveCurrentPageToHistory() + path = path || location.pathname + location.search + const cached = getCachedHistory(path) + if (cached) { + const fragment = makeFragment(cached.content) + const historyElement = getHistoryElement() + const settleInfo = makeSettleInfo(historyElement) + handleTitle(fragment.title) + swapInnerHTML(historyElement, fragment, settleInfo) + settleImmediately(settleInfo.tasks) + getWindow().setTimeout(function() { + window.scrollTo(0, cached.scroll) + }, 0) // next 'tick', so browser has time to render layout + currentPathForHistory = path + triggerEvent(getDocument().body, 'htmx:historyRestore', { path, item: cached }) + } else { + if (htmx.config.refreshOnHistoryMiss) { + // @ts-ignore: optional parameter in reload() function throws error + // noinspection JSUnresolvedReference + window.location.reload(true) + } else { + loadHistoryFromServer(path) + } + } + } + + /** + * @param {Element} elt + * @returns {Element[]} + */ + function addRequestIndicatorClasses(elt) { + let indicators = /** @type Element[] */ (findAttributeTargets(elt, 'hx-indicator')) + if (indicators == null) { + indicators = [elt] + } + forEach(indicators, function(ic) { + const internalData = getInternalData(ic) + internalData.requestCount = (internalData.requestCount || 0) + 1 + ic.classList.add.call(ic.classList, htmx.config.requestClass) + }) + return indicators + } + + /** + * @param {Element} elt + * @returns {Element[]} + */ + function disableElements(elt) { + let disabledElts = /** @type Element[] */ (findAttributeTargets(elt, 'hx-disabled-elt')) + if (disabledElts == null) { + disabledElts = [] + } + forEach(disabledElts, function(disabledElement) { + const internalData = getInternalData(disabledElement) + internalData.requestCount = (internalData.requestCount || 0) + 1 + disabledElement.setAttribute('disabled', '') + }) + return disabledElts + } + + /** + * @param {Element[]} indicators + * @param {Element[]} disabled + */ + function removeRequestIndicators(indicators, disabled) { + forEach(indicators, function(ic) { + const internalData = getInternalData(ic) + internalData.requestCount = (internalData.requestCount || 0) - 1 + if (internalData.requestCount === 0) { + ic.classList.remove.call(ic.classList, htmx.config.requestClass) + } + }) + forEach(disabled, function(disabledElement) { + const internalData = getInternalData(disabledElement) + internalData.requestCount = (internalData.requestCount || 0) - 1 + if (internalData.requestCount === 0) { + disabledElement.removeAttribute('disabled') + } + }) + } + + //= =================================================================== + // Input Value Processing + //= =================================================================== + + /** + * @param {Element[]} processed + * @param {Element} elt + * @returns {boolean} + */ + function haveSeenNode(processed, elt) { + for (let i = 0; i < processed.length; i++) { + const node = processed[i] + if (node.isSameNode(elt)) { + return true + } + } + return false + } + + /** + * @param {Element} element + * @return {boolean} + */ + function shouldInclude(element) { + // Cast to trick tsc, undefined values will work fine here + const elt = /** @type {HTMLInputElement} */ (element) + if (elt.name === '' || elt.name == null || elt.disabled || closest(elt, 'fieldset[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 + } + + /** @param {string} name + * @param {string|Array|FormDataEntryValue} value + * @param {FormData} formData */ + function addValueToFormData(name, value, formData) { + if (name != null && value != null) { + if (Array.isArray(value)) { + value.forEach(function(v) { formData.append(name, v) }) + } else { + formData.append(name, value) + } + } + } + + /** @param {string} name + * @param {string|Array} value + * @param {FormData} formData */ + function removeValueFromFormData(name, value, formData) { + if (name != null && value != null) { + let values = formData.getAll(name) + if (Array.isArray(value)) { + values = values.filter(v => value.indexOf(v) < 0) + } else { + values = values.filter(v => v !== value) + } + formData.delete(name) + forEach(values, v => formData.append(name, v)) + } + } + + /** + * @param {Element[]} processed + * @param {FormData} formData + * @param {HtmxElementValidationError[]} errors + * @param {Element|HTMLInputElement|HTMLSelectElement|HTMLFormElement} elt + * @param {boolean} validate + */ + function processInputValue(processed, formData, errors, elt, validate) { + if (elt == null || haveSeenNode(processed, elt)) { + return + } else { + processed.push(elt) + } + if (shouldInclude(elt)) { + const name = getRawAttribute(elt, 'name') + // @ts-ignore value will be undefined for non-input elements, which is fine + let value = elt.value + if (elt instanceof HTMLSelectElement && elt.multiple) { + value = toArray(elt.querySelectorAll('option:checked')).map(function(e) { return (/** @type HTMLOptionElement */(e)).value }) + } + // include file inputs + if (elt instanceof HTMLInputElement && elt.files) { + value = toArray(elt.files) + } + addValueToFormData(name, value, formData) + if (validate) { + validateElement(elt, errors) + } + } + if (elt instanceof HTMLFormElement) { + forEach(elt.elements, function(input) { + if (processed.indexOf(input) >= 0) { + // The input has already been processed and added to the values, but the FormData that will be + // constructed right after on the form, will include it once again. So remove that input's value + // now to avoid duplicates + removeValueFromFormData(input.name, input.value, formData) + } else { + processed.push(input) + } + if (validate) { + validateElement(input, errors) + } + }) + new FormData(elt).forEach(function(value, name) { + if (value instanceof File && value.name === '') { + return // ignore no-name files + } + addValueToFormData(name, value, formData) + }) + } + } + + /** + * + * @param {Element} elt + * @param {HtmxElementValidationError[]} errors + */ + function validateElement(elt, errors) { + const element = /** @type {HTMLElement & ElementInternals} */ (elt) + if (element.willValidate) { + triggerEvent(element, 'htmx:validation:validate') + if (!element.checkValidity()) { + errors.push({ elt: element, message: element.validationMessage, validity: element.validity }) + triggerEvent(element, 'htmx:validation:failed', { message: element.validationMessage, validity: element.validity }) + } + } + } + + /** + * Override values in the one FormData with those from another. + * @param {FormData} receiver the formdata that will be mutated + * @param {FormData} donor the formdata that will provide the overriding values + * @returns {FormData} the {@linkcode receiver} + */ + function overrideFormData(receiver, donor) { + for (const key of donor.keys()) { + receiver.delete(key) + donor.getAll(key).forEach(function(value) { + receiver.append(key, value) + }) + } + return receiver + } + + /** + * @param {Element|HTMLFormElement} elt + * @param {HttpVerb} verb + * @returns {{errors: HtmxElementValidationError[], formData: FormData, values: Object}} + */ + function getInputValues(elt, verb) { + /** @type Element[] */ + const processed = [] + const formData = new FormData() + const priorityFormData = new FormData() + /** @type HtmxElementValidationError[] */ + const errors = [] + const internalData = getInternalData(elt) + if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { + internalData.lastButtonClicked = null + } - if (!verifyPath(elt, finalPath, requestConfig)) { - triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) - maybeCall(reject); - return promise; - }; + // only validate when form is directly submitted and novalidate or formnovalidate are not set + // or if the element has an explicit hx-validate="true" on it + let validate = (elt instanceof HTMLFormElement && elt.noValidate !== true) || getAttributeValue(elt, 'hx-validate') === 'true' + if (internalData.lastButtonClicked) { + validate = validate && internalData.lastButtonClicked.formNoValidate !== true + } - xhr.open(verb.toUpperCase(), finalPath, true); - xhr.overrideMimeType("text/html"); - xhr.withCredentials = requestConfig.withCredentials; - xhr.timeout = requestConfig.timeout; + // for a non-GET include the closest form + if (verb !== 'get') { + processInputValue(processed, priorityFormData, errors, closest(elt, 'form'), validate) + } - // request headers - if (requestAttrValues.noHeaders) { - // ignore all headers - } else { - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - var headerValue = headers[header]; - safelySetHeaderValue(xhr, header, headerValue); - } - } - } + // include the element itself + processInputValue(processed, formData, errors, elt, validate) - var responseInfo = { - xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select, - pathInfo: { - requestPath: path, - finalRequestPath: finalPath, - anchor: anchor - } - }; - - xhr.onload = function () { - try { - var hierarchy = hierarchyForElt(elt); - responseInfo.pathInfo.responsePath = getPathFromResponse(xhr); - responseHandler(elt, responseInfo); - removeRequestIndicators(indicators, disableElts); - triggerEvent(elt, 'htmx:afterRequest', responseInfo); - triggerEvent(elt, 'htmx:afterOnLoad', responseInfo); - // if the body no longer contains the element, trigger the event on the closest parent - // remaining in the DOM - if (!bodyContains(elt)) { - var secondaryTriggerElt = null; - while (hierarchy.length > 0 && secondaryTriggerElt == null) { - var parentEltInHierarchy = hierarchy.shift(); - if (bodyContains(parentEltInHierarchy)) { - secondaryTriggerElt = parentEltInHierarchy; - } - } - if (secondaryTriggerElt) { - triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo); - triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo); - } - } - maybeCall(resolve); - endRequestLock(); - } catch (e) { - triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({error:e}, responseInfo)); - throw e; - } - } - xhr.onerror = function () { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:sendError', responseInfo); - maybeCall(reject); - endRequestLock(); - } - xhr.onabort = function() { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo); - maybeCall(reject); - endRequestLock(); - } - xhr.ontimeout = function() { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:timeout', responseInfo); - maybeCall(reject); - endRequestLock(); - } - if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){ - maybeCall(resolve); - endRequestLock() - return promise - } - var indicators = addRequestIndicatorClasses(elt); - var disableElts = disableElements(elt); - - forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { - forEach([xhr, xhr.upload], function (target) { - target.addEventListener(eventName, function(event){ - triggerEvent(elt, "htmx:xhr:" + eventName, { - lengthComputable:event.lengthComputable, - loaded:event.loaded, - total:event.total - }); - }) - }); - }); - triggerEvent(elt, 'htmx:beforeSend', responseInfo); - var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) - xhr.send(params); - return promise; - } - - function determineHistoryUpdates(elt, responseInfo) { - - var xhr = responseInfo.xhr; - - //=========================================== - // First consult response headers - //=========================================== - var pathFromHeaders = null; - var typeFromHeaders = null; - if (hasHeader(xhr,/HX-Push:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Push"); - typeFromHeaders = "push"; - } else if (hasHeader(xhr,/HX-Push-Url:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Push-Url"); - typeFromHeaders = "push"; - } else if (hasHeader(xhr,/HX-Replace-Url:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url"); - typeFromHeaders = "replace"; - } + // if a button or submit was clicked last, include its value + if (internalData.lastButtonClicked || elt.tagName === 'BUTTON' || + (elt.tagName === 'INPUT' && getRawAttribute(elt, 'type') === 'submit')) { + const button = internalData.lastButtonClicked || (/** @type HTMLInputElement|HTMLButtonElement */(elt)) + const name = getRawAttribute(button, 'name') + addValueToFormData(name, button.value, priorityFormData) + } - // if there was a response header, that has priority - if (pathFromHeaders) { - if (pathFromHeaders === "false") { - return {} - } else { - return { - type: typeFromHeaders, - path : pathFromHeaders - } - } - } + // include any explicit includes + const includes = findAttributeTargets(elt, 'hx-include') + forEach(includes, function(node) { + processInputValue(processed, formData, errors, asElement(node), validate) + // if a non-form is included, include any input values within it + if (!matches(node, 'form')) { + forEach(asParentNode(node).querySelectorAll(INPUT_SELECTOR), function(descendant) { + processInputValue(processed, formData, errors, descendant, validate) + }) + } + }) + + // values from a <form> take precedence, overriding the regular values + overrideFormData(formData, priorityFormData) + + return { errors, formData, values: formDataProxy(formData) } + } + + /** + * @param {string} returnStr + * @param {string} name + * @param {any} realValue + * @returns {string} + */ + function appendParam(returnStr, name, realValue) { + if (returnStr !== '') { + returnStr += '&' + } + if (String(realValue) === '[object Object]') { + realValue = JSON.stringify(realValue) + } + const s = encodeURIComponent(realValue) + returnStr += encodeURIComponent(name) + '=' + s + return returnStr + } + + /** + * @param {FormData|Object} values + * @returns string + */ + function urlEncode(values) { + values = formDataFromObject(values) + let returnStr = '' + values.forEach(function(value, key) { + returnStr = appendParam(returnStr, key, value) + }) + return returnStr + } + + //= =================================================================== + // Ajax + //= =================================================================== + + /** + * @param {Element} elt + * @param {Element} target + * @param {string} prompt + * @returns {HtmxHeaderSpecification} + */ + function getHeaders(elt, target, prompt) { + /** @type HtmxHeaderSpecification */ + const headers = { + 'HX-Request': 'true', + 'HX-Trigger': getRawAttribute(elt, 'id'), + 'HX-Trigger-Name': getRawAttribute(elt, 'name'), + 'HX-Target': getAttributeValue(target, 'id'), + 'HX-Current-URL': getDocument().location.href + } + getValuesForElement(elt, 'hx-headers', false, headers) + if (prompt !== undefined) { + headers['HX-Prompt'] = prompt + } + if (getInternalData(elt).boosted) { + headers['HX-Boosted'] = 'true' + } + return headers + } + + /** + * filterValues takes an object containing form input values + * and returns a new object that only contains keys that are + * specified by the closest "hx-params" attribute + * @param {FormData} inputValues + * @param {Element} elt + * @returns {FormData} + */ + function filterValues(inputValues, elt) { + const paramsValue = getClosestAttributeValue(elt, 'hx-params') + if (paramsValue) { + if (paramsValue === 'none') { + return new FormData() + } else if (paramsValue === '*') { + return inputValues + } else if (paramsValue.indexOf('not ') === 0) { + forEach(paramsValue.substr(4).split(','), function(name) { + name = name.trim() + inputValues.delete(name) + }) + return inputValues + } else { + const newValues = new FormData() + forEach(paramsValue.split(','), function(name) { + name = name.trim() + if (inputValues.has(name)) { + inputValues.getAll(name).forEach(function(value) { newValues.append(name, value) }) + } + }) + return newValues + } + } else { + return inputValues + } + } + + /** + * @param {Element} elt + * @return {boolean} + */ + function isAnchorLink(elt) { + return !!getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf('#') >= 0 + } + + /** + * @param {Element} elt + * @param {HtmxSwapStyle} [swapInfoOverride] + * @returns {HtmxSwapSpecification} + */ + function getSwapSpecification(elt, swapInfoOverride) { + const swapInfo = swapInfoOverride || getClosestAttributeValue(elt, 'hx-swap') + /** @type HtmxSwapSpecification */ + const swapSpec = { + swapStyle: getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, + swapDelay: htmx.config.defaultSwapDelay, + settleDelay: htmx.config.defaultSettleDelay + } + if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { + swapSpec.show = 'top' + } + if (swapInfo) { + const split = splitOnWhitespace(swapInfo) + if (split.length > 0) { + for (let i = 0; i < split.length; i++) { + const value = split[i] + if (value.indexOf('swap:') === 0) { + swapSpec.swapDelay = parseInterval(value.substr(5)) + } else if (value.indexOf('settle:') === 0) { + swapSpec.settleDelay = parseInterval(value.substr(7)) + } else if (value.indexOf('transition:') === 0) { + swapSpec.transition = value.substr(11) === 'true' + } else if (value.indexOf('ignoreTitle:') === 0) { + swapSpec.ignoreTitle = value.substr(12) === 'true' + } else if (value.indexOf('scroll:') === 0) { + const scrollSpec = value.substr(7) + var splitSpec = scrollSpec.split(':') + const scrollVal = splitSpec.pop() + var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null + // @ts-ignore + swapSpec.scroll = scrollVal + swapSpec.scrollTarget = selectorVal + } else if (value.indexOf('show:') === 0) { + const showSpec = value.substr(5) + var splitSpec = showSpec.split(':') + const showVal = splitSpec.pop() + var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null + swapSpec.show = showVal + swapSpec.showTarget = selectorVal + } else if (value.indexOf('focus-scroll:') === 0) { + const focusScrollVal = value.substr('focus-scroll:'.length) + swapSpec.focusScroll = focusScrollVal == 'true' + } else if (i == 0) { + swapSpec.swapStyle = value + } else { + logError('Unknown modifier in hx-swap: ' + value) + } + } + } + } + return swapSpec + } + + /** + * @param {Element} elt + * @return {boolean} + */ + function usesFormData(elt) { + return getClosestAttributeValue(elt, 'hx-encoding') === 'multipart/form-data' || + (matches(elt, 'form') && getRawAttribute(elt, 'enctype') === 'multipart/form-data') + } + + /** + * @param {XMLHttpRequest} xhr + * @param {Element} elt + * @param {FormData} filteredParameters + * @returns {*|string|null} + */ + function encodeParamsForBody(xhr, elt, filteredParameters) { + let encodedParameters = null + withExtensions(elt, function(extension) { + if (encodedParameters == null) { + encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt) + } + }) + if (encodedParameters != null) { + return encodedParameters + } else { + if (usesFormData(elt)) { + // Force conversion to an actual FormData object in case filteredParameters is a formDataProxy + // See https://github.com/bigskysoftware/htmx/issues/2317 + return overrideFormData(new FormData(), formDataFromObject(filteredParameters)) + } else { + return urlEncode(filteredParameters) + } + } + } + + /** + * + * @param {Element} target + * @returns {HtmxSettleInfo} + */ + function makeSettleInfo(target) { + return { tasks: [], elts: [target] } + } + + /** + * @param {Element[]} content + * @param {HtmxSwapSpecification} swapSpec + */ + function updateScrollState(content, swapSpec) { + const first = content[0] + const last = content[content.length - 1] + if (swapSpec.scroll) { + var target = null + if (swapSpec.scrollTarget) { + target = asElement(querySelectorExt(first, swapSpec.scrollTarget)) + } + if (swapSpec.scroll === 'top' && (first || target)) { + target = target || first + target.scrollTop = 0 + } + if (swapSpec.scroll === 'bottom' && (last || target)) { + target = target || last + target.scrollTop = target.scrollHeight + } + } + if (swapSpec.show) { + var target = null + if (swapSpec.showTarget) { + let targetStr = swapSpec.showTarget + if (swapSpec.showTarget === 'window') { + targetStr = 'body' + } + target = asElement(querySelectorExt(first, targetStr)) + } + if (swapSpec.show === 'top' && (first || target)) { + target = target || first + // @ts-ignore For some reason tsc doesn't recognize "instant" as a valid option for now + target.scrollIntoView({ block: 'start', behavior: htmx.config.scrollBehavior }) + } + if (swapSpec.show === 'bottom' && (last || target)) { + target = target || last + // @ts-ignore For some reason tsc doesn't recognize "instant" as a valid option for now + target.scrollIntoView({ block: 'end', behavior: htmx.config.scrollBehavior }) + } + } + } + + /** + * @param {Element} elt + * @param {string} attr + * @param {boolean=} evalAsDefault + * @param {Object=} values + * @returns {Object} + */ + function getValuesForElement(elt, attr, evalAsDefault, values) { + if (values == null) { + values = {} + } + if (elt == null) { + return values + } + const attributeValue = getAttributeValue(elt, attr) + if (attributeValue) { + let str = attributeValue.trim() + let evaluateValue = evalAsDefault + if (str === 'unset') { + return null + } + if (str.indexOf('javascript:') === 0) { + str = str.substr(11) + evaluateValue = true + } else if (str.indexOf('js:') === 0) { + str = str.substr(3) + evaluateValue = true + } + if (str.indexOf('{') !== 0) { + str = '{' + str + '}' + } + let varsValues + if (evaluateValue) { + varsValues = maybeEval(elt, function() { return Function('return (' + str + ')')() }, {}) + } else { + varsValues = parseJSON(str) + } + for (const key in varsValues) { + if (varsValues.hasOwnProperty(key)) { + if (values[key] == null) { + values[key] = varsValues[key] + } + } + } + } + return getValuesForElement(asElement(parentElt(elt)), attr, evalAsDefault, values) + } + + /** + * @param {EventTarget|string} elt + * @param {() => any} toEval + * @param {any=} defaultVal + * @returns {any} + */ + function maybeEval(elt, toEval, defaultVal) { + if (htmx.config.allowEval) { + return toEval() + } else { + triggerErrorEvent(elt, 'htmx:evalDisallowedError') + return defaultVal + } + } + + /** + * @param {Element} elt + * @param {*?} expressionVars + * @returns + */ + function getHXVarsForElement(elt, expressionVars) { + return getValuesForElement(elt, 'hx-vars', true, expressionVars) + } + + /** + * @param {Element} elt + * @param {*?} expressionVars + * @returns + */ + function getHXValsForElement(elt, expressionVars) { + return getValuesForElement(elt, 'hx-vals', false, expressionVars) + } + + /** + * @param {Element} elt + * @returns {FormData} + */ + function getExpressionVars(elt) { + return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)) + } + + /** + * @param {XMLHttpRequest} xhr + * @param {string} header + * @param {string|null} headerValue + */ + function safelySetHeaderValue(xhr, header, headerValue) { + if (headerValue !== null) { + try { + xhr.setRequestHeader(header, headerValue) + } catch (e) { + // On an exception, try to set the header URI encoded instead + xhr.setRequestHeader(header, encodeURIComponent(headerValue)) + xhr.setRequestHeader(header + '-URI-AutoEncoded', 'true') + } + } + } + + /** + * @param {XMLHttpRequest} xhr + * @return {string} + */ + function getPathFromResponse(xhr) { + // NB: IE11 does not support this stuff + if (xhr.responseURL && typeof (URL) !== 'undefined') { + try { + const url = new URL(xhr.responseURL) + return url.pathname + url.search + } catch (e) { + triggerErrorEvent(getDocument().body, 'htmx:badResponseUrl', { url: xhr.responseURL }) + } + } + } + + /** + * @param {XMLHttpRequest} xhr + * @param {RegExp} regexp + * @return {boolean} + */ + function hasHeader(xhr, regexp) { + return regexp.test(xhr.getAllResponseHeaders()) + } + + /** + * Issues an htmx-style AJAX request + * + * @see https://htmx.org/api/#ajax + * + * @param {HttpVerb} verb + * @param {string} path the URL path to make the AJAX + * @param {Element|string|HtmxAjaxHelperContext} context the element to target (defaults to the **body**) | a selector for the target | a context object that contains any of the following + * @return {Promise<void>} Promise that resolves immediately if no request is sent, or when the request is complete + */ + function ajaxHelper(verb, path, context) { + verb = (/** @type HttpVerb */(verb.toLowerCase())) + if (context) { + if (context instanceof Element || typeof context === 'string') { + return issueAjaxRequest(verb, path, null, null, { + targetOverride: resolveTarget(context), + returnPromise: true + }) + } else { + return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, + { + handler: context.handler, + headers: context.headers, + values: context.values, + targetOverride: resolveTarget(context.target), + swapOverride: context.swap, + select: context.select, + returnPromise: true + }) + } + } else { + return issueAjaxRequest(verb, path, null, null, { + returnPromise: true + }) + } + } + + /** + * @param {Element} elt + * @return {Element[]} + */ + function hierarchyForElt(elt) { + const arr = [] + while (elt) { + arr.push(elt) + elt = elt.parentElement + } + return arr + } + + /** + * @param {Element} elt + * @param {string} path + * @param {HtmxRequestConfig} requestConfig + * @return {boolean} + */ + function verifyPath(elt, path, requestConfig) { + let sameHost + let url + if (typeof URL === 'function') { + url = new URL(path, document.location.href) + const origin = document.location.origin + sameHost = origin === url.origin + } else { + // IE11 doesn't support URL + url = path + sameHost = startsWith(path, document.location.origin) + } - //=========================================== - // Next resolve via DOM values - //=========================================== - var requestPath = responseInfo.pathInfo.finalRequestPath; - var responsePath = responseInfo.pathInfo.responsePath; - - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url"); - var elementIsBoosted = getInternalData(elt).boosted; - - var saveType = null; - var path = null; - - if (pushUrl) { - saveType = "push"; - path = pushUrl; - } else if (replaceUrl) { - saveType = "replace"; - path = replaceUrl; - } else if (elementIsBoosted) { - saveType = "push"; - path = responsePath || requestPath; // if there is no response path, go with the original request path - } + if (htmx.config.selfRequestsOnly) { + if (!sameHost) { + return false + } + } + return triggerEvent(elt, 'htmx:validateUrl', mergeObjects({ url, sameHost }, requestConfig)) + } + + /** + * @param {Object|FormData} obj + * @return {FormData} + */ + function formDataFromObject(obj) { + if (obj instanceof FormData) return obj + const formData = new FormData() + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + if (typeof obj[key].forEach === 'function') { + obj[key].forEach(function(v) { formData.append(key, v) }) + } else if (typeof obj[key] === 'object') { + formData.append(key, JSON.stringify(obj[key])) + } else { + formData.append(key, obj[key]) + } + } + } + return formData + } + + /** + * @param {FormData} formData + * @param {string} name + * @param {Array} array + * @returns {Array} + */ + function formDataArrayProxy(formData, name, array) { + // mutating the array should mutate the underlying form data + return new Proxy(array, { + get: function(target, key) { + if (typeof key === 'number') return target[key] + if (key === 'length') return target.length + if (key === 'push') { + return function(value) { + target.push(value) + formData.append(name, value) + } + } + if (typeof target[key] === 'function') { + return function() { + target[key].apply(target, arguments) + formData.delete(name) + target.forEach(function(v) { formData.append(name, v) }) + } + } + + if (target[key] && target[key].length === 1) { + return target[key][0] + } else { + return target[key] + } + }, + set: function(target, index, value) { + target[index] = value + formData.delete(name) + target.forEach(function(v) { formData.append(name, v) }) + return true + } + }) + } + + /** + * @param {FormData} formData + * @returns {Object} + */ + function formDataProxy(formData) { + return new Proxy(formData, { + get: function(target, name) { + if (typeof name === 'symbol') { + // Forward symbol calls to the FormData itself directly + return Reflect.get(target, name) + } + if (name === 'toJSON') { + // Support JSON.stringify call on proxy + return () => Object.fromEntries(formData) + } + if (name in target) { + // Wrap in function with apply to correctly bind the FormData context, as a direct call would result in an illegal invocation error + if (typeof target[name] === 'function') { + return function() { + return formData[name].apply(formData, arguments) + } + } else { + return target[name] + } + } + const array = formData.getAll(name) + // Those 2 undefined & single value returns are for retro-compatibility as we weren't using FormData before + if (array.length === 0) { + return undefined + } else if (array.length === 1) { + return array[0] + } else { + return formDataArrayProxy(target, name, array) + } + }, + set: function(target, name, value) { + if (typeof name !== 'string') { + return false + } + target.delete(name) + if (typeof value.forEach === 'function') { + value.forEach(function(v) { target.append(name, v) }) + } else { + target.append(name, value) + } + return true + }, + deleteProperty: function(target, name) { + if (typeof name === 'string') { + target.delete(name) + } + return true + }, + // Support Object.assign call from proxy + ownKeys: function(target) { + return Reflect.ownKeys(Object.fromEntries(target)) + }, + getOwnPropertyDescriptor: function(target, prop) { + return Reflect.getOwnPropertyDescriptor(Object.fromEntries(target), prop) + } + }) + } + + /** + * @param {HttpVerb} verb + * @param {string} path + * @param {Element} elt + * @param {Event} event + * @param {HtmxAjaxEtc} [etc] + * @param {boolean} [confirmed] + * @return {Promise<void>} + */ + function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { + let resolve = null + let reject = null + etc = etc != null ? etc : {} + if (etc.returnPromise && typeof Promise !== 'undefined') { + var promise = new Promise(function(_resolve, _reject) { + resolve = _resolve + reject = _reject + }) + } + if (elt == null) { + elt = getDocument().body + } + const responseHandler = etc.handler || handleAjaxResponse + const select = etc.select || null - if (path) { - // false indicates no push, return empty object - if (path === "false") { - return {}; - } + if (!bodyContains(elt)) { + // do not issue requests for elements removed from the DOM + maybeCall(resolve) + return promise + } + const target = etc.targetOverride || asElement(getTarget(elt)) + if (target == null || target == DUMMY_ELT) { + triggerErrorEvent(elt, 'htmx:targetError', { target: getAttributeValue(elt, 'hx-target') }) + maybeCall(reject) + return promise + } - // true indicates we want to follow wherever the server ended up sending us - if (path === "true") { - path = responsePath || requestPath; // if there is no response path, go with the original request path - } + let eltData = getInternalData(elt) + const submitter = eltData.lastButtonClicked - // restore any anchor associated with the request - if (responseInfo.pathInfo.anchor && - path.indexOf("#") === -1) { - path = path + "#" + responseInfo.pathInfo.anchor; - } + if (submitter) { + const buttonPath = getRawAttribute(submitter, 'formaction') + if (buttonPath != null) { + path = buttonPath + } - return { - type:saveType, - path: path - } - } else { - return {}; - } + const buttonVerb = getRawAttribute(submitter, 'formmethod') + if (buttonVerb != null) { + // ignore buttons with formmethod="dialog" + if (buttonVerb.toLowerCase() !== 'dialog') { + verb = (/** @type HttpVerb */(buttonVerb)) } + } + } - function handleAjaxResponse(elt, responseInfo) { - var xhr = responseInfo.xhr; - var target = responseInfo.target; - var etc = responseInfo.etc; - var requestConfig = responseInfo.requestConfig; - var select = responseInfo.select; + const confirmQuestion = getClosestAttributeValue(elt, 'hx-confirm') + // allow event-based confirmation w/ a callback + if (confirmed === undefined) { + const issueRequest = function(skipConfirmation) { + return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation) + } + const confirmDetails = { target, elt, path, verb, triggeringEvent: event, etc, issueRequest, question: confirmQuestion } + if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { + maybeCall(resolve) + return promise + } + } - if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; + let syncElt = elt + let syncStrategy = getClosestAttributeValue(elt, 'hx-sync') + let queueStrategy = null + let abortable = false + if (syncStrategy) { + const syncStrings = syncStrategy.split(':') + const selector = syncStrings[0].trim() + if (selector === 'this') { + syncElt = findThisElement(elt, 'hx-sync') + } else { + syncElt = asElement(querySelectorExt(elt, selector)) + } + // default to the drop strategy + syncStrategy = (syncStrings[1] || 'drop').trim() + eltData = getInternalData(syncElt) + if (syncStrategy === 'drop' && eltData.xhr && eltData.abortable !== true) { + maybeCall(resolve) + return promise + } else if (syncStrategy === 'abort') { + if (eltData.xhr) { + maybeCall(resolve) + return promise + } else { + abortable = true + } + } else if (syncStrategy === 'replace') { + triggerEvent(syncElt, 'htmx:abort') // abort the current request and continue + } else if (syncStrategy.indexOf('queue') === 0) { + const queueStrArray = syncStrategy.split(' ') + queueStrategy = (queueStrArray[1] || 'last').trim() + } + } - if (hasHeader(xhr, /HX-Trigger:/i)) { - handleTrigger(xhr, "HX-Trigger", elt); - } + if (eltData.xhr) { + if (eltData.abortable) { + triggerEvent(syncElt, 'htmx:abort') // abort the current request and continue + } else { + if (queueStrategy == null) { + if (event) { + const eventData = getInternalData(event) + if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { + queueStrategy = eventData.triggerSpec.queue + } + } + if (queueStrategy == null) { + queueStrategy = 'last' + } + } + if (eltData.queuedRequests == null) { + eltData.queuedRequests = [] + } + if (queueStrategy === 'first' && eltData.queuedRequests.length === 0) { + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } else if (queueStrategy === 'all') { + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } else if (queueStrategy === 'last') { + eltData.queuedRequests = [] // dump existing queue + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } + maybeCall(resolve) + return promise + } + } - if (hasHeader(xhr, /HX-Location:/i)) { - saveCurrentPageToHistory(); - var redirectPath = xhr.getResponseHeader("HX-Location"); - var swapSpec; - if (redirectPath.indexOf("{") === 0) { - swapSpec = parseJSON(redirectPath); - // what's the best way to throw an error if the user didn't include this - redirectPath = swapSpec['path']; - delete swapSpec['path']; - } - ajaxHelper('GET', redirectPath, swapSpec).then(function(){ - pushUrlIntoHistory(redirectPath); - }); - return; - } + const xhr = new XMLHttpRequest() + eltData.xhr = xhr + eltData.abortable = abortable + const endRequestLock = function() { + eltData.xhr = null + eltData.abortable = false + if (eltData.queuedRequests != null && + eltData.queuedRequests.length > 0) { + const queuedRequest = eltData.queuedRequests.shift() + queuedRequest() + } + } + const promptQuestion = getClosestAttributeValue(elt, 'hx-prompt') + if (promptQuestion) { + var promptResponse = prompt(promptQuestion) + // prompt returns null if cancelled and empty string if accepted with no entry + if (promptResponse === null || + !triggerEvent(elt, 'htmx:prompt', { prompt: promptResponse, target })) { + maybeCall(resolve) + endRequestLock() + return promise + } + } - var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh"); + if (confirmQuestion && !confirmed) { + if (!confirm(confirmQuestion)) { + maybeCall(resolve) + endRequestLock() + return promise + } + } - if (hasHeader(xhr, /HX-Redirect:/i)) { - location.href = xhr.getResponseHeader("HX-Redirect"); - shouldRefresh && location.reload(); - return; - } + let headers = getHeaders(elt, target, promptResponse) - if (shouldRefresh) { - location.reload(); - return; - } + if (verb !== 'get' && !usesFormData(elt)) { + headers['Content-Type'] = 'application/x-www-form-urlencoded' + } - if (hasHeader(xhr,/HX-Retarget:/i)) { - if (xhr.getResponseHeader("HX-Retarget") === "this") { - responseInfo.target = elt; - } else { - responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget")); - } - } + if (etc.headers) { + headers = mergeObjects(headers, etc.headers) + } + const results = getInputValues(elt, verb) + let errors = results.errors + const rawFormData = results.formData + if (etc.values) { + overrideFormData(rawFormData, formDataFromObject(etc.values)) + } + const expressionVars = formDataFromObject(getExpressionVars(elt)) + const allFormData = overrideFormData(rawFormData, expressionVars) + let filteredFormData = filterValues(allFormData, elt) - var historyUpdate = determineHistoryUpdates(elt, responseInfo); - - // by default htmx only swaps on 200 return codes and does not swap - // on 204 'No Content' - // this can be ovverriden by responding to the htmx:beforeSwap event and - // overriding the detail.shouldSwap property - var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; - var serverResponse = xhr.response; - var isError = xhr.status >= 400; - var ignoreTitle = htmx.config.ignoreTitle - var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo); - if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; - - target = beforeSwapDetails.target; // allow re-targeting - serverResponse = beforeSwapDetails.serverResponse; // allow updating content - isError = beforeSwapDetails.isError; // allow updating error - ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title - - responseInfo.target = target; // Make updated target available to response events - responseInfo.failed = isError; // Make failed property available to response events - responseInfo.successful = !isError; // Make successful property available to response events - - if (beforeSwapDetails.shouldSwap) { - if (xhr.status === 286) { - cancelPolling(elt); - } + if (htmx.config.getCacheBusterParam && verb === 'get') { + filteredFormData.set('org.htmx.cache-buster', getRawAttribute(target, 'id') || 'true') + } - withExtensions(elt, function (extension) { - serverResponse = extension.transformResponse(serverResponse, xhr, elt); - }); + // behavior of anchors w/ empty href is to use the current URL + if (path == null || path === '') { + path = getDocument().location.href + } - // Save current page if there will be a history update - if (historyUpdate.type) { - saveCurrentPageToHistory(); - } + /** + * @type {Object} + * @property {boolean} [credentials] + * @property {number} [timeout] + * @property {boolean} [noHeaders] + */ + const requestAttrValues = getValuesForElement(elt, 'hx-request') + + const eltIsBoosted = getInternalData(elt).boosted + + let useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + + /** @type HtmxRequestConfig */ + const requestConfig = { + boosted: eltIsBoosted, + useUrlParams, + formData: filteredFormData, + parameters: formDataProxy(filteredFormData), + unfilteredFormData: allFormData, + unfilteredParameters: formDataProxy(allFormData), + headers, + target, + verb, + errors, + withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, + timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, + path, + triggeringEvent: event + } - var swapOverride = etc.swapOverride; - if (hasHeader(xhr,/HX-Reswap:/i)) { - swapOverride = xhr.getResponseHeader("HX-Reswap"); - } - var swapSpec = getSwapSpecification(elt, swapOverride); + if (!triggerEvent(elt, 'htmx:configRequest', requestConfig)) { + maybeCall(resolve) + endRequestLock() + return promise + } - if (swapSpec.hasOwnProperty('ignoreTitle')) { - ignoreTitle = swapSpec.ignoreTitle; - } + // copy out in case the object was overwritten + path = requestConfig.path + verb = requestConfig.verb + headers = requestConfig.headers + filteredFormData = formDataFromObject(requestConfig.parameters) + errors = requestConfig.errors + useUrlParams = requestConfig.useUrlParams + + if (errors && errors.length > 0) { + triggerEvent(elt, 'htmx:validation:halted', requestConfig) + maybeCall(resolve) + endRequestLock() + return promise + } - target.classList.add(htmx.config.swappingClass); - - // optional transition API promise callbacks - var settleResolve = null; - var settleReject = null; - - var doSwap = function () { - try { - var activeElt = document.activeElement; - var selectionInfo = {}; - try { - selectionInfo = { - elt: activeElt, - // @ts-ignore - start: activeElt ? activeElt.selectionStart : null, - // @ts-ignore - end: activeElt ? activeElt.selectionEnd : null - }; - } catch (e) { - // safari issue - see https://github.com/microsoft/playwright/issues/5894 - } - - var selectOverride; - if (select) { - selectOverride = select; - } - - if (hasHeader(xhr, /HX-Reselect:/i)) { - selectOverride = xhr.getResponseHeader("HX-Reselect"); - } - - // if we need to save history, do so, before swapping so that relative resources have the correct base URL - if (historyUpdate.type) { - triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)); - if (historyUpdate.type === "push") { - pushUrlIntoHistory(historyUpdate.path); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path}); - } else { - replaceUrlInHistory(historyUpdate.path); - triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path}); - } - } - - var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride); - - if (selectionInfo.elt && - !bodyContains(selectionInfo.elt) && - getRawAttribute(selectionInfo.elt, "id")) { - var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id")); - var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; - if (newActiveElt) { - // @ts-ignore - if (selectionInfo.start && newActiveElt.setSelectionRange) { - // @ts-ignore - try { - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); - } catch (e) { - // the setSelectionRange method is present on fields that don't support it, so just let this fail - } - } - newActiveElt.focus(focusOptions); - } - } - - target.classList.remove(htmx.config.swappingClass); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.add(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSwap', responseInfo); - }); - - if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); - } - - var doSettle = function () { - forEach(settleInfo.tasks, function (task) { - task.call(); - }); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.remove(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSettle', responseInfo); - }); - - if (responseInfo.pathInfo.anchor) { - var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor); - if(anchorTarget) { - anchorTarget.scrollIntoView({block:'start', behavior: "auto"}); - } - } - - if(settleInfo.title && !ignoreTitle) { - var titleElt = find("title"); - if(titleElt) { - titleElt.innerHTML = settleInfo.title; - } else { - window.document.title = settleInfo.title; - } - } - - updateScrollState(settleInfo.elts, swapSpec); - - if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); - } - maybeCall(settleResolve); - } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'htmx:swapError', responseInfo); - maybeCall(settleReject); - throw e; - } - }; - - var shouldTransition = htmx.config.globalViewTransitions - if(swapSpec.hasOwnProperty('transition')){ - shouldTransition = swapSpec.transition; - } + const splitPath = path.split('#') + const pathNoAnchor = splitPath[0] + const anchor = splitPath[1] + + let finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor + const hasValues = !filteredFormData.keys().next().done + if (hasValues) { + if (finalPath.indexOf('?') < 0) { + finalPath += '?' + } else { + finalPath += '&' + } + finalPath += urlEncode(filteredFormData) + if (anchor) { + finalPath += '#' + anchor + } + } + } - if(shouldTransition && - triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && - typeof Promise !== "undefined" && document.startViewTransition){ - var settlePromise = new Promise(function (_resolve, _reject) { - settleResolve = _resolve; - settleReject = _reject; - }); - // wrap the original doSwap() in a call to startViewTransition() - var innerDoSwap = doSwap; - doSwap = function() { - document.startViewTransition(function () { - innerDoSwap(); - return settlePromise; - }); - } - } + if (!verifyPath(elt, finalPath, requestConfig)) { + triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) + maybeCall(reject) + return promise + } + xhr.open(verb.toUpperCase(), finalPath, true) + xhr.overrideMimeType('text/html') + xhr.withCredentials = requestConfig.withCredentials + xhr.timeout = requestConfig.timeout - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); - } - } - if (isError) { - triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo)); - } + // request headers + if (requestAttrValues.noHeaders) { + // ignore all headers + } else { + for (const header in headers) { + if (headers.hasOwnProperty(header)) { + const headerValue = headers[header] + safelySetHeaderValue(xhr, header, headerValue) } + } + } - //==================================================================== - // Extensions API - //==================================================================== - - /** @type {Object<string, import("./htmx").HtmxExtension>} */ - var extensions = {}; - - /** - * extensionBase defines the default functions for all extensions. - * @returns {import("./htmx").HtmxExtension} - */ - function extensionBase() { - return { - init: function(api) {return null;}, - onEvent : function(name, evt) {return true;}, - transformResponse : function(text, xhr, elt) {return text;}, - isInlineSwap : function(swapStyle) {return false;}, - handleSwap : function(swapStyle, target, fragment, settleInfo) {return false;}, - encodeParameters : function(xhr, parameters, elt) {return null;} - } - } + /** @type {HtmxResponseInfo} */ + const responseInfo = { + xhr, + target, + requestConfig, + etc, + boosted: eltIsBoosted, + select, + pathInfo: { + requestPath: path, + finalRequestPath: finalPath, + responsePath: null, + anchor + } + } - /** - * defineExtension initializes the extension and adds it to the htmx registry - * - * @param {string} name - * @param {import("./htmx").HtmxExtension} extension - */ - function defineExtension(name, extension) { - if(extension.init) { - extension.init(internalAPI) - } - extensions[name] = mergeObjects(extensionBase(), extension); - } + xhr.onload = function() { + try { + const hierarchy = hierarchyForElt(elt) + responseInfo.pathInfo.responsePath = getPathFromResponse(xhr) + responseHandler(elt, responseInfo) + removeRequestIndicators(indicators, disableElts) + triggerEvent(elt, 'htmx:afterRequest', responseInfo) + triggerEvent(elt, 'htmx:afterOnLoad', responseInfo) + // if the body no longer contains the element, trigger the event on the closest parent + // remaining in the DOM + if (!bodyContains(elt)) { + let secondaryTriggerElt = null + while (hierarchy.length > 0 && secondaryTriggerElt == null) { + const parentEltInHierarchy = hierarchy.shift() + if (bodyContains(parentEltInHierarchy)) { + secondaryTriggerElt = parentEltInHierarchy + } + } + if (secondaryTriggerElt) { + triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo) + triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo) + } + } + maybeCall(resolve) + endRequestLock() + } catch (e) { + triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({ error: e }, responseInfo)) + throw e + } + } + xhr.onerror = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:sendError', responseInfo) + maybeCall(reject) + endRequestLock() + } + xhr.onabort = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo) + maybeCall(reject) + endRequestLock() + } + xhr.ontimeout = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:timeout', responseInfo) + maybeCall(reject) + endRequestLock() + } + if (!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)) { + maybeCall(resolve) + endRequestLock() + return promise + } + var indicators = addRequestIndicatorClasses(elt) + var disableElts = disableElements(elt) + + forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { + forEach([xhr, xhr.upload], function(target) { + target.addEventListener(eventName, function(event) { + triggerEvent(elt, 'htmx:xhr:' + eventName, { + lengthComputable: event.lengthComputable, + loaded: event.loaded, + total: event.total + }) + }) + }) + }) + triggerEvent(elt, 'htmx:beforeSend', responseInfo) + const params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredFormData) + xhr.send(params) + return promise + } + + /** + * @typedef {Object} HtmxHistoryUpdate + * @property {string|null} [type] + * @property {string|null} [path] + */ + + /** + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + * @return {HtmxHistoryUpdate} + */ + function determineHistoryUpdates(elt, responseInfo) { + const xhr = responseInfo.xhr + + //= ========================================== + // First consult response headers + //= ========================================== + let pathFromHeaders = null + let typeFromHeaders = null + if (hasHeader(xhr, /HX-Push:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Push') + typeFromHeaders = 'push' + } else if (hasHeader(xhr, /HX-Push-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Push-Url') + typeFromHeaders = 'push' + } else if (hasHeader(xhr, /HX-Replace-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Replace-Url') + typeFromHeaders = 'replace' + } - /** - * removeExtension removes an extension from the htmx registry - * - * @param {string} name - */ - function removeExtension(name) { - delete extensions[name]; + // if there was a response header, that has priority + if (pathFromHeaders) { + if (pathFromHeaders === 'false') { + return {} + } else { + return { + type: typeFromHeaders, + path: pathFromHeaders } + } + } - /** - * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element - * - * @param {HTMLElement} elt - * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn - * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore - */ - function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + //= ========================================== + // Next resolve via DOM values + //= ========================================== + const requestPath = responseInfo.pathInfo.finalRequestPath + const responsePath = responseInfo.pathInfo.responsePath + + const pushUrl = getClosestAttributeValue(elt, 'hx-push-url') + const replaceUrl = getClosestAttributeValue(elt, 'hx-replace-url') + const elementIsBoosted = getInternalData(elt).boosted + + let saveType = null + let path = null + + if (pushUrl) { + saveType = 'push' + path = pushUrl + } else if (replaceUrl) { + saveType = 'replace' + path = replaceUrl + } else if (elementIsBoosted) { + saveType = 'push' + path = responsePath || requestPath // if there is no response path, go with the original request path + } - if (elt == undefined) { - return extensionsToReturn; - } - if (extensionsToReturn == undefined) { - extensionsToReturn = []; - } - if (extensionsToIgnore == undefined) { - extensionsToIgnore = []; - } - var extensionsForElement = getAttributeValue(elt, "hx-ext"); - if (extensionsForElement) { - forEach(extensionsForElement.split(","), function(extensionName){ - extensionName = extensionName.replace(/ /g, ''); - if (extensionName.slice(0, 7) == "ignore:") { - extensionsToIgnore.push(extensionName.slice(7)); - return; - } - if (extensionsToIgnore.indexOf(extensionName) < 0) { - var extension = extensions[extensionName]; - if (extension && extensionsToReturn.indexOf(extension) < 0) { - extensionsToReturn.push(extension); - } - } - }); - } - return getExtensions(parentElt(elt), extensionsToReturn, extensionsToIgnore); - } + if (path) { + // false indicates no push, return empty object + if (path === 'false') { + return {} + } + + // true indicates we want to follow wherever the server ended up sending us + if (path === 'true') { + path = responsePath || requestPath // if there is no response path, go with the original request path + } + + // restore any anchor associated with the request + if (responseInfo.pathInfo.anchor && path.indexOf('#') === -1) { + path = path + '#' + responseInfo.pathInfo.anchor + } + + return { + type: saveType, + path + } + } else { + return {} + } + } + + /** + * @param {HtmxResponseHandlingConfig} responseHandlingConfig + * @param {number} status + * @return {boolean} + */ + function codeMatches(responseHandlingConfig, status) { + var regExp = new RegExp(responseHandlingConfig.code) + return regExp.test(status.toString(10)) + } + + /** + * @param {XMLHttpRequest} xhr + * @return {HtmxResponseHandlingConfig} + */ + function resolveResponseHandling(xhr) { + for (var i = 0; i < htmx.config.responseHandling.length; i++) { + /** @type HtmxResponseHandlingConfig */ + var responseHandlingElement = htmx.config.responseHandling[i] + if (codeMatches(responseHandlingElement, xhr.status)) { + return responseHandlingElement + } + } + // no matches, return no swap + return { + swap: false + } + } + + /** + * @param {string} title + */ + function handleTitle(title) { + if (title) { + const titleElt = find('title') + if (titleElt) { + titleElt.innerHTML = title + } else { + window.document.title = title + } + } + } + + /** + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + */ + function handleAjaxResponse(elt, responseInfo) { + const xhr = responseInfo.xhr + let target = responseInfo.target + const etc = responseInfo.etc + const responseInfoSelect = responseInfo.select + + if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return + + if (hasHeader(xhr, /HX-Trigger:/i)) { + handleTriggerHeader(xhr, 'HX-Trigger', elt) + } - //==================================================================== - // Initialization - //==================================================================== - var isReady = false - getDocument().addEventListener('DOMContentLoaded', function() { - isReady = true - }) + if (hasHeader(xhr, /HX-Location:/i)) { + saveCurrentPageToHistory() + let redirectPath = xhr.getResponseHeader('HX-Location') + /** @type {HtmxAjaxHelperContext&{path:string}} */ + var redirectSwapSpec + if (redirectPath.indexOf('{') === 0) { + redirectSwapSpec = parseJSON(redirectPath) + // what's the best way to throw an error if the user didn't include this + redirectPath = redirectSwapSpec.path + delete redirectSwapSpec.path + } + ajaxHelper('get', redirectPath, redirectSwapSpec).then(function() { + pushUrlIntoHistory(redirectPath) + }) + return + } - /** - * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. - * - * This function uses isReady because there is no realiable way to ask the browswer whether - * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded - * firing and readystate=complete. - */ - function ready(fn) { - // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by - // some means other than the initial page load. - if (isReady || getDocument().readyState === 'complete') { - fn(); - } else { - getDocument().addEventListener('DOMContentLoaded', fn); - } - } + const shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && xhr.getResponseHeader('HX-Refresh') === 'true' - function insertIndicatorStyles() { - if (htmx.config.includeIndicatorStyles !== false) { - getDocument().head.insertAdjacentHTML("beforeend", - "<style>\ - ." + htmx.config.indicatorClass + "{opacity:0}\ - ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ - ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ - </style>"); - } - } + if (hasHeader(xhr, /HX-Redirect:/i)) { + location.href = xhr.getResponseHeader('HX-Redirect') + shouldRefresh && location.reload() + return + } - function getMetaConfig() { - var element = getDocument().querySelector('meta[name="htmx-config"]'); - if (element) { - // @ts-ignore - return parseJSON(element.content); - } else { - return null; - } - } + if (shouldRefresh) { + location.reload() + return + } - function mergeMetaConfig() { - var metaConfig = getMetaConfig(); - if (metaConfig) { - htmx.config = mergeObjects(htmx.config , metaConfig) - } - } + if (hasHeader(xhr, /HX-Retarget:/i)) { + if (xhr.getResponseHeader('HX-Retarget') === 'this') { + responseInfo.target = elt + } else { + responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget'))) + } + } - // initialize the document - ready(function () { - mergeMetaConfig(); - insertIndicatorStyles(); - var body = getDocument().body; - processNode(body); - var restoredElts = getDocument().querySelectorAll( - "[hx-trigger='restored'],[data-hx-trigger='restored']" - ); - body.addEventListener("htmx:abort", function (evt) { - var target = evt.target; - var internalData = getInternalData(target); - if (internalData && internalData.xhr) { - internalData.xhr.abort(); - } - }); - /** @type {(ev: PopStateEvent) => any} */ - const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null; - /** @type {(ev: PopStateEvent) => any} */ - window.onpopstate = function (event) { - if (event.state && event.state.htmx) { - restoreHistory(); - forEach(restoredElts, function(elt){ - triggerEvent(elt, 'htmx:restored', { - 'document': getDocument(), - 'triggerEvent': triggerEvent - }); - }); - } else { - if (originalPopstate) { - originalPopstate(event); - } - } - }; - setTimeout(function () { - triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event - body = null; // kill reference for gc - }, 0); + const historyUpdate = determineHistoryUpdates(elt, responseInfo) + + const responseHandling = resolveResponseHandling(xhr) + const shouldSwap = responseHandling.swap + let isError = !!responseHandling.error + let ignoreTitle = htmx.config.ignoreTitle || responseHandling.ignoreTitle + let selectOverride = responseHandling.select + if (responseHandling.target) { + responseInfo.target = asElement(querySelectorExt(elt, responseHandling.target)) + } + var swapOverride = etc.swapOverride + if (swapOverride == null && responseHandling.swapOverride) { + swapOverride = responseHandling.swapOverride + } + + // response headers override response handling config + if (hasHeader(xhr, /HX-Retarget:/i)) { + if (xhr.getResponseHeader('HX-Retarget') === 'this') { + responseInfo.target = elt + } else { + responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget'))) + } + } + if (hasHeader(xhr, /HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader('HX-Reswap') + } + + var serverResponse = xhr.response + /** @type HtmxBeforeSwapDetails */ + var beforeSwapDetails = mergeObjects({ + shouldSwap, + serverResponse, + isError, + ignoreTitle, + selectOverride + }, responseInfo) + + if (responseHandling.event && !triggerEvent(target, responseHandling.event, beforeSwapDetails)) return + + if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return + + target = beforeSwapDetails.target // allow re-targeting + serverResponse = beforeSwapDetails.serverResponse // allow updating content + isError = beforeSwapDetails.isError // allow updating error + ignoreTitle = beforeSwapDetails.ignoreTitle // allow updating ignoring title + selectOverride = beforeSwapDetails.selectOverride // allow updating select override + + responseInfo.target = target // Make updated target available to response events + responseInfo.failed = isError // Make failed property available to response events + responseInfo.successful = !isError // Make successful property available to response events + + if (beforeSwapDetails.shouldSwap) { + if (xhr.status === 286) { + cancelPolling(elt) + } + + withExtensions(elt, function(extension) { + serverResponse = extension.transformResponse(serverResponse, xhr, elt) + }) + + // Save current page if there will be a history update + if (historyUpdate.type) { + saveCurrentPageToHistory() + } + + if (hasHeader(xhr, /HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader('HX-Reswap') + } + var swapSpec = getSwapSpecification(elt, swapOverride) + + if (!swapSpec.hasOwnProperty('ignoreTitle')) { + swapSpec.ignoreTitle = ignoreTitle + } + + target.classList.add(htmx.config.swappingClass) + + // optional transition API promise callbacks + let settleResolve = null + let settleReject = null + + if (responseInfoSelect) { + selectOverride = responseInfoSelect + } + + if (hasHeader(xhr, /HX-Reselect:/i)) { + selectOverride = xhr.getResponseHeader('HX-Reselect') + } + + const selectOOB = getClosestAttributeValue(elt, 'hx-select-oob') + const select = getClosestAttributeValue(elt, 'hx-select') + + let doSwap = function() { + try { + // if we need to save history, do so, before swapping so that relative resources have the correct base URL + if (historyUpdate.type) { + triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)) + if (historyUpdate.type === 'push') { + pushUrlIntoHistory(historyUpdate.path) + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', { path: historyUpdate.path }) + } else { + replaceUrlInHistory(historyUpdate.path) + triggerEvent(getDocument().body, 'htmx:replacedInHistory', { path: historyUpdate.path }) + } + } + + swap(target, serverResponse, swapSpec, { + select: selectOverride || select, + selectOOB, + eventInfo: responseInfo, + anchor: responseInfo.pathInfo.anchor, + contextElement: elt, + afterSwapCallback: function() { + if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { + let finalElt = elt + if (!bodyContains(elt)) { + finalElt = getDocument().body + } + handleTriggerHeader(xhr, 'HX-Trigger-After-Swap', finalElt) + } + }, + afterSettleCallback: function() { + if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { + let finalElt = elt + if (!bodyContains(elt)) { + finalElt = getDocument().body + } + handleTriggerHeader(xhr, 'HX-Trigger-After-Settle', finalElt) + } + maybeCall(settleResolve) + } + }) + } catch (e) { + triggerErrorEvent(elt, 'htmx:swapError', responseInfo) + maybeCall(settleReject) + throw e + } + } + + let shouldTransition = htmx.config.globalViewTransitions + if (swapSpec.hasOwnProperty('transition')) { + shouldTransition = swapSpec.transition + } + + if (shouldTransition && + triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && + typeof Promise !== 'undefined' && + // @ts-ignore experimental feature atm + document.startViewTransition) { + const settlePromise = new Promise(function(_resolve, _reject) { + settleResolve = _resolve + settleReject = _reject }) + // wrap the original doSwap() in a call to startViewTransition() + const innerDoSwap = doSwap + doSwap = function() { + // @ts-ignore experimental feature atm + document.startViewTransition(function() { + innerDoSwap() + return settlePromise + }) + } + } + + if (swapSpec.swapDelay > 0) { + getWindow().setTimeout(doSwap, swapSpec.swapDelay) + } else { + doSwap() + } + } + if (isError) { + triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({ error: 'Response Status Error Code ' + xhr.status + ' from ' + responseInfo.pathInfo.requestPath }, responseInfo)) + } + } + + //= =================================================================== + // Extensions API + //= =================================================================== + + /** @type {Object<string, HtmxExtension>} */ + const extensions = {} + + /** + * extensionBase defines the default functions for all extensions. + * @returns {HtmxExtension} + */ + function extensionBase() { + return { + init: function(api) { return null }, + getSelectors: function() { return null }, + onEvent: function(name, evt) { return true }, + transformResponse: function(text, xhr, elt) { return text }, + isInlineSwap: function(swapStyle) { return false }, + handleSwap: function(swapStyle, target, fragment, settleInfo) { return false }, + encodeParameters: function(xhr, parameters, elt) { return null } + } + } + + /** + * defineExtension initializes the extension and adds it to the htmx registry + * + * @see https://htmx.org/api/#defineExtension + * + * @param {string} name the extension name + * @param {HtmxExtension} extension the extension definition + */ + function defineExtension(name, extension) { + if (extension.init) { + extension.init(internalAPI) + } + extensions[name] = mergeObjects(extensionBase(), extension) + } + + /** + * removeExtension removes an extension from the htmx registry + * + * @see https://htmx.org/api/#removeExtension + * + * @param {string} name + */ + function removeExtension(name) { + delete extensions[name] + } + + /** + * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element + * + * @param {Element} elt + * @param {HtmxExtension[]=} extensionsToReturn + * @param {string[]=} extensionsToIgnore + * @returns {HtmxExtension[]} + */ + function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + if (extensionsToReturn == undefined) { + extensionsToReturn = [] + } + if (elt == undefined) { + return extensionsToReturn + } + if (extensionsToIgnore == undefined) { + extensionsToIgnore = [] + } + const extensionsForElement = getAttributeValue(elt, 'hx-ext') + if (extensionsForElement) { + forEach(extensionsForElement.split(','), function(extensionName) { + extensionName = extensionName.replace(/ /g, '') + if (extensionName.slice(0, 7) == 'ignore:') { + extensionsToIgnore.push(extensionName.slice(7)) + return + } + if (extensionsToIgnore.indexOf(extensionName) < 0) { + const extension = extensions[extensionName] + if (extension && extensionsToReturn.indexOf(extension) < 0) { + extensionsToReturn.push(extension) + } + } + }) + } + return getExtensions(asElement(parentElt(elt)), extensionsToReturn, extensionsToIgnore) + } + + //= =================================================================== + // Initialization + //= =================================================================== + var isReady = false + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true + }) + + /** + * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. + * + * This function uses isReady because there is no reliable way to ask the browser whether + * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded + * firing and readystate=complete. + */ + function ready(fn) { + // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by + // some means other than the initial page load. + if (isReady || getDocument().readyState === 'complete') { + fn() + } else { + getDocument().addEventListener('DOMContentLoaded', fn) + } + } + + function insertIndicatorStyles() { + if (htmx.config.includeIndicatorStyles !== false) { + const nonceAttribute = htmx.config.inlineStyleNonce ? ` nonce="${htmx.config.inlineStyleNonce}"` : '' + getDocument().head.insertAdjacentHTML('beforeend', + '<style' + nonceAttribute + '>\ + .' + htmx.config.indicatorClass + '{opacity:0}\ + .' + htmx.config.requestClass + ' .' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\ + .' + htmx.config.requestClass + '.' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\ + </style>') + } + } + + function getMetaConfig() { + /** @type HTMLMetaElement */ + const element = getDocument().querySelector('meta[name="htmx-config"]') + if (element) { + return parseJSON(element.content) + } else { + return null + } + } - return htmx; + function mergeMetaConfig() { + const metaConfig = getMetaConfig() + if (metaConfig) { + htmx.config = mergeObjects(htmx.config, metaConfig) + } + } + + // initialize the document + ready(function() { + mergeMetaConfig() + insertIndicatorStyles() + let body = getDocument().body + processNode(body) + const restoredElts = getDocument().querySelectorAll( + "[hx-trigger='restored'],[data-hx-trigger='restored']" + ) + body.addEventListener('htmx:abort', function(evt) { + const target = evt.target + const internalData = getInternalData(target) + if (internalData && internalData.xhr) { + internalData.xhr.abort() + } + }) + /** @type {(ev: PopStateEvent) => any} */ + const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null + /** @type {(ev: PopStateEvent) => any} */ + window.onpopstate = function(event) { + if (event.state && event.state.htmx) { + restoreHistory() + forEach(restoredElts, function(elt) { + triggerEvent(elt, 'htmx:restored', { + document: getDocument(), + triggerEvent + }) + }) + } else { + if (originalPopstate) { + originalPopstate(event) + } + } } -)() -})); + getWindow().setTimeout(function() { + triggerEvent(body, 'htmx:load', {}) // give ready handlers a chance to load up before firing this event + body = null // kill reference for gc + }, 0) + }) + + return htmx +})() + +/** @typedef {'get'|'head'|'post'|'put'|'delete'|'connect'|'options'|'trace'|'patch'} HttpVerb */ + +/** + * @typedef {Object} SwapOptions + * @property {string} [select] + * @property {string} [selectOOB] + * @property {*} [eventInfo] + * @property {string} [anchor] + * @property {Element} [contextElement] + * @property {swapCallback} [afterSwapCallback] + * @property {swapCallback} [afterSettleCallback] + */ + +/** + * @callback swapCallback + */ + +/** + * @typedef {'innerHTML' | 'outerHTML' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'delete' | 'none' | string} HtmxSwapStyle + */ + +/** + * @typedef HtmxSwapSpecification + * @property {HtmxSwapStyle} swapStyle + * @property {number} swapDelay + * @property {number} settleDelay + * @property {boolean} [transition] + * @property {boolean} [ignoreTitle] + * @property {string} [head] + * @property {'top' | 'bottom'} [scroll] + * @property {string} [scrollTarget] + * @property {string} [show] + * @property {string} [showTarget] + * @property {boolean} [focusScroll] + */ + +/** + * @typedef {((this:Node, evt:Event) => boolean) & {source: string}} ConditionalFunction + */ + +/** + * @typedef {Object} HtmxTriggerSpecification + * @property {string} trigger + * @property {number} [pollInterval] + * @property {ConditionalFunction} [eventFilter] + * @property {boolean} [changed] + * @property {boolean} [once] + * @property {boolean} [consume] + * @property {number} [delay] + * @property {string} [from] + * @property {string} [target] + * @property {number} [throttle] + * @property {string} [queue] + * @property {string} [root] + * @property {string} [threshold] + */ + +/** + * @typedef {{elt: Element, message: string, validity: ValidityState}} HtmxElementValidationError + */ + +/** + * @typedef {Record<string, string>} HtmxHeaderSpecification + * @property {'true'} HX-Request + * @property {string|null} HX-Trigger + * @property {string|null} HX-Trigger-Name + * @property {string|null} HX-Target + * @property {string} HX-Current-URL + * @property {string} [HX-Prompt] + * @property {'true'} [HX-Boosted] + * @property {string} [Content-Type] + * @property {'true'} [HX-History-Restore-Request] + */ + +/** @typedef HtmxAjaxHelperContext + * @property {Element|string} [source] + * @property {Event} [event] + * @property {HtmxAjaxHandler} [handler] + * @property {Element|string} target + * @property {HtmxSwapStyle} [swap] + * @property {Object|FormData} [values] + * @property {Record<string,string>} [headers] + * @property {string} [select] + */ + +/** + * @typedef {Object} HtmxRequestConfig + * @property {boolean} boosted + * @property {boolean} useUrlParams + * @property {FormData} formData + * @property {Object} parameters formData proxy + * @property {FormData} unfilteredFormData + * @property {Object} unfilteredParameters unfilteredFormData proxy + * @property {HtmxHeaderSpecification} headers + * @property {Element} target + * @property {HttpVerb} verb + * @property {HtmxElementValidationError[]} errors + * @property {boolean} withCredentials + * @property {number} timeout + * @property {string} path + * @property {Event} triggeringEvent + */ + +/** + * @typedef {Object} HtmxResponseInfo + * @property {XMLHttpRequest} xhr + * @property {Element} target + * @property {HtmxRequestConfig} requestConfig + * @property {HtmxAjaxEtc} etc + * @property {boolean} boosted + * @property {string} select + * @property {{requestPath: string, finalRequestPath: string, responsePath: string|null, anchor: string}} pathInfo + * @property {boolean} [failed] + * @property {boolean} [successful] + */ + +/** + * @typedef {Object} HtmxAjaxEtc + * @property {boolean} [returnPromise] + * @property {HtmxAjaxHandler} [handler] + * @property {string} [select] + * @property {Element} [targetOverride] + * @property {HtmxSwapStyle} [swapOverride] + * @property {Record<string,string>} [headers] + * @property {Object|FormData} [values] + * @property {boolean} [credentials] + * @property {number} [timeout] + */ + +/** + * @typedef {Object} HtmxResponseHandlingConfig + * @property {string} [code] + * @property {boolean} swap + * @property {boolean} [error] + * @property {boolean} [ignoreTitle] + * @property {string} [select] + * @property {string} [target] + * @property {string} [swapOverride] + * @property {string} [event] + */ + +/** + * @typedef {HtmxResponseInfo & {shouldSwap: boolean, serverResponse: any, isError: boolean, ignoreTitle: boolean, selectOverride:string}} HtmxBeforeSwapDetails + */ + +/** + * @callback HtmxAjaxHandler + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + */ + +/** + * @typedef {(() => void)} HtmxSettleTask + */ + +/** + * @typedef {Object} HtmxSettleInfo + * @property {HtmxSettleTask[]} tasks + * @property {Element[]} elts + * @property {string} [title] + */ + +/** + * @typedef {Object} HtmxExtension + * @see https://htmx.org/extensions/#defining + * @property {(api: any) => void} init + * @property {(name: string, event: Event|CustomEvent) => boolean} onEvent + * @property {(text: string, xhr: XMLHttpRequest, elt: Element) => string} transformResponse + * @property {(swapStyle: HtmxSwapStyle) => boolean} isInlineSwap + * @property {(swapStyle: HtmxSwapStyle, target: Element, fragment: Node, settleInfo: HtmxSettleInfo) => boolean} handleSwap + * @property {(xhr: XMLHttpRequest, parameters: FormData, elt: Element) => *|string|null} encodeParameters + */ diff --git a/code/ch5_partials/ch5_final_video_collector/static/js/htmx.min.js b/code/ch5_partials/ch5_final_video_collector/static/js/htmx.min.js index 53bbdf6..d66acce 100644 --- a/code/ch5_partials/ch5_final_video_collector/static/js/htmx.min.js +++ b/code/ch5_partials/ch5_final_video_collector/static/js/htmx.min.js @@ -1,4 +1,2 @@ -// /////////////////////////////////////////////////////////////////// -// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js -// -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(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 a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/<body/.test(e)}function l(e){var t=!N(e);var r=A(e);var n=e;if(r==="head"){n=n.replace(S,"")}if(Q.config.useTemplateFragments&&t){var i=a("<body><template>"+n+"</template></body>",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a("<table>"+n+"</table>",1);case"col":return a("<table><colgroup>"+n+"</colgroup></table>",2);case"tr":return a("<table><tbody>"+n+"</tbody></table>",2);case"td":case"th":return a("<table><tbody><tr>"+n+"</tr></tbody></table>",3);case"script":case"style":return a("<div>"+n+"</div>",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function oe(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function X(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var Y=function(e,t){var r=re().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function we(t,r){oe(t.attributes,function(e){if(!r.hasAttribute(e.name)&&be(e.name)){t.removeAttribute(e.name)}});oe(r.attributes,function(e){if(be(e.name)){t.setAttribute(e.name,e.value)}})}function Se(e,t){var r=Fr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){b(e)}}return e==="outerHTML"}function Ee(e,i,a){var t="#"+ee(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a<i.length;a++){var o=i[a].split(":",2);var s=o[0].trim();if(s.indexOf("#")===0){s=s.substring(1)}var l=o[1]||"true";var u=t.querySelector("#"+s);if(u){Ee(l,u,r)}}}oe(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=te(e,"hx-swap-oob");if(t!=null){Ee(t,e,r)}})}function Re(e){oe(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=te(e,"id");var r=re().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function Te(o,e,s){oe(e.querySelectorAll("[id]"),function(e){var t=ee(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Le(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=He(n.name,t);t=He(n.value,t)}}}return t}function Ae(e){var t=ae(e);if(t.onHandlers){for(var r=0;r<t.onHandlers.length;r++){const n=t.onHandlers[r];e.removeEventListener(n.event,n.listener)}delete t.onHandlers}}function Ne(e){var t=ae(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){oe(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}Ae(e);oe(Object.keys(t),function(e){delete t[e]})}function p(e){ce(e,"htmx:beforeCleanupElement");Ne(e);if(e.children){oe(e.children,function(e){p(e)})}}function Ie(t,e,r){if(t.tagName==="BODY"){return Ue(t,e,r)}else{var n;var i=t.previousSibling;m(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}p(t);u(t).removeChild(t)}}function ke(e,t,r){return m(e,e.firstChild,t,r)}function Pe(e,t,r){return m(u(e),e,t,r)}function Me(e,t,r){return m(e,null,t,r)}function Xe(e,t,r){return m(u(e),e.nextSibling,t,r)}function De(e,t,r){p(e);return u(e).removeChild(e)}function Ue(e,t,r){var n=e.firstChild;m(e,n,t,r);if(n){while(n.nextSibling){p(n.nextSibling);e.removeChild(n.nextSibling)}p(n);e.removeChild(n)}}function Be(e,t,r){var n=r||ne(e,"hx-select");if(n){var i=re().createDocumentFragment();oe(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function Fe(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Ie(r,n,i);return;case"afterbegin":ke(r,n,i);return;case"beforebegin":Pe(r,n,i);return;case"beforeend":Me(r,n,i);return;case"afterend":Xe(r,n,i);return;case"delete":De(r,n,i);return;default:var a=Fr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Oe(f))}}}return}}catch(e){b(e)}}if(e==="innerHTML"){Ue(r,n,i)}else{Fe(Q.config.defaultSwapStyle,t,r,n,i)}}}function Ve(e){if(e.indexOf("<title")>-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){ce(r,s[l].trim(),[])}}}var ze=/\s/;var x=/[\s,]/;var $e=/[_$a-zA-Z]/;var We=/[_$a-zA-Z0-9]/;var Ge=['"',"'","/"];var Je=/[^\s]/;var Ze=/[{(]/;var Ke=/[})]/;function Ye(e){var t=[];var r=0;while(r<e.length){if($e.exec(e.charAt(r))){var n=r;while(We.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ge.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function Qe(e,t,r){return $e.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function et(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){xt(e,a[1],0)}if(a[0]==="send"){bt(e)}}}function xt(s,r,n){if(!se(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=Q.createWebSocket(r);t.onerror=function(e){fe(s,"htmx:wsError",{error:e,socket:t});yt(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a<i.length;a++){var o=i[a];Ee(te(o,"hx-swap-oob")||"true",o,r)}nr(r.tasks)})}function yt(e){if(!se(e)){ae(e).webSocket.close();return true}}function bt(u){var f=c(u,function(e){return ae(e).webSocket!=null});if(f){u.addEventListener(it(u)[0].trigger,function(e){var t=ae(f).webSocket;var r=xr(u,f);var n=dr(u,"post");var i=n.errors;var a=n.values;var o=Hr(u);var s=le(a,o);var l=yr(s,u);l["HEADERS"]=r;if(i&&i.length>0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){Et(e,a[1])}if(a[0]==="swap"){Ct(e,a[1])}}}function Et(t,e){var r=Q.createEventSource(e);r.onerror=function(e){fe(t,"htmx:sseError",{error:e,source:r});Tt(t)};ae(t).sseEventSource=r}function Ct(a,o){var s=c(a,Ot);if(s){var l=ae(s).sseEventSource;var u=function(e){if(Tt(s)){return}if(!se(a)){l.removeEventListener(o,u);return}var t=e.data;R(a,function(e){t=e.transformResponse(t,null,a)});var r=wr(a);var n=ye(a);var i=T(a);je(r.swapStyle,n,a,t,i);nr(i.tasks);ce(a,"htmx:sseMessage",e)};ae(a).sseListener=u;l.addEventListener(o,u)}else{fe(a,"htmx:noSSESourceError")}}function Rt(e,t,r){var n=c(e,Ot);if(n){var i=ae(n).sseEventSource;var a=function(){if(!Tt(n)){if(se(e)){t(e)}else{i.removeEventListener(r,a)}}};ae(e).sseListener=a;i.addEventListener(r,a)}else{fe(e,"htmx:noSSESourceError")}}function Tt(e){if(!se(e)){ae(e).sseEventSource.close();return true}}function Ot(e){return ae(e).sseEventSource!=null}function qt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n>0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){ce(n,"intersect");break}}},i);a.observe(n);ht(n,r,t,e)}else if(e.trigger==="load"){if(!ct(e,n,Wt("load",{elt:n}))){qt(n,r,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r<t.length;r++){var n=t[r].name;if(s(n,"hx-on:")||s(n,"data-hx-on:")||s(n,"hx-on-")||s(n,"data-hx-on-")){return true}}return false}function kt(e){var t=null;var r=[];if(It(e)){r.push(e)}if(document.evaluate){var n=document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]',e);while(t=n.iterateNext())r.push(t)}else{var i=e.getElementsByTagName("*");for(var a=0;a<i.length;a++){if(It(i[a])){r.push(i[a])}}}return r}function Pt(e){if(e.querySelectorAll){var t=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";var r=e.querySelectorAll(i+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Mt(e){var t=v(e.target,"button, input[type='submit']");var r=Dt(e);if(r){r.lastButtonClicked=t}}function Xt(e){var t=Dt(e);if(t){t.lastButtonClicked=null}}function Dt(e){var t=v(e.target,"button, input[type='submit']");if(!t){return}var r=g("#"+ee(t,"form"))||v(t,"form");if(!r){return}return ae(r)}function Ut(e){e.addEventListener("click",Mt);e.addEventListener("focusin",Mt);e.addEventListener("focusout",Xt)}function Bt(e){var t=Ye(e);var r=0;for(var n=0;n<t.length;n++){const i=t[n];if(i==="{"){r++}else if(i==="}"){r--}}return r}function Ft(t,e,r){var n=ae(t);if(!Array.isArray(n.onHandlers)){n.onHandlers=[]}var i;var a=function(e){return Tr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Vt(e){var t=te(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;t<e.attributes.length;t++){var r=e.attributes[t].name;var n=e.attributes[t].value;if(s(r,"hx-on")||s(r,"data-hx-on")){var i=r.indexOf("-on")+3;var a=r.slice(i,i+1);if(a==="-"||a===":"){var o=r.slice(i+1);if(s(o,":")){o="htmx"+o}else if(s(o,"-")){o="htmx:"+o.slice(1)}else if(s(o,"htmx-")){o="htmx:"+o.slice(5)}Ft(e,o,n)}}}}function _t(t){if(v(t,Q.config.disableSelector)){p(t);return}var r=ae(t);if(r.initHash!==Le(t)){Ne(t);r.initHash=Le(t);Vt(t);ce(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=it(t);var n=Ht(t,r,e);if(!n){if(ne(t,"hx-boost")==="true"){lt(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){Lt(t,e,r,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&o(t,"form")){Ut(t)}var i=te(t,"hx-sse");if(i){St(t,r,i)}var a=te(t,"hx-ws");if(a){pt(t,r,a)}ce(t,"htmx:afterProcessNode")}}function zt(e){e=g(e);if(v(e,Q.config.disableSelector)){p(e);return}_t(e);oe(Pt(e),function(e){_t(e)});oe(kt(e),jt)}function $t(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=re().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function fe(e,t,r){ce(e,t,le({error:t},r))}function Gt(e){return e==="htmx:afterProcessNode"}function R(e,t){oe(Fr(e),function(e){try{t(e)}catch(e){b(e)}})}function b(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ce(e,t,r){e=g(e);if(r==null){r={}}r["elt"]=e;var n=Wt(t,r);if(Q.logger&&!Gt(t)){Q.logger(e,t,r)}if(r.error){b(r.error);ce(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=$t(t);if(i&&a!==t){var o=Wt(a,n.detail);i=i&&e.dispatchEvent(o)}R(e,function(e){i=i&&(e.onEvent(t,n)!==false&&!n.defaultPrevented)});return i}var Jt=location.pathname+location.search;function Zt(){var e=re().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||re().body}function Kt(e,t,r,n){if(!U()){return}if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}e=B(e);var i=E(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};ce(re().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Qt(e){var t=Q.config.requestClass;var r=e.cloneNode(true);oe(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function er(){var e=Zt();var t=Jt||location.pathname+location.search;var r;try{r=re().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){r=re().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!r){ce(re().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Kt(t,Qt(e),re().title,window.scrollY)}if(Q.config.historyEnabled)history.replaceState({htmx:true},re().title,window.location.href)}function tr(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(G(e,"&")||G(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Jt=e}function rr(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Jt=e}function nr(e){oe(e,function(e){e.call()})}function ir(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};ce(re().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",re().location.href);e.onload=function(){if(this.status>=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function fr(e){if(e.name===""||e.name==null||e.disabled||v(e,"fieldset[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 cr(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function hr(t,r,n,e,i){if(e==null||ur(t,e)){return}else{t.push(e)}if(fr(e)){var a=ee(e,"name");var o=e.value;if(e.multiple&&e.tagName==="SELECT"){o=M(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=M(e.files)}cr(a,o,r);if(i){vr(e,n)}}if(h(e,"form")){var s=e.elements;oe(s,function(e){hr(t,r,n,e,i)})}}function vr(e,t){if(e.willValidate){ce(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});ce(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function dr(e,t){var r=[];var n={};var i={};var a=[];var o=ae(e);if(o.lastButtonClicked&&!se(o.lastButtonClicked)){o.lastButtonClicked=null}var s=h(e,"form")&&e.noValidate!==true||te(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){hr(r,i,a,v(e,"form"),s)}hr(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=ee(l,"name");cr(u,l.value,i)}var f=pe(e,"hx-include");oe(f,function(e){hr(r,n,a,e,s);if(!h(e,"form")){oe(e.querySelectorAll(rt),function(e){hr(r,n,a,e,s)})}});n=le(n,i);return{errors:a,values:n}}function gr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function mr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t=gr(t,r,e)})}else{t=gr(t,r,n)}}}return t}function pr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function xr(e,t,r){var n={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":re().location.href};Rr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ae(e).boosted){n["HX-Boosted"]="true"}return n}function yr(t,e){var r=ne(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){oe(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};oe(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function br(e){return ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=d(o.substr(5))}else if(o.indexOf("settle:")===0){n["settleDelay"]=d(o.substr(7))}else if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}else if(o.indexOf("ignoreTitle:")===0){n["ignoreTitle"]=o.substr(12)==="true"}else if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","<style> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file +// v2.0.0 from https://github.com/bigskysoftware/htmx/releases +var htmx=function(){"use strict";const Q={onLoad:null,process:null,on:null,off:null,trigger:null,ajax:null,find:null,findAll:null,closest:null,values:function(e,t){const n=cn(e,t||"post");return n.values},remove:null,addClass:null,removeClass:null,toggleClass:null,takeClass:null,swap:null,defineExtension:null,removeExtension:null,logAll:null,logNone:null,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",inlineStyleNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",scrollBehavior:"instant",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get","delete"],selfRequestsOnly:true,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null,disableInheritance:false,responseHandling:[{code:"204",swap:false},{code:"[23]..",swap:true},{code:"[45]..",swap:false,error:true}],allowNestedOobSwaps:true},parseInterval:null,_:null,version:"2.0.0"};Q.onLoad=$;Q.process=Dt;Q.on=be;Q.off=we;Q.trigger=he;Q.ajax=Hn;Q.find=r;Q.findAll=p;Q.closest=g;Q.remove=K;Q.addClass=W;Q.removeClass=o;Q.toggleClass=Y;Q.takeClass=ge;Q.swap=ze;Q.defineExtension=Un;Q.removeExtension=Bn;Q.logAll=z;Q.logNone=J;Q.parseInterval=d;Q._=_;const n={addTriggerHandler:Et,bodyContains:le,canAccessLocalStorage:j,findThisElement:Ee,filterValues:dn,swap:ze,hasAttribute:s,getAttributeValue:te,getClosestAttributeValue:re,getClosestMatch:T,getExpressionVars:Cn,getHeaders:hn,getInputValues:cn,getInternalData:ie,getSwapSpecification:pn,getTriggerSpecs:lt,getTarget:Ce,makeFragment:D,mergeObjects:ue,makeSettleInfo:xn,oobSwap:Te,querySelectorExt:fe,settleImmediately:Gt,shouldCancel:dt,triggerEvent:he,triggerErrorEvent:ae,withExtensions:Ut};const v=["get","post","put","delete","patch"];const R=v.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");const O=e("head");function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e instanceof Element&&e.getAttribute(t)}function s(e,t){return!!e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){const t=e.parentElement;if(!t&&e.parentNode instanceof ShadowRoot)return e.parentNode;return t}function ne(){return document}function H(e,t){return e.getRootNode?e.getRootNode({composed:t}):ne()}function T(e,t){while(e&&!t(e)){e=u(e)}return e||null}function q(e,t,n){const r=te(t,n);const o=te(t,"hx-disinherit");var i=te(t,"hx-inherit");if(e!==t){if(Q.config.disableInheritance){if(i&&(i==="*"||i.split(" ").indexOf(n)>=0)){return r}else{return null}}if(o&&(o==="*"||o.split(" ").indexOf(n)>=0)){return"unset"}}return r}function re(t,n){let r=null;T(t,function(e){return!!(r=q(t,ce(e),n))});if(r!=="unset"){return r}}function a(e,t){const n=e instanceof Element&&(e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector);return!!n&&n.call(e,t)}function L(e){const t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;const n=t.exec(e);if(n){return n[1].toLowerCase()}else{return""}}function N(e){const t=new DOMParser;return t.parseFromString(e,"text/html")}function A(e,t){while(t.childNodes.length>0){e.append(t.childNodes[0])}}function I(e){const t=ne().createElement("script");se(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}return t}function P(e){return e.matches("script")&&(e.type==="text/javascript"||e.type==="module"||e.type==="")}function k(e){Array.from(e.querySelectorAll("script")).forEach(e=>{if(P(e)){const t=I(e);const n=e.parentNode;try{n.insertBefore(t,e)}catch(e){w(e)}finally{e.remove()}}})}function D(e){const t=e.replace(O,"");const n=L(t);let r;if(n==="html"){r=new DocumentFragment;const i=N(e);A(r,i.body);r.title=i.title}else if(n==="body"){r=new DocumentFragment;const i=N(t);A(r,i.body);r.title=i.title}else{const i=N('<body><template class="internal-htmx-wrapper">'+t+"</template></body>");r=i.querySelector("template").content;r.title=i.title;var o=r.querySelector("title");if(o&&o.parentNode===r){o.remove();r.title=o.innerText}}if(r){if(Q.config.allowScriptTags){k(r)}else{r.querySelectorAll("script").forEach(e=>e.remove())}}return r}function oe(e){if(e){e()}}function t(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function M(e){return typeof e==="function"}function X(e){return t(e,"Object")}function ie(e){const t="htmx-internal-data";let n=e[t];if(!n){n=e[t]={}}return n}function F(t){const n=[];if(t){for(let e=0;e<t.length;e++){n.push(t[e])}}return n}function se(t,n){if(t){for(let e=0;e<t.length;e++){n(t[e])}}}function U(e){const t=e.getBoundingClientRect();const n=t.top;const r=t.bottom;return n<window.innerHeight&&r>=0}function le(e){const t=e.getRootNode&&e.getRootNode();if(t&&t instanceof window.ShadowRoot){return ne().body.contains(t.host)}else{return ne().body.contains(e)}}function B(e){return e.trim().split(/\s+/)}function ue(e,t){for(const n in t){if(t.hasOwnProperty(n)){e[n]=t[n]}}return e}function S(e){try{return JSON.parse(e)}catch(e){w(e);return null}}function j(){const e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function V(t){try{const e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function _(e){return vn(ne().body,function(){return eval(e)})}function $(t){const e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function z(){Q.logger=function(e,t,n){if(console){console.log(t,e,n)}}}function J(){Q.logger=null}function r(e,t){if(typeof e!=="string"){return e.querySelector(t)}else{return r(ne(),e)}}function p(e,t){if(typeof e!=="string"){return e.querySelectorAll(t)}else{return p(ne(),e)}}function E(){return window}function K(e,t){e=y(e);if(t){E().setTimeout(function(){K(e);e=null},t)}else{u(e).removeChild(e)}}function ce(e){return e instanceof Element?e:null}function G(e){return e instanceof HTMLElement?e:null}function Z(e){return typeof e==="string"?e:null}function h(e){return e instanceof Element||e instanceof Document||e instanceof DocumentFragment?e:null}function W(e,t,n){e=ce(y(e));if(!e){return}if(n){E().setTimeout(function(){W(e,t);e=null},n)}else{e.classList&&e.classList.add(t)}}function o(e,t,n){let r=ce(y(e));if(!r){return}if(n){E().setTimeout(function(){o(r,t);r=null},n)}else{if(r.classList){r.classList.remove(t);if(r.classList.length===0){r.removeAttribute("class")}}}}function Y(e,t){e=y(e);e.classList.toggle(t)}function ge(e,t){e=y(e);se(e.parentElement.children,function(e){o(e,t)});W(ce(e),t)}function g(e,t){e=ce(y(e));if(e&&e.closest){return e.closest(t)}else{do{if(e==null||a(e,t)){return e}}while(e=e&&ce(u(e)));return null}}function l(e,t){return e.substring(0,t.length)===t}function pe(e,t){return e.substring(e.length-t.length)===t}function i(e){const t=e.trim();if(l(t,"<")&&pe(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function m(e,t,n){e=y(e);if(t.indexOf("closest ")===0){return[g(ce(e),i(t.substr(8)))]}else if(t.indexOf("find ")===0){return[r(h(e),i(t.substr(5)))]}else if(t==="next"){return[ce(e).nextElementSibling]}else if(t.indexOf("next ")===0){return[me(e,i(t.substr(5)),!!n)]}else if(t==="previous"){return[ce(e).previousElementSibling]}else if(t.indexOf("previous ")===0){return[ye(e,i(t.substr(9)),!!n)]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else if(t==="root"){return[H(e,!!n)]}else if(t.indexOf("global ")===0){return m(e,t.slice(7),true)}else{return F(h(H(e,!!n)).querySelectorAll(i(t)))}}var me=function(t,e,n){const r=h(H(t,n)).querySelectorAll(e);for(let e=0;e<r.length;e++){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_PRECEDING){return o}}};var ye=function(t,e,n){const r=h(H(t,n)).querySelectorAll(e);for(let e=r.length-1;e>=0;e--){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_FOLLOWING){return o}}};function fe(e,t){if(typeof e!=="string"){return m(e,t)[0]}else{return m(ne().body,e)[0]}}function y(e,t){if(typeof e==="string"){return r(h(t)||document,e)}else{return e}}function xe(e,t,n){if(M(t)){return{target:ne().body,event:Z(e),listener:t}}else{return{target:y(e),event:Z(t),listener:n}}}function be(t,n,r){_n(function(){const e=xe(t,n,r);e.target.addEventListener(e.event,e.listener)});const e=M(n);return e?n:r}function we(t,n,r){_n(function(){const e=xe(t,n,r);e.target.removeEventListener(e.event,e.listener)});return M(n)?n:r}const ve=ne().createElement("output");function Se(e,t){const n=re(e,t);if(n){if(n==="this"){return[Ee(e,t)]}else{const r=m(e,n);if(r.length===0){w('The selector "'+n+'" on '+t+" returned no matches!");return[ve]}else{return r}}}}function Ee(e,t){return ce(T(e,function(e){return te(ce(e),t)!=null}))}function Ce(e){const t=re(e,"hx-target");if(t){if(t==="this"){return Ee(e,"hx-target")}else{return fe(e,t)}}else{const n=ie(e);if(n.boosted){return ne().body}else{return e}}}function Re(t){const n=Q.config.attributesToSettle;for(let e=0;e<n.length;e++){if(t===n[e]){return true}}return false}function Oe(t,n){se(t.attributes,function(e){if(!n.hasAttribute(e.name)&&Re(e.name)){t.removeAttribute(e.name)}});se(n.attributes,function(e){if(Re(e.name)){t.setAttribute(e.name,e.value)}})}function He(t,e){const n=jn(e);for(let e=0;e<n.length;e++){const r=n[e];try{if(r.isInlineSwap(t)){return true}}catch(e){w(e)}}return t==="outerHTML"}function Te(e,o,i){let t="#"+ee(o,"id");let s="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){s=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{s=e}const n=ne().querySelectorAll(t);if(n){se(n,function(e){let t;const n=o.cloneNode(true);t=ne().createDocumentFragment();t.appendChild(n);if(!He(s,e)){t=h(n)}const r={shouldSwap:true,target:e,fragment:t};if(!he(e,"htmx:oobBeforeSwap",r))return;e=r.target;if(r.shouldSwap){_e(s,e,e,t,i)}se(i.elts,function(e){he(e,"htmx:oobAfterSwap",r)})});o.parentNode.removeChild(o)}else{o.parentNode.removeChild(o);ae(ne().body,"htmx:oobErrorNoTarget",{content:o})}return e}function qe(e){se(p(e,"[hx-preserve], [data-hx-preserve]"),function(e){const t=te(e,"id");const n=ne().getElementById(t);if(n!=null){e.parentNode.replaceChild(n,e)}})}function Le(l,e,u){se(e.querySelectorAll("[id]"),function(t){const n=ee(t,"id");if(n&&n.length>0){const r=n.replace("'","\\'");const o=t.tagName.replace(":","\\:");const e=h(l);const i=e&&e.querySelector(o+"[id='"+r+"']");if(i&&i!==e){const s=t.cloneNode();Oe(t,i);u.tasks.push(function(){Oe(t,s)})}}})}function Ne(e){return function(){o(e,Q.config.addedClass);Dt(ce(e));Ae(h(e));he(e,"htmx:load")}}function Ae(e){const t="[autofocus]";const n=G(a(e,t)?e:e.querySelector(t));if(n!=null){n.focus()}}function c(e,t,n,r){Le(e,n,r);while(n.childNodes.length>0){const o=n.firstChild;W(ce(o),Q.config.addedClass);e.insertBefore(o,t);if(o.nodeType!==Node.TEXT_NODE&&o.nodeType!==Node.COMMENT_NODE){r.tasks.push(Ne(o))}}}function Ie(e,t){let n=0;while(n<e.length){t=(t<<5)-t+e.charCodeAt(n++)|0}return t}function Pe(t){let n=0;if(t.attributes){for(let e=0;e<t.attributes.length;e++){const r=t.attributes[e];if(r.value){n=Ie(r.name,n);n=Ie(r.value,n)}}}return n}function ke(t){const n=ie(t);if(n.onHandlers){for(let e=0;e<n.onHandlers.length;e++){const r=n.onHandlers[e];we(t,r.event,r.listener)}delete n.onHandlers}}function De(e){const t=ie(e);if(t.timeout){clearTimeout(t.timeout)}if(t.listenerInfos){se(t.listenerInfos,function(e){if(e.on){we(e.on,e.trigger,e.listener)}})}ke(e);se(Object.keys(t),function(e){delete t[e]})}function f(e){he(e,"htmx:beforeCleanupElement");De(e);if(e.children){se(e.children,function(e){f(e)})}}function Me(t,e,n){let r;const o=t.previousSibling;c(u(t),t,e,n);if(o==null){r=u(t).firstChild}else{r=o.nextSibling}n.elts=n.elts.filter(function(e){return e!==t});while(r&&r!==t){if(r instanceof Element){n.elts.push(r);r=r.nextElementSibling}else{r=null}}f(t);if(t instanceof Element){t.remove()}else{t.parentNode.removeChild(t)}}function Xe(e,t,n){return c(e,e.firstChild,t,n)}function Fe(e,t,n){return c(u(e),e,t,n)}function Ue(e,t,n){return c(e,null,t,n)}function Be(e,t,n){return c(u(e),e.nextSibling,t,n)}function je(e){f(e);return u(e).removeChild(e)}function Ve(e,t,n){const r=e.firstChild;c(e,r,t,n);if(r){while(r.nextSibling){f(r.nextSibling);e.removeChild(r.nextSibling)}f(r);e.removeChild(r)}}function _e(t,e,n,r,o){switch(t){case"none":return;case"outerHTML":Me(n,r,o);return;case"afterbegin":Xe(n,r,o);return;case"beforebegin":Fe(n,r,o);return;case"beforeend":Ue(n,r,o);return;case"afterend":Be(n,r,o);return;case"delete":je(n);return;default:var i=jn(e);for(let e=0;e<i.length;e++){const s=i[e];try{const l=s.handleSwap(t,n,r,o);if(l){if(typeof l.length!=="undefined"){for(let e=0;e<l.length;e++){const u=l[e];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){o.tasks.push(Ne(u))}}}return}}catch(e){w(e)}}if(t==="innerHTML"){Ve(n,r,o)}else{_e(Q.config.defaultSwapStyle,e,n,r,o)}}}function $e(e,n){se(p(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){if(Q.config.allowNestedOobSwaps||e.parentElement===null){const t=te(e,"hx-swap-oob");if(t!=null){Te(t,e,n)}}else{e.removeAttribute("hx-swap-oob");e.removeAttribute("data-hx-swap-oob")}})}function ze(e,t,r,o){if(!o){o={}}e=y(e);const n=document.activeElement;let i={};try{i={elt:n,start:n?n.selectionStart:null,end:n?n.selectionEnd:null}}catch(e){}const s=xn(e);if(r.swapStyle==="textContent"){e.textContent=t}else{let n=D(t);s.title=n.title;if(o.selectOOB){const u=o.selectOOB.split(",");for(let t=0;t<u.length;t++){const c=u[t].split(":",2);let e=c[0].trim();if(e.indexOf("#")===0){e=e.substring(1)}const f=c[1]||"true";const a=n.querySelector("#"+e);if(a){Te(f,a,s)}}}$e(n,s);se(p(n,"template"),function(e){$e(e.content,s);if(e.content.childElementCount===0){e.remove()}});if(o.select){const h=ne().createDocumentFragment();se(n.querySelectorAll(o.select),function(e){h.appendChild(e)});n=h}qe(n);_e(r.swapStyle,o.contextElement,e,n,s)}if(i.elt&&!le(i.elt)&&ee(i.elt,"id")){const d=document.getElementById(ee(i.elt,"id"));const g={preventScroll:r.focusScroll!==undefined?!r.focusScroll:!Q.config.defaultFocusScroll};if(d){if(i.start&&d.setSelectionRange){try{d.setSelectionRange(i.start,i.end)}catch(e){}}d.focus(g)}}e.classList.remove(Q.config.swappingClass);se(s.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}he(e,"htmx:afterSwap",o.eventInfo)});if(o.afterSwapCallback){o.afterSwapCallback()}if(!r.ignoreTitle){Dn(s.title)}const l=function(){se(s.tasks,function(e){e.call()});se(s.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}he(e,"htmx:afterSettle",o.eventInfo)});if(o.anchor){const e=ce(y("#"+o.anchor));if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}bn(s.elts,r);if(o.afterSettleCallback){o.afterSettleCallback()}};if(r.settleDelay>0){E().setTimeout(l,r.settleDelay)}else{l()}}function Je(e,t,n){const r=e.getResponseHeader(t);if(r.indexOf("{")===0){const o=S(r);for(const i in o){if(o.hasOwnProperty(i)){let e=o[i];if(!X(e)){e={value:e}}he(n,i,e)}}}else{const s=r.split(",");for(let e=0;e<s.length;e++){he(n,s[e].trim(),[])}}}const Ke=/\s/;const x=/[\s,]/;const Ge=/[_$a-zA-Z]/;const Ze=/[_$a-zA-Z0-9]/;const We=['"',"'","/"];const Ye=/[^\s]/;const Qe=/[{(]/;const et=/[})]/;function tt(e){const t=[];let n=0;while(n<e.length){if(Ge.exec(e.charAt(n))){var r=n;while(Ze.exec(e.charAt(n+1))){n++}t.push(e.substr(r,n-r+1))}else if(We.indexOf(e.charAt(n))!==-1){const o=e.charAt(n);var r=n;n++;while(n<e.length&&e.charAt(n)!==o){if(e.charAt(n)==="\\"){n++}n++}t.push(e.substr(r,n-r+1))}else{const i=e.charAt(n);t.push(i)}n++}return t}function nt(e,t,n){return Ge.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==n&&t!=="."}function rt(r,o,i){if(o[0]==="["){o.shift();let e=1;let t=" return (function("+i+"){ return (";let n=null;while(o.length>0){const s=o[0];if(s==="]"){e--;if(e===0){if(n===null){t=t+"true"}o.shift();t+=")})";try{const l=vn(r,function(){return Function(t)()},function(){return true});l.source=t;return l}catch(e){ae(ne().body,"htmx:syntax:error",{error:e,source:t});return null}}}else if(s==="["){e++}if(nt(s,n,i)){t+="(("+i+"."+s+") ? ("+i+"."+s+") : (window."+s+"))"}else{t=t+s}n=o.shift()}}}function b(e,t){let n="";while(e.length>0&&!t.test(e[0])){n+=e.shift()}return n}function ot(e){let t;if(e.length>0&&Qe.test(e[0])){e.shift();t=b(e,et).trim();e.shift()}else{t=b(e,x)}return t}const it="input, textarea, select";function st(e,t,n){const r=[];const o=tt(t);do{b(o,Ye);const l=o.length;const u=b(o,/[,\[\s]/);if(u!==""){if(u==="every"){const c={trigger:"every"};b(o,Ye);c.pollInterval=d(b(o,/[,\[\s]/));b(o,Ye);var i=rt(e,o,"event");if(i){c.eventFilter=i}r.push(c)}else{const f={trigger:u};var i=rt(e,o,"event");if(i){f.eventFilter=i}while(o.length>0&&o[0]!==","){b(o,Ye);const a=o.shift();if(a==="changed"){f.changed=true}else if(a==="once"){f.once=true}else if(a==="consume"){f.consume=true}else if(a==="delay"&&o[0]===":"){o.shift();f.delay=d(b(o,x))}else if(a==="from"&&o[0]===":"){o.shift();if(Qe.test(o[0])){var s=ot(o)}else{var s=b(o,x);if(s==="closest"||s==="find"||s==="next"||s==="previous"){o.shift();const h=ot(o);if(h.length>0){s+=" "+h}}}f.from=s}else if(a==="target"&&o[0]===":"){o.shift();f.target=ot(o)}else if(a==="throttle"&&o[0]===":"){o.shift();f.throttle=d(b(o,x))}else if(a==="queue"&&o[0]===":"){o.shift();f.queue=b(o,x)}else if(a==="root"&&o[0]===":"){o.shift();f[a]=ot(o)}else if(a==="threshold"&&o[0]===":"){o.shift();f[a]=b(o,x)}else{ae(e,"htmx:syntax:error",{token:o.shift()})}}r.push(f)}}if(o.length===l){ae(e,"htmx:syntax:error",{token:o.shift()})}b(o,Ye)}while(o[0]===","&&o.shift());if(n){n[t]=r}return r}function lt(e){const t=te(e,"hx-trigger");let n=[];if(t){const r=Q.config.triggerSpecsCache;n=r&&r[t]||st(e,t,r)}if(n.length>0){return n}else if(a(e,"form")){return[{trigger:"submit"}]}else if(a(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(a(e,it)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function ut(e){ie(e).cancelled=true}function ct(e,t,n){const r=ie(e);r.timeout=E().setTimeout(function(){if(le(e)&&r.cancelled!==true){if(!pt(n,e,Xt("hx:poll:trigger",{triggerSpec:n,target:e}))){t(e)}ct(e,t,n)}},n.pollInterval)}function ft(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function at(e){return g(e,Q.config.disableSelector)}function ht(t,n,e){if(t instanceof HTMLAnchorElement&&ft(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){n.boosted=true;let r,o;if(t.tagName==="A"){r="get";o=ee(t,"href")}else{const i=ee(t,"method");r=i?i.toLowerCase():"get";if(r==="get"){}o=ee(t,"action")}e.forEach(function(e){mt(t,function(e,t){const n=ce(e);if(at(n)){f(n);return}de(r,o,n,t)},n,e,true)})}}function dt(e,t){const n=ce(t);if(!n){return false}if(e.type==="submit"||e.type==="click"){if(n.tagName==="FORM"){return true}if(a(n,'input[type="submit"], button')&&g(n,"form")!==null){return true}if(n instanceof HTMLAnchorElement&&n.href&&(n.getAttribute("href")==="#"||n.getAttribute("href").indexOf("#")!==0)){return true}}return false}function gt(e,t){return ie(e).boosted&&e instanceof HTMLAnchorElement&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function pt(e,t,n){const r=e.eventFilter;if(r){try{return r.call(t,n)!==true}catch(e){const o=r.source;ae(ne().body,"htmx:eventFilter:error",{error:e,source:o});return true}}return false}function mt(s,l,e,u,c){const f=ie(s);let t;if(u.from){t=m(s,u.from)}else{t=[s]}if(u.changed){t.forEach(function(e){const t=ie(e);t.lastValue=e.value})}se(t,function(o){const i=function(e){if(!le(s)){o.removeEventListener(u.trigger,i);return}if(gt(s,e)){return}if(c||dt(e,s)){e.preventDefault()}if(pt(u,s,e)){return}const t=ie(e);t.triggerSpec=u;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(s)<0){t.handledFor.push(s);if(u.consume){e.stopPropagation()}if(u.target&&e.target){if(!a(ce(e.target),u.target)){return}}if(u.once){if(f.triggeredOnce){return}else{f.triggeredOnce=true}}if(u.changed){const n=ie(o);const r=o.value;if(n.lastValue===r){return}n.lastValue=r}if(f.delayed){clearTimeout(f.delayed)}if(f.throttle){return}if(u.throttle>0){if(!f.throttle){l(s,e);f.throttle=E().setTimeout(function(){f.throttle=null},u.throttle)}}else if(u.delay>0){f.delayed=E().setTimeout(function(){l(s,e)},u.delay)}else{he(s,"htmx:trigger");l(s,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:u.trigger,listener:i,on:o});o.addEventListener(u.trigger,i)})}let yt=false;let xt=null;function bt(){if(!xt){xt=function(){yt=true};window.addEventListener("scroll",xt);setInterval(function(){if(yt){yt=false;se(ne().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"),function(e){wt(e)})}},200)}}function wt(e){if(!s(e,"data-hx-revealed")&&U(e)){e.setAttribute("data-hx-revealed","true");const t=ie(e);if(t.initHash){he(e,"revealed")}else{e.addEventListener("htmx:afterProcessNode",function(){he(e,"revealed")},{once:true})}}}function vt(e,t,n,r){const o=function(){if(!n.loaded){n.loaded=true;t(e)}};if(r>0){E().setTimeout(o,r)}else{o()}}function St(t,n,e){let i=false;se(v,function(r){if(s(t,"hx-"+r)){const o=te(t,"hx-"+r);i=true;n.path=o;n.verb=r;e.forEach(function(e){Et(t,e,n,function(e,t){const n=ce(e);if(g(n,Q.config.disableSelector)){f(n);return}de(r,o,n,t)})})}});return i}function Et(r,e,t,n){if(e.trigger==="revealed"){bt();mt(r,n,t,e);wt(ce(r))}else if(e.trigger==="intersect"){const o={};if(e.root){o.root=fe(r,e.root)}if(e.threshold){o.threshold=parseFloat(e.threshold)}const i=new IntersectionObserver(function(t){for(let e=0;e<t.length;e++){const n=t[e];if(n.isIntersecting){he(r,"intersect");break}}},o);i.observe(ce(r));mt(ce(r),n,t,e)}else if(e.trigger==="load"){if(!pt(e,r,Xt("load",{elt:r}))){vt(ce(r),n,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ct(ce(r),n,e)}else{mt(r,n,t,e)}}function Ct(e){const t=ce(e);if(!t){return false}const n=t.attributes;for(let e=0;e<n.length;e++){const r=n[e].name;if(l(r,"hx-on:")||l(r,"data-hx-on:")||l(r,"hx-on-")||l(r,"data-hx-on-")){return true}}return false}const Rt=(new XPathEvaluator).createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]');function Ot(e,t){if(Ct(e)){t.push(ce(e))}const n=Rt.evaluate(e);let r=null;while(r=n.iterateNext())t.push(ce(r))}function Ht(e){const t=[];if(e instanceof DocumentFragment){for(const n of e.childNodes){Ot(n,t)}}else{Ot(e,t)}return t}function Tt(e){if(e.querySelectorAll){const n=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";const r=[];for(const i in Xn){const s=Xn[i];if(s.getSelectors){var t=s.getSelectors();if(t){r.push(t)}}}const o=e.querySelectorAll(R+n+", form, [type='submit'],"+" [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]"+r.flat().map(e=>", "+e).join(""));return o}else{return[]}}function qt(e){const t=g(ce(e.target),"button, input[type='submit']");const n=Nt(e);if(n){n.lastButtonClicked=t}}function Lt(e){const t=Nt(e);if(t){t.lastButtonClicked=null}}function Nt(e){const t=g(ce(e.target),"button, input[type='submit']");if(!t){return}const n=y("#"+ee(t,"form"),t.getRootNode())||g(t,"form");if(!n){return}return ie(n)}function At(e){e.addEventListener("click",qt);e.addEventListener("focusin",qt);e.addEventListener("focusout",Lt)}function It(t,e,n){const r=ie(t);if(!Array.isArray(r.onHandlers)){r.onHandlers=[]}let o;const i=function(e){vn(t,function(){if(at(t)){return}if(!o){o=new Function("event",n)}o.call(t,e)})};t.addEventListener(e,i);r.onHandlers.push({event:e,listener:i})}function Pt(t){ke(t);for(let e=0;e<t.attributes.length;e++){const n=t.attributes[e].name;const r=t.attributes[e].value;if(l(n,"hx-on")||l(n,"data-hx-on")){const o=n.indexOf("-on")+3;const i=n.slice(o,o+1);if(i==="-"||i===":"){let e=n.slice(o+1);if(l(e,":")){e="htmx"+e}else if(l(e,"-")){e="htmx:"+e.slice(1)}else if(l(e,"htmx-")){e="htmx:"+e.slice(5)}It(t,e,r)}}}}function kt(t){if(g(t,Q.config.disableSelector)){f(t);return}const n=ie(t);if(n.initHash!==Pe(t)){De(t);n.initHash=Pe(t);he(t,"htmx:beforeProcessNode");if(t.value){n.lastValue=t.value}const e=lt(t);const r=St(t,n,e);if(!r){if(re(t,"hx-boost")==="true"){ht(t,n,e)}else if(s(t,"hx-trigger")){e.forEach(function(e){Et(t,e,n,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&s(t,"form")){At(t)}he(t,"htmx:afterProcessNode")}}function Dt(e){e=y(e);if(g(e,Q.config.disableSelector)){f(e);return}kt(e);se(Tt(e),function(e){kt(e)});se(Ht(e),Pt)}function Mt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Xt(e,t){let n;if(window.CustomEvent&&typeof window.CustomEvent==="function"){n=new CustomEvent(e,{bubbles:true,cancelable:true,composed:true,detail:t})}else{n=ne().createEvent("CustomEvent");n.initCustomEvent(e,true,true,t)}return n}function ae(e,t,n){he(e,t,ue({error:t},n))}function Ft(e){return e==="htmx:afterProcessNode"}function Ut(e,t){se(jn(e),function(e){try{t(e)}catch(e){w(e)}})}function w(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function he(e,t,n){e=y(e);if(n==null){n={}}n.elt=e;const r=Xt(t,n);if(Q.logger&&!Ft(t)){Q.logger(e,t,n)}if(n.error){w(n.error);he(e,"htmx:error",{errorInfo:n})}let o=e.dispatchEvent(r);const i=Mt(t);if(o&&i!==t){const s=Xt(i,r.detail);o=o&&e.dispatchEvent(s)}Ut(ce(e),function(e){o=o&&(e.onEvent(t,r)!==false&&!r.defaultPrevented)});return o}let Bt=location.pathname+location.search;function jt(){const e=ne().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||ne().body}function Vt(t,e){if(!j()){return}const n=$t(e);const r=ne().title;const o=window.scrollY;if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}t=V(t);const i=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e<i.length;e++){if(i[e].url===t){i.splice(e,1);break}}const s={url:t,content:n,title:r,scroll:o};he(ne().body,"htmx:historyItemCreated",{item:s,cache:i});i.push(s);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ae(ne().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function _t(t){if(!j()){return null}t=V(t);const n=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e<n.length;e++){if(n[e].url===t){return n[e]}}return null}function $t(e){const t=Q.config.requestClass;const n=e.cloneNode(true);se(p(n,"."+t),function(e){o(e,t)});return n.innerHTML}function zt(){const e=jt();const t=Bt||location.pathname+location.search;let n;try{n=ne().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){n=ne().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!n){he(ne().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Vt(t,e)}if(Q.config.historyEnabled)history.replaceState({htmx:true},ne().title,window.location.href)}function Jt(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(pe(e,"&")||pe(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Bt=e}function Kt(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Bt=e}function Gt(e){se(e,function(e){e.call(undefined)})}function Zt(o){const e=new XMLHttpRequest;const i={path:o,xhr:e};he(ne().body,"htmx:historyCacheMiss",i);e.open("GET",o,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",ne().location.href);e.onload=function(){if(this.status>=200&&this.status<400){he(ne().body,"htmx:historyCacheMissLoad",i);const e=D(this.response);const t=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;const n=jt();const r=xn(n);Dn(e.title);Ve(n,t,r);Gt(r.tasks);Bt=o;he(ne().body,"htmx:historyRestore",{path:o,cacheMiss:true,serverResponse:this.response})}else{ae(ne().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Wt(e){zt();e=e||location.pathname+location.search;const t=_t(e);if(t){const n=D(t.content);const r=jt();const o=xn(r);Dn(n.title);Ve(r,n,o);Gt(o.tasks);E().setTimeout(function(){window.scrollTo(0,t.scroll)},0);Bt=e;he(ne().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{Zt(e)}}}function Yt(e){let t=Se(e,"hx-indicator");if(t==null){t=[e]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.classList.add.call(e.classList,Q.config.requestClass)});return t}function Qt(e){let t=Se(e,"hx-disabled-elt");if(t==null){t=[]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function en(e,t){se(e,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList.remove.call(e.classList,Q.config.requestClass)}});se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function tn(t,n){for(let e=0;e<t.length;e++){const r=t[e];if(r.isSameNode(n)){return true}}return false}function nn(e){const t=e;if(t.name===""||t.name==null||t.disabled||g(t,"fieldset[disabled]")){return false}if(t.type==="button"||t.type==="submit"||t.tagName==="image"||t.tagName==="reset"||t.tagName==="file"){return false}if(t.type==="checkbox"||t.type==="radio"){return t.checked}return true}function rn(t,e,n){if(t!=null&&e!=null){if(Array.isArray(e)){e.forEach(function(e){n.append(t,e)})}else{n.append(t,e)}}}function on(t,n,r){if(t!=null&&n!=null){let e=r.getAll(t);if(Array.isArray(n)){e=e.filter(e=>n.indexOf(e)<0)}else{e=e.filter(e=>e!==n)}r.delete(t);se(e,e=>r.append(t,e))}}function sn(t,n,r,o,i){if(o==null||tn(t,o)){return}else{t.push(o)}if(nn(o)){const s=ee(o,"name");let e=o.value;if(o instanceof HTMLSelectElement&&o.multiple){e=F(o.querySelectorAll("option:checked")).map(function(e){return e.value})}if(o instanceof HTMLInputElement&&o.files){e=F(o.files)}rn(s,e,n);if(i){ln(o,r)}}if(o instanceof HTMLFormElement){se(o.elements,function(e){if(t.indexOf(e)>=0){on(e.name,e.value,n)}else{t.push(e)}if(i){ln(e,r)}});new FormData(o).forEach(function(e,t){if(e instanceof File&&e.name===""){return}rn(t,e,n)})}}function ln(e,t){const n=e;if(n.willValidate){he(n,"htmx:validation:validate");if(!n.checkValidity()){t.push({elt:n,message:n.validationMessage,validity:n.validity});he(n,"htmx:validation:failed",{message:n.validationMessage,validity:n.validity})}}}function un(t,e){for(const n of e.keys()){t.delete(n);e.getAll(n).forEach(function(e){t.append(n,e)})}return t}function cn(e,t){const n=[];const r=new FormData;const o=new FormData;const i=[];const s=ie(e);if(s.lastButtonClicked&&!le(s.lastButtonClicked)){s.lastButtonClicked=null}let l=e instanceof HTMLFormElement&&e.noValidate!==true||te(e,"hx-validate")==="true";if(s.lastButtonClicked){l=l&&s.lastButtonClicked.formNoValidate!==true}if(t!=="get"){sn(n,o,i,g(e,"form"),l)}sn(n,r,i,e,l);if(s.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){const c=s.lastButtonClicked||e;const f=ee(c,"name");rn(f,c.value,o)}const u=Se(e,"hx-include");se(u,function(e){sn(n,r,i,ce(e),l);if(!a(e,"form")){se(h(e).querySelectorAll(it),function(e){sn(n,r,i,e,l)})}});un(r,o);return{errors:i,formData:r,values:An(r)}}function fn(e,t,n){if(e!==""){e+="&"}if(String(n)==="[object Object]"){n=JSON.stringify(n)}const r=encodeURIComponent(n);e+=encodeURIComponent(t)+"="+r;return e}function an(e){e=Ln(e);let n="";e.forEach(function(e,t){n=fn(n,t,e)});return n}function hn(e,t,n){const r={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":ne().location.href};wn(e,"hx-headers",false,r);if(n!==undefined){r["HX-Prompt"]=n}if(ie(e).boosted){r["HX-Boosted"]="true"}return r}function dn(n,e){const t=re(e,"hx-params");if(t){if(t==="none"){return new FormData}else if(t==="*"){return n}else if(t.indexOf("not ")===0){se(t.substr(4).split(","),function(e){e=e.trim();n.delete(e)});return n}else{const r=new FormData;se(t.split(","),function(t){t=t.trim();if(n.has(t)){n.getAll(t).forEach(function(e){r.append(t,e)})}});return r}}else{return n}}function gn(e){return!!ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function pn(e,t){const n=t||re(e,"hx-swap");const r={swapStyle:ie(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ie(e).boosted&&!gn(e)){r.show="top"}if(n){const s=B(n);if(s.length>0){for(let e=0;e<s.length;e++){const l=s[e];if(l.indexOf("swap:")===0){r.swapDelay=d(l.substr(5))}else if(l.indexOf("settle:")===0){r.settleDelay=d(l.substr(7))}else if(l.indexOf("transition:")===0){r.transition=l.substr(11)==="true"}else if(l.indexOf("ignoreTitle:")===0){r.ignoreTitle=l.substr(12)==="true"}else if(l.indexOf("scroll:")===0){const u=l.substr(7);var o=u.split(":");const c=o.pop();var i=o.length>0?o.join(":"):null;r.scroll=c;r.scrollTarget=i}else if(l.indexOf("show:")===0){const f=l.substr(5);var o=f.split(":");const a=o.pop();var i=o.length>0?o.join(":"):null;r.show=a;r.showTarget=i}else if(l.indexOf("focus-scroll:")===0){const h=l.substr("focus-scroll:".length);r.focusScroll=h=="true"}else if(e==0){r.swapStyle=l}else{w("Unknown modifier in hx-swap: "+l)}}}}return r}function mn(e){return re(e,"hx-encoding")==="multipart/form-data"||a(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function yn(t,n,r){let o=null;Ut(n,function(e){if(o==null){o=e.encodeParameters(t,r,n)}});if(o!=null){return o}else{if(mn(n)){return un(new FormData,Ln(r))}else{return an(r)}}}function xn(e){return{tasks:[],elts:[e]}}function bn(e,t){const n=e[0];const r=e[e.length-1];if(t.scroll){var o=null;if(t.scrollTarget){o=ce(fe(n,t.scrollTarget))}if(t.scroll==="top"&&(n||o)){o=o||n;o.scrollTop=0}if(t.scroll==="bottom"&&(r||o)){o=o||r;o.scrollTop=o.scrollHeight}}if(t.show){var o=null;if(t.showTarget){let e=t.showTarget;if(t.showTarget==="window"){e="body"}o=ce(fe(n,e))}if(t.show==="top"&&(n||o)){o=o||n;o.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(r||o)){o=o||r;o.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function wn(r,e,o,i){if(i==null){i={}}if(r==null){return i}const s=te(r,e);if(s){let e=s.trim();let t=o;if(e==="unset"){return null}if(e.indexOf("javascript:")===0){e=e.substr(11);t=true}else if(e.indexOf("js:")===0){e=e.substr(3);t=true}if(e.indexOf("{")!==0){e="{"+e+"}"}let n;if(t){n=vn(r,function(){return Function("return ("+e+")")()},{})}else{n=S(e)}for(const l in n){if(n.hasOwnProperty(l)){if(i[l]==null){i[l]=n[l]}}}}return wn(ce(u(r)),e,o,i)}function vn(e,t,n){if(Q.config.allowEval){return t()}else{ae(e,"htmx:evalDisallowedError");return n}}function Sn(e,t){return wn(e,"hx-vars",true,t)}function En(e,t){return wn(e,"hx-vals",false,t)}function Cn(e){return ue(Sn(e),En(e))}function Rn(t,n,r){if(r!==null){try{t.setRequestHeader(n,r)}catch(e){t.setRequestHeader(n,encodeURIComponent(r));t.setRequestHeader(n+"-URI-AutoEncoded","true")}}}function On(t){if(t.responseURL&&typeof URL!=="undefined"){try{const e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ae(ne().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function C(e,t){return t.test(e.getAllResponseHeaders())}function Hn(e,t,n){e=e.toLowerCase();if(n){if(n instanceof Element||typeof n==="string"){return de(e,t,null,null,{targetOverride:y(n),returnPromise:true})}else{return de(e,t,y(n.source),n.event,{handler:n.handler,headers:n.headers,values:n.values,targetOverride:y(n.target),swapOverride:n.swap,select:n.select,returnPromise:true})}}else{return de(e,t,null,null,{returnPromise:true})}}function Tn(e){const t=[];while(e){t.push(e);e=e.parentElement}return t}function qn(e,t,n){let r;let o;if(typeof URL==="function"){o=new URL(t,document.location.href);const i=document.location.origin;r=i===o.origin}else{o=t;r=l(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!r){return false}}return he(e,"htmx:validateUrl",ue({url:o,sameHost:r},n))}function Ln(e){if(e instanceof FormData)return e;const t=new FormData;for(const n in e){if(e.hasOwnProperty(n)){if(typeof e[n].forEach==="function"){e[n].forEach(function(e){t.append(n,e)})}else if(typeof e[n]==="object"){t.append(n,JSON.stringify(e[n]))}else{t.append(n,e[n])}}}return t}function Nn(r,o,e){return new Proxy(e,{get:function(t,e){if(typeof e==="number")return t[e];if(e==="length")return t.length;if(e==="push"){return function(e){t.push(e);r.append(o,e)}}if(typeof t[e]==="function"){return function(){t[e].apply(t,arguments);r.delete(o);t.forEach(function(e){r.append(o,e)})}}if(t[e]&&t[e].length===1){return t[e][0]}else{return t[e]}},set:function(e,t,n){e[t]=n;r.delete(o);e.forEach(function(e){r.append(o,e)});return true}})}function An(r){return new Proxy(r,{get:function(e,t){if(typeof t==="symbol"){return Reflect.get(e,t)}if(t==="toJSON"){return()=>Object.fromEntries(r)}if(t in e){if(typeof e[t]==="function"){return function(){return r[t].apply(r,arguments)}}else{return e[t]}}const n=r.getAll(t);if(n.length===0){return undefined}else if(n.length===1){return n[0]}else{return Nn(e,t,n)}},set:function(t,n,e){if(typeof n!=="string"){return false}t.delete(n);if(typeof e.forEach==="function"){e.forEach(function(e){t.append(n,e)})}else{t.append(n,e)}return true},deleteProperty:function(e,t){if(typeof t==="string"){e.delete(t)}return true},ownKeys:function(e){return Reflect.ownKeys(Object.fromEntries(e))},getOwnPropertyDescriptor:function(e,t){return Reflect.getOwnPropertyDescriptor(Object.fromEntries(e),t)}})}function de(t,n,r,o,i,D){let s=null;let l=null;i=i!=null?i:{};if(i.returnPromise&&typeof Promise!=="undefined"){var e=new Promise(function(e,t){s=e;l=t})}if(r==null){r=ne().body}const M=i.handler||Mn;const X=i.select||null;if(!le(r)){oe(s);return e}const u=i.targetOverride||ce(Ce(r));if(u==null||u==ve){ae(r,"htmx:targetError",{target:te(r,"hx-target")});oe(l);return e}let c=ie(r);const f=c.lastButtonClicked;if(f){const L=ee(f,"formaction");if(L!=null){n=L}const N=ee(f,"formmethod");if(N!=null){if(N.toLowerCase()!=="dialog"){t=N}}}const a=re(r,"hx-confirm");if(D===undefined){const K=function(e){return de(t,n,r,o,i,!!e)};const G={target:u,elt:r,path:n,verb:t,triggeringEvent:o,etc:i,issueRequest:K,question:a};if(he(r,"htmx:confirm",G)===false){oe(s);return e}}let h=r;let d=re(r,"hx-sync");let g=null;let F=false;if(d){const A=d.split(":");const I=A[0].trim();if(I==="this"){h=Ee(r,"hx-sync")}else{h=ce(fe(r,I))}d=(A[1]||"drop").trim();c=ie(h);if(d==="drop"&&c.xhr&&c.abortable!==true){oe(s);return e}else if(d==="abort"){if(c.xhr){oe(s);return e}else{F=true}}else if(d==="replace"){he(h,"htmx:abort")}else if(d.indexOf("queue")===0){const Z=d.split(" ");g=(Z[1]||"last").trim()}}if(c.xhr){if(c.abortable){he(h,"htmx:abort")}else{if(g==null){if(o){const P=ie(o);if(P&&P.triggerSpec&&P.triggerSpec.queue){g=P.triggerSpec.queue}}if(g==null){g="last"}}if(c.queuedRequests==null){c.queuedRequests=[]}if(g==="first"&&c.queuedRequests.length===0){c.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="all"){c.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="last"){c.queuedRequests=[];c.queuedRequests.push(function(){de(t,n,r,o,i)})}oe(s);return e}}const p=new XMLHttpRequest;c.xhr=p;c.abortable=F;const m=function(){c.xhr=null;c.abortable=false;if(c.queuedRequests!=null&&c.queuedRequests.length>0){const e=c.queuedRequests.shift();e()}};const U=re(r,"hx-prompt");if(U){var y=prompt(U);if(y===null||!he(r,"htmx:prompt",{prompt:y,target:u})){oe(s);m();return e}}if(a&&!D){if(!confirm(a)){oe(s);m();return e}}let x=hn(r,u,y);if(t!=="get"&&!mn(r)){x["Content-Type"]="application/x-www-form-urlencoded"}if(i.headers){x=ue(x,i.headers)}const B=cn(r,t);let b=B.errors;const j=B.formData;if(i.values){un(j,Ln(i.values))}const V=Ln(Cn(r));const w=un(j,V);let v=dn(w,r);if(Q.config.getCacheBusterParam&&t==="get"){v.set("org.htmx.cache-buster",ee(u,"id")||"true")}if(n==null||n===""){n=ne().location.href}const S=wn(r,"hx-request");const _=ie(r).boosted;let E=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;const C={boosted:_,useUrlParams:E,formData:v,parameters:An(v),unfilteredFormData:w,unfilteredParameters:An(w),headers:x,target:u,verb:t,errors:b,withCredentials:i.credentials||S.credentials||Q.config.withCredentials,timeout:i.timeout||S.timeout||Q.config.timeout,path:n,triggeringEvent:o};if(!he(r,"htmx:configRequest",C)){oe(s);m();return e}n=C.path;t=C.verb;x=C.headers;v=Ln(C.parameters);b=C.errors;E=C.useUrlParams;if(b&&b.length>0){he(r,"htmx:validation:halted",C);oe(s);m();return e}const $=n.split("#");const z=$[0];const R=$[1];let O=n;if(E){O=z;const W=!v.keys().next().done;if(W){if(O.indexOf("?")<0){O+="?"}else{O+="&"}O+=an(v);if(R){O+="#"+R}}}if(!qn(r,O,C)){ae(r,"htmx:invalidPath",C);oe(l);return e}p.open(t.toUpperCase(),O,true);p.overrideMimeType("text/html");p.withCredentials=C.withCredentials;p.timeout=C.timeout;if(S.noHeaders){}else{for(const k in x){if(x.hasOwnProperty(k)){const Y=x[k];Rn(p,k,Y)}}}const H={xhr:p,target:u,requestConfig:C,etc:i,boosted:_,select:X,pathInfo:{requestPath:n,finalRequestPath:O,responsePath:null,anchor:R}};p.onload=function(){try{const t=Tn(r);H.pathInfo.responsePath=On(p);M(r,H);en(T,q);he(r,"htmx:afterRequest",H);he(r,"htmx:afterOnLoad",H);if(!le(r)){let e=null;while(t.length>0&&e==null){const n=t.shift();if(le(n)){e=n}}if(e){he(e,"htmx:afterRequest",H);he(e,"htmx:afterOnLoad",H)}}oe(s);m()}catch(e){ae(r,"htmx:onLoadError",ue({error:e},H));throw e}};p.onerror=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:sendError",H);oe(l);m()};p.onabort=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:sendAbort",H);oe(l);m()};p.ontimeout=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:timeout",H);oe(l);m()};if(!he(r,"htmx:beforeRequest",H)){oe(s);m();return e}var T=Yt(r);var q=Qt(r);se(["loadstart","loadend","progress","abort"],function(t){se([p,p.upload],function(e){e.addEventListener(t,function(e){he(r,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});he(r,"htmx:beforeSend",H);const J=E?null:yn(p,r,v);p.send(J);return e}function In(e,t){const n=t.xhr;let r=null;let o=null;if(C(n,/HX-Push:/i)){r=n.getResponseHeader("HX-Push");o="push"}else if(C(n,/HX-Push-Url:/i)){r=n.getResponseHeader("HX-Push-Url");o="push"}else if(C(n,/HX-Replace-Url:/i)){r=n.getResponseHeader("HX-Replace-Url");o="replace"}if(r){if(r==="false"){return{}}else{return{type:o,path:r}}}const i=t.pathInfo.finalRequestPath;const s=t.pathInfo.responsePath;const l=re(e,"hx-push-url");const u=re(e,"hx-replace-url");const c=ie(e).boosted;let f=null;let a=null;if(l){f="push";a=l}else if(u){f="replace";a=u}else if(c){f="push";a=s||i}if(a){if(a==="false"){return{}}if(a==="true"){a=s||i}if(t.pathInfo.anchor&&a.indexOf("#")===-1){a=a+"#"+t.pathInfo.anchor}return{type:f,path:a}}else{return{}}}function Pn(e,t){var n=new RegExp(e.code);return n.test(t.toString(10))}function kn(e){for(var t=0;t<Q.config.responseHandling.length;t++){var n=Q.config.responseHandling[t];if(Pn(n,e.status)){return n}}return{swap:false}}function Dn(e){if(e){const t=r("title");if(t){t.innerHTML=e}else{window.document.title=e}}}function Mn(o,i){const s=i.xhr;let l=i.target;const e=i.etc;const u=i.select;if(!he(o,"htmx:beforeOnLoad",i))return;if(C(s,/HX-Trigger:/i)){Je(s,"HX-Trigger",o)}if(C(s,/HX-Location:/i)){zt();let e=s.getResponseHeader("HX-Location");var t;if(e.indexOf("{")===0){t=S(e);e=t.path;delete t.path}Hn("get",e,t).then(function(){Jt(e)});return}const n=C(s,/HX-Refresh:/i)&&s.getResponseHeader("HX-Refresh")==="true";if(C(s,/HX-Redirect:/i)){location.href=s.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(C(s,/HX-Retarget:/i)){if(s.getResponseHeader("HX-Retarget")==="this"){i.target=o}else{i.target=ce(fe(o,s.getResponseHeader("HX-Retarget")))}}const c=In(o,i);const r=kn(s);const f=r.swap;let a=!!r.error;let h=Q.config.ignoreTitle||r.ignoreTitle;let d=r.select;if(r.target){i.target=ce(fe(o,r.target))}var g=e.swapOverride;if(g==null&&r.swapOverride){g=r.swapOverride}if(C(s,/HX-Retarget:/i)){if(s.getResponseHeader("HX-Retarget")==="this"){i.target=o}else{i.target=ce(fe(o,s.getResponseHeader("HX-Retarget")))}}if(C(s,/HX-Reswap:/i)){g=s.getResponseHeader("HX-Reswap")}var p=s.response;var m=ue({shouldSwap:f,serverResponse:p,isError:a,ignoreTitle:h,selectOverride:d},i);if(r.event&&!he(l,r.event,m))return;if(!he(l,"htmx:beforeSwap",m))return;l=m.target;p=m.serverResponse;a=m.isError;h=m.ignoreTitle;d=m.selectOverride;i.target=l;i.failed=a;i.successful=!a;if(m.shouldSwap){if(s.status===286){ut(o)}Ut(o,function(e){p=e.transformResponse(p,s,o)});if(c.type){zt()}if(C(s,/HX-Reswap:/i)){g=s.getResponseHeader("HX-Reswap")}var y=pn(o,g);if(!y.hasOwnProperty("ignoreTitle")){y.ignoreTitle=h}l.classList.add(Q.config.swappingClass);let n=null;let r=null;if(u){d=u}if(C(s,/HX-Reselect:/i)){d=s.getResponseHeader("HX-Reselect")}const x=re(o,"hx-select-oob");const b=re(o,"hx-select");let e=function(){try{if(c.type){he(ne().body,"htmx:beforeHistoryUpdate",ue({history:c},i));if(c.type==="push"){Jt(c.path);he(ne().body,"htmx:pushedIntoHistory",{path:c.path})}else{Kt(c.path);he(ne().body,"htmx:replacedInHistory",{path:c.path})}}ze(l,p,y,{select:d||b,selectOOB:x,eventInfo:i,anchor:i.pathInfo.anchor,contextElement:o,afterSwapCallback:function(){if(C(s,/HX-Trigger-After-Swap:/i)){let e=o;if(!le(o)){e=ne().body}Je(s,"HX-Trigger-After-Swap",e)}},afterSettleCallback:function(){if(C(s,/HX-Trigger-After-Settle:/i)){let e=o;if(!le(o)){e=ne().body}Je(s,"HX-Trigger-After-Settle",e)}oe(n)}})}catch(e){ae(o,"htmx:swapError",i);oe(r);throw e}};let t=Q.config.globalViewTransitions;if(y.hasOwnProperty("transition")){t=y.transition}if(t&&he(o,"htmx:beforeTransition",i)&&typeof Promise!=="undefined"&&document.startViewTransition){const w=new Promise(function(e,t){n=e;r=t});const v=e;e=function(){document.startViewTransition(function(){v();return w})}}if(y.swapDelay>0){E().setTimeout(e,y.swapDelay)}else{e()}}if(a){ae(o,"htmx:responseError",ue({error:"Response Status Error Code "+s.status+" from "+i.pathInfo.requestPath},i))}}const Xn={};function Fn(){return{init:function(e){return null},getSelectors:function(){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,n){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,n,r){return false},encodeParameters:function(e,t,n){return null}}}function Un(e,t){if(t.init){t.init(n)}Xn[e]=ue(Fn(),t)}function Bn(e){delete Xn[e]}function jn(e,n,r){if(n==undefined){n=[]}if(e==undefined){return n}if(r==undefined){r=[]}const t=te(e,"hx-ext");if(t){se(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){r.push(e.slice(7));return}if(r.indexOf(e)<0){const t=Xn[e];if(t&&n.indexOf(t)<0){n.push(t)}}})}return jn(ce(u(e)),n,r)}var Vn=false;ne().addEventListener("DOMContentLoaded",function(){Vn=true});function _n(e){if(Vn||ne().readyState==="complete"){e()}else{ne().addEventListener("DOMContentLoaded",e)}}function $n(){if(Q.config.includeIndicatorStyles!==false){const e=Q.config.inlineStyleNonce?` nonce="${Q.config.inlineStyleNonce}"`:"";ne().head.insertAdjacentHTML("beforeend","<style"+e+"> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zn(){const e=ne().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function Jn(){const e=zn();if(e){Q.config=ue(Q.config,e)}}_n(function(){Jn();$n();let e=ne().body;Dt(e);const t=ne().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){const t=e.target;const n=ie(t);if(n&&n.xhr){n.xhr.abort()}});const n=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){Wt();se(t,function(e){he(e,"htmx:restored",{document:ne(),triggerEvent:he})})}else{if(n){n(e)}}};E().setTimeout(function(){he(e,"htmx:load",{});e=null},0)});return Q}(); \ No newline at end of file diff --git a/code/ch5_partials/ch5_final_video_collector/templates/shared/_layout.html b/code/ch5_partials/ch5_final_video_collector/templates/shared/_layout.html index b4738bb..d8fe9b9 100644 --- a/code/ch5_partials/ch5_final_video_collector/templates/shared/_layout.html +++ b/code/ch5_partials/ch5_final_video_collector/templates/shared/_layout.html @@ -51,7 +51,7 @@ </footer> -<script src="/https/github.com/static/js/htmx.min.js?v=1.5.0"></script> +<script src="/https/github.com/static/js/htmx.min.js?v=2.0.0"></script> <script src="/https/github.com/static/js/jquery-3.5.1.slim.min.js"></script> <script src="/https/github.com/static/js/popper-1.16.1.min.js"></script> diff --git a/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.d.ts b/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.d.ts new file mode 100644 index 0000000..3775459 --- /dev/null +++ b/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.d.ts @@ -0,0 +1,195 @@ +declare namespace htmx { + const onLoad: (callback: (elt: Node) => void) => EventListener; + const process: (elt: string | Element) => void; + const on: (arg1: string | EventTarget, arg2: string | EventListener, arg3?: EventListener) => EventListener; + const off: (arg1: string | EventTarget, arg2: string | EventListener, arg3?: EventListener) => EventListener; + const trigger: (elt: string | EventTarget, eventName: string, detail?: any) => boolean; + const ajax: (verb: HttpVerb, path: string, context: string | Element | HtmxAjaxHelperContext) => Promise<void>; + const find: (eltOrSelector: string | ParentNode, selector?: string) => Element; + const findAll: (eltOrSelector: string | ParentNode, selector?: string) => NodeListOf<Element>; + const closest: (elt: string | Element, selector: string) => Element; + function values(elt: Element, type: HttpVerb): any; + const remove: (elt: Node, delay?: number) => void; + const addClass: (elt: string | Element, clazz: string, delay?: number) => void; + const removeClass: (node: string | Node, clazz: string, delay?: number) => void; + const toggleClass: (elt: string | Element, clazz: string) => void; + const takeClass: (elt: string | Node, clazz: string) => void; + const swap: (target: string | Element, content: string, swapSpec: HtmxSwapSpecification, swapOptions?: SwapOptions) => void; + const defineExtension: (name: string, extension: any) => void; + const removeExtension: (name: string) => void; + const logAll: () => void; + const logNone: () => void; + const logger: any; + namespace config { + const historyEnabled: boolean; + const historyCacheSize: number; + const refreshOnHistoryMiss: boolean; + const defaultSwapStyle: HtmxSwapStyle; + const defaultSwapDelay: number; + const defaultSettleDelay: number; + const includeIndicatorStyles: boolean; + const indicatorClass: string; + const requestClass: string; + const addedClass: string; + const settlingClass: string; + const swappingClass: string; + const allowEval: boolean; + const allowScriptTags: boolean; + const inlineScriptNonce: string; + const inlineStyleNonce: string; + const attributesToSettle: string[]; + const withCredentials: boolean; + const timeout: number; + const wsReconnectDelay: "full-jitter" | ((retryCount: number) => number); + const wsBinaryType: BinaryType; + const disableSelector: string; + const scrollBehavior: 'auto' | 'instant' | 'smooth'; + const defaultFocusScroll: boolean; + const getCacheBusterParam: boolean; + const globalViewTransitions: boolean; + const methodsThatUseUrlParams: (HttpVerb)[]; + const selfRequestsOnly: boolean; + const ignoreTitle: boolean; + const scrollIntoViewOnBoost: boolean; + const triggerSpecsCache: any | null; + const disableInheritance: boolean; + const responseHandling: HtmxResponseHandlingConfig[]; + const allowNestedOobSwaps: boolean; + } + const parseInterval: (str: string) => number; + const _: (str: string) => any; + const version: string; +} +type HttpVerb = 'get' | 'head' | 'post' | 'put' | 'delete' | 'connect' | 'options' | 'trace' | 'patch'; +type SwapOptions = { + select?: string; + selectOOB?: string; + eventInfo?: any; + anchor?: string; + contextElement?: Element; + afterSwapCallback?: swapCallback; + afterSettleCallback?: swapCallback; +}; +type swapCallback = () => any; +type HtmxSwapStyle = 'innerHTML' | 'outerHTML' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'delete' | 'none' | string; +type HtmxSwapSpecification = { + swapStyle: HtmxSwapStyle; + swapDelay: number; + settleDelay: number; + transition?: boolean; + ignoreTitle?: boolean; + head?: string; + scroll?: 'top' | 'bottom'; + scrollTarget?: string; + show?: string; + showTarget?: string; + focusScroll?: boolean; +}; +type ConditionalFunction = ((this: Node, evt: Event) => boolean) & { + source: string; +}; +type HtmxTriggerSpecification = { + trigger: string; + pollInterval?: number; + eventFilter?: ConditionalFunction; + changed?: boolean; + once?: boolean; + consume?: boolean; + delay?: number; + from?: string; + target?: string; + throttle?: number; + queue?: string; + root?: string; + threshold?: string; +}; +type HtmxElementValidationError = { + elt: Element; + message: string; + validity: ValidityState; +}; +type HtmxHeaderSpecification = Record<string, string>; +type HtmxAjaxHelperContext = { + source?: Element | string; + event?: Event; + handler?: HtmxAjaxHandler; + target: Element | string; + swap?: HtmxSwapStyle; + values?: any | FormData; + headers?: Record<string, string>; + select?: string; +}; +type HtmxRequestConfig = { + boosted: boolean; + useUrlParams: boolean; + formData: FormData; + /** + * formData proxy + */ + parameters: any; + unfilteredFormData: FormData; + /** + * unfilteredFormData proxy + */ + unfilteredParameters: any; + headers: HtmxHeaderSpecification; + target: Element; + verb: HttpVerb; + errors: HtmxElementValidationError[]; + withCredentials: boolean; + timeout: number; + path: string; + triggeringEvent: Event; +}; +type HtmxResponseInfo = { + xhr: XMLHttpRequest; + target: Element; + requestConfig: HtmxRequestConfig; + etc: HtmxAjaxEtc; + boosted: boolean; + select: string; + pathInfo: { + requestPath: string; + finalRequestPath: string; + responsePath: string | null; + anchor: string; + }; + failed?: boolean; + successful?: boolean; +}; +type HtmxAjaxEtc = { + returnPromise?: boolean; + handler?: HtmxAjaxHandler; + select?: string; + targetOverride?: Element; + swapOverride?: HtmxSwapStyle; + headers?: Record<string, string>; + values?: any | FormData; + credentials?: boolean; + timeout?: number; +}; +type HtmxResponseHandlingConfig = { + code?: string; + swap: boolean; + error?: boolean; + ignoreTitle?: boolean; + select?: string; + target?: string; + swapOverride?: string; + event?: string; +}; +type HtmxBeforeSwapDetails = HtmxResponseInfo & { + shouldSwap: boolean; + serverResponse: any; + isError: boolean; + ignoreTitle: boolean; + selectOverride: string; +}; +type HtmxAjaxHandler = (elt: Element, responseInfo: HtmxResponseInfo) => any; +type HtmxSettleTask = (() => void); +type HtmxSettleInfo = { + tasks: HtmxSettleTask[]; + elts: Element[]; + title?: string; +}; +type HtmxExtension = any; diff --git a/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.js b/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.js index 86e7668..c57bcd7 100644 --- a/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.js +++ b/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.js @@ -1,3909 +1,5131 @@ -// /////////////////////////////////////////////////////////////////// -// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.js -// - -// UMD insanity -// This code sets up support for (in order) AMD, ES6 modules, and globals. -(function (root, factory) { - //@ts-ignore - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - //@ts-ignore - define([], factory); - } else if (typeof module === 'object' && module.exports) { - // Node. Does not work with strict CommonJS, but - // only CommonJS-like environments that support module.exports, - // like Node. - module.exports = factory(); - } else { - // Browser globals - root.htmx = root.htmx || factory(); - } -}(typeof self !== 'undefined' ? self : this, function () { -return (function () { - 'use strict'; - - // Public API - //** @type {import("./htmx").HtmxApi} */ - // TODO: list all methods in public API - var htmx = { - onLoad: onLoadHelper, - process: processNode, - on: addEventListenerImpl, - off: removeEventListenerImpl, - trigger : triggerEvent, - ajax : ajaxHelper, - find : find, - findAll : findAll, - closest : closest, - values : function(elt, type){ - var inputValues = getInputValues(elt, type || "post"); - return inputValues.values; - }, - remove : removeElement, - addClass : addClassToElement, - removeClass : removeClassFromElement, - toggleClass : toggleClassOnElement, - takeClass : takeClassForElement, - defineExtension : defineExtension, - removeExtension : removeExtension, - logAll : logAll, - logNone : logNone, - logger : null, - config : { - historyEnabled:true, - historyCacheSize:10, - refreshOnHistoryMiss:false, - defaultSwapStyle:'innerHTML', - defaultSwapDelay:0, - defaultSettleDelay:20, - includeIndicatorStyles:true, - indicatorClass:'htmx-indicator', - requestClass:'htmx-request', - addedClass:'htmx-added', - settlingClass:'htmx-settling', - swappingClass:'htmx-swapping', - allowEval:true, - allowScriptTags:true, - inlineScriptNonce:'', - attributesToSettle:["class", "style", "width", "height"], - withCredentials:false, - timeout:0, - wsReconnectDelay: 'full-jitter', - wsBinaryType: 'blob', - disableSelector: "[hx-disable], [data-hx-disable]", - useTemplateFragments: false, - scrollBehavior: 'smooth', - defaultFocusScroll: false, - getCacheBusterParam: false, - globalViewTransitions: false, - methodsThatUseUrlParams: ["get"], - selfRequestsOnly: false, - ignoreTitle: false, - scrollIntoViewOnBoost: true, - triggerSpecsCache: null, - }, - parseInterval:parseInterval, - _:internalEval, - createEventSource: function(url){ - return new EventSource(url, {withCredentials:true}) - }, - createWebSocket: function(url){ - var sock = new WebSocket(url, []); - sock.binaryType = htmx.config.wsBinaryType; - return sock; - }, - version: "1.9.10" - }; - - /** @type {import("./htmx").HtmxInternalApi} */ - var internalAPI = { - addTriggerHandler: addTriggerHandler, - bodyContains: bodyContains, - canAccessLocalStorage: canAccessLocalStorage, - findThisElement: findThisElement, - filterValues: filterValues, - hasAttribute: hasAttribute, - getAttributeValue: getAttributeValue, - getClosestAttributeValue: getClosestAttributeValue, - getClosestMatch: getClosestMatch, - getExpressionVars: getExpressionVars, - getHeaders: getHeaders, - getInputValues: getInputValues, - getInternalData: getInternalData, - getSwapSpecification: getSwapSpecification, - getTriggerSpecs: getTriggerSpecs, - getTarget: getTarget, - makeFragment: makeFragment, - mergeObjects: mergeObjects, - makeSettleInfo: makeSettleInfo, - oobSwap: oobSwap, - querySelectorExt: querySelectorExt, - selectAndSwap: selectAndSwap, - settleImmediately: settleImmediately, - shouldCancel: shouldCancel, - triggerEvent: triggerEvent, - triggerErrorEvent: triggerErrorEvent, - withExtensions: withExtensions, - } - - var VERBS = ['get', 'post', 'put', 'delete', 'patch']; - var VERB_SELECTOR = VERBS.map(function(verb){ - return "[hx-" + verb + "], [data-hx-" + verb + "]" - }).join(", "); - - var HEAD_TAG_REGEX = makeTagRegEx('head'), - TITLE_TAG_REGEX = makeTagRegEx('title'), - SVG_TAGS_REGEX = makeTagRegEx('svg', true); - - //==================================================================== - // Utilities - //==================================================================== - - /** - * @param {string} tag - * @param {boolean} global - * @returns {RegExp} - */ - function makeTagRegEx(tag, global = false) { - return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, - global ? 'gim' : 'im'); - } - - function parseInterval(str) { - if (str == undefined) { - return undefined; - } - - let interval = NaN; - if (str.slice(-2) == "ms") { - interval = parseFloat(str.slice(0, -2)); - } else if (str.slice(-1) == "s") { - interval = parseFloat(str.slice(0, -1)) * 1000; - } else if (str.slice(-1) == "m") { - interval = parseFloat(str.slice(0, -1)) * 1000 * 60; - } else { - interval = parseFloat(str); - } - return isNaN(interval) ? undefined : interval; - } - - /** - * @param {HTMLElement} elt - * @param {string} name - * @returns {(string | null)} - */ - function getRawAttribute(elt, name) { - return elt.getAttribute && elt.getAttribute(name); - } - - // resolve with both hx and data-hx prefixes - function hasAttribute(elt, qualifiedName) { - return elt.hasAttribute && (elt.hasAttribute(qualifiedName) || - elt.hasAttribute("data-" + qualifiedName)); - } - - /** - * - * @param {HTMLElement} elt - * @param {string} qualifiedName - * @returns {(string | null)} - */ - function getAttributeValue(elt, qualifiedName) { - return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); - } - - /** - * @param {HTMLElement} elt - * @returns {HTMLElement | null} - */ - function parentElt(elt) { - return elt.parentElement; - } - - /** - * @returns {Document} - */ - function getDocument() { - return document; - } - - /** - * @param {HTMLElement} elt - * @param {(e:HTMLElement) => boolean} condition - * @returns {HTMLElement | null} - */ - function getClosestMatch(elt, condition) { - while (elt && !condition(elt)) { - elt = parentElt(elt); - } - - return elt ? elt : null; - } - - function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ - var attributeValue = getAttributeValue(ancestor, attributeName); - var disinherit = getAttributeValue(ancestor, "hx-disinherit"); - if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) { - return "unset"; - } else { - return attributeValue - } - } - - /** - * @param {HTMLElement} elt - * @param {string} attributeName - * @returns {string | null} - */ - function getClosestAttributeValue(elt, attributeName) { - var closestAttr = null; - getClosestMatch(elt, function (e) { - return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName); - }); - if (closestAttr !== "unset") { - return closestAttr; - } - } - - /** - * @param {HTMLElement} elt - * @param {string} selector - * @returns {boolean} - */ - function matches(elt, selector) { - // @ts-ignore: non-standard properties for browser compatibility - // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; - return matchesFunction && matchesFunction.call(elt, selector); - } - - /** - * @param {string} str - * @returns {string} - */ - 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 ""; - } - } - - /** - * - * @param {string} resp - * @param {number} depth - * @returns {Element} - */ - function parseHTML(resp, depth) { - var parser = new DOMParser(); - var responseDoc = parser.parseFromString(resp, "text/html"); - - /** @type {Element} */ - var responseNode = responseDoc.body; - while (depth > 0) { - depth--; - // @ts-ignore - responseNode = responseNode.firstChild; - } - if (responseNode == null) { - // @ts-ignore - responseNode = getDocument().createDocumentFragment(); - } - return responseNode; - } - - function aFullPageResponse(resp) { - return /<body/.test(resp) - } +// v2.0.0 from https://github.com/bigskysoftware/htmx/releases + +var htmx = (function() { + 'use strict' + + // Public API + const htmx = { + // Tsc madness here, assigning the functions directly results in an invalid TypeScript output, but reassigning is fine + /* Event processing */ + /** @type {typeof onLoadHelper} */ + onLoad: null, + /** @type {typeof processNode} */ + process: null, + /** @type {typeof addEventListenerImpl} */ + on: null, + /** @type {typeof removeEventListenerImpl} */ + off: null, + /** @type {typeof triggerEvent} */ + trigger: null, + /** @type {typeof ajaxHelper} */ + ajax: null, + /* DOM querying helpers */ + /** @type {typeof find} */ + find: null, + /** @type {typeof findAll} */ + findAll: null, + /** @type {typeof closest} */ + closest: null, + /** + * Returns the input values that would resolve for a given element via the htmx value resolution mechanism + * + * @see https://htmx.org/api/#values + * + * @param {Element} elt the element to resolve values on + * @param {HttpVerb} type the request type (e.g. **get** or **post**) non-GET's will include the enclosing form of the element. Defaults to **post** + * @returns {Object} + */ + values: function(elt, type) { + const inputValues = getInputValues(elt, type || 'post') + return inputValues.values + }, + /* DOM manipulation helpers */ + /** @type {typeof removeElement} */ + remove: null, + /** @type {typeof addClassToElement} */ + addClass: null, + /** @type {typeof removeClassFromElement} */ + removeClass: null, + /** @type {typeof toggleClassOnElement} */ + toggleClass: null, + /** @type {typeof takeClassForElement} */ + takeClass: null, + /** @type {typeof swap} */ + swap: null, + /* Extension entrypoints */ + /** @type {typeof defineExtension} */ + defineExtension: null, + /** @type {typeof removeExtension} */ + removeExtension: null, + /* Debugging */ + /** @type {typeof logAll} */ + logAll: null, + /** @type {typeof logNone} */ + logNone: null, + /* Debugging */ + /** + * The logger htmx uses to log with + * + * @see https://htmx.org/api/#logger + */ + logger: null, + /** + * A property holding the configuration htmx uses at runtime. + * + * Note that using a [meta tag](https://htmx.org/docs/#config) is the preferred mechanism for setting these properties. + * + * @see https://htmx.org/api/#config + */ + config: { + /** + * Whether to use history. + * @type boolean + * @default true + */ + historyEnabled: true, + /** + * The number of pages to keep in **localStorage** for history support. + * @type number + * @default 10 + */ + historyCacheSize: 10, + /** + * @type boolean + * @default false + */ + refreshOnHistoryMiss: false, + /** + * The default swap style to use if **[hx-swap](https://htmx.org/attributes/hx-swap)** is omitted. + * @type HtmxSwapStyle + * @default 'innerHTML' + */ + defaultSwapStyle: 'innerHTML', + /** + * The default delay between receiving a response from the server and doing the swap. + * @type number + * @default 0 + */ + defaultSwapDelay: 0, + /** + * The default delay between completing the content swap and settling attributes. + * @type number + * @default 20 + */ + defaultSettleDelay: 20, + /** + * If true, htmx will inject a small amount of CSS into the page to make indicators invisible unless the **htmx-indicator** class is present. + * @type boolean + * @default true + */ + includeIndicatorStyles: true, + /** + * The class to place on indicators when a request is in flight. + * @type string + * @default 'htmx-indicator' + */ + indicatorClass: 'htmx-indicator', + /** + * The class to place on triggering elements when a request is in flight. + * @type string + * @default 'htmx-request' + */ + requestClass: 'htmx-request', + /** + * The class to temporarily place on elements that htmx has added to the DOM. + * @type string + * @default 'htmx-added' + */ + addedClass: 'htmx-added', + /** + * The class to place on target elements when htmx is in the settling phase. + * @type string + * @default 'htmx-settling' + */ + settlingClass: 'htmx-settling', + /** + * The class to place on target elements when htmx is in the swapping phase. + * @type string + * @default 'htmx-swapping' + */ + swappingClass: 'htmx-swapping', + /** + * Allows the use of eval-like functionality in htmx, to enable **hx-vars**, trigger conditions & script tag evaluation. Can be set to **false** for CSP compatibility. + * @type boolean + * @default true + */ + allowEval: true, + /** + * If set to false, disables the interpretation of script tags. + * @type boolean + * @default true + */ + allowScriptTags: true, + /** + * If set, the nonce will be added to inline scripts. + * @type string + * @default '' + */ + inlineScriptNonce: '', + /** + * If set, the nonce will be added to inline styles. + * @type string + * @default '' + */ + inlineStyleNonce: '', + /** + * The attributes to settle during the settling phase. + * @type string[] + * @default ['class', 'style', 'width', 'height'] + */ + attributesToSettle: ['class', 'style', 'width', 'height'], + /** + * Allow cross-site Access-Control requests using credentials such as cookies, authorization headers or TLS client certificates. + * @type boolean + * @default false + */ + withCredentials: false, + /** + * @type number + * @default 0 + */ + timeout: 0, + /** + * The default implementation of **getWebSocketReconnectDelay** for reconnecting after unexpected connection loss by the event code **Abnormal Closure**, **Service Restart** or **Try Again Later**. + * @type {'full-jitter' | ((retryCount:number) => number)} + * @default "full-jitter" + */ + wsReconnectDelay: 'full-jitter', + /** + * The type of binary data being received over the WebSocket connection + * @type BinaryType + * @default 'blob' + */ + wsBinaryType: 'blob', + /** + * @type string + * @default '[hx-disable], [data-hx-disable]' + */ + disableSelector: '[hx-disable], [data-hx-disable]', + /** + * @type {'auto' | 'instant' | 'smooth'} + * @default 'smooth' + */ + scrollBehavior: 'instant', + /** + * If the focused element should be scrolled into view. + * @type boolean + * @default false + */ + defaultFocusScroll: false, + /** + * If set to true htmx will include a cache-busting parameter in GET requests to avoid caching partial responses by the browser + * @type boolean + * @default false + */ + getCacheBusterParam: false, + /** + * If set to true, htmx will use the View Transition API when swapping in new content. + * @type boolean + * @default false + */ + globalViewTransitions: false, + /** + * htmx will format requests with these methods by encoding their parameters in the URL, not the request body + * @type {(HttpVerb)[]} + * @default ['get', 'delete'] + */ + methodsThatUseUrlParams: ['get', 'delete'], + /** + * If set to true, disables htmx-based requests to non-origin hosts. + * @type boolean + * @default false + */ + selfRequestsOnly: true, + /** + * If set to true htmx will not update the title of the document when a title tag is found in new content + * @type boolean + * @default false + */ + ignoreTitle: false, + /** + * Whether the target of a boosted element is scrolled into the viewport. + * @type boolean + * @default true + */ + scrollIntoViewOnBoost: true, + /** + * The cache to store evaluated trigger specifications into. + * You may define a simple object to use a never-clearing cache, or implement your own system using a [proxy object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Proxy) + * @type {Object|null} + * @default null + */ + triggerSpecsCache: null, + /** @type boolean */ + disableInheritance: false, + /** @type HtmxResponseHandlingConfig[] */ + responseHandling: [ + { code: '204', swap: false }, + { code: '[23]..', swap: true }, + { code: '[45]..', swap: false, error: true } + ], + /** + * Whether to process OOB swaps on elements that are nested within the main response element. + * @type boolean + * @default true + */ + allowNestedOobSwaps: true + }, + /** @type {typeof parseInterval} */ + parseInterval: null, + /** @type {typeof internalEval} */ + _: null, + version: '2.0.0' + } + // Tsc madness part 2 + htmx.onLoad = onLoadHelper + htmx.process = processNode + htmx.on = addEventListenerImpl + htmx.off = removeEventListenerImpl + htmx.trigger = triggerEvent + htmx.ajax = ajaxHelper + htmx.find = find + htmx.findAll = findAll + htmx.closest = closest + htmx.remove = removeElement + htmx.addClass = addClassToElement + htmx.removeClass = removeClassFromElement + htmx.toggleClass = toggleClassOnElement + htmx.takeClass = takeClassForElement + htmx.swap = swap + htmx.defineExtension = defineExtension + htmx.removeExtension = removeExtension + htmx.logAll = logAll + htmx.logNone = logNone + htmx.parseInterval = parseInterval + htmx._ = internalEval + + const internalAPI = { + addTriggerHandler, + bodyContains, + canAccessLocalStorage, + findThisElement, + filterValues, + swap, + hasAttribute, + getAttributeValue, + getClosestAttributeValue, + getClosestMatch, + getExpressionVars, + getHeaders, + getInputValues, + getInternalData, + getSwapSpecification, + getTriggerSpecs, + getTarget, + makeFragment, + mergeObjects, + makeSettleInfo, + oobSwap, + querySelectorExt, + settleImmediately, + shouldCancel, + triggerEvent, + triggerErrorEvent, + withExtensions + } + + const VERBS = ['get', 'post', 'put', 'delete', 'patch'] + const VERB_SELECTOR = VERBS.map(function(verb) { + return '[hx-' + verb + '], [data-hx-' + verb + ']' + }).join(', ') + + const HEAD_TAG_REGEX = makeTagRegEx('head') + + //= =================================================================== + // Utilities + //= =================================================================== + + /** + * @param {string} tag + * @param {boolean} global + * @returns {RegExp} + */ + function makeTagRegEx(tag, global = false) { + return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, + global ? 'gim' : 'im') + } + + /** + * Parses an interval string consistent with the way htmx does. Useful for plugins that have timing-related attributes. + * + * Caution: Accepts an int followed by either **s** or **ms**. All other values use **parseFloat** + * + * @see https://htmx.org/api/#parseInterval + * + * @param {string} str timing string + * @returns {number|undefined} + */ + function parseInterval(str) { + if (str == undefined) { + return undefined + } - /** - * - * @param {string} response - * @returns {Element} - */ - function makeFragment(response) { - var partialResponse = !aFullPageResponse(response); - var startTag = getStartTag(response); - var content = response; - if (startTag === 'head') { - content = content.replace(HEAD_TAG_REGEX, ''); - } - if (htmx.config.useTemplateFragments && partialResponse) { - var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0); - // @ts-ignore type mismatch between DocumentFragment and Element. - // TODO: Are these close enough for htmx to use interchangeably? - return documentFragment.querySelector('template').content; - } - switch (startTag) { - case "thead": - case "tbody": - case "tfoot": - case "colgroup": - case "caption": - return parseHTML("<table>" + content + "</table>", 1); - case "col": - return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2); - case "tr": - return parseHTML("<table><tbody>" + content + "</tbody></table>", 2); - case "td": - case "th": - return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3); - case "script": - case "style": - return parseHTML("<div>" + content + "</div>", 1); - default: - return parseHTML(content, 0); - } - } + let interval = NaN + if (str.slice(-2) == 'ms') { + interval = parseFloat(str.slice(0, -2)) + } else if (str.slice(-1) == 's') { + interval = parseFloat(str.slice(0, -1)) * 1000 + } else if (str.slice(-1) == 'm') { + interval = parseFloat(str.slice(0, -1)) * 1000 * 60 + } else { + interval = parseFloat(str) + } + return isNaN(interval) ? undefined : interval + } + + /** + * @param {Node} elt + * @param {string} name + * @returns {(string | null)} + */ + function getRawAttribute(elt, name) { + return elt instanceof Element && elt.getAttribute(name) + } + + /** + * @param {Element} elt + * @param {string} qualifiedName + * @returns {boolean} + */ + // resolve with both hx and data-hx prefixes + function hasAttribute(elt, qualifiedName) { + return !!elt.hasAttribute && (elt.hasAttribute(qualifiedName) || + elt.hasAttribute('data-' + qualifiedName)) + } + + /** + * + * @param {Node} elt + * @param {string} qualifiedName + * @returns {(string | null)} + */ + function getAttributeValue(elt, qualifiedName) { + return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, 'data-' + qualifiedName) + } + + /** + * @param {Node} elt + * @returns {Node | null} + */ + function parentElt(elt) { + const parent = elt.parentElement + if (!parent && elt.parentNode instanceof ShadowRoot) return elt.parentNode + return parent + } + + /** + * @returns {Document} + */ + function getDocument() { + return document + } + + /** + * @param {Node} elt + * @param {boolean} global + * @returns {Node|Document} + */ + function getRootNode(elt, global) { + return elt.getRootNode ? elt.getRootNode({ composed: global }) : getDocument() + } + + /** + * @param {Node} elt + * @param {(e:Node) => boolean} condition + * @returns {Node | null} + */ + function getClosestMatch(elt, condition) { + while (elt && !condition(elt)) { + elt = parentElt(elt) + } - /** - * @param {Function} func - */ - function maybeCall(func){ - if(func) { - func(); - } + return elt || null + } + + /** + * @param {Element} initialElement + * @param {Element} ancestor + * @param {string} attributeName + * @returns {string|null} + */ + function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName) { + const attributeValue = getAttributeValue(ancestor, attributeName) + const disinherit = getAttributeValue(ancestor, 'hx-disinherit') + var inherit = getAttributeValue(ancestor, 'hx-inherit') + if (initialElement !== ancestor) { + if (htmx.config.disableInheritance) { + if (inherit && (inherit === '*' || inherit.split(' ').indexOf(attributeName) >= 0)) { + return attributeValue + } else { + return null + } + } + if (disinherit && (disinherit === '*' || disinherit.split(' ').indexOf(attributeName) >= 0)) { + return 'unset' + } + } + return attributeValue + } + + /** + * @param {Element} elt + * @param {string} attributeName + * @returns {string | null} + */ + function getClosestAttributeValue(elt, attributeName) { + let closestAttr = null + getClosestMatch(elt, function(e) { + return !!(closestAttr = getAttributeValueWithDisinheritance(elt, asElement(e), attributeName)) + }) + if (closestAttr !== 'unset') { + return closestAttr + } + } + + /** + * @param {Node} elt + * @param {string} selector + * @returns {boolean} + */ + function matches(elt, selector) { + // @ts-ignore: non-standard properties for browser compatibility + // noinspection JSUnresolvedVariable + const matchesFunction = elt instanceof Element && (elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector) + return !!matchesFunction && matchesFunction.call(elt, selector) + } + + /** + * @param {string} str + * @returns {string} + */ + function getStartTag(str) { + const tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i + const match = tagMatcher.exec(str) + if (match) { + return match[1].toLowerCase() + } else { + return '' + } + } + + /** + * @param {string} resp + * @returns {Document} + */ + function parseHTML(resp) { + const parser = new DOMParser() + return parser.parseFromString(resp, 'text/html') + } + + /** + * @param {DocumentFragment} fragment + * @param {Node} elt + */ + function takeChildrenFor(fragment, elt) { + while (elt.childNodes.length > 0) { + fragment.append(elt.childNodes[0]) + } + } + + /** + * @param {HTMLScriptElement} script + * @returns {HTMLScriptElement} + */ + function duplicateScript(script) { + const newScript = getDocument().createElement('script') + forEach(script.attributes, function(attr) { + newScript.setAttribute(attr.name, attr.value) + }) + newScript.textContent = script.textContent + newScript.async = false + if (htmx.config.inlineScriptNonce) { + newScript.nonce = htmx.config.inlineScriptNonce + } + return newScript + } + + /** + * @param {HTMLScriptElement} script + * @returns {boolean} + */ + function isJavaScriptScriptNode(script) { + return script.matches('script') && (script.type === 'text/javascript' || script.type === 'module' || script.type === '') + } + + /** + * we have to make new copies of script tags that we are going to insert because + * SOME browsers (not saying who, but it involves an element and an animal) don't + * execute scripts created in <template> tags when they are inserted into the DOM + * and all the others do lmao + * @param {DocumentFragment} fragment + */ + function normalizeScriptTags(fragment) { + Array.from(fragment.querySelectorAll('script')).forEach(/** @param {HTMLScriptElement} script */ (script) => { + if (isJavaScriptScriptNode(script)) { + const newScript = duplicateScript(script) + const parent = script.parentNode + try { + parent.insertBefore(newScript, script) + } catch (e) { + logError(e) + } finally { + script.remove() + } + } + }) + } + + /** + * @typedef {DocumentFragment & {title?: string}} DocumentFragmentWithTitle + * @description a document fragment representing the response HTML, including + * a `title` property for any title information found + */ + + /** + * @param {string} response HTML + * @returns {DocumentFragmentWithTitle} + */ + function makeFragment(response) { + // strip head tag to determine shape of response we are dealing with + const responseWithNoHead = response.replace(HEAD_TAG_REGEX, '') + const startTag = getStartTag(responseWithNoHead) + /** @type DocumentFragmentWithTitle */ + let fragment + if (startTag === 'html') { + // if it is a full document, parse it and return the body + fragment = /** @type DocumentFragmentWithTitle */ (new DocumentFragment()) + const doc = parseHTML(response) + takeChildrenFor(fragment, doc.body) + fragment.title = doc.title + } else if (startTag === 'body') { + // parse body w/o wrapping in template + fragment = /** @type DocumentFragmentWithTitle */ (new DocumentFragment()) + const doc = parseHTML(responseWithNoHead) + takeChildrenFor(fragment, doc.body) + fragment.title = doc.title + } else { + // otherwise we have non-body partial HTML content, so wrap it in a template to maximize parsing flexibility + const doc = parseHTML('<body><template class="internal-htmx-wrapper">' + responseWithNoHead + '</template></body>') + fragment = /** @type DocumentFragmentWithTitle */ (doc.querySelector('template').content) + // extract title into fragment for later processing + fragment.title = doc.title + + // for legacy reasons we support a title tag at the root level of non-body responses, so we need to handle it + var titleElement = fragment.querySelector('title') + if (titleElement && titleElement.parentNode === fragment) { + titleElement.remove() + fragment.title = titleElement.innerText + } + } + if (fragment) { + if (htmx.config.allowScriptTags) { + normalizeScriptTags(fragment) + } else { + // remove all script tags if scripts are disabled + fragment.querySelectorAll('script').forEach((script) => script.remove()) + } + } + return fragment + } + + /** + * @param {Function} func + */ + function maybeCall(func) { + if (func) { + func() + } + } + + /** + * @param {any} o + * @param {string} type + * @returns + */ + function isType(o, type) { + return Object.prototype.toString.call(o) === '[object ' + type + ']' + } + + /** + * @param {*} o + * @returns {o is Function} + */ + function isFunction(o) { + return typeof o === 'function' + } + + /** + * @param {*} o + * @returns {o is Object} + */ + function isRawObject(o) { + return isType(o, 'Object') + } + + /** + * @typedef {Object} OnHandler + * @property {(keyof HTMLElementEventMap)|string} event + * @property {EventListener} listener + */ + + /** + * @typedef {Object} ListenerInfo + * @property {string} trigger + * @property {EventListener} listener + * @property {EventTarget} on + */ + + /** + * @typedef {Object} HtmxNodeInternalData + * Element data + * @property {number} [initHash] + * @property {boolean} [boosted] + * @property {OnHandler[]} [onHandlers] + * @property {number} [timeout] + * @property {ListenerInfo[]} [listenerInfos] + * @property {boolean} [cancelled] + * @property {boolean} [triggeredOnce] + * @property {number} [delayed] + * @property {number|null} [throttle] + * @property {string} [lastValue] + * @property {boolean} [loaded] + * @property {string} [path] + * @property {string} [verb] + * @property {boolean} [polling] + * @property {HTMLButtonElement|HTMLInputElement|null} [lastButtonClicked] + * @property {number} [requestCount] + * @property {XMLHttpRequest} [xhr] + * @property {(() => void)[]} [queuedRequests] + * @property {boolean} [abortable] + * + * Event data + * @property {HtmxTriggerSpecification} [triggerSpec] + * @property {EventTarget[]} [handledFor] + */ + + /** + * getInternalData retrieves "private" data stored by htmx within an element + * @param {EventTarget|Event} elt + * @returns {HtmxNodeInternalData} + */ + function getInternalData(elt) { + const dataProp = 'htmx-internal-data' + let data = elt[dataProp] + if (!data) { + data = elt[dataProp] = {} + } + return data + } + + /** + * toArray converts an ArrayLike object into a real array. + * @template T + * @param {ArrayLike<T>} arr + * @returns {T[]} + */ + function toArray(arr) { + const returnArr = [] + if (arr) { + for (let i = 0; i < arr.length; i++) { + returnArr.push(arr[i]) + } + } + return returnArr + } + + /** + * @template T + * @param {T[]|NamedNodeMap|HTMLCollection|HTMLFormControlsCollection|ArrayLike<T>} arr + * @param {(T) => void} func + */ + function forEach(arr, func) { + if (arr) { + for (let i = 0; i < arr.length; i++) { + func(arr[i]) + } + } + } + + /** + * @param {Element} el + * @returns {boolean} + */ + function isScrolledIntoView(el) { + const rect = el.getBoundingClientRect() + const elemTop = rect.top + const elemBottom = rect.bottom + return elemTop < window.innerHeight && elemBottom >= 0 + } + + /** + * @param {Node} elt + * @returns {boolean} + */ + function bodyContains(elt) { + // IE Fix + const rootNode = elt.getRootNode && elt.getRootNode() + if (rootNode && rootNode instanceof window.ShadowRoot) { + return getDocument().body.contains(rootNode.host) + } else { + return getDocument().body.contains(elt) + } + } + + /** + * @param {string} trigger + * @returns {string[]} + */ + function splitOnWhitespace(trigger) { + return trigger.trim().split(/\s+/) + } + + /** + * mergeObjects takes all the keys from + * obj2 and duplicates them into obj1 + * @template T1 + * @template T2 + * @param {T1} obj1 + * @param {T2} obj2 + * @returns {T1 & T2} + */ + function mergeObjects(obj1, obj2) { + for (const key in obj2) { + if (obj2.hasOwnProperty(key)) { + // @ts-ignore tsc doesn't seem to properly handle types merging + obj1[key] = obj2[key] + } + } + // @ts-ignore tsc doesn't seem to properly handle types merging + return obj1 + } + + /** + * @param {string} jString + * @returns {any|null} + */ + function parseJSON(jString) { + try { + return JSON.parse(jString) + } catch (error) { + logError(error) + return null + } + } + + /** + * @returns {boolean} + */ + function canAccessLocalStorage() { + const test = 'htmx:localStorageTest' + try { + localStorage.setItem(test, test) + localStorage.removeItem(test) + return true + } catch (e) { + return false + } + } + + /** + * @param {string} path + * @returns {string} + */ + function normalizePath(path) { + try { + const url = new URL(path) + if (url) { + path = url.pathname + url.search + } + // remove trailing slash, unless index page + if (!(/^\/$/.test(path))) { + path = path.replace(/\/+$/, '') + } + return path + } catch (e) { + // be kind to IE11, which doesn't support URL() + return path + } + } + + //= ========================================================================================= + // public API + //= ========================================================================================= + + /** + * @param {string} str + * @returns {any} + */ + function internalEval(str) { + return maybeEval(getDocument().body, function() { + return eval(str) + }) + } + + /** + * Adds a callback for the **htmx:load** event. This can be used to process new content, for example initializing the content with a javascript library + * + * @see https://htmx.org/api/#onLoad + * + * @param {(elt: Node) => void} callback the callback to call on newly loaded content + * @returns {EventListener} + */ + function onLoadHelper(callback) { + const value = htmx.on('htmx:load', /** @param {CustomEvent} evt */ function(evt) { + callback(evt.detail.elt) + }) + return value + } + + /** + * Log all htmx events, useful for debugging. + * + * @see https://htmx.org/api/#logAll + */ + function logAll() { + htmx.logger = function(elt, event, data) { + if (console) { + console.log(event, elt, data) + } + } + } + + function logNone() { + htmx.logger = null + } + + /** + * Finds an element matching the selector + * + * @see https://htmx.org/api/#find + * + * @param {ParentNode|string} eltOrSelector the root element to find the matching element in, inclusive | the selector to match + * @param {string} [selector] the selector to match + * @returns {Element|null} + */ + function find(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return eltOrSelector.querySelector(selector) + } else { + return find(getDocument(), eltOrSelector) + } + } + + /** + * Finds all elements matching the selector + * + * @see https://htmx.org/api/#findAll + * + * @param {ParentNode|string} eltOrSelector the root element to find the matching elements in, inclusive | the selector to match + * @param {string} [selector] the selector to match + * @returns {NodeListOf<Element>} + */ + function findAll(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return eltOrSelector.querySelectorAll(selector) + } else { + return findAll(getDocument(), eltOrSelector) + } + } + + /** + * @returns Window + */ + function getWindow() { + return window + } + + /** + * Removes an element from the DOM + * + * @see https://htmx.org/api/#remove + * + * @param {Node} elt + * @param {number} [delay] + */ + function removeElement(elt, delay) { + elt = resolveTarget(elt) + if (delay) { + getWindow().setTimeout(function() { + removeElement(elt) + elt = null + }, delay) + } else { + parentElt(elt).removeChild(elt) + } + } + + /** + * @param {any} elt + * @return {Element|null} + */ + function asElement(elt) { + return elt instanceof Element ? elt : null + } + + /** + * @param {any} elt + * @return {HTMLElement|null} + */ + function asHtmlElement(elt) { + return elt instanceof HTMLElement ? elt : null + } + + /** + * @param {any} value + * @return {string|null} + */ + function asString(value) { + return typeof value === 'string' ? value : null + } + + /** + * @param {EventTarget} elt + * @return {ParentNode|null} + */ + function asParentNode(elt) { + return elt instanceof Element || elt instanceof Document || elt instanceof DocumentFragment ? elt : null + } + + /** + * This method adds a class to the given element. + * + * @see https://htmx.org/api/#addClass + * + * @param {Element|string} elt the element to add the class to + * @param {string} clazz the class to add + * @param {number} [delay] the delay (in milliseconds) before class is added + */ + function addClassToElement(elt, clazz, delay) { + elt = asElement(resolveTarget(elt)) + if (!elt) { + return + } + if (delay) { + getWindow().setTimeout(function() { + addClassToElement(elt, clazz) + elt = null + }, delay) + } else { + elt.classList && elt.classList.add(clazz) + } + } + + /** + * Removes a class from the given element + * + * @see https://htmx.org/api/#removeClass + * + * @param {Node|string} node element to remove the class from + * @param {string} clazz the class to remove + * @param {number} [delay] the delay (in milliseconds before class is removed) + */ + function removeClassFromElement(node, clazz, delay) { + let elt = asElement(resolveTarget(node)) + if (!elt) { + return + } + if (delay) { + getWindow().setTimeout(function() { + removeClassFromElement(elt, clazz) + elt = null + }, delay) + } else { + if (elt.classList) { + elt.classList.remove(clazz) + // if there are no classes left, remove the class attribute + if (elt.classList.length === 0) { + elt.removeAttribute('class') } + } + } + } + + /** + * Toggles the given class on an element + * + * @see https://htmx.org/api/#toggleClass + * + * @param {Element|string} elt the element to toggle the class on + * @param {string} clazz the class to toggle + */ + function toggleClassOnElement(elt, clazz) { + elt = resolveTarget(elt) + elt.classList.toggle(clazz) + } + + /** + * Takes the given class from its siblings, so that among its siblings, only the given element will have the class. + * + * @see https://htmx.org/api/#takeClass + * + * @param {Node|string} elt the element that will take the class + * @param {string} clazz the class to take + */ + function takeClassForElement(elt, clazz) { + elt = resolveTarget(elt) + forEach(elt.parentElement.children, function(child) { + removeClassFromElement(child, clazz) + }) + addClassToElement(asElement(elt), clazz) + } + + /** + * Finds the closest matching element in the given elements parentage, inclusive of the element + * + * @see https://htmx.org/api/#closest + * + * @param {Element|string} elt the element to find the selector from + * @param {string} selector the selector to find + * @returns {Element|null} + */ + function closest(elt, selector) { + elt = asElement(resolveTarget(elt)) + if (elt && elt.closest) { + return elt.closest(selector) + } else { + // TODO remove when IE goes away + do { + if (elt == null || matches(elt, selector)) { + return elt + } + } + while (elt = elt && asElement(parentElt(elt))) + return null + } + } + + /** + * @param {string} str + * @param {string} prefix + * @returns {boolean} + */ + function startsWith(str, prefix) { + return str.substring(0, prefix.length) === prefix + } + + /** + * @param {string} str + * @param {string} suffix + * @returns {boolean} + */ + function endsWith(str, suffix) { + return str.substring(str.length - suffix.length) === suffix + } + + /** + * @param {string} selector + * @returns {string} + */ + function normalizeSelector(selector) { + const trimmedSelector = selector.trim() + if (startsWith(trimmedSelector, '<') && endsWith(trimmedSelector, '/>')) { + return trimmedSelector.substring(1, trimmedSelector.length - 2) + } else { + return trimmedSelector + } + } + + /** + * @param {Node|Element|Document|string} elt + * @param {string} selector + * @param {boolean=} global + * @returns {(Node|Window)[]} + */ + function querySelectorAllExt(elt, selector, global) { + elt = resolveTarget(elt) + if (selector.indexOf('closest ') === 0) { + return [closest(asElement(elt), normalizeSelector(selector.substr(8)))] + } else if (selector.indexOf('find ') === 0) { + return [find(asParentNode(elt), normalizeSelector(selector.substr(5)))] + } else if (selector === 'next') { + return [asElement(elt).nextElementSibling] + } else if (selector.indexOf('next ') === 0) { + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)), !!global)] + } else if (selector === 'previous') { + return [asElement(elt).previousElementSibling] + } else if (selector.indexOf('previous ') === 0) { + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)), !!global)] + } else if (selector === 'document') { + return [document] + } else if (selector === 'window') { + return [window] + } else if (selector === 'body') { + return [document.body] + } else if (selector === 'root') { + return [getRootNode(elt, !!global)] + } else if (selector.indexOf('global ') === 0) { + return querySelectorAllExt(elt, selector.slice(7), true) + } else { + return toArray(asParentNode(getRootNode(elt, !!global)).querySelectorAll(normalizeSelector(selector))) + } + } + + /** + * @param {Node} start + * @param {string} match + * @param {boolean} global + * @returns {Element} + */ + var scanForwardQuery = function(start, match, global) { + const results = asParentNode(getRootNode(start, global)).querySelectorAll(match) + for (let i = 0; i < results.length; i++) { + const elt = results[i] + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { + return elt + } + } + } + + /** + * @param {Node} start + * @param {string} match + * @param {boolean} global + * @returns {Element} + */ + var scanBackwardsQuery = function(start, match, global) { + const results = asParentNode(getRootNode(start, global)).querySelectorAll(match) + for (let i = results.length - 1; i >= 0; i--) { + const elt = results[i] + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { + return elt + } + } + } + + /** + * @param {Node|string} eltOrSelector + * @param {string=} selector + * @returns {Node|Window} + */ + function querySelectorExt(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return querySelectorAllExt(eltOrSelector, selector)[0] + } else { + return querySelectorAllExt(getDocument().body, eltOrSelector)[0] + } + } + + /** + * @template {EventTarget} T + * @param {T|string} eltOrSelector + * @param {T} [context] + * @returns {Element|T|null} + */ + function resolveTarget(eltOrSelector, context) { + if (typeof eltOrSelector === 'string') { + return find(asParentNode(context) || document, eltOrSelector) + } else { + return eltOrSelector + } + } + + /** + * @typedef {keyof HTMLElementEventMap|string} AnyEventName + */ + + /** + * @typedef {Object} EventArgs + * @property {EventTarget} target + * @property {AnyEventName} event + * @property {EventListener} listener + */ + + /** + * @param {EventTarget|AnyEventName} arg1 + * @param {AnyEventName|EventListener} arg2 + * @param {EventListener} [arg3] + * @returns {EventArgs} + */ + function processEventArgs(arg1, arg2, arg3) { + if (isFunction(arg2)) { + return { + target: getDocument().body, + event: asString(arg1), + listener: arg2 + } + } else { + return { + target: resolveTarget(arg1), + event: asString(arg2), + listener: arg3 + } + } + } + + /** + * Adds an event listener to an element + * + * @see https://htmx.org/api/#on + * + * @param {EventTarget|string} arg1 the element to add the listener to | the event name to add the listener for + * @param {string|EventListener} arg2 the event name to add the listener for | the listener to add + * @param {EventListener} [arg3] the listener to add + * @returns {EventListener} + */ + function addEventListenerImpl(arg1, arg2, arg3) { + ready(function() { + const eventArgs = processEventArgs(arg1, arg2, arg3) + eventArgs.target.addEventListener(eventArgs.event, eventArgs.listener) + }) + const b = isFunction(arg2) + return b ? arg2 : arg3 + } + + /** + * Removes an event listener from an element + * + * @see https://htmx.org/api/#off + * + * @param {EventTarget|string} arg1 the element to remove the listener from | the event name to remove the listener from + * @param {string|EventListener} arg2 the event name to remove the listener from | the listener to remove + * @param {EventListener} [arg3] the listener to remove + * @returns {EventListener} + */ + function removeEventListenerImpl(arg1, arg2, arg3) { + ready(function() { + const eventArgs = processEventArgs(arg1, arg2, arg3) + eventArgs.target.removeEventListener(eventArgs.event, eventArgs.listener) + }) + return isFunction(arg2) ? arg2 : arg3 + } + + //= =================================================================== + // Node processing + //= =================================================================== + + const DUMMY_ELT = getDocument().createElement('output') // dummy element for bad selectors + /** + * @param {Element} elt + * @param {string} attrName + * @returns {(Node|Window)[]} + */ + function findAttributeTargets(elt, attrName) { + const attrTarget = getClosestAttributeValue(elt, attrName) + if (attrTarget) { + if (attrTarget === 'this') { + return [findThisElement(elt, attrName)] + } else { + const result = querySelectorAllExt(elt, attrTarget) + if (result.length === 0) { + logError('The selector "' + attrTarget + '" on ' + attrName + ' returned no matches!') + return [DUMMY_ELT] + } else { + return result + } + } + } + } + + /** + * @param {Element} elt + * @param {string} attribute + * @returns {Element|null} + */ + function findThisElement(elt, attribute) { + return asElement(getClosestMatch(elt, function(elt) { + return getAttributeValue(asElement(elt), attribute) != null + })) + } + + /** + * @param {Element} elt + * @returns {Node|Window|null} + */ + function getTarget(elt) { + const targetStr = getClosestAttributeValue(elt, 'hx-target') + if (targetStr) { + if (targetStr === 'this') { + return findThisElement(elt, 'hx-target') + } else { + return querySelectorExt(elt, targetStr) + } + } else { + const data = getInternalData(elt) + if (data.boosted) { + return getDocument().body + } else { + return elt + } + } + } + + /** + * @param {string} name + * @returns {boolean} + */ + function shouldSettleAttribute(name) { + const attributesToSettle = htmx.config.attributesToSettle + for (let i = 0; i < attributesToSettle.length; i++) { + if (name === attributesToSettle[i]) { + return true + } + } + return false + } + + /** + * @param {Element} mergeTo + * @param {Element} mergeFrom + */ + function cloneAttributes(mergeTo, mergeFrom) { + forEach(mergeTo.attributes, function(attr) { + if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) { + mergeTo.removeAttribute(attr.name) + } + }) + forEach(mergeFrom.attributes, function(attr) { + if (shouldSettleAttribute(attr.name)) { + mergeTo.setAttribute(attr.name, attr.value) + } + }) + } + + /** + * @param {HtmxSwapStyle} swapStyle + * @param {Element} target + * @returns {boolean} + */ + function isInlineSwap(swapStyle, target) { + const extensions = getExtensions(target) + for (let i = 0; i < extensions.length; i++) { + const extension = extensions[i] + try { + if (extension.isInlineSwap(swapStyle)) { + return true + } + } catch (e) { + logError(e) + } + } + return swapStyle === 'outerHTML' + } + + /** + * @param {string} oobValue + * @param {Element} oobElement + * @param {HtmxSettleInfo} settleInfo + * @returns + */ + function oobSwap(oobValue, oobElement, settleInfo) { + let selector = '#' + getRawAttribute(oobElement, 'id') + /** @type HtmxSwapStyle */ + let swapStyle = 'outerHTML' + if (oobValue === 'true') { + // do nothing + } else if (oobValue.indexOf(':') > 0) { + swapStyle = oobValue.substr(0, oobValue.indexOf(':')) + selector = oobValue.substr(oobValue.indexOf(':') + 1, oobValue.length) + } else { + swapStyle = oobValue + } - /** - * @param {any} o - * @param {string} type - * @returns - */ - function isType(o, type) { - return Object.prototype.toString.call(o) === "[object " + type + "]"; - } - - /** - * @param {*} o - * @returns {o is Function} - */ - function isFunction(o) { - return isType(o, "Function"); - } - - /** - * @param {*} o - * @returns {o is Object} - */ - function isRawObject(o) { - return isType(o, "Object"); - } - - /** - * getInternalData retrieves "private" data stored by htmx within an element - * @param {HTMLElement} elt - * @returns {*} - */ - function getInternalData(elt) { - var dataProp = 'htmx-internal-data'; - var data = elt[dataProp]; - if (!data) { - data = elt[dataProp] = {}; - } - return data; - } - - /** - * toArray converts an ArrayLike object into a real array. - * @param {ArrayLike} arr - * @returns {any[]} - */ - function toArray(arr) { - var returnArr = []; - if (arr) { - for (var i = 0; i < arr.length; i++) { - returnArr.push(arr[i]); - } - } - return returnArr + const targets = getDocument().querySelectorAll(selector) + if (targets) { + forEach( + targets, + function(target) { + let fragment + const oobElementClone = oobElement.cloneNode(true) + fragment = getDocument().createDocumentFragment() + fragment.appendChild(oobElementClone) + if (!isInlineSwap(swapStyle, target)) { + fragment = asParentNode(oobElementClone) // if this is not an inline swap, we use the content of the node, not the node itself + } + + const beforeSwapDetails = { shouldSwap: true, target, fragment } + if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return + + target = beforeSwapDetails.target // allow re-targeting + if (beforeSwapDetails.shouldSwap) { + swapWithStyle(swapStyle, target, target, fragment, settleInfo) + } + forEach(settleInfo.elts, function(elt) { + triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails) + }) + } + ) + oobElement.parentNode.removeChild(oobElement) + } else { + oobElement.parentNode.removeChild(oobElement) + triggerErrorEvent(getDocument().body, 'htmx:oobErrorNoTarget', { content: oobElement }) + } + return oobValue + } + + /** + * @param {DocumentFragment} fragment + */ + function handlePreservedElements(fragment) { + forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function(preservedElt) { + const id = getAttributeValue(preservedElt, 'id') + const oldElt = getDocument().getElementById(id) + if (oldElt != null) { + preservedElt.parentNode.replaceChild(oldElt, preservedElt) + } + }) + } + + /** + * @param {Node} parentNode + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function handleAttributes(parentNode, fragment, settleInfo) { + forEach(fragment.querySelectorAll('[id]'), function(newNode) { + const id = getRawAttribute(newNode, 'id') + if (id && id.length > 0) { + const normalizedId = id.replace("'", "\\'") + const normalizedTag = newNode.tagName.replace(':', '\\:') + const parentElt = asParentNode(parentNode) + const oldNode = parentElt && parentElt.querySelector(normalizedTag + "[id='" + normalizedId + "']") + if (oldNode && oldNode !== parentElt) { + const newAttributes = newNode.cloneNode() + cloneAttributes(newNode, oldNode) + settleInfo.tasks.push(function() { + cloneAttributes(newNode, newAttributes) + }) + } + } + }) + } + + /** + * @param {Node} child + * @returns {HtmxSettleTask} + */ + function makeAjaxLoadTask(child) { + return function() { + removeClassFromElement(child, htmx.config.addedClass) + processNode(asElement(child)) + processFocus(asParentNode(child)) + triggerEvent(child, 'htmx:load') + } + } + + /** + * @param {ParentNode} child + */ + function processFocus(child) { + const autofocus = '[autofocus]' + const autoFocusedElt = asHtmlElement(matches(child, autofocus) ? child : child.querySelector(autofocus)) + if (autoFocusedElt != null) { + autoFocusedElt.focus() + } + } + + /** + * @param {Node} parentNode + * @param {Node} insertBefore + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) { + handleAttributes(parentNode, fragment, settleInfo) + while (fragment.childNodes.length > 0) { + const child = fragment.firstChild + addClassToElement(asElement(child), htmx.config.addedClass) + parentNode.insertBefore(child, insertBefore) + if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { + settleInfo.tasks.push(makeAjaxLoadTask(child)) + } + } + } + + /** + * based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, + * derived from Java's string hashcode implementation + * @param {string} string + * @param {number} hash + * @returns {number} + */ + function stringHash(string, hash) { + let char = 0 + while (char < string.length) { + hash = (hash << 5) - hash + string.charCodeAt(char++) | 0 // bitwise or ensures we have a 32-bit int + } + return hash + } + + /** + * @param {Element} elt + * @returns {number} + */ + function attributeHash(elt) { + let hash = 0 + // IE fix + if (elt.attributes) { + for (let i = 0; i < elt.attributes.length; i++) { + const attribute = elt.attributes[i] + if (attribute.value) { // only include attributes w/ actual values (empty is same as non-existent) + hash = stringHash(attribute.name, hash) + hash = stringHash(attribute.value, hash) + } + } + } + return hash + } + + /** + * @param {EventTarget} elt + */ + function deInitOnHandlers(elt) { + const internalData = getInternalData(elt) + if (internalData.onHandlers) { + for (let i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i] + removeEventListenerImpl(elt, handlerInfo.event, handlerInfo.listener) + } + delete internalData.onHandlers + } + } + + /** + * @param {Node} element + */ + function deInitNode(element) { + const internalData = getInternalData(element) + if (internalData.timeout) { + clearTimeout(internalData.timeout) + } + if (internalData.listenerInfos) { + forEach(internalData.listenerInfos, function(info) { + if (info.on) { + removeEventListenerImpl(info.on, info.trigger, info.listener) } - - function forEach(arr, func) { - if (arr) { - for (var i = 0; i < arr.length; i++) { - func(arr[i]); - } - } + }) + } + deInitOnHandlers(element) + forEach(Object.keys(internalData), function(key) { delete internalData[key] }) + } + + /** + * @param {Node} element + */ + function cleanUpElement(element) { + triggerEvent(element, 'htmx:beforeCleanupElement') + deInitNode(element) + // @ts-ignore IE11 code + // noinspection JSUnresolvedReference + if (element.children) { // IE + // @ts-ignore + forEach(element.children, function(child) { cleanUpElement(child) }) + } + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapOuterHTML(target, fragment, settleInfo) { + /** @type {Node} */ + let newElt + const eltBeforeNewContent = target.previousSibling + insertNodesBefore(parentElt(target), target, fragment, settleInfo) + if (eltBeforeNewContent == null) { + newElt = parentElt(target).firstChild + } else { + newElt = eltBeforeNewContent.nextSibling + } + settleInfo.elts = settleInfo.elts.filter(function(e) { return e !== target }) + while (newElt && newElt !== target) { + if (newElt instanceof Element) { + settleInfo.elts.push(newElt) + newElt = newElt.nextElementSibling + } else { + newElt = null + } + } + cleanUpElement(target) + if (target instanceof Element) { + target.remove() + } else { + target.parentNode.removeChild(target) + } + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapAfterBegin(target, fragment, settleInfo) { + return insertNodesBefore(target, target.firstChild, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapBeforeBegin(target, fragment, settleInfo) { + return insertNodesBefore(parentElt(target), target, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapBeforeEnd(target, fragment, settleInfo) { + return insertNodesBefore(target, null, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapAfterEnd(target, fragment, settleInfo) { + return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo) + } + + /** + * @param {Node} target + */ + function swapDelete(target) { + cleanUpElement(target) + return parentElt(target).removeChild(target) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapInnerHTML(target, fragment, settleInfo) { + const firstChild = target.firstChild + insertNodesBefore(target, firstChild, fragment, settleInfo) + if (firstChild) { + while (firstChild.nextSibling) { + cleanUpElement(firstChild.nextSibling) + target.removeChild(firstChild.nextSibling) + } + cleanUpElement(firstChild) + target.removeChild(firstChild) + } + } + + /** + * @param {HtmxSwapStyle} swapStyle + * @param {Element} elt + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapWithStyle(swapStyle, elt, target, fragment, settleInfo) { + switch (swapStyle) { + case 'none': + return + case 'outerHTML': + swapOuterHTML(target, fragment, settleInfo) + return + case 'afterbegin': + swapAfterBegin(target, fragment, settleInfo) + return + case 'beforebegin': + swapBeforeBegin(target, fragment, settleInfo) + return + case 'beforeend': + swapBeforeEnd(target, fragment, settleInfo) + return + case 'afterend': + swapAfterEnd(target, fragment, settleInfo) + return + case 'delete': + swapDelete(target) + return + default: + var extensions = getExtensions(elt) + for (let i = 0; i < extensions.length; i++) { + const ext = extensions[i] + try { + const newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo) + if (newElements) { + if (typeof newElements.length !== 'undefined') { + // if handleSwap returns an array (like) of elements, we handle them + for (let j = 0; j < newElements.length; j++) { + const child = newElements[j] + if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { + settleInfo.tasks.push(makeAjaxLoadTask(child)) + } + } + } + return + } + } catch (e) { + logError(e) + } + } + if (swapStyle === 'innerHTML') { + swapInnerHTML(target, fragment, settleInfo) + } else { + swapWithStyle(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo) } + } + } + + /** + * @param {DocumentFragment} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function findAndSwapOobElements(fragment, settleInfo) { + forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function(oobElement) { + if (htmx.config.allowNestedOobSwaps || oobElement.parentElement === null) { + const oobValue = getAttributeValue(oobElement, 'hx-swap-oob') + if (oobValue != null) { + oobSwap(oobValue, oobElement, settleInfo) + } + } else { + oobElement.removeAttribute('hx-swap-oob') + oobElement.removeAttribute('data-hx-swap-oob') + } + }) + } + + /** + * Implements complete swapping pipeline, including: focus and selection preservation, + * title updates, scroll, OOB swapping, normal swapping and settling + * @param {string|Element} target + * @param {string} content + * @param {HtmxSwapSpecification} swapSpec + * @param {SwapOptions} [swapOptions] + */ + function swap(target, content, swapSpec, swapOptions) { + if (!swapOptions) { + swapOptions = {} + } - function isScrolledIntoView(el) { - var rect = el.getBoundingClientRect(); - var elemTop = rect.top; - var elemBottom = rect.bottom; - return elemTop < window.innerHeight && elemBottom >= 0; - } + target = resolveTarget(target) + + // preserve focus and selection + const activeElt = document.activeElement + let selectionInfo = {} + try { + selectionInfo = { + elt: activeElt, + // @ts-ignore + start: activeElt ? activeElt.selectionStart : null, + // @ts-ignore + end: activeElt ? activeElt.selectionEnd : null + } + } catch (e) { + // safari issue - see https://github.com/microsoft/playwright/issues/5894 + } + const settleInfo = makeSettleInfo(target) - function bodyContains(elt) { - // IE Fix - if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) { - return getDocument().body.contains(elt.getRootNode().host); - } else { - return getDocument().body.contains(elt); - } - } + // For text content swaps, don't parse the response as HTML, just insert it + if (swapSpec.swapStyle === 'textContent') { + target.textContent = content + // Otherwise, make the fragment and process it + } else { + let fragment = makeFragment(content) + + settleInfo.title = fragment.title + + // select-oob swaps + if (swapOptions.selectOOB) { + const oobSelectValues = swapOptions.selectOOB.split(',') + for (let i = 0; i < oobSelectValues.length; i++) { + const oobSelectValue = oobSelectValues[i].split(':', 2) + let id = oobSelectValue[0].trim() + if (id.indexOf('#') === 0) { + id = id.substring(1) + } + const oobValue = oobSelectValue[1] || 'true' + const oobElement = fragment.querySelector('#' + id) + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo) + } + } + } + // oob swaps + findAndSwapOobElements(fragment, settleInfo) + forEach(findAll(fragment, 'template'), /** @param {HTMLTemplateElement} template */function(template) { + findAndSwapOobElements(template.content, settleInfo) + if (template.content.childElementCount === 0) { + // Avoid polluting the DOM with empty templates that were only used to encapsulate oob swap + template.remove() + } + }) + + // normal swap + if (swapOptions.select) { + const newFragment = getDocument().createDocumentFragment() + forEach(fragment.querySelectorAll(swapOptions.select), function(node) { + newFragment.appendChild(node) + }) + fragment = newFragment + } + handlePreservedElements(fragment) + swapWithStyle(swapSpec.swapStyle, swapOptions.contextElement, target, fragment, settleInfo) + } - function splitOnWhitespace(trigger) { - return trigger.trim().split(/\s+/); - } + // apply saved focus and selection information to swapped content + if (selectionInfo.elt && + !bodyContains(selectionInfo.elt) && + getRawAttribute(selectionInfo.elt, 'id')) { + const newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, 'id')) + const focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll } + if (newActiveElt) { + // @ts-ignore + if (selectionInfo.start && newActiveElt.setSelectionRange) { + try { + // @ts-ignore + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end) + } catch (e) { + // the setSelectionRange method is present on fields that don't support it, so just let this fail + } + } + newActiveElt.focus(focusOptions) + } + } - /** - * mergeObjects takes all of the keys from - * obj2 and duplicates them into obj1 - * @param {Object} obj1 - * @param {Object} obj2 - * @returns {Object} - */ - function mergeObjects(obj1, obj2) { - for (var key in obj2) { - if (obj2.hasOwnProperty(key)) { - obj1[key] = obj2[key]; - } - } - return obj1; - } + target.classList.remove(htmx.config.swappingClass) + forEach(settleInfo.elts, function(elt) { + if (elt.classList) { + elt.classList.add(htmx.config.settlingClass) + } + triggerEvent(elt, 'htmx:afterSwap', swapOptions.eventInfo) + }) + if (swapOptions.afterSwapCallback) { + swapOptions.afterSwapCallback() + } - function parseJSON(jString) { - try { - return JSON.parse(jString); - } catch(error) { - logError(error); - return null; - } - } + // merge in new title after swap but before settle + if (!swapSpec.ignoreTitle) { + handleTitle(settleInfo.title) + } - function canAccessLocalStorage() { - var test = 'htmx:localStorageTest'; - try { - localStorage.setItem(test, test); - localStorage.removeItem(test); - return true; - } catch(e) { - return false; - } - } + // settle + const doSettle = function() { + forEach(settleInfo.tasks, function(task) { + task.call() + }) + forEach(settleInfo.elts, function(elt) { + if (elt.classList) { + elt.classList.remove(htmx.config.settlingClass) + } + triggerEvent(elt, 'htmx:afterSettle', swapOptions.eventInfo) + }) + + if (swapOptions.anchor) { + const anchorTarget = asElement(resolveTarget('#' + swapOptions.anchor)) + if (anchorTarget) { + anchorTarget.scrollIntoView({ block: 'start', behavior: 'auto' }) + } + } + + updateScrollState(settleInfo.elts, swapSpec) + if (swapOptions.afterSettleCallback) { + swapOptions.afterSettleCallback() + } + } - function normalizePath(path) { + if (swapSpec.settleDelay > 0) { + getWindow().setTimeout(doSettle, swapSpec.settleDelay) + } else { + doSettle() + } + } + + /** + * @param {XMLHttpRequest} xhr + * @param {string} header + * @param {EventTarget} elt + */ + function handleTriggerHeader(xhr, header, elt) { + const triggerBody = xhr.getResponseHeader(header) + if (triggerBody.indexOf('{') === 0) { + const triggers = parseJSON(triggerBody) + for (const eventName in triggers) { + if (triggers.hasOwnProperty(eventName)) { + let detail = triggers[eventName] + if (!isRawObject(detail)) { + detail = { value: detail } + } + triggerEvent(elt, eventName, detail) + } + } + } else { + const eventNames = triggerBody.split(',') + for (let i = 0; i < eventNames.length; i++) { + triggerEvent(elt, eventNames[i].trim(), []) + } + } + } + + const WHITESPACE = /\s/ + const WHITESPACE_OR_COMMA = /[\s,]/ + const SYMBOL_START = /[_$a-zA-Z]/ + const SYMBOL_CONT = /[_$a-zA-Z0-9]/ + const STRINGISH_START = ['"', "'", '/'] + const NOT_WHITESPACE = /[^\s]/ + const COMBINED_SELECTOR_START = /[{(]/ + const COMBINED_SELECTOR_END = /[})]/ + + /** + * @param {string} str + * @returns {string[]} + */ + function tokenizeString(str) { + /** @type string[] */ + const tokens = [] + let position = 0 + while (position < str.length) { + if (SYMBOL_START.exec(str.charAt(position))) { + var startPosition = position + while (SYMBOL_CONT.exec(str.charAt(position + 1))) { + position++ + } + tokens.push(str.substr(startPosition, position - startPosition + 1)) + } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) { + const startChar = str.charAt(position) + var startPosition = position + position++ + while (position < str.length && str.charAt(position) !== startChar) { + if (str.charAt(position) === '\\') { + position++ + } + position++ + } + tokens.push(str.substr(startPosition, position - startPosition + 1)) + } else { + const symbol = str.charAt(position) + tokens.push(symbol) + } + position++ + } + return tokens + } + + /** + * @param {string} token + * @param {string|null} last + * @param {string} paramName + * @returns {boolean} + */ + function isPossibleRelativeReference(token, last, paramName) { + return SYMBOL_START.exec(token.charAt(0)) && + token !== 'true' && + token !== 'false' && + token !== 'this' && + token !== paramName && + last !== '.' + } + + /** + * @param {EventTarget|string} elt + * @param {string[]} tokens + * @param {string} paramName + * @returns {ConditionalFunction|null} + */ + function maybeGenerateConditional(elt, tokens, paramName) { + if (tokens[0] === '[') { + tokens.shift() + let bracketCount = 1 + let conditionalSource = ' return (function(' + paramName + '){ return (' + let last = null + while (tokens.length > 0) { + const token = tokens[0] + // @ts-ignore For some reason tsc doesn't understand the shift call, and thinks we're comparing the same value here, i.e. '[' vs ']' + if (token === ']') { + bracketCount-- + if (bracketCount === 0) { + if (last === null) { + conditionalSource = conditionalSource + 'true' + } + tokens.shift() + conditionalSource += ')})' try { - var url = new URL(path); - if (url) { - path = url.pathname + url.search; - } - // remove trailing slash, unless index page - if (!(/^\/$/.test(path))) { - path = path.replace(/\/+$/, ''); - } - return path; + const conditionFunction = maybeEval(elt, function() { + return Function(conditionalSource)() + }, + function() { return true }) + conditionFunction.source = conditionalSource + return conditionFunction } catch (e) { - // be kind to IE11, which doesn't support URL() - return path; - } - } - - //========================================================================================== - // public API - //========================================================================================== - - function internalEval(str){ - return maybeEval(getDocument().body, function () { - return eval(str); - }); - } - - function onLoadHelper(callback) { - var value = htmx.on("htmx:load", function(evt) { - callback(evt.detail.elt); - }); - return value; - } - - function logAll(){ - htmx.logger = function(elt, event, data) { - if(console) { - console.log(event, elt, data); - } - } - } - - function logNone() { - htmx.logger = null - } - - function find(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelector(selector); - } else { - return find(getDocument(), eltOrSelector); - } - } - - function findAll(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelectorAll(selector); - } else { - return findAll(getDocument(), eltOrSelector); - } - } - - function removeElement(elt, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - removeElement(elt); - elt = null; - }, delay); - } else { - elt.parentElement.removeChild(elt); - } - } - - function addClassToElement(elt, clazz, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - addClassToElement(elt, clazz); - elt = null; - }, delay); - } else { - elt.classList && elt.classList.add(clazz); - } - } - - function removeClassFromElement(elt, clazz, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - removeClassFromElement(elt, clazz); - elt = null; - }, delay); - } else { - if (elt.classList) { - elt.classList.remove(clazz); - // if there are no classes left, remove the class attribute - if (elt.classList.length === 0) { - elt.removeAttribute("class"); - } - } - } - } - - function toggleClassOnElement(elt, clazz) { - elt = resolveTarget(elt); - elt.classList.toggle(clazz); - } - - function takeClassForElement(elt, clazz) { - elt = resolveTarget(elt); - forEach(elt.parentElement.children, function(child){ - removeClassFromElement(child, clazz); - }) - addClassToElement(elt, clazz); - } - - function closest(elt, selector) { - elt = resolveTarget(elt); - if (elt.closest) { - return elt.closest(selector); - } else { - // TODO remove when IE goes away - do{ - if (elt == null || matches(elt, selector)){ - return elt; - } - } - while (elt = elt && parentElt(elt)); - return null; - } - } - - function startsWith(str, prefix) { - return str.substring(0, prefix.length) === prefix - } - - function endsWith(str, suffix) { - return str.substring(str.length - suffix.length) === suffix - } - - function normalizeSelector(selector) { - var trimmedSelector = selector.trim(); - if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) { - return trimmedSelector.substring(1, trimmedSelector.length - 2); - } else { - return trimmedSelector; - } - } - - function querySelectorAllExt(elt, selector) { - if (selector.indexOf("closest ") === 0) { - return [closest(elt, normalizeSelector(selector.substr(8)))]; - } else if (selector.indexOf("find ") === 0) { - return [find(elt, normalizeSelector(selector.substr(5)))]; - } else if (selector === "next") { - return [elt.nextElementSibling] - } else if (selector.indexOf("next ") === 0) { - return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; - } else if (selector === "previous") { - return [elt.previousElementSibling] - } else if (selector.indexOf("previous ") === 0) { - return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; - } else if (selector === 'document') { - return [document]; - } else if (selector === 'window') { - return [window]; - } else if (selector === 'body') { - return [document.body]; - } else { - return getDocument().querySelectorAll(normalizeSelector(selector)); - } - } - - var scanForwardQuery = function(start, match) { - var results = getDocument().querySelectorAll(match); - for (var i = 0; i < results.length; i++) { - var elt = results[i]; - if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { - return elt; - } - } - } - - var scanBackwardsQuery = function(start, match) { - var results = getDocument().querySelectorAll(match); - for (var i = results.length - 1; i >= 0; i--) { - var elt = results[i]; - if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { - return elt; - } - } - } - - function querySelectorExt(eltOrSelector, selector) { - if (selector) { - return querySelectorAllExt(eltOrSelector, selector)[0]; - } else { - return querySelectorAllExt(getDocument().body, eltOrSelector)[0]; - } - } - - function resolveTarget(arg2) { - if (isType(arg2, 'String')) { - return find(arg2); - } else { - return arg2; - } - } - - function processEventArgs(arg1, arg2, arg3) { - if (isFunction(arg2)) { - return { - target: getDocument().body, - event: arg1, - listener: arg2 - } - } else { - return { - target: resolveTarget(arg1), - event: arg2, - listener: arg3 - } - } - - } - - function addEventListenerImpl(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 removeEventListenerImpl(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 - //==================================================================== - - var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors - function findAttributeTargets(elt, attrName) { - var attrTarget = getClosestAttributeValue(elt, attrName); - if (attrTarget) { - if (attrTarget === "this") { - return [findThisElement(elt, attrName)]; - } else { - var result = querySelectorAllExt(elt, attrTarget); - if (result.length === 0) { - logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!"); - return [DUMMY_ELT] - } else { - return result; - } - } - } - } - - function findThisElement(elt, attribute){ - return getClosestMatch(elt, function (elt) { - return getAttributeValue(elt, attribute) != null; - }) - } - - function getTarget(elt) { - var targetStr = getClosestAttributeValue(elt, "hx-target"); - if (targetStr) { - if (targetStr === "this") { - return findThisElement(elt,'hx-target'); - } else { - return querySelectorExt(elt, targetStr) - } - } else { - var data = getInternalData(elt); - if (data.boosted) { - return getDocument().body; - } else { - return elt; - } - } - } - - function shouldSettleAttribute(name) { - var attributesToSettle = htmx.config.attributesToSettle; - for (var i = 0; i < attributesToSettle.length; i++) { - if (name === attributesToSettle[i]) { - return true; - } - } - return false; - } - - function cloneAttributes(mergeTo, mergeFrom) { - forEach(mergeTo.attributes, function (attr) { - if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) { - mergeTo.removeAttribute(attr.name) - } - }); - forEach(mergeFrom.attributes, function (attr) { - if (shouldSettleAttribute(attr.name)) { - mergeTo.setAttribute(attr.name, attr.value); - } - }); - } - - function isInlineSwap(swapStyle, target) { - var extensions = getExtensions(target); - for (var i = 0; i < extensions.length; i++) { - var extension = extensions[i]; - try { - if (extension.isInlineSwap(swapStyle)) { - return true; - } - } catch(e) { - logError(e); - } - } - return swapStyle === "outerHTML"; - } - - /** - * - * @param {string} oobValue - * @param {HTMLElement} oobElement - * @param {*} settleInfo - * @returns - */ - function oobSwap(oobValue, oobElement, settleInfo) { - var selector = "#" + getRawAttribute(oobElement, "id"); - var swapStyle = "outerHTML"; - if (oobValue === "true") { - // do nothing - } else if (oobValue.indexOf(":") > 0) { - swapStyle = oobValue.substr(0, oobValue.indexOf(":")); - selector = oobValue.substr(oobValue.indexOf(":") + 1, oobValue.length); - } else { - swapStyle = oobValue; - } - - var targets = getDocument().querySelectorAll(selector); - if (targets) { - forEach( - targets, - function (target) { - var fragment; - var oobElementClone = oobElement.cloneNode(true); - fragment = getDocument().createDocumentFragment(); - fragment.appendChild(oobElementClone); - if (!isInlineSwap(swapStyle, target)) { - fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself - } - - var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment }; - if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return; - - target = beforeSwapDetails.target; // allow re-targeting - if (beforeSwapDetails['shouldSwap']){ - swap(swapStyle, target, target, fragment, settleInfo); - } - forEach(settleInfo.elts, function (elt) { - triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails); - }); - } - ); - oobElement.parentNode.removeChild(oobElement); - } else { - oobElement.parentNode.removeChild(oobElement); - triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}); - } - return oobValue; - } - - function handleOutOfBandSwaps(elt, fragment, settleInfo) { - var oobSelects = getClosestAttributeValue(elt, "hx-select-oob"); - if (oobSelects) { - var oobSelectValues = oobSelects.split(","); - for (var i = 0; i < oobSelectValues.length; i++) { - var oobSelectValue = oobSelectValues[i].split(":", 2); - var id = oobSelectValue[0].trim(); - if (id.indexOf("#") === 0) { - id = id.substring(1); - } - var oobValue = oobSelectValue[1] || "true"; - var oobElement = fragment.querySelector("#" + id); - if (oobElement) { - oobSwap(oobValue, oobElement, settleInfo); - } - } - } - forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) { - var oobValue = getAttributeValue(oobElement, "hx-swap-oob"); - if (oobValue != null) { - oobSwap(oobValue, oobElement, settleInfo); - } - }); - } - - function handlePreservedElements(fragment) { - forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function (preservedElt) { - var id = getAttributeValue(preservedElt, "id"); - var oldElt = getDocument().getElementById(id); - if (oldElt != null) { - preservedElt.parentNode.replaceChild(oldElt, preservedElt); - } - }); - } - - function handleAttributes(parentNode, fragment, settleInfo) { - forEach(fragment.querySelectorAll("[id]"), function (newNode) { - var id = getRawAttribute(newNode, "id") - if (id && id.length > 0) { - var normalizedId = id.replace("'", "\\'"); - var normalizedTag = newNode.tagName.replace(':', '\\:'); - var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']"); - if (oldNode && oldNode !== parentNode) { - var newAttributes = newNode.cloneNode(); - cloneAttributes(newNode, oldNode); - settleInfo.tasks.push(function () { - cloneAttributes(newNode, newAttributes); - }); - } - } - }); - } - - function makeAjaxLoadTask(child) { - return function () { - removeClassFromElement(child, htmx.config.addedClass); - processNode(child); - processScripts(child); - processFocus(child) - triggerEvent(child, 'htmx:load'); - }; - } - - function processFocus(child) { - var autofocus = "[autofocus]"; - var autoFocusedElt = matches(child, autofocus) ? child : child.querySelector(autofocus) - if (autoFocusedElt != null) { - autoFocusedElt.focus(); - } - } - - function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) { - handleAttributes(parentNode, fragment, settleInfo); - while(fragment.childNodes.length > 0){ - var child = fragment.firstChild; - addClassToElement(child, htmx.config.addedClass); - parentNode.insertBefore(child, insertBefore); - if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { - settleInfo.tasks.push(makeAjaxLoadTask(child)); - } - } - } - - // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, - // derived from Java's string hashcode implementation - function stringHash(string, hash) { - var char = 0; - while (char < string.length){ - hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int - } - return hash; - } - - function attributeHash(elt) { - var hash = 0; - // IE fix - if (elt.attributes) { - for (var i = 0; i < elt.attributes.length; i++) { - var attribute = elt.attributes[i]; - if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent) - hash = stringHash(attribute.name, hash); - hash = stringHash(attribute.value, hash); - } - } - } - return hash; - } - - function deInitOnHandlers(elt) { - var internalData = getInternalData(elt); - if (internalData.onHandlers) { - for (var i = 0; i < internalData.onHandlers.length; i++) { - const handlerInfo = internalData.onHandlers[i]; - elt.removeEventListener(handlerInfo.event, handlerInfo.listener); - } - delete internalData.onHandlers - } - } - - function deInitNode(element) { - var internalData = getInternalData(element); - if (internalData.timeout) { - clearTimeout(internalData.timeout); - } - if (internalData.webSocket) { - internalData.webSocket.close(); - } - if (internalData.sseEventSource) { - internalData.sseEventSource.close(); - } - if (internalData.listenerInfos) { - forEach(internalData.listenerInfos, function (info) { - if (info.on) { - info.on.removeEventListener(info.trigger, info.listener); - } - }); - } - deInitOnHandlers(element); - forEach(Object.keys(internalData), function(key) { delete internalData[key] }); - } - - function cleanUpElement(element) { - triggerEvent(element, "htmx:beforeCleanupElement") - deInitNode(element); - if (element.children) { // IE - forEach(element.children, function(child) { cleanUpElement(child) }); - } - } - - function swapOuterHTML(target, fragment, settleInfo) { - if (target.tagName === "BODY") { - return swapInnerHTML(target, fragment, settleInfo); - } else { - // @type {HTMLElement} - var newElt - var eltBeforeNewContent = target.previousSibling; - insertNodesBefore(parentElt(target), target, fragment, settleInfo); - if (eltBeforeNewContent == null) { - newElt = parentElt(target).firstChild; - } else { - newElt = eltBeforeNewContent.nextSibling; - } - settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target }); - while(newElt && newElt !== target) { - if (newElt.nodeType === Node.ELEMENT_NODE) { - settleInfo.elts.push(newElt); - } - newElt = newElt.nextElementSibling; - } - cleanUpElement(target); - parentElt(target).removeChild(target); - } - } - - function swapAfterBegin(target, fragment, settleInfo) { - return insertNodesBefore(target, target.firstChild, fragment, settleInfo); - } - - function swapBeforeBegin(target, fragment, settleInfo) { - return insertNodesBefore(parentElt(target), target, fragment, settleInfo); - } - - function swapBeforeEnd(target, fragment, settleInfo) { - return insertNodesBefore(target, null, fragment, settleInfo); - } - - function swapAfterEnd(target, fragment, settleInfo) { - return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo); - } - function swapDelete(target, fragment, settleInfo) { - cleanUpElement(target); - return parentElt(target).removeChild(target); - } - - function swapInnerHTML(target, fragment, settleInfo) { - var firstChild = target.firstChild; - insertNodesBefore(target, firstChild, fragment, settleInfo); - if (firstChild) { - while (firstChild.nextSibling) { - cleanUpElement(firstChild.nextSibling) - target.removeChild(firstChild.nextSibling); - } - cleanUpElement(firstChild) - target.removeChild(firstChild); - } - } - - function maybeSelectFromResponse(elt, fragment, selectOverride) { - var selector = selectOverride || getClosestAttributeValue(elt, "hx-select"); - if (selector) { - var newFragment = getDocument().createDocumentFragment(); - forEach(fragment.querySelectorAll(selector), function (node) { - newFragment.appendChild(node); - }); - fragment = newFragment; - } - return fragment; - } - - function swap(swapStyle, elt, target, fragment, settleInfo) { - switch (swapStyle) { - case "none": - return; - case "outerHTML": - swapOuterHTML(target, fragment, settleInfo); - return; - case "afterbegin": - swapAfterBegin(target, fragment, settleInfo); - return; - case "beforebegin": - swapBeforeBegin(target, fragment, settleInfo); - return; - case "beforeend": - swapBeforeEnd(target, fragment, settleInfo); - return; - case "afterend": - swapAfterEnd(target, fragment, settleInfo); - return; - case "delete": - swapDelete(target, fragment, settleInfo); - return; - default: - var extensions = getExtensions(elt); - for (var i = 0; i < extensions.length; i++) { - var ext = extensions[i]; - try { - var newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo); - if (newElements) { - if (typeof newElements.length !== 'undefined') { - // if handleSwap returns an array (like) of elements, we handle them - for (var j = 0; j < newElements.length; j++) { - var child = newElements[j]; - if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { - settleInfo.tasks.push(makeAjaxLoadTask(child)); - } - } - } - return; - } - } catch (e) { - logError(e); - } - } - if (swapStyle === "innerHTML") { - swapInnerHTML(target, fragment, settleInfo); - } else { - swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo); - } - } - } - - function findTitle(content) { - if (content.indexOf('<title') > -1) { - var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, ''); - var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX); - if (result) { - return result[2]; - } - } - } - - function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) { - settleInfo.title = findTitle(responseText); - var fragment = makeFragment(responseText); - if (fragment) { - handleOutOfBandSwaps(elt, fragment, settleInfo); - fragment = maybeSelectFromResponse(elt, fragment, selectOverride); - handlePreservedElements(fragment); - return swap(swapStyle, elt, target, fragment, settleInfo); - } - } - - function handleTrigger(xhr, header, elt) { - var triggerBody = xhr.getResponseHeader(header); - if (triggerBody.indexOf("{") === 0) { - var triggers = parseJSON(triggerBody); - for (var eventName in triggers) { - if (triggers.hasOwnProperty(eventName)) { - var detail = triggers[eventName]; - if (!isRawObject(detail)) { - detail = {"value": detail} - } - triggerEvent(elt, eventName, detail); - } - } - } else { - var eventNames = triggerBody.split(",") - for (var i = 0; i < eventNames.length; i++) { - triggerEvent(elt, eventNames[i].trim(), []); - } - } - } - - var WHITESPACE = /\s/; - var WHITESPACE_OR_COMMA = /[\s,]/; - var SYMBOL_START = /[_$a-zA-Z]/; - var SYMBOL_CONT = /[_$a-zA-Z0-9]/; - var STRINGISH_START = ['"', "'", "/"]; - var NOT_WHITESPACE = /[^\s]/; - var COMBINED_SELECTOR_START = /[{(]/; - var COMBINED_SELECTOR_END = /[})]/; - function tokenizeString(str) { - var tokens = []; - var position = 0; - while (position < str.length) { - if(SYMBOL_START.exec(str.charAt(position))) { - var startPosition = position; - while (SYMBOL_CONT.exec(str.charAt(position + 1))) { - position++; - } - tokens.push(str.substr(startPosition, position - startPosition + 1)); - } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) { - var startChar = str.charAt(position); - var startPosition = position; - position++; - while (position < str.length && str.charAt(position) !== startChar ) { - if (str.charAt(position) === "\\") { - position++; - } - position++; - } - tokens.push(str.substr(startPosition, position - startPosition + 1)); - } else { - var symbol = str.charAt(position); - tokens.push(symbol); - } - position++; - } - return tokens; - } - - function isPossibleRelativeReference(token, last, paramName) { - return SYMBOL_START.exec(token.charAt(0)) && - token !== "true" && - token !== "false" && - token !== "this" && - token !== paramName && - last !== "."; - } - - function maybeGenerateConditional(elt, tokens, paramName) { - if (tokens[0] === '[') { - tokens.shift(); - var bracketCount = 1; - var conditionalSource = " return (function(" + paramName + "){ return ("; - var last = null; - while (tokens.length > 0) { - var token = tokens[0]; - if (token === "]") { - bracketCount--; - if (bracketCount === 0) { - if (last === null) { - conditionalSource = conditionalSource + "true"; - } - tokens.shift(); - conditionalSource += ")})"; - try { - var conditionFunction = maybeEval(elt,function () { - return Function(conditionalSource)(); - }, - function(){return true}) - conditionFunction.source = conditionalSource; - return conditionFunction; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:syntax:error", {error:e, source:conditionalSource}) - return null; - } - } - } else if (token === "[") { - bracketCount++; - } - if (isPossibleRelativeReference(token, last, paramName)) { - conditionalSource += "((" + paramName + "." + token + ") ? (" + paramName + "." + token + ") : (window." + token + "))"; - } else { - conditionalSource = conditionalSource + token; - } - last = tokens.shift(); - } - } - } - - function consumeUntil(tokens, match) { - var result = ""; - while (tokens.length > 0 && !match.test(tokens[0])) { - result += tokens.shift(); - } - return result; - } - - function consumeCSSSelector(tokens) { - var result; - if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { - tokens.shift(); - result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim(); - tokens.shift(); - } else { - result = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } - return result; - } - - var INPUT_SELECTOR = 'input, textarea, select'; - - /** - * @param {HTMLElement} elt - * @param {string} explicitTrigger - * @param {cache} cache for trigger specs - * @returns {import("./htmx").HtmxTriggerSpecification[]} - */ - function parseAndCacheTrigger(elt, explicitTrigger, cache) { - var triggerSpecs = []; - var tokens = tokenizeString(explicitTrigger); - do { - consumeUntil(tokens, NOT_WHITESPACE); - var initialLength = tokens.length; - var trigger = consumeUntil(tokens, /[,\[\s]/); - if (trigger !== "") { - if (trigger === "every") { - var every = {trigger: 'every'}; - consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); - consumeUntil(tokens, NOT_WHITESPACE); - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - every.eventFilter = eventFilter; - } - triggerSpecs.push(every); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); - } else { - var triggerSpec = {trigger: trigger}; - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - triggerSpec.eventFilter = eventFilter; - } - while (tokens.length > 0 && tokens[0] !== ",") { - consumeUntil(tokens, NOT_WHITESPACE) - var token = tokens.shift(); - if (token === "changed") { - triggerSpec.changed = true; - } else if (token === "once") { - triggerSpec.once = true; - } else if (token === "consume") { - triggerSpec.consume = true; - } else if (token === "delay" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "from" && tokens[0] === ":") { - tokens.shift(); - if (COMBINED_SELECTOR_START.test(tokens[0])) { - var from_arg = consumeCSSSelector(tokens); - } else { - var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); - if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") { - tokens.shift(); - var selector = consumeCSSSelector(tokens); - // `next` and `previous` allow a selector-less syntax - if (selector.length > 0) { - from_arg += " " + selector; - } - } - } - triggerSpec.from = from_arg; - } else if (token === "target" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.target = consumeCSSSelector(tokens); - } else if (token === "throttle" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "queue" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if (token === "root" && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeCSSSelector(tokens); - } else if (token === "threshold" && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - } - triggerSpecs.push(triggerSpec); - } - } - if (tokens.length === initialLength) { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - consumeUntil(tokens, NOT_WHITESPACE); - } while (tokens[0] === "," && tokens.shift()) - if (cache) { - cache[explicitTrigger] = triggerSpecs - } - return triggerSpecs - } - - /** - * @param {HTMLElement} elt - * @returns {import("./htmx").HtmxTriggerSpecification[]} - */ - function getTriggerSpecs(elt) { - var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); - var triggerSpecs = []; - if (explicitTrigger) { - var cache = htmx.config.triggerSpecsCache - triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) - } - - if (triggerSpecs.length > 0) { - return triggerSpecs; - } else if (matches(elt, 'form')) { - return [{trigger: 'submit'}]; - } else if (matches(elt, 'input[type="button"], input[type="submit"]')){ - return [{trigger: 'click'}]; - } else if (matches(elt, INPUT_SELECTOR)) { - return [{trigger: 'change'}]; - } else { - return [{trigger: 'click'}]; - } - } - - function cancelPolling(elt) { - getInternalData(elt).cancelled = true; - } - - function processPolling(elt, handler, spec) { - var nodeData = getInternalData(elt); - nodeData.timeout = setTimeout(function () { - if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { - triggerSpec: spec, - target: elt - }))) { - handler(elt); - } - processPolling(elt, handler, spec); - } - }, spec.pollInterval); - } - - function isLocalLink(elt) { - return location.hostname === elt.hostname && - getRawAttribute(elt,'href') && - getRawAttribute(elt,'href').indexOf("#") !== 0; - } - - function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || 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"; - if (verb === "get") { - } - path = getRawAttribute(elt, 'action'); - } - triggerSpecs.forEach(function(triggerSpec) { - addEventListener(elt, function(elt, evt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return - } - issueAjaxRequest(verb, path, elt, evt) - }, nodeData, triggerSpec, true); - }); - } - } - - /** - * - * @param {Event} evt - * @param {HTMLElement} elt - * @returns - */ - function shouldCancel(evt, elt) { - if (evt.type === "submit" || evt.type === "click") { - if (elt.tagName === "FORM") { - return true; - } - if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { - return true; - } - if (elt.tagName === "A" && elt.href && - (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) { - return true; - } - } - return false; - } - - function ignoreBoostedAnchorCtrlClick(elt, evt) { - return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); - } - - function maybeFilterEvent(triggerSpec, elt, evt) { - var eventFilter = triggerSpec.eventFilter; - if(eventFilter){ - try { - return eventFilter.call(elt, evt) !== true; - } catch(e) { - triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); - return true; - } - } - return false; - } - - function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { - var elementData = getInternalData(elt); - var eltsToListenOn; - if (triggerSpec.from) { - eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); - } else { - eltsToListenOn = [elt]; - } - // store the initial values of the elements, so we can tell if they change - if (triggerSpec.changed) { - eltsToListenOn.forEach(function (eltToListenOn) { - var eltToListenOnData = getInternalData(eltToListenOn); - eltToListenOnData.lastValue = eltToListenOn.value; - }) - } - forEach(eltsToListenOn, function (eltToListenOn) { - var eventListener = function (evt) { - if (!bodyContains(elt)) { - eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); - return; - } - if (ignoreBoostedAnchorCtrlClick(elt, evt)) { - return; - } - if (explicitCancel || shouldCancel(evt, elt)) { - evt.preventDefault(); - } - if (maybeFilterEvent(triggerSpec, elt, evt)) { - return; - } - var eventData = getInternalData(evt); - eventData.triggerSpec = triggerSpec; - if (eventData.handledFor == null) { - eventData.handledFor = []; - } - if (eventData.handledFor.indexOf(elt) < 0) { - eventData.handledFor.push(elt); - if (triggerSpec.consume) { - evt.stopPropagation(); - } - if (triggerSpec.target && evt.target) { - if (!matches(evt.target, triggerSpec.target)) { - return; - } - } - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } - } - if (triggerSpec.changed) { - var eltToListenOnData = getInternalData(eltToListenOn) - if (eltToListenOnData.lastValue === eltToListenOn.value) { - return; - } - eltToListenOnData.lastValue = eltToListenOn.value - } - if (elementData.delayed) { - clearTimeout(elementData.delayed); - } - if (elementData.throttle) { - return; - } - - if (triggerSpec.throttle > 0) { - if (!elementData.throttle) { - handler(elt, evt); - elementData.throttle = setTimeout(function () { - elementData.throttle = null; - }, triggerSpec.throttle); - } - } else if (triggerSpec.delay > 0) { - elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); - } else { - triggerEvent(elt, 'htmx:trigger') - handler(elt, evt); - } - } - }; - if (nodeData.listenerInfos == null) { - nodeData.listenerInfos = []; - } - nodeData.listenerInfos.push({ - trigger: triggerSpec.trigger, - listener: eventListener, - on: eltToListenOn - }) - eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); - }); - } - - var windowIsScrolling = false // used by initScrollHandler - var scrollHandler = null; - function initScrollHandler() { - if (!scrollHandler) { - scrollHandler = function() { - windowIsScrolling = true - }; - window.addEventListener("scroll", scrollHandler) - setInterval(function() { - if (windowIsScrolling) { - windowIsScrolling = false; - forEach(getDocument().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"), function (elt) { - maybeReveal(elt); - }) - } - }, 200); - } - } - - function maybeReveal(elt) { - if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { - elt.setAttribute('data-hx-revealed', 'true'); - var nodeData = getInternalData(elt); - if (nodeData.initHash) { - triggerEvent(elt, 'revealed'); - } else { - // if the node isn't initialized, wait for it before triggering the request - elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true}); - } - } - } - - //==================================================================== - // Web Sockets - //==================================================================== - - function processWebSocketInfo(elt, nodeData, info) { - var values = splitOnWhitespace(info); - for (var i = 0; i < values.length; i++) { - var value = values[i].split(/:(.+)/); - if (value[0] === "connect") { - ensureWebSocket(elt, value[1], 0); - } - if (value[0] === "send") { - processWebSocketSend(elt); - } - } - } - - function ensureWebSocket(elt, wssSource, retryCount) { - if (!bodyContains(elt)) { - return; // stop ensuring websocket connection when socket bearing element ceases to exist - } - - if (wssSource.indexOf("/") == 0) { // complete absolute paths only - var base_part = location.hostname + (location.port ? ':'+location.port: ''); - if (location.protocol == 'https:') { - wssSource = "wss://" + base_part + wssSource; - } else if (location.protocol == 'http:') { - wssSource = "ws://" + base_part + wssSource; - } - } - var socket = htmx.createWebSocket(wssSource); - socket.onerror = function (e) { - triggerErrorEvent(elt, "htmx:wsError", {error:e, socket:socket}); - maybeCloseWebSocketSource(elt); - }; - - socket.onclose = function (e) { - if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later - var delay = getWebSocketReconnectDelay(retryCount); - setTimeout(function() { - ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout - }, delay); - } - }; - socket.onopen = function (e) { - retryCount = 0; - } - - getInternalData(elt).webSocket = socket; - socket.addEventListener('message', function (event) { - if (maybeCloseWebSocketSource(elt)) { - return; - } - - var response = event.data; - withExtensions(elt, function(extension){ - response = extension.transformResponse(response, null, elt); - }); - - var settleInfo = makeSettleInfo(elt); - var fragment = makeFragment(response); - var children = toArray(fragment.children); - for (var i = 0; i < children.length; i++) { - var child = children[i]; - oobSwap(getAttributeValue(child, "hx-swap-oob") || "true", child, settleInfo); - } - - settleImmediately(settleInfo.tasks); - }); - } - - function maybeCloseWebSocketSource(elt) { - if (!bodyContains(elt)) { - getInternalData(elt).webSocket.close(); - return true; - } - } - - function processWebSocketSend(elt) { - var webSocketSourceElt = getClosestMatch(elt, function (parent) { - return getInternalData(parent).webSocket != null; - }); - if (webSocketSourceElt) { - elt.addEventListener(getTriggerSpecs(elt)[0].trigger, function (evt) { - var webSocket = getInternalData(webSocketSourceElt).webSocket; - var headers = getHeaders(elt, webSocketSourceElt); - var results = getInputValues(elt, 'post'); - var errors = results.errors; - var rawParameters = results.values; - var expressionVars = getExpressionVars(elt); - var allParameters = mergeObjects(rawParameters, expressionVars); - var filteredParameters = filterValues(allParameters, elt); - filteredParameters['HEADERS'] = headers; - if (errors && errors.length > 0) { - triggerEvent(elt, 'htmx:validation:halted', errors); - return; - } - webSocket.send(JSON.stringify(filteredParameters)); - if(shouldCancel(evt, elt)){ - evt.preventDefault(); - } - }); - } else { - triggerErrorEvent(elt, "htmx:noWebSocketSourceError"); - } - } - - function getWebSocketReconnectDelay(retryCount) { - var delay = htmx.config.wsReconnectDelay; - if (typeof delay === 'function') { - // @ts-ignore - return delay(retryCount); - } - if (delay === 'full-jitter') { - var exp = Math.min(retryCount, 6); - var maxDelay = 1000 * Math.pow(2, exp); - return maxDelay * Math.random(); - } - logError('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"'); - } - - //==================================================================== - // Server Sent Events - //==================================================================== - - function processSSEInfo(elt, nodeData, info) { - var values = splitOnWhitespace(info); - for (var i = 0; i < values.length; i++) { - var value = values[i].split(/:(.+)/); - if (value[0] === "connect") { - processSSESource(elt, value[1]); - } - - if ((value[0] === "swap")) { - processSSESwap(elt, value[1]) - } - } - } - - function processSSESource(elt, sseSrc) { - var source = htmx.createEventSource(sseSrc); - source.onerror = function (e) { - triggerErrorEvent(elt, "htmx:sseError", {error:e, source:source}); - maybeCloseSSESource(elt); - }; - getInternalData(elt).sseEventSource = source; - } - - function processSSESwap(elt, sseEventName) { - var sseSourceElt = getClosestMatch(elt, hasEventSource); - if (sseSourceElt) { - var sseEventSource = getInternalData(sseSourceElt).sseEventSource; - var sseListener = function (event) { - if (maybeCloseSSESource(sseSourceElt)) { - return; - } - if (!bodyContains(elt)) { - sseEventSource.removeEventListener(sseEventName, sseListener); - return; - } - - /////////////////////////// - // TODO: merge this code with AJAX and WebSockets code in the future. - - var response = event.data; - withExtensions(elt, function(extension){ - response = extension.transformResponse(response, null, elt); - }); - - var swapSpec = getSwapSpecification(elt) - var target = getTarget(elt) - var settleInfo = makeSettleInfo(elt); - - selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) - settleImmediately(settleInfo.tasks) - triggerEvent(elt, "htmx:sseMessage", event) - }; - - getInternalData(elt).sseListener = sseListener; - sseEventSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "htmx:noSSESourceError"); - } - } - - function processSSETrigger(elt, handler, sseEventName) { - var sseSourceElt = getClosestMatch(elt, hasEventSource); - if (sseSourceElt) { - var sseEventSource = getInternalData(sseSourceElt).sseEventSource; - var sseListener = function () { - if (!maybeCloseSSESource(sseSourceElt)) { - if (bodyContains(elt)) { - handler(elt); - } else { - sseEventSource.removeEventListener(sseEventName, sseListener); - } - } - }; - getInternalData(elt).sseListener = sseListener; - sseEventSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "htmx:noSSESourceError"); - } - } - - function maybeCloseSSESource(elt) { - if (!bodyContains(elt)) { - getInternalData(elt).sseEventSource.close(); - return true; - } - } - - function hasEventSource(node) { - return getInternalData(node).sseEventSource != null; - } - - //==================================================================== - - function loadImmediately(elt, handler, nodeData, delay) { - var load = function(){ - if (!nodeData.loaded) { - nodeData.loaded = true; - handler(elt); - } - } - if (delay > 0) { - setTimeout(load, delay); - } else { - load(); - } - } - - function processVerbs(elt, nodeData, triggerSpecs) { - var explicitAction = false; - forEach(VERBS, function (verb) { - if (hasAttribute(elt,'hx-' + verb)) { - var path = getAttributeValue(elt, 'hx-' + verb); - explicitAction = true; - nodeData.path = path; - nodeData.verb = verb; - triggerSpecs.forEach(function(triggerSpec) { - addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return - } - issueAjaxRequest(verb, path, elt, evt) - }) - }); - } - }); - return explicitAction; - } - - function addTriggerHandler(elt, triggerSpec, nodeData, handler) { - if (triggerSpec.sseEvent) { - processSSETrigger(elt, handler, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - addEventListener(elt, handler, nodeData, triggerSpec); - maybeReveal(elt); - } else if (triggerSpec.trigger === "intersect") { - var observerOptions = {}; - if (triggerSpec.root) { - observerOptions.root = querySelectorExt(elt, triggerSpec.root) - } - if (triggerSpec.threshold) { - observerOptions.threshold = parseFloat(triggerSpec.threshold); - } - var observer = new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - if (entry.isIntersecting) { - triggerEvent(elt, "intersect"); - break; - } - } - }, observerOptions); - observer.observe(elt); - addEventListener(elt, handler, nodeData, triggerSpec); - } else if (triggerSpec.trigger === "load") { - if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { - loadImmediately(elt, handler, nodeData, triggerSpec.delay); - } - } else if (triggerSpec.pollInterval > 0) { - nodeData.polling = true; - processPolling(elt, handler, triggerSpec); - } else { - addEventListener(elt, handler, nodeData, triggerSpec); - } - } - - function evalScript(script) { - if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) { - var newScript = getDocument().createElement("script"); - forEach(script.attributes, function (attr) { - newScript.setAttribute(attr.name, attr.value); - }); - newScript.textContent = script.textContent; - newScript.async = false; - if (htmx.config.inlineScriptNonce) { - newScript.nonce = htmx.config.inlineScriptNonce; - } - var parent = script.parentElement; - - try { - parent.insertBefore(newScript, script); - } catch (e) { - logError(e); - } finally { - // remove old script element, but only if it is still in DOM - if (script.parentElement) { - script.parentElement.removeChild(script); - } - } - } - } - - function processScripts(elt) { - if (matches(elt, "script")) { - evalScript(elt); - } - forEach(findAll(elt, "script"), function (script) { - evalScript(script); - }); - } - - function shouldProcessHxOn(elt) { - var attributes = elt.attributes - for (var j = 0; j < attributes.length; j++) { - var attrName = attributes[j].name - if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") || - startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) { - return true - } - } - return false - } - - function findHxOnWildcardElements(elt) { - var node = null - var elements = [] - - if (shouldProcessHxOn(elt)) { - elements.push(elt) - } - - if (document.evaluate) { - var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + - ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt) - while (node = iter.iterateNext()) elements.push(node) - } else { - var allElements = elt.getElementsByTagName("*") - for (var i = 0; i < allElements.length; i++) { - if (shouldProcessHxOn(allElements[i])) { - elements.push(allElements[i]) - } - } - } - - return elements - } - - function findElementsToProcess(elt) { - if (elt.querySelectorAll) { - var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; - var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]"); - return results; - } else { - return []; - } - } - - // Handle submit buttons/inputs that have the form attribute set - // see https://developer.mozilla.org/docs/Web/HTML/Element/button - function maybeSetLastButtonClicked(evt) { - var elt = closest(evt.target, "button, input[type='submit']"); - var internalData = getRelatedFormData(evt) - if (internalData) { - internalData.lastButtonClicked = elt; - } - }; - function maybeUnsetLastButtonClicked(evt){ - var internalData = getRelatedFormData(evt) - if (internalData) { - internalData.lastButtonClicked = null; - } - } - function getRelatedFormData(evt) { - var elt = closest(evt.target, "button, input[type='submit']"); - if (!elt) { - return; - } - var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form'); - if (!form) { - return; - } - return getInternalData(form); - } - function initButtonTracking(elt) { - // need to handle both click and focus in: - // focusin - in case someone tabs in to a button and hits the space bar - // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 - elt.addEventListener('click', maybeSetLastButtonClicked) - elt.addEventListener('focusin', maybeSetLastButtonClicked) - elt.addEventListener('focusout', maybeUnsetLastButtonClicked) - } - - function countCurlies(line) { - var tokens = tokenizeString(line); - var netCurlies = 0; - for (var i = 0; i < tokens.length; i++) { - const token = tokens[i]; - if (token === "{") { - netCurlies++; - } else if (token === "}") { - netCurlies--; - } - } - return netCurlies; - } - - function addHxOnEventHandler(elt, eventName, code) { - var nodeData = getInternalData(elt); - if (!Array.isArray(nodeData.onHandlers)) { - nodeData.onHandlers = []; - } - var func; - var listener = function (e) { - return maybeEval(elt, function() { - if (!func) { - func = new Function("event", code); - } - func.call(elt, e); - }); - }; - elt.addEventListener(eventName, listener); - nodeData.onHandlers.push({event:eventName, listener:listener}); - } - - function processHxOn(elt) { - var hxOnValue = getAttributeValue(elt, 'hx-on'); - if (hxOnValue) { - var handlers = {} - var lines = hxOnValue.split("\n"); - var currentEvent = null; - var curlyCount = 0; - while (lines.length > 0) { - var line = lines.shift(); - var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/); - if (curlyCount === 0 && match) { - line.split(":") - currentEvent = match[1].slice(0, -1); // strip last colon - handlers[currentEvent] = match[2]; - } else { - handlers[currentEvent] += line; - } - curlyCount += countCurlies(line); - } - - for (var eventName in handlers) { - addHxOnEventHandler(elt, eventName, handlers[eventName]); - } - } - } - - function processHxOnWildcard(elt) { - // wipe any previous on handlers so that this function takes precedence - deInitOnHandlers(elt) - - for (var i = 0; i < elt.attributes.length; i++) { - var name = elt.attributes[i].name - var value = elt.attributes[i].value - if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) { - var afterOnPosition = name.indexOf("-on") + 3; - var nextChar = name.slice(afterOnPosition, afterOnPosition + 1); - if (nextChar === "-" || nextChar === ":") { - var eventName = name.slice(afterOnPosition + 1); - // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support - if (startsWith(eventName, ":")) { - eventName = "htmx" + eventName - } else if (startsWith(eventName, "-")) { - eventName = "htmx:" + eventName.slice(1); - } else if (startsWith(eventName, "htmx-")) { - eventName = "htmx:" + eventName.slice(5); - } - - addHxOnEventHandler(elt, eventName, value) - } - } - } - } - - function initNode(elt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return; - } - var nodeData = getInternalData(elt); - if (nodeData.initHash !== attributeHash(elt)) { - // clean up any previously processed info - deInitNode(elt); - - nodeData.initHash = attributeHash(elt); - - processHxOn(elt); - - triggerEvent(elt, "htmx:beforeProcessNode") - - if (elt.value) { - nodeData.lastValue = elt.value; - } - - var triggerSpecs = getTriggerSpecs(elt); - var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs); - - if (!hasExplicitHttpAction) { - if (getClosestAttributeValue(elt, "hx-boost") === "true") { - boostElement(elt, nodeData, triggerSpecs); - } else if (hasAttribute(elt, 'hx-trigger')) { - triggerSpecs.forEach(function (triggerSpec) { - // For "naked" triggers, don't do anything at all - addTriggerHandler(elt, triggerSpec, nodeData, function () { - }) - }) - } - } - - // Handle submit buttons/inputs that have the form attribute set - // see https://developer.mozilla.org/docs/Web/HTML/Element/button - if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) { - initButtonTracking(elt) - } - - var sseInfo = getAttributeValue(elt, 'hx-sse'); - if (sseInfo) { - processSSEInfo(elt, nodeData, sseInfo); - } - - var wsInfo = getAttributeValue(elt, 'hx-ws'); - if (wsInfo) { - processWebSocketInfo(elt, nodeData, wsInfo); - } - triggerEvent(elt, "htmx:afterProcessNode"); - } - } - - function processNode(elt) { - elt = resolveTarget(elt); - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return; - } - initNode(elt); - forEach(findElementsToProcess(elt), function(child) { initNode(child) }); - // Because it happens second, the new way of adding onHandlers superseeds the old one - // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored - forEach(findHxOnWildcardElements(elt), processHxOnWildcard); - } - - //==================================================================== - // Event/Log Support - //==================================================================== - - function kebabEventName(str) { - return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase(); - } - - 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({error:eventName}, detail)); - } - - function ignoreEventForLogging(eventName) { - return eventName === "htmx:afterProcessNode" - } - - /** - * `withExtensions` locates all active extensions for a provided element, then - * executes the provided function using each of the active extensions. It should - * be called internally at every extendable execution point in htmx. - * - * @param {HTMLElement} elt - * @param {(extension:import("./htmx").HtmxExtension) => void} toDo - * @returns void - */ - function withExtensions(elt, toDo) { - forEach(getExtensions(elt), function(extension){ - try { - toDo(extension); - } catch (e) { - logError(e); - } - }); - } - - function logError(msg) { - if(console.error) { - console.error(msg); - } else if (console.log) { - console.log("ERROR: ", msg); - } - } - - function triggerEvent(elt, eventName, detail) { - elt = resolveTarget(elt); - if (detail == null) { - detail = {}; - } - detail["elt"] = elt; - var event = makeEvent(eventName, detail); - if (htmx.logger && !ignoreEventForLogging(eventName)) { - htmx.logger(elt, eventName, detail); - } - if (detail.error) { - logError(detail.error); - triggerEvent(elt, "htmx:error", {errorInfo:detail}) - } - var eventResult = elt.dispatchEvent(event); - var kebabName = kebabEventName(eventName); - if (eventResult && kebabName !== eventName) { - var kebabedEvent = makeEvent(kebabName, event.detail); - eventResult = eventResult && elt.dispatchEvent(kebabedEvent) - } - withExtensions(elt, function (extension) { - eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) - }); - return eventResult; - } - - //==================================================================== - // History Support - //==================================================================== - var currentPathForHistory = location.pathname+location.search; - - function getHistoryElement() { - var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]'); - return historyElt || getDocument().body; - } - - function saveToHistoryCache(url, content, title, scroll) { - if (!canAccessLocalStorage()) { - return; - } - - if (htmx.config.historyCacheSize <= 0) { - // make sure that an eventually already existing cache is purged - localStorage.removeItem("htmx-history-cache"); - return; - } - - url = normalizePath(url); - - var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - historyCache.splice(i, 1); - break; - } - } - var newHistoryItem = {url:url, content: content, title:title, scroll:scroll}; - triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache}) - historyCache.push(newHistoryItem) - while (historyCache.length > htmx.config.historyCacheSize) { - historyCache.shift(); - } - while(historyCache.length > 0){ - try { - localStorage.setItem("htmx-history-cache", JSON.stringify(historyCache)); - break; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:historyCacheError", {cause:e, cache: historyCache}) - historyCache.shift(); // shrink the cache and retry - } - } - } - - function getCachedHistory(url) { - if (!canAccessLocalStorage()) { - return null; - } - - url = normalizePath(url); - - var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - return historyCache[i]; - } - } - return null; - } - - function cleanInnerHtmlForHistory(elt) { - var className = htmx.config.requestClass; - var clone = elt.cloneNode(true); - forEach(findAll(clone, "." + className), function(child){ - removeClassFromElement(child, className); - }); - return clone.innerHTML; - } - - function saveCurrentPageToHistory() { - var elt = getHistoryElement(); - var path = currentPathForHistory || location.pathname+location.search; - - // Allow history snapshot feature to be disabled where hx-history="false" - // is present *anywhere* in the current document we're about to save, - // so we can prevent privileged data entering the cache. - // The page will still be reachable as a history entry, but htmx will fetch it - // live from the server onpopstate rather than look in the localStorage cache - var disableHistoryCache - try { - disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') - } catch (e) { - // IE11: insensitive modifier not supported so fallback to case sensitive selector - disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') - } - if (!disableHistoryCache) { - triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt}); - saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); - } - - if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href); - } - - function pushUrlIntoHistory(path) { - // remove the cache buster parameter, if any - if (htmx.config.getCacheBusterParam) { - path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') - if (endsWith(path, '&') || endsWith(path, "?")) { - path = path.slice(0, -1); - } - } - if(htmx.config.historyEnabled) { - history.pushState({htmx:true}, "", path); - } - currentPathForHistory = path; - } - - function replaceUrlInHistory(path) { - if(htmx.config.historyEnabled) history.replaceState({htmx:true}, "", path); - currentPathForHistory = path; - } - - function settleImmediately(tasks) { - forEach(tasks, function (task) { - task.call(); - }); - } - - function loadHistoryFromServer(path) { - var request = new XMLHttpRequest(); - var details = {path: path, xhr:request}; - triggerEvent(getDocument().body, "htmx:historyCacheMiss", details); - request.open('GET', path, true); - request.setRequestHeader("HX-Request", "true"); - request.setRequestHeader("HX-History-Restore-Request", "true"); - request.setRequestHeader("HX-Current-URL", getDocument().location.href); - request.onload = function () { - if (this.status >= 200 && this.status < 400) { - triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); - var fragment = makeFragment(this.response); - // @ts-ignore - fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; - var historyElement = getHistoryElement(); - var settleInfo = makeSettleInfo(historyElement); - var title = findTitle(this.response); - if (title) { - var titleElt = find("title"); - if (titleElt) { - titleElt.innerHTML = title; - } else { - window.document.title = title; - } - } - // @ts-ignore - swapInnerHTML(historyElement, fragment, settleInfo) - settleImmediately(settleInfo.tasks); - currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response}); - } else { - triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details); - } - }; - request.send(); - } - - function restoreHistory(path) { - saveCurrentPageToHistory(); - path = path || location.pathname+location.search; - var cached = getCachedHistory(path); - if (cached) { - var fragment = makeFragment(cached.content); - var historyElement = getHistoryElement(); - var settleInfo = makeSettleInfo(historyElement); - swapInnerHTML(historyElement, fragment, settleInfo) - settleImmediately(settleInfo.tasks); - document.title = cached.title; - setTimeout(function () { - window.scrollTo(0, cached.scroll); - }, 0); // next 'tick', so browser has time to render layout - currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); - } else { - if (htmx.config.refreshOnHistoryMiss) { - - // @ts-ignore: optional parameter in reload() function throws error - window.location.reload(true); - } else { - loadHistoryFromServer(path); - } - } - } - - function addRequestIndicatorClasses(elt) { - var indicators = findAttributeTargets(elt, 'hx-indicator'); - if (indicators == null) { - indicators = [elt]; - } - forEach(indicators, function (ic) { - var internalData = getInternalData(ic); - internalData.requestCount = (internalData.requestCount || 0) + 1; - ic.classList["add"].call(ic.classList, htmx.config.requestClass); - }); - return indicators; - } - - function disableElements(elt) { - var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt'); - if (disabledElts == null) { - disabledElts = []; - } - forEach(disabledElts, function (disabledElement) { - var internalData = getInternalData(disabledElement); - internalData.requestCount = (internalData.requestCount || 0) + 1; - disabledElement.setAttribute("disabled", ""); - }); - return disabledElts; - } - - function removeRequestIndicators(indicators, disabled) { - forEach(indicators, function (ic) { - var internalData = getInternalData(ic); - internalData.requestCount = (internalData.requestCount || 0) - 1; - if (internalData.requestCount === 0) { - ic.classList["remove"].call(ic.classList, htmx.config.requestClass); - } - }); - forEach(disabled, function (disabledElement) { - var internalData = getInternalData(disabledElement); - internalData.requestCount = (internalData.requestCount || 0) - 1; - if (internalData.requestCount === 0) { - disabledElement.removeAttribute('disabled'); - } - }); - } - - //==================================================================== - // 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 || closest(elt, "fieldset[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 addValueToValues(name, value, values) { - // This is a little ugly because both the current value of the named value in the form - // and the new value could be arrays, so we have to handle all four cases :/ - if (name != null && value != null) { - var current = values[name]; - if (current === undefined) { - values[name] = value; - } else if (Array.isArray(current)) { - if (Array.isArray(value)) { - values[name] = current.concat(value); - } else { - current.push(value); - } - } else { - if (Array.isArray(value)) { - values[name] = [current].concat(value); - } else { - values[name] = [current, value]; - } - } - } - } - - function processInputValue(processed, values, errors, elt, validate) { - if (elt == null || haveSeenNode(processed, elt)) { - return; - } else { - processed.push(elt); - } - if (shouldInclude(elt)) { - var name = getRawAttribute(elt,"name"); - var value = elt.value; - if (elt.multiple && elt.tagName === "SELECT") { - value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value }); - } - // include file inputs - if (elt.files) { - value = toArray(elt.files); - } - addValueToValues(name, value, values); - if (validate) { - validateElement(elt, errors); - } - } - if (matches(elt, 'form')) { - var inputs = elt.elements; - forEach(inputs, function(input) { - processInputValue(processed, values, errors, input, validate); - }); - } - } - - function validateElement(element, errors) { - if (element.willValidate) { - triggerEvent(element, "htmx:validation:validate") - if (!element.checkValidity()) { - errors.push({elt: element, message:element.validationMessage, validity:element.validity}); - triggerEvent(element, "htmx:validation:failed", {message:element.validationMessage, validity:element.validity}) - } - } - } - - /** - * @param {HTMLElement} elt - * @param {string} verb - */ - function getInputValues(elt, verb) { - var processed = []; - var values = {}; - var formValues = {}; - var errors = []; - var internalData = getInternalData(elt); - if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { - internalData.lastButtonClicked = null - } - - // only validate when form is directly submitted and novalidate or formnovalidate are not set - // or if the element has an explicit hx-validate="true" on it - var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true"; - if (internalData.lastButtonClicked) { - validate = validate && internalData.lastButtonClicked.formNoValidate !== true; - } - - // for a non-GET include the closest form - if (verb !== 'get') { - processInputValue(processed, formValues, errors, closest(elt, 'form'), validate); - } - - // include the element itself - processInputValue(processed, values, errors, elt, validate); - - // if a button or submit was clicked last, include its value - if (internalData.lastButtonClicked || elt.tagName === "BUTTON" || - (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) { - var button = internalData.lastButtonClicked || elt - var name = getRawAttribute(button, "name") - addValueToValues(name, button.value, formValues) - } - - // include any explicit includes - var includes = findAttributeTargets(elt, "hx-include"); - forEach(includes, function(node) { - processInputValue(processed, values, errors, node, validate); - // if a non-form is included, include any input values within it - if (!matches(node, 'form')) { - forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { - processInputValue(processed, values, errors, descendant, validate); - }) - } - }); - - // form values take precedence, overriding the regular values - values = mergeObjects(values, formValues); - - return {errors:errors, values:values}; - } - - function appendParam(returnStr, name, realValue) { - if (returnStr !== "") { - returnStr += "&"; - } - if (String(realValue) === "[object Object]") { - realValue = JSON.stringify(realValue); - } - var s = encodeURIComponent(realValue); - returnStr += encodeURIComponent(name) + "=" + s; - 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; - } - - function makeFormData(values) { - var formData = new FormData(); - for (var name in values) { - if (values.hasOwnProperty(name)) { - var value = values[name]; - if (Array.isArray(value)) { - forEach(value, function(v) { - formData.append(name, v); - }); - } else { - formData.append(name, value); - } - } - } - return formData; - } - - //==================================================================== - // Ajax - //==================================================================== - - /** - * @param {HTMLElement} elt - * @param {HTMLElement} target - * @param {string} prompt - * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification - */ - function getHeaders(elt, target, prompt) { - var headers = { - "HX-Request" : "true", - "HX-Trigger" : getRawAttribute(elt, "id"), - "HX-Trigger-Name" : getRawAttribute(elt, "name"), - "HX-Target" : getAttributeValue(target, "id"), - "HX-Current-URL" : getDocument().location.href, - } - getValuesForElement(elt, "hx-headers", false, headers) - if (prompt !== undefined) { - headers["HX-Prompt"] = prompt; - } - if (getInternalData(elt).boosted) { - headers["HX-Boosted"] = "true"; - } - return headers; - } - - /** - * filterValues takes an object containing form input values - * and returns a new object that only contains keys that are - * specified by the closest "hx-params" attribute - * @param {Object} inputValues - * @param {HTMLElement} elt - * @returns {Object} - */ - function filterValues(inputValues, elt) { - var paramsValue = getClosestAttributeValue(elt, "hx-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 isAnchorLink(elt) { - return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0 - } - - /** - * - * @param {HTMLElement} elt - * @param {string} swapInfoOverride - * @returns {import("./htmx").HtmxSwapSpecification} - */ - function getSwapSpecification(elt, swapInfoOverride) { - var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap"); - var swapSpec = { - "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, - "swapDelay" : htmx.config.defaultSwapDelay, - "settleDelay" : htmx.config.defaultSettleDelay - } - if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { - swapSpec["show"] = "top" - } - if (swapInfo) { - var split = splitOnWhitespace(swapInfo); - if (split.length > 0) { - for (var i = 0; i < split.length; i++) { - var value = split[i]; - if (value.indexOf("swap:") === 0) { - swapSpec["swapDelay"] = parseInterval(value.substr(5)); - } else if (value.indexOf("settle:") === 0) { - swapSpec["settleDelay"] = parseInterval(value.substr(7)); - } else if (value.indexOf("transition:") === 0) { - swapSpec["transition"] = value.substr(11) === "true"; - } else if (value.indexOf("ignoreTitle:") === 0) { - swapSpec["ignoreTitle"] = value.substr(12) === "true"; - } else if (value.indexOf("scroll:") === 0) { - var scrollSpec = value.substr(7); - var splitSpec = scrollSpec.split(":"); - var scrollVal = splitSpec.pop(); - var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; - swapSpec["scroll"] = scrollVal; - swapSpec["scrollTarget"] = selectorVal; - } else if (value.indexOf("show:") === 0) { - var showSpec = value.substr(5); - var splitSpec = showSpec.split(":"); - var showVal = splitSpec.pop(); - var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; - swapSpec["show"] = showVal; - swapSpec["showTarget"] = selectorVal; - } else if (value.indexOf("focus-scroll:") === 0) { - var focusScrollVal = value.substr("focus-scroll:".length); - swapSpec["focusScroll"] = focusScrollVal == "true"; - } else if (i == 0) { - swapSpec["swapStyle"] = value; - } else { - logError('Unknown modifier in hx-swap: ' + value); - } - } - } - } - return swapSpec; - } - - function usesFormData(elt) { - return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || - (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data"); - } - - function encodeParamsForBody(xhr, elt, filteredParameters) { - var encodedParameters = null; - withExtensions(elt, function (extension) { - if (encodedParameters == null) { - encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt); - } - }); - if (encodedParameters != null) { - return encodedParameters; - } else { - if (usesFormData(elt)) { - return makeFormData(filteredParameters); - } else { - return urlEncode(filteredParameters); - } - } - } - - /** - * - * @param {Element} target - * @returns {import("./htmx").HtmxSettleInfo} - */ - function makeSettleInfo(target) { - return {tasks: [], elts: [target]}; - } - - function updateScrollState(content, swapSpec) { - var first = content[0]; - var last = content[content.length - 1]; - if (swapSpec.scroll) { - var target = null; - if (swapSpec.scrollTarget) { - target = querySelectorExt(first, swapSpec.scrollTarget); - } - if (swapSpec.scroll === "top" && (first || target)) { - target = target || first; - target.scrollTop = 0; - } - if (swapSpec.scroll === "bottom" && (last || target)) { - target = target || last; - target.scrollTop = target.scrollHeight; - } - } - if (swapSpec.show) { - var target = null; - if (swapSpec.showTarget) { - var targetStr = swapSpec.showTarget; - if (swapSpec.showTarget === "window") { - targetStr = "body"; - } - target = querySelectorExt(first, targetStr); - } - if (swapSpec.show === "top" && (first || target)) { - target = target || first; - target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior}); - } - if (swapSpec.show === "bottom" && (last || target)) { - target = target || last; - target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior}); - } - } - } - - /** - * @param {HTMLElement} elt - * @param {string} attr - * @param {boolean=} evalAsDefault - * @param {Object=} values - * @returns {Object} - */ - function getValuesForElement(elt, attr, evalAsDefault, values) { - if (values == null) { - values = {}; - } - if (elt == null) { - return values; - } - var attributeValue = getAttributeValue(elt, attr); - if (attributeValue) { - var str = attributeValue.trim(); - var evaluateValue = evalAsDefault; - if (str === "unset") { - return null; - } - if (str.indexOf("javascript:") === 0) { - str = str.substr(11); - evaluateValue = true; - } else if (str.indexOf("js:") === 0) { - str = str.substr(3); - evaluateValue = true; - } - if (str.indexOf('{') !== 0) { - str = "{" + str + "}"; - } - var varsValues; - if (evaluateValue) { - varsValues = maybeEval(elt,function () {return Function("return (" + str + ")")();}, {}); - } else { - varsValues = parseJSON(str); - } - for (var key in varsValues) { - if (varsValues.hasOwnProperty(key)) { - if (values[key] == null) { - values[key] = varsValues[key]; - } - } - } - } - return getValuesForElement(parentElt(elt), attr, evalAsDefault, values); - } - - function maybeEval(elt, toEval, defaultVal) { - if (htmx.config.allowEval) { - return toEval(); - } else { - triggerErrorEvent(elt, 'htmx:evalDisallowedError'); - return defaultVal; - } - } - - /** - * @param {HTMLElement} elt - * @param {*} expressionVars - * @returns - */ - function getHXVarsForElement(elt, expressionVars) { - return getValuesForElement(elt, "hx-vars", true, expressionVars); - } - - /** - * @param {HTMLElement} elt - * @param {*} expressionVars - * @returns - */ - function getHXValsForElement(elt, expressionVars) { - return getValuesForElement(elt, "hx-vals", false, expressionVars); - } - - /** - * @param {HTMLElement} elt - * @returns {Object} - */ - function getExpressionVars(elt) { - return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)); - } - - function safelySetHeaderValue(xhr, header, headerValue) { - if (headerValue !== null) { - try { - xhr.setRequestHeader(header, headerValue); - } catch (e) { - // On an exception, try to set the header URI encoded instead - xhr.setRequestHeader(header, encodeURIComponent(headerValue)); - xhr.setRequestHeader(header + "-URI-AutoEncoded", "true"); - } - } - } - - function getPathFromResponse(xhr) { - // NB: IE11 does not support this stuff - if (xhr.responseURL && typeof(URL) !== "undefined") { - try { - var url = new URL(xhr.responseURL); - return url.pathname + url.search; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:badResponseUrl", {url: xhr.responseURL}); - } - } - } - - function hasHeader(xhr, regexp) { - return regexp.test(xhr.getAllResponseHeaders()) - } - - function ajaxHelper(verb, path, context) { - verb = verb.toLowerCase(); - if (context) { - if (context instanceof Element || isType(context, 'String')) { - return issueAjaxRequest(verb, path, null, null, { - targetOverride: resolveTarget(context), - returnPromise: true - }); - } else { - return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, - { - handler : context.handler, - headers : context.headers, - values : context.values, - targetOverride: resolveTarget(context.target), - swapOverride: context.swap, - select: context.select, - returnPromise: true - }); - } - } else { - return issueAjaxRequest(verb, path, null, null, { - returnPromise: true - }); - } - } - - function hierarchyForElt(elt) { - var arr = []; - while (elt) { - arr.push(elt); - elt = elt.parentElement; - } - return arr; - } - - function verifyPath(elt, path, requestConfig) { - var sameHost - var url - if (typeof URL === "function") { - url = new URL(path, document.location.href); - var origin = document.location.origin; - sameHost = origin === url.origin; - } else { - // IE11 doesn't support URL - url = path - sameHost = startsWith(path, document.location.origin) - } - - if (htmx.config.selfRequestsOnly) { - if (!sameHost) { - return false; - } - } - return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig)); - } - - function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { - var resolve = null; - var reject = null; - etc = etc != null ? etc : {}; - if(etc.returnPromise && typeof Promise !== "undefined"){ - var promise = new Promise(function (_resolve, _reject) { - resolve = _resolve; - reject = _reject; - }); - } - if(elt == null) { - elt = getDocument().body; - } - var responseHandler = etc.handler || handleAjaxResponse; - var select = etc.select || null; - - if (!bodyContains(elt)) { - // do not issue requests for elements removed from the DOM - maybeCall(resolve); - return promise; - } - var target = etc.targetOverride || getTarget(elt); - if (target == null || target == DUMMY_ELT) { - triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); - maybeCall(reject); - return promise; - } - - var eltData = getInternalData(elt); - var submitter = eltData.lastButtonClicked; - - if (submitter) { - var buttonPath = getRawAttribute(submitter, "formaction"); - if (buttonPath != null) { - path = buttonPath; - } - - var buttonVerb = getRawAttribute(submitter, "formmethod") - if (buttonVerb != null) { - // ignore buttons with formmethod="dialog" - if (buttonVerb.toLowerCase() !== "dialog") { - verb = buttonVerb; - } - } - } - - var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); - // allow event-based confirmation w/ a callback - if (confirmed === undefined) { - var issueRequest = function(skipConfirmation) { - return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation); - } - var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion}; - if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { - maybeCall(resolve); - return promise; - } - } - - var syncElt = elt; - var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); - var queueStrategy = null; - var abortable = false; - if (syncStrategy) { - var syncStrings = syncStrategy.split(":"); - var selector = syncStrings[0].trim(); - if (selector === "this") { - syncElt = findThisElement(elt, 'hx-sync'); - } else { - syncElt = querySelectorExt(elt, selector); - } - // default to the drop strategy - syncStrategy = (syncStrings[1] || 'drop').trim(); - eltData = getInternalData(syncElt); - if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { - maybeCall(resolve); - return promise; - } else if (syncStrategy === "abort") { - if (eltData.xhr) { - maybeCall(resolve); - return promise; - } else { - abortable = true; - } - } else if (syncStrategy === "replace") { - triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue - } else if (syncStrategy.indexOf("queue") === 0) { - var queueStrArray = syncStrategy.split(" "); - queueStrategy = (queueStrArray[1] || "last").trim(); - } - } - - if (eltData.xhr) { - if (eltData.abortable) { - triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue - } else { - if(queueStrategy == null){ - if (event) { - var eventData = getInternalData(event); - if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { - queueStrategy = eventData.triggerSpec.queue; - } - } - if (queueStrategy == null) { - queueStrategy = "last"; - } - } - if (eltData.queuedRequests == null) { - eltData.queuedRequests = []; - } - if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } else if (queueStrategy === "all") { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } else if (queueStrategy === "last") { - eltData.queuedRequests = []; // dump existing queue - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } - maybeCall(resolve); - return promise; - } - } - - var xhr = new XMLHttpRequest(); - eltData.xhr = xhr; - eltData.abortable = abortable; - var endRequestLock = function(){ - eltData.xhr = null; - eltData.abortable = false; - if (eltData.queuedRequests != null && - eltData.queuedRequests.length > 0) { - var queuedRequest = eltData.queuedRequests.shift(); - queuedRequest(); - } - } - var promptQuestion = getClosestAttributeValue(elt, "hx-prompt"); - if (promptQuestion) { - var promptResponse = prompt(promptQuestion); - // prompt returns null if cancelled and empty string if accepted with no entry - if (promptResponse === null || - !triggerEvent(elt, 'htmx:prompt', {prompt: promptResponse, target:target})) { - maybeCall(resolve); - endRequestLock(); - return promise; - } + triggerErrorEvent(getDocument().body, 'htmx:syntax:error', { error: e, source: conditionalSource }) + return null } + } + } else if (token === '[') { + bracketCount++ + } + if (isPossibleRelativeReference(token, last, paramName)) { + conditionalSource += '((' + paramName + '.' + token + ') ? (' + paramName + '.' + token + ') : (window.' + token + '))' + } else { + conditionalSource = conditionalSource + token + } + last = tokens.shift() + } + } + } + + /** + * @param {string[]} tokens + * @param {RegExp} match + * @returns {string} + */ + function consumeUntil(tokens, match) { + let result = '' + while (tokens.length > 0 && !match.test(tokens[0])) { + result += tokens.shift() + } + return result + } + + /** + * @param {string[]} tokens + * @returns {string} + */ + function consumeCSSSelector(tokens) { + let result + if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { + tokens.shift() + result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim() + tokens.shift() + } else { + result = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } + return result + } + + const INPUT_SELECTOR = 'input, textarea, select' + + /** + * @param {Element} elt + * @param {string} explicitTrigger + * @param {Object} cache for trigger specs + * @returns {HtmxTriggerSpecification[]} + */ + function parseAndCacheTrigger(elt, explicitTrigger, cache) { + /** @type HtmxTriggerSpecification[] */ + const triggerSpecs = [] + const tokens = tokenizeString(explicitTrigger) + do { + consumeUntil(tokens, NOT_WHITESPACE) + const initialLength = tokens.length + const trigger = consumeUntil(tokens, /[,\[\s]/) + if (trigger !== '') { + if (trigger === 'every') { + /** @type HtmxTriggerSpecification */ + const every = { trigger: 'every' } + consumeUntil(tokens, NOT_WHITESPACE) + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)) + consumeUntil(tokens, NOT_WHITESPACE) + var eventFilter = maybeGenerateConditional(elt, tokens, 'event') + if (eventFilter) { + every.eventFilter = eventFilter + } + triggerSpecs.push(every) + } else { + /** @type HtmxTriggerSpecification */ + const triggerSpec = { trigger } + var eventFilter = maybeGenerateConditional(elt, tokens, 'event') + if (eventFilter) { + triggerSpec.eventFilter = eventFilter + } + while (tokens.length > 0 && tokens[0] !== ',') { + consumeUntil(tokens, NOT_WHITESPACE) + const token = tokens.shift() + if (token === 'changed') { + triggerSpec.changed = true + } else if (token === 'once') { + triggerSpec.once = true + } else if (token === 'consume') { + triggerSpec.consume = true + } else if (token === 'delay' && tokens[0] === ':') { + tokens.shift() + triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)) + } else if (token === 'from' && tokens[0] === ':') { + tokens.shift() + if (COMBINED_SELECTOR_START.test(tokens[0])) { + var from_arg = consumeCSSSelector(tokens) + } else { + var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA) + if (from_arg === 'closest' || from_arg === 'find' || from_arg === 'next' || from_arg === 'previous') { + tokens.shift() + const selector = consumeCSSSelector(tokens) + // `next` and `previous` allow a selector-less syntax + if (selector.length > 0) { + from_arg += ' ' + selector + } + } + } + triggerSpec.from = from_arg + } else if (token === 'target' && tokens[0] === ':') { + tokens.shift() + triggerSpec.target = consumeCSSSelector(tokens) + } else if (token === 'throttle' && tokens[0] === ':') { + tokens.shift() + triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)) + } else if (token === 'queue' && tokens[0] === ':') { + tokens.shift() + triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } else if (token === 'root' && tokens[0] === ':') { + tokens.shift() + triggerSpec[token] = consumeCSSSelector(tokens) + } else if (token === 'threshold' && tokens[0] === ':') { + tokens.shift() + triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } else { + triggerErrorEvent(elt, 'htmx:syntax:error', { token: tokens.shift() }) + } + } + triggerSpecs.push(triggerSpec) + } + } + if (tokens.length === initialLength) { + triggerErrorEvent(elt, 'htmx:syntax:error', { token: tokens.shift() }) + } + consumeUntil(tokens, NOT_WHITESPACE) + } while (tokens[0] === ',' && tokens.shift()) + if (cache) { + cache[explicitTrigger] = triggerSpecs + } + return triggerSpecs + } + + /** + * @param {Element} elt + * @returns {HtmxTriggerSpecification[]} + */ + function getTriggerSpecs(elt) { + const explicitTrigger = getAttributeValue(elt, 'hx-trigger') + let triggerSpecs = [] + if (explicitTrigger) { + const cache = htmx.config.triggerSpecsCache + triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) + } - if (confirmQuestion && !confirmed) { - if(!confirm(confirmQuestion)) { - maybeCall(resolve); - endRequestLock() - return promise; - } + if (triggerSpecs.length > 0) { + return triggerSpecs + } else if (matches(elt, 'form')) { + return [{ trigger: 'submit' }] + } else if (matches(elt, 'input[type="button"], input[type="submit"]')) { + return [{ trigger: 'click' }] + } else if (matches(elt, INPUT_SELECTOR)) { + return [{ trigger: 'change' }] + } else { + return [{ trigger: 'click' }] + } + } + + /** + * @param {Element} elt + */ + function cancelPolling(elt) { + getInternalData(elt).cancelled = true + } + + /** + * @param {Element} elt + * @param {TriggerHandler} handler + * @param {HtmxTriggerSpecification} spec + */ + function processPolling(elt, handler, spec) { + const nodeData = getInternalData(elt) + nodeData.timeout = getWindow().setTimeout(function() { + if (bodyContains(elt) && nodeData.cancelled !== true) { + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { + handler(elt) + } + processPolling(elt, handler, spec) + } + }, spec.pollInterval) + } + + /** + * @param {HTMLAnchorElement} elt + * @returns {boolean} + */ + function isLocalLink(elt) { + return location.hostname === elt.hostname && + getRawAttribute(elt, 'href') && + getRawAttribute(elt, 'href').indexOf('#') !== 0 + } + + /** + * @param {Element} elt + */ + function eltIsDisabled(elt) { + return closest(elt, htmx.config.disableSelector) + } + + /** + * @param {Element} elt + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification[]} triggerSpecs + */ + function boostElement(elt, nodeData, triggerSpecs) { + if ((elt instanceof HTMLAnchorElement && isLocalLink(elt) && (elt.target === '' || elt.target === '_self')) || elt.tagName === 'FORM') { + nodeData.boosted = true + let verb, path + if (elt.tagName === 'A') { + verb = 'get' + path = getRawAttribute(elt, 'href') + } else { + const rawAttribute = getRawAttribute(elt, 'method') + verb = rawAttribute ? rawAttribute.toLowerCase() : 'get' + if (verb === 'get') { + } + path = getRawAttribute(elt, 'action') + } + triggerSpecs.forEach(function(triggerSpec) { + addEventListener(elt, function(node, evt) { + const elt = asElement(node) + if (eltIsDisabled(elt)) { + cleanUpElement(elt) + return + } + issueAjaxRequest(verb, path, elt, evt) + }, nodeData, triggerSpec, true) + }) + } + } + + /** + * @param {Event} evt + * @param {Node} node + * @returns {boolean} + */ + function shouldCancel(evt, node) { + const elt = asElement(node) + if (!elt) { + return false + } + if (evt.type === 'submit' || evt.type === 'click') { + if (elt.tagName === 'FORM') { + return true + } + if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { + return true + } + if (elt instanceof HTMLAnchorElement && elt.href && + (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf('#') !== 0)) { + return true + } + } + return false + } + + /** + * @param {Node} elt + * @param {Event|MouseEvent|KeyboardEvent|TouchEvent} evt + * @returns {boolean} + */ + function ignoreBoostedAnchorCtrlClick(elt, evt) { + return getInternalData(elt).boosted && elt instanceof HTMLAnchorElement && evt.type === 'click' && + // @ts-ignore this will resolve to undefined for events that don't define those properties, which is fine + (evt.ctrlKey || evt.metaKey) + } + + /** + * @param {HtmxTriggerSpecification} triggerSpec + * @param {Node} elt + * @param {Event} evt + * @returns {boolean} + */ + function maybeFilterEvent(triggerSpec, elt, evt) { + const eventFilter = triggerSpec.eventFilter + if (eventFilter) { + try { + return eventFilter.call(elt, evt) !== true + } catch (e) { + const source = eventFilter.source + triggerErrorEvent(getDocument().body, 'htmx:eventFilter:error', { error: e, source }) + return true + } + } + return false + } + + /** + * @param {Node} elt + * @param {TriggerHandler} handler + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification} triggerSpec + * @param {boolean} [explicitCancel] + */ + function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { + const elementData = getInternalData(elt) + /** @type {(Node|Window)[]} */ + let eltsToListenOn + if (triggerSpec.from) { + eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from) + } else { + eltsToListenOn = [elt] + } + // store the initial values of the elements, so we can tell if they change + if (triggerSpec.changed) { + eltsToListenOn.forEach(function(eltToListenOn) { + const eltToListenOnData = getInternalData(eltToListenOn) + // @ts-ignore value will be undefined for non-input elements, which is fine + eltToListenOnData.lastValue = eltToListenOn.value + }) + } + forEach(eltsToListenOn, function(eltToListenOn) { + /** @type EventListener */ + const eventListener = function(evt) { + if (!bodyContains(elt)) { + eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener) + return + } + if (ignoreBoostedAnchorCtrlClick(elt, evt)) { + return + } + if (explicitCancel || shouldCancel(evt, elt)) { + evt.preventDefault() + } + if (maybeFilterEvent(triggerSpec, elt, evt)) { + return + } + const eventData = getInternalData(evt) + eventData.triggerSpec = triggerSpec + if (eventData.handledFor == null) { + eventData.handledFor = [] + } + if (eventData.handledFor.indexOf(elt) < 0) { + eventData.handledFor.push(elt) + if (triggerSpec.consume) { + evt.stopPropagation() + } + if (triggerSpec.target && evt.target) { + if (!matches(asElement(evt.target), triggerSpec.target)) { + return + } + } + if (triggerSpec.once) { + if (elementData.triggeredOnce) { + return + } else { + elementData.triggeredOnce = true + } + } + if (triggerSpec.changed) { + const eltToListenOnData = getInternalData(eltToListenOn) + // @ts-ignore value will be undefined for non-input elements, which is fine + const value = eltToListenOn.value + if (eltToListenOnData.lastValue === value) { + return + } + eltToListenOnData.lastValue = value + } + if (elementData.delayed) { + clearTimeout(elementData.delayed) + } + if (elementData.throttle) { + return + } + + if (triggerSpec.throttle > 0) { + if (!elementData.throttle) { + handler(elt, evt) + elementData.throttle = getWindow().setTimeout(function() { + elementData.throttle = null + }, triggerSpec.throttle) + } + } else if (triggerSpec.delay > 0) { + elementData.delayed = getWindow().setTimeout(function() { handler(elt, evt) }, triggerSpec.delay) + } else { + triggerEvent(elt, 'htmx:trigger') + handler(elt, evt) + } + } + } + if (nodeData.listenerInfos == null) { + nodeData.listenerInfos = [] + } + nodeData.listenerInfos.push({ + trigger: triggerSpec.trigger, + listener: eventListener, + on: eltToListenOn + }) + eltToListenOn.addEventListener(triggerSpec.trigger, eventListener) + }) + } + + let windowIsScrolling = false // used by initScrollHandler + let scrollHandler = null + function initScrollHandler() { + if (!scrollHandler) { + scrollHandler = function() { + windowIsScrolling = true + } + window.addEventListener('scroll', scrollHandler) + setInterval(function() { + if (windowIsScrolling) { + windowIsScrolling = false + forEach(getDocument().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"), function(elt) { + maybeReveal(elt) + }) + } + }, 200) + } + } + + /** + * @param {Element} elt + */ + function maybeReveal(elt) { + if (!hasAttribute(elt, 'data-hx-revealed') && isScrolledIntoView(elt)) { + elt.setAttribute('data-hx-revealed', 'true') + const nodeData = getInternalData(elt) + if (nodeData.initHash) { + triggerEvent(elt, 'revealed') + } else { + // if the node isn't initialized, wait for it before triggering the request + elt.addEventListener('htmx:afterProcessNode', function() { triggerEvent(elt, 'revealed') }, { once: true }) + } + } + } + + //= =================================================================== + + /** + * @param {Element} elt + * @param {TriggerHandler} handler + * @param {HtmxNodeInternalData} nodeData + * @param {number} delay + */ + function loadImmediately(elt, handler, nodeData, delay) { + const load = function() { + if (!nodeData.loaded) { + nodeData.loaded = true + handler(elt) + } + } + if (delay > 0) { + getWindow().setTimeout(load, delay) + } else { + load() + } + } + + /** + * @param {Element} elt + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification[]} triggerSpecs + * @returns {boolean} + */ + function processVerbs(elt, nodeData, triggerSpecs) { + let explicitAction = false + forEach(VERBS, function(verb) { + if (hasAttribute(elt, 'hx-' + verb)) { + const path = getAttributeValue(elt, 'hx-' + verb) + explicitAction = true + nodeData.path = path + nodeData.verb = verb + triggerSpecs.forEach(function(triggerSpec) { + addTriggerHandler(elt, triggerSpec, nodeData, function(node, evt) { + const elt = asElement(node) + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return } + issueAjaxRequest(verb, path, elt, evt) + }) + }) + } + }) + return explicitAction + } + + /** + * @callback TriggerHandler + * @param {Node} elt + * @param {Event} [evt] + */ + + /** + * @param {Node} elt + * @param {HtmxTriggerSpecification} triggerSpec + * @param {HtmxNodeInternalData} nodeData + * @param {TriggerHandler} handler + */ + function addTriggerHandler(elt, triggerSpec, nodeData, handler) { + if (triggerSpec.trigger === 'revealed') { + initScrollHandler() + addEventListener(elt, handler, nodeData, triggerSpec) + maybeReveal(asElement(elt)) + } else if (triggerSpec.trigger === 'intersect') { + const observerOptions = {} + if (triggerSpec.root) { + observerOptions.root = querySelectorExt(elt, triggerSpec.root) + } + if (triggerSpec.threshold) { + observerOptions.threshold = parseFloat(triggerSpec.threshold) + } + const observer = new IntersectionObserver(function(entries) { + for (let i = 0; i < entries.length; i++) { + const entry = entries[i] + if (entry.isIntersecting) { + triggerEvent(elt, 'intersect') + break + } + } + }, observerOptions) + observer.observe(asElement(elt)) + addEventListener(asElement(elt), handler, nodeData, triggerSpec) + } else if (triggerSpec.trigger === 'load') { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent('load', { elt }))) { + loadImmediately(asElement(elt), handler, nodeData, triggerSpec.delay) + } + } else if (triggerSpec.pollInterval > 0) { + nodeData.polling = true + processPolling(asElement(elt), handler, triggerSpec) + } else { + addEventListener(elt, handler, nodeData, triggerSpec) + } + } + + /** + * @param {Node} node + * @returns {boolean} + */ + function shouldProcessHxOn(node) { + const elt = asElement(node) + if (!elt) { + return false + } + const attributes = elt.attributes + for (let j = 0; j < attributes.length; j++) { + const attrName = attributes[j].name + if (startsWith(attrName, 'hx-on:') || startsWith(attrName, 'data-hx-on:') || + startsWith(attrName, 'hx-on-') || startsWith(attrName, 'data-hx-on-')) { + return true + } + } + return false + } + + /** + * @param {Node} elt + * @returns {Element[]} + */ + const HX_ON_QUERY = new XPathEvaluator() + .createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + + ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]') + + function processHXOnRoot(elt, elements) { + if (shouldProcessHxOn(elt)) { + elements.push(asElement(elt)) + } + const iter = HX_ON_QUERY.evaluate(elt) + let node = null + while (node = iter.iterateNext()) elements.push(asElement(node)) + } + + function findHxOnWildcardElements(elt) { + /** @type {Element[]} */ + const elements = [] + if (elt instanceof DocumentFragment) { + for (const child of elt.childNodes) { + processHXOnRoot(child, elements) + } + } else { + processHXOnRoot(elt, elements) + } + return elements + } + + /** + * @param {Element} elt + * @returns {NodeListOf<Element>|[]} + */ + function findElementsToProcess(elt) { + if (elt.querySelectorAll) { + const boostedSelector = ', [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]' + + const extensionSelectors = [] + for (const e in extensions) { + const extension = extensions[e] + if (extension.getSelectors) { + var selectors = extension.getSelectors() + if (selectors) { + extensionSelectors.push(selectors) + } + } + } + + const results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit']," + + ' [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]' + extensionSelectors.flat().map(s => ', ' + s).join('')) + + return results + } else { + return [] + } + } + + /** + * Handle submit buttons/inputs that have the form attribute set + * see https://developer.mozilla.org/docs/Web/HTML/Element/button + * @param {Event} evt + */ + function maybeSetLastButtonClicked(evt) { + const elt = /** @type {HTMLButtonElement|HTMLInputElement} */ (closest(asElement(evt.target), "button, input[type='submit']")) + const internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = elt + } + } + + /** + * @param {Event} evt + */ + function maybeUnsetLastButtonClicked(evt) { + const internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = null + } + } + + /** + * @param {Event} evt + * @returns {HtmxNodeInternalData|undefined} + */ + function getRelatedFormData(evt) { + const elt = closest(asElement(evt.target), "button, input[type='submit']") + if (!elt) { + return + } + const form = resolveTarget('#' + getRawAttribute(elt, 'form'), elt.getRootNode()) || closest(elt, 'form') + if (!form) { + return + } + return getInternalData(form) + } + + /** + * @param {EventTarget} elt + */ + function initButtonTracking(elt) { + // need to handle both click and focus in: + // focusin - in case someone tabs in to a button and hits the space bar + // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + elt.addEventListener('click', maybeSetLastButtonClicked) + elt.addEventListener('focusin', maybeSetLastButtonClicked) + elt.addEventListener('focusout', maybeUnsetLastButtonClicked) + } + + /** + * @param {Element} elt + * @param {string} eventName + * @param {string} code + */ + function addHxOnEventHandler(elt, eventName, code) { + const nodeData = getInternalData(elt) + if (!Array.isArray(nodeData.onHandlers)) { + nodeData.onHandlers = [] + } + let func + /** @type EventListener */ + const listener = function(e) { + maybeEval(elt, function() { + if (eltIsDisabled(elt)) { + return + } + if (!func) { + func = new Function('event', code) + } + func.call(elt, e) + }) + } + elt.addEventListener(eventName, listener) + nodeData.onHandlers.push({ event: eventName, listener }) + } + + /** + * @param {Element} elt + */ + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (let i = 0; i < elt.attributes.length; i++) { + const name = elt.attributes[i].name + const value = elt.attributes[i].value + if (startsWith(name, 'hx-on') || startsWith(name, 'data-hx-on')) { + const afterOnPosition = name.indexOf('-on') + 3 + const nextChar = name.slice(afterOnPosition, afterOnPosition + 1) + if (nextChar === '-' || nextChar === ':') { + let eventName = name.slice(afterOnPosition + 1) + // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support + if (startsWith(eventName, ':')) { + eventName = 'htmx' + eventName + } else if (startsWith(eventName, '-')) { + eventName = 'htmx:' + eventName.slice(1) + } else if (startsWith(eventName, 'htmx-')) { + eventName = 'htmx:' + eventName.slice(5) + } + + addHxOnEventHandler(elt, eventName, value) + } + } + } + } + + /** + * @param {Element|HTMLInputElement} elt + */ + function initNode(elt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + const nodeData = getInternalData(elt) + if (nodeData.initHash !== attributeHash(elt)) { + // clean up any previously processed info + deInitNode(elt) + + nodeData.initHash = attributeHash(elt) + + triggerEvent(elt, 'htmx:beforeProcessNode') + + // @ts-ignore value will be undefined for non-input elements, which is fine + if (elt.value) { + // @ts-ignore + nodeData.lastValue = elt.value + } + + const triggerSpecs = getTriggerSpecs(elt) + const hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs) + + if (!hasExplicitHttpAction) { + if (getClosestAttributeValue(elt, 'hx-boost') === 'true') { + boostElement(elt, nodeData, triggerSpecs) + } else if (hasAttribute(elt, 'hx-trigger')) { + triggerSpecs.forEach(function(triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function() { + }) + }) + } + } + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + if (elt.tagName === 'FORM' || (getRawAttribute(elt, 'type') === 'submit' && hasAttribute(elt, 'form'))) { + initButtonTracking(elt) + } - var headers = getHeaders(elt, target, promptResponse); - - if (verb !== 'get' && !usesFormData(elt)) { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; - } + triggerEvent(elt, 'htmx:afterProcessNode') + } + } + + /** + * Processes new content, enabling htmx behavior. This can be useful if you have content that is added to the DOM outside of the normal htmx request cycle but still want htmx attributes to work. + * + * @see https://htmx.org/api/#process + * + * @param {Element|string} elt element to process + */ + function processNode(elt) { + elt = resolveTarget(elt) + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + initNode(elt) + forEach(findElementsToProcess(elt), function(child) { initNode(child) }) + forEach(findHxOnWildcardElements(elt), processHxOnWildcard) + } + + //= =================================================================== + // Event/Log Support + //= =================================================================== + + /** + * @param {string} str + * @returns {string} + */ + function kebabEventName(str) { + return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase() + } + + /** + * @param {string} eventName + * @param {any} detail + * @returns {CustomEvent} + */ + function makeEvent(eventName, detail) { + let evt + if (window.CustomEvent && typeof window.CustomEvent === 'function') { + // TODO: `composed: true` here is a hack to make global event handlers work with events in shadow DOM + // This breaks expected encapsulation but needs to be here until decided otherwise by core devs + evt = new CustomEvent(eventName, { bubbles: true, cancelable: true, composed: true, detail }) + } else { + evt = getDocument().createEvent('CustomEvent') + evt.initCustomEvent(eventName, true, true, detail) + } + return evt + } + + /** + * @param {EventTarget|string} elt + * @param {string} eventName + * @param {any=} detail + */ + function triggerErrorEvent(elt, eventName, detail) { + triggerEvent(elt, eventName, mergeObjects({ error: eventName }, detail)) + } + + /** + * @param {string} eventName + * @returns {boolean} + */ + function ignoreEventForLogging(eventName) { + return eventName === 'htmx:afterProcessNode' + } + + /** + * `withExtensions` locates all active extensions for a provided element, then + * executes the provided function using each of the active extensions. It should + * be called internally at every extendable execution point in htmx. + * + * @param {Element} elt + * @param {(extension:HtmxExtension) => void} toDo + * @returns void + */ + function withExtensions(elt, toDo) { + forEach(getExtensions(elt), function(extension) { + try { + toDo(extension) + } catch (e) { + logError(e) + } + }) + } + + function logError(msg) { + if (console.error) { + console.error(msg) + } else if (console.log) { + console.log('ERROR: ', msg) + } + } + + /** + * Triggers a given event on an element + * + * @see https://htmx.org/api/#trigger + * + * @param {EventTarget|string} elt the element to trigger the event on + * @param {string} eventName the name of the event to trigger + * @param {any=} detail details for the event + * @returns {boolean} + */ + function triggerEvent(elt, eventName, detail) { + elt = resolveTarget(elt) + if (detail == null) { + detail = {} + } + detail.elt = elt + const event = makeEvent(eventName, detail) + if (htmx.logger && !ignoreEventForLogging(eventName)) { + htmx.logger(elt, eventName, detail) + } + if (detail.error) { + logError(detail.error) + triggerEvent(elt, 'htmx:error', { errorInfo: detail }) + } + let eventResult = elt.dispatchEvent(event) + const kebabName = kebabEventName(eventName) + if (eventResult && kebabName !== eventName) { + const kebabedEvent = makeEvent(kebabName, event.detail) + eventResult = eventResult && elt.dispatchEvent(kebabedEvent) + } + withExtensions(asElement(elt), function(extension) { + eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) + }) + return eventResult + } + + //= =================================================================== + // History Support + //= =================================================================== + let currentPathForHistory = location.pathname + location.search + + /** + * @returns {Element} + */ + function getHistoryElement() { + const historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]') + return historyElt || getDocument().body + } + + /** + * @param {string} url + * @param {Element} rootElt + */ + function saveToHistoryCache(url, rootElt) { + if (!canAccessLocalStorage()) { + return + } - if (etc.headers) { - headers = mergeObjects(headers, etc.headers); - } - var results = getInputValues(elt, verb); - var errors = results.errors; - var rawParameters = results.values; - if (etc.values) { - rawParameters = mergeObjects(rawParameters, etc.values); - } - var expressionVars = getExpressionVars(elt); - var allParameters = mergeObjects(rawParameters, expressionVars); - var filteredParameters = filterValues(allParameters, elt); + // get state to save + const innerHTML = cleanInnerHtmlForHistory(rootElt) + const title = getDocument().title + const scroll = window.scrollY - if (htmx.config.getCacheBusterParam && verb === 'get') { - filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true"; - } + if (htmx.config.historyCacheSize <= 0) { + // make sure that an eventually already existing cache is purged + localStorage.removeItem('htmx-history-cache') + return + } - // behavior of anchors w/ empty href is to use the current URL - if (path == null || path === "") { - path = getDocument().location.href; - } + url = normalizePath(url) + const historyCache = parseJSON(localStorage.getItem('htmx-history-cache')) || [] + for (let i = 0; i < historyCache.length; i++) { + if (historyCache[i].url === url) { + historyCache.splice(i, 1) + break + } + } - var requestAttrValues = getValuesForElement(elt, 'hx-request'); + /** @type HtmxHistoryItem */ + const newHistoryItem = { url, content: innerHTML, title, scroll } - var eltIsBoosted = getInternalData(elt).boosted; + triggerEvent(getDocument().body, 'htmx:historyItemCreated', { item: newHistoryItem, cache: historyCache }) - var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + historyCache.push(newHistoryItem) + while (historyCache.length > htmx.config.historyCacheSize) { + historyCache.shift() + } - var requestConfig = { - boosted: eltIsBoosted, - useUrlParams: useUrlParams, - parameters: filteredParameters, - unfilteredParameters: allParameters, - headers:headers, - target:target, - verb:verb, - errors:errors, - withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, - timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, - path:path, - triggeringEvent:event - }; + // keep trying to save the cache until it succeeds or is empty + while (historyCache.length > 0) { + try { + localStorage.setItem('htmx-history-cache', JSON.stringify(historyCache)) + break + } catch (e) { + triggerErrorEvent(getDocument().body, 'htmx:historyCacheError', { cause: e, cache: historyCache }) + historyCache.shift() // shrink the cache and retry + } + } + } + + /** + * @typedef {Object} HtmxHistoryItem + * @property {string} url + * @property {string} content + * @property {string} title + * @property {number} scroll + */ + + /** + * @param {string} url + * @returns {HtmxHistoryItem|null} + */ + function getCachedHistory(url) { + if (!canAccessLocalStorage()) { + return null + } - if(!triggerEvent(elt, 'htmx:configRequest', requestConfig)){ - maybeCall(resolve); - endRequestLock(); - return promise; - } + url = normalizePath(url) - // copy out in case the object was overwritten - path = requestConfig.path; - verb = requestConfig.verb; - headers = requestConfig.headers; - filteredParameters = requestConfig.parameters; - errors = requestConfig.errors; - useUrlParams = requestConfig.useUrlParams; - - if(errors && errors.length > 0){ - triggerEvent(elt, 'htmx:validation:halted', requestConfig) - maybeCall(resolve); - endRequestLock(); - return promise; - } + const historyCache = parseJSON(localStorage.getItem('htmx-history-cache')) || [] + for (let i = 0; i < historyCache.length; i++) { + if (historyCache[i].url === url) { + return historyCache[i] + } + } + return null + } + + /** + * @param {Element} elt + * @returns {string} + */ + function cleanInnerHtmlForHistory(elt) { + const className = htmx.config.requestClass + const clone = /** @type Element */ (elt.cloneNode(true)) + forEach(findAll(clone, '.' + className), function(child) { + removeClassFromElement(child, className) + }) + return clone.innerHTML + } + + function saveCurrentPageToHistory() { + const elt = getHistoryElement() + const path = currentPathForHistory || location.pathname + location.search + + // Allow history snapshot feature to be disabled where hx-history="false" + // is present *anywhere* in the current document we're about to save, + // so we can prevent privileged data entering the cache. + // The page will still be reachable as a history entry, but htmx will fetch it + // live from the server onpopstate rather than look in the localStorage cache + let disableHistoryCache + try { + disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') + } catch (e) { + // IE11: insensitive modifier not supported so fallback to case sensitive selector + disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') + } + if (!disableHistoryCache) { + triggerEvent(getDocument().body, 'htmx:beforeHistorySave', { path, historyElt: elt }) + saveToHistoryCache(path, elt) + } - var splitPath = path.split("#"); - var pathNoAnchor = splitPath[0]; - var anchor = splitPath[1]; - - var finalPath = path - if (useUrlParams) { - finalPath = pathNoAnchor; - var values = Object.keys(filteredParameters).length !== 0; - if (values) { - if (finalPath.indexOf("?") < 0) { - finalPath += "?"; - } else { - finalPath += "&"; - } - finalPath += urlEncode(filteredParameters); - if (anchor) { - finalPath += "#" + anchor; - } - } - } + if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, getDocument().title, window.location.href) + } + + /** + * @param {string} path + */ + function pushUrlIntoHistory(path) { + // remove the cache buster parameter, if any + if (htmx.config.getCacheBusterParam) { + path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') + if (endsWith(path, '&') || endsWith(path, '?')) { + path = path.slice(0, -1) + } + } + if (htmx.config.historyEnabled) { + history.pushState({ htmx: true }, '', path) + } + currentPathForHistory = path + } + + /** + * @param {string} path + */ + function replaceUrlInHistory(path) { + if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, '', path) + currentPathForHistory = path + } + + /** + * @param {HtmxSettleTask[]} tasks + */ + function settleImmediately(tasks) { + forEach(tasks, function(task) { + task.call(undefined) + }) + } + + /** + * @param {string} path + */ + function loadHistoryFromServer(path) { + const request = new XMLHttpRequest() + const details = { path, xhr: request } + triggerEvent(getDocument().body, 'htmx:historyCacheMiss', details) + request.open('GET', path, true) + request.setRequestHeader('HX-Request', 'true') + request.setRequestHeader('HX-History-Restore-Request', 'true') + request.setRequestHeader('HX-Current-URL', getDocument().location.href) + request.onload = function() { + if (this.status >= 200 && this.status < 400) { + triggerEvent(getDocument().body, 'htmx:historyCacheMissLoad', details) + const fragment = makeFragment(this.response) + /** @type ParentNode */ + const content = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment + const historyElement = getHistoryElement() + const settleInfo = makeSettleInfo(historyElement) + handleTitle(fragment.title) + + swapInnerHTML(historyElement, content, settleInfo) + settleImmediately(settleInfo.tasks) + currentPathForHistory = path + triggerEvent(getDocument().body, 'htmx:historyRestore', { path, cacheMiss: true, serverResponse: this.response }) + } else { + triggerErrorEvent(getDocument().body, 'htmx:historyCacheMissLoadError', details) + } + } + request.send() + } + + /** + * @param {string} [path] + */ + function restoreHistory(path) { + saveCurrentPageToHistory() + path = path || location.pathname + location.search + const cached = getCachedHistory(path) + if (cached) { + const fragment = makeFragment(cached.content) + const historyElement = getHistoryElement() + const settleInfo = makeSettleInfo(historyElement) + handleTitle(fragment.title) + swapInnerHTML(historyElement, fragment, settleInfo) + settleImmediately(settleInfo.tasks) + getWindow().setTimeout(function() { + window.scrollTo(0, cached.scroll) + }, 0) // next 'tick', so browser has time to render layout + currentPathForHistory = path + triggerEvent(getDocument().body, 'htmx:historyRestore', { path, item: cached }) + } else { + if (htmx.config.refreshOnHistoryMiss) { + // @ts-ignore: optional parameter in reload() function throws error + // noinspection JSUnresolvedReference + window.location.reload(true) + } else { + loadHistoryFromServer(path) + } + } + } + + /** + * @param {Element} elt + * @returns {Element[]} + */ + function addRequestIndicatorClasses(elt) { + let indicators = /** @type Element[] */ (findAttributeTargets(elt, 'hx-indicator')) + if (indicators == null) { + indicators = [elt] + } + forEach(indicators, function(ic) { + const internalData = getInternalData(ic) + internalData.requestCount = (internalData.requestCount || 0) + 1 + ic.classList.add.call(ic.classList, htmx.config.requestClass) + }) + return indicators + } + + /** + * @param {Element} elt + * @returns {Element[]} + */ + function disableElements(elt) { + let disabledElts = /** @type Element[] */ (findAttributeTargets(elt, 'hx-disabled-elt')) + if (disabledElts == null) { + disabledElts = [] + } + forEach(disabledElts, function(disabledElement) { + const internalData = getInternalData(disabledElement) + internalData.requestCount = (internalData.requestCount || 0) + 1 + disabledElement.setAttribute('disabled', '') + }) + return disabledElts + } + + /** + * @param {Element[]} indicators + * @param {Element[]} disabled + */ + function removeRequestIndicators(indicators, disabled) { + forEach(indicators, function(ic) { + const internalData = getInternalData(ic) + internalData.requestCount = (internalData.requestCount || 0) - 1 + if (internalData.requestCount === 0) { + ic.classList.remove.call(ic.classList, htmx.config.requestClass) + } + }) + forEach(disabled, function(disabledElement) { + const internalData = getInternalData(disabledElement) + internalData.requestCount = (internalData.requestCount || 0) - 1 + if (internalData.requestCount === 0) { + disabledElement.removeAttribute('disabled') + } + }) + } + + //= =================================================================== + // Input Value Processing + //= =================================================================== + + /** + * @param {Element[]} processed + * @param {Element} elt + * @returns {boolean} + */ + function haveSeenNode(processed, elt) { + for (let i = 0; i < processed.length; i++) { + const node = processed[i] + if (node.isSameNode(elt)) { + return true + } + } + return false + } + + /** + * @param {Element} element + * @return {boolean} + */ + function shouldInclude(element) { + // Cast to trick tsc, undefined values will work fine here + const elt = /** @type {HTMLInputElement} */ (element) + if (elt.name === '' || elt.name == null || elt.disabled || closest(elt, 'fieldset[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 + } + + /** @param {string} name + * @param {string|Array|FormDataEntryValue} value + * @param {FormData} formData */ + function addValueToFormData(name, value, formData) { + if (name != null && value != null) { + if (Array.isArray(value)) { + value.forEach(function(v) { formData.append(name, v) }) + } else { + formData.append(name, value) + } + } + } + + /** @param {string} name + * @param {string|Array} value + * @param {FormData} formData */ + function removeValueFromFormData(name, value, formData) { + if (name != null && value != null) { + let values = formData.getAll(name) + if (Array.isArray(value)) { + values = values.filter(v => value.indexOf(v) < 0) + } else { + values = values.filter(v => v !== value) + } + formData.delete(name) + forEach(values, v => formData.append(name, v)) + } + } + + /** + * @param {Element[]} processed + * @param {FormData} formData + * @param {HtmxElementValidationError[]} errors + * @param {Element|HTMLInputElement|HTMLSelectElement|HTMLFormElement} elt + * @param {boolean} validate + */ + function processInputValue(processed, formData, errors, elt, validate) { + if (elt == null || haveSeenNode(processed, elt)) { + return + } else { + processed.push(elt) + } + if (shouldInclude(elt)) { + const name = getRawAttribute(elt, 'name') + // @ts-ignore value will be undefined for non-input elements, which is fine + let value = elt.value + if (elt instanceof HTMLSelectElement && elt.multiple) { + value = toArray(elt.querySelectorAll('option:checked')).map(function(e) { return (/** @type HTMLOptionElement */(e)).value }) + } + // include file inputs + if (elt instanceof HTMLInputElement && elt.files) { + value = toArray(elt.files) + } + addValueToFormData(name, value, formData) + if (validate) { + validateElement(elt, errors) + } + } + if (elt instanceof HTMLFormElement) { + forEach(elt.elements, function(input) { + if (processed.indexOf(input) >= 0) { + // The input has already been processed and added to the values, but the FormData that will be + // constructed right after on the form, will include it once again. So remove that input's value + // now to avoid duplicates + removeValueFromFormData(input.name, input.value, formData) + } else { + processed.push(input) + } + if (validate) { + validateElement(input, errors) + } + }) + new FormData(elt).forEach(function(value, name) { + if (value instanceof File && value.name === '') { + return // ignore no-name files + } + addValueToFormData(name, value, formData) + }) + } + } + + /** + * + * @param {Element} elt + * @param {HtmxElementValidationError[]} errors + */ + function validateElement(elt, errors) { + const element = /** @type {HTMLElement & ElementInternals} */ (elt) + if (element.willValidate) { + triggerEvent(element, 'htmx:validation:validate') + if (!element.checkValidity()) { + errors.push({ elt: element, message: element.validationMessage, validity: element.validity }) + triggerEvent(element, 'htmx:validation:failed', { message: element.validationMessage, validity: element.validity }) + } + } + } + + /** + * Override values in the one FormData with those from another. + * @param {FormData} receiver the formdata that will be mutated + * @param {FormData} donor the formdata that will provide the overriding values + * @returns {FormData} the {@linkcode receiver} + */ + function overrideFormData(receiver, donor) { + for (const key of donor.keys()) { + receiver.delete(key) + donor.getAll(key).forEach(function(value) { + receiver.append(key, value) + }) + } + return receiver + } + + /** + * @param {Element|HTMLFormElement} elt + * @param {HttpVerb} verb + * @returns {{errors: HtmxElementValidationError[], formData: FormData, values: Object}} + */ + function getInputValues(elt, verb) { + /** @type Element[] */ + const processed = [] + const formData = new FormData() + const priorityFormData = new FormData() + /** @type HtmxElementValidationError[] */ + const errors = [] + const internalData = getInternalData(elt) + if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { + internalData.lastButtonClicked = null + } - if (!verifyPath(elt, finalPath, requestConfig)) { - triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) - maybeCall(reject); - return promise; - }; + // only validate when form is directly submitted and novalidate or formnovalidate are not set + // or if the element has an explicit hx-validate="true" on it + let validate = (elt instanceof HTMLFormElement && elt.noValidate !== true) || getAttributeValue(elt, 'hx-validate') === 'true' + if (internalData.lastButtonClicked) { + validate = validate && internalData.lastButtonClicked.formNoValidate !== true + } - xhr.open(verb.toUpperCase(), finalPath, true); - xhr.overrideMimeType("text/html"); - xhr.withCredentials = requestConfig.withCredentials; - xhr.timeout = requestConfig.timeout; + // for a non-GET include the closest form + if (verb !== 'get') { + processInputValue(processed, priorityFormData, errors, closest(elt, 'form'), validate) + } - // request headers - if (requestAttrValues.noHeaders) { - // ignore all headers - } else { - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - var headerValue = headers[header]; - safelySetHeaderValue(xhr, header, headerValue); - } - } - } + // include the element itself + processInputValue(processed, formData, errors, elt, validate) - var responseInfo = { - xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select, - pathInfo: { - requestPath: path, - finalRequestPath: finalPath, - anchor: anchor - } - }; - - xhr.onload = function () { - try { - var hierarchy = hierarchyForElt(elt); - responseInfo.pathInfo.responsePath = getPathFromResponse(xhr); - responseHandler(elt, responseInfo); - removeRequestIndicators(indicators, disableElts); - triggerEvent(elt, 'htmx:afterRequest', responseInfo); - triggerEvent(elt, 'htmx:afterOnLoad', responseInfo); - // if the body no longer contains the element, trigger the event on the closest parent - // remaining in the DOM - if (!bodyContains(elt)) { - var secondaryTriggerElt = null; - while (hierarchy.length > 0 && secondaryTriggerElt == null) { - var parentEltInHierarchy = hierarchy.shift(); - if (bodyContains(parentEltInHierarchy)) { - secondaryTriggerElt = parentEltInHierarchy; - } - } - if (secondaryTriggerElt) { - triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo); - triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo); - } - } - maybeCall(resolve); - endRequestLock(); - } catch (e) { - triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({error:e}, responseInfo)); - throw e; - } - } - xhr.onerror = function () { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:sendError', responseInfo); - maybeCall(reject); - endRequestLock(); - } - xhr.onabort = function() { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo); - maybeCall(reject); - endRequestLock(); - } - xhr.ontimeout = function() { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:timeout', responseInfo); - maybeCall(reject); - endRequestLock(); - } - if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){ - maybeCall(resolve); - endRequestLock() - return promise - } - var indicators = addRequestIndicatorClasses(elt); - var disableElts = disableElements(elt); - - forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { - forEach([xhr, xhr.upload], function (target) { - target.addEventListener(eventName, function(event){ - triggerEvent(elt, "htmx:xhr:" + eventName, { - lengthComputable:event.lengthComputable, - loaded:event.loaded, - total:event.total - }); - }) - }); - }); - triggerEvent(elt, 'htmx:beforeSend', responseInfo); - var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) - xhr.send(params); - return promise; - } - - function determineHistoryUpdates(elt, responseInfo) { - - var xhr = responseInfo.xhr; - - //=========================================== - // First consult response headers - //=========================================== - var pathFromHeaders = null; - var typeFromHeaders = null; - if (hasHeader(xhr,/HX-Push:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Push"); - typeFromHeaders = "push"; - } else if (hasHeader(xhr,/HX-Push-Url:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Push-Url"); - typeFromHeaders = "push"; - } else if (hasHeader(xhr,/HX-Replace-Url:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url"); - typeFromHeaders = "replace"; - } + // if a button or submit was clicked last, include its value + if (internalData.lastButtonClicked || elt.tagName === 'BUTTON' || + (elt.tagName === 'INPUT' && getRawAttribute(elt, 'type') === 'submit')) { + const button = internalData.lastButtonClicked || (/** @type HTMLInputElement|HTMLButtonElement */(elt)) + const name = getRawAttribute(button, 'name') + addValueToFormData(name, button.value, priorityFormData) + } - // if there was a response header, that has priority - if (pathFromHeaders) { - if (pathFromHeaders === "false") { - return {} - } else { - return { - type: typeFromHeaders, - path : pathFromHeaders - } - } - } + // include any explicit includes + const includes = findAttributeTargets(elt, 'hx-include') + forEach(includes, function(node) { + processInputValue(processed, formData, errors, asElement(node), validate) + // if a non-form is included, include any input values within it + if (!matches(node, 'form')) { + forEach(asParentNode(node).querySelectorAll(INPUT_SELECTOR), function(descendant) { + processInputValue(processed, formData, errors, descendant, validate) + }) + } + }) + + // values from a <form> take precedence, overriding the regular values + overrideFormData(formData, priorityFormData) + + return { errors, formData, values: formDataProxy(formData) } + } + + /** + * @param {string} returnStr + * @param {string} name + * @param {any} realValue + * @returns {string} + */ + function appendParam(returnStr, name, realValue) { + if (returnStr !== '') { + returnStr += '&' + } + if (String(realValue) === '[object Object]') { + realValue = JSON.stringify(realValue) + } + const s = encodeURIComponent(realValue) + returnStr += encodeURIComponent(name) + '=' + s + return returnStr + } + + /** + * @param {FormData|Object} values + * @returns string + */ + function urlEncode(values) { + values = formDataFromObject(values) + let returnStr = '' + values.forEach(function(value, key) { + returnStr = appendParam(returnStr, key, value) + }) + return returnStr + } + + //= =================================================================== + // Ajax + //= =================================================================== + + /** + * @param {Element} elt + * @param {Element} target + * @param {string} prompt + * @returns {HtmxHeaderSpecification} + */ + function getHeaders(elt, target, prompt) { + /** @type HtmxHeaderSpecification */ + const headers = { + 'HX-Request': 'true', + 'HX-Trigger': getRawAttribute(elt, 'id'), + 'HX-Trigger-Name': getRawAttribute(elt, 'name'), + 'HX-Target': getAttributeValue(target, 'id'), + 'HX-Current-URL': getDocument().location.href + } + getValuesForElement(elt, 'hx-headers', false, headers) + if (prompt !== undefined) { + headers['HX-Prompt'] = prompt + } + if (getInternalData(elt).boosted) { + headers['HX-Boosted'] = 'true' + } + return headers + } + + /** + * filterValues takes an object containing form input values + * and returns a new object that only contains keys that are + * specified by the closest "hx-params" attribute + * @param {FormData} inputValues + * @param {Element} elt + * @returns {FormData} + */ + function filterValues(inputValues, elt) { + const paramsValue = getClosestAttributeValue(elt, 'hx-params') + if (paramsValue) { + if (paramsValue === 'none') { + return new FormData() + } else if (paramsValue === '*') { + return inputValues + } else if (paramsValue.indexOf('not ') === 0) { + forEach(paramsValue.substr(4).split(','), function(name) { + name = name.trim() + inputValues.delete(name) + }) + return inputValues + } else { + const newValues = new FormData() + forEach(paramsValue.split(','), function(name) { + name = name.trim() + if (inputValues.has(name)) { + inputValues.getAll(name).forEach(function(value) { newValues.append(name, value) }) + } + }) + return newValues + } + } else { + return inputValues + } + } + + /** + * @param {Element} elt + * @return {boolean} + */ + function isAnchorLink(elt) { + return !!getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf('#') >= 0 + } + + /** + * @param {Element} elt + * @param {HtmxSwapStyle} [swapInfoOverride] + * @returns {HtmxSwapSpecification} + */ + function getSwapSpecification(elt, swapInfoOverride) { + const swapInfo = swapInfoOverride || getClosestAttributeValue(elt, 'hx-swap') + /** @type HtmxSwapSpecification */ + const swapSpec = { + swapStyle: getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, + swapDelay: htmx.config.defaultSwapDelay, + settleDelay: htmx.config.defaultSettleDelay + } + if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { + swapSpec.show = 'top' + } + if (swapInfo) { + const split = splitOnWhitespace(swapInfo) + if (split.length > 0) { + for (let i = 0; i < split.length; i++) { + const value = split[i] + if (value.indexOf('swap:') === 0) { + swapSpec.swapDelay = parseInterval(value.substr(5)) + } else if (value.indexOf('settle:') === 0) { + swapSpec.settleDelay = parseInterval(value.substr(7)) + } else if (value.indexOf('transition:') === 0) { + swapSpec.transition = value.substr(11) === 'true' + } else if (value.indexOf('ignoreTitle:') === 0) { + swapSpec.ignoreTitle = value.substr(12) === 'true' + } else if (value.indexOf('scroll:') === 0) { + const scrollSpec = value.substr(7) + var splitSpec = scrollSpec.split(':') + const scrollVal = splitSpec.pop() + var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null + // @ts-ignore + swapSpec.scroll = scrollVal + swapSpec.scrollTarget = selectorVal + } else if (value.indexOf('show:') === 0) { + const showSpec = value.substr(5) + var splitSpec = showSpec.split(':') + const showVal = splitSpec.pop() + var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null + swapSpec.show = showVal + swapSpec.showTarget = selectorVal + } else if (value.indexOf('focus-scroll:') === 0) { + const focusScrollVal = value.substr('focus-scroll:'.length) + swapSpec.focusScroll = focusScrollVal == 'true' + } else if (i == 0) { + swapSpec.swapStyle = value + } else { + logError('Unknown modifier in hx-swap: ' + value) + } + } + } + } + return swapSpec + } + + /** + * @param {Element} elt + * @return {boolean} + */ + function usesFormData(elt) { + return getClosestAttributeValue(elt, 'hx-encoding') === 'multipart/form-data' || + (matches(elt, 'form') && getRawAttribute(elt, 'enctype') === 'multipart/form-data') + } + + /** + * @param {XMLHttpRequest} xhr + * @param {Element} elt + * @param {FormData} filteredParameters + * @returns {*|string|null} + */ + function encodeParamsForBody(xhr, elt, filteredParameters) { + let encodedParameters = null + withExtensions(elt, function(extension) { + if (encodedParameters == null) { + encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt) + } + }) + if (encodedParameters != null) { + return encodedParameters + } else { + if (usesFormData(elt)) { + // Force conversion to an actual FormData object in case filteredParameters is a formDataProxy + // See https://github.com/bigskysoftware/htmx/issues/2317 + return overrideFormData(new FormData(), formDataFromObject(filteredParameters)) + } else { + return urlEncode(filteredParameters) + } + } + } + + /** + * + * @param {Element} target + * @returns {HtmxSettleInfo} + */ + function makeSettleInfo(target) { + return { tasks: [], elts: [target] } + } + + /** + * @param {Element[]} content + * @param {HtmxSwapSpecification} swapSpec + */ + function updateScrollState(content, swapSpec) { + const first = content[0] + const last = content[content.length - 1] + if (swapSpec.scroll) { + var target = null + if (swapSpec.scrollTarget) { + target = asElement(querySelectorExt(first, swapSpec.scrollTarget)) + } + if (swapSpec.scroll === 'top' && (first || target)) { + target = target || first + target.scrollTop = 0 + } + if (swapSpec.scroll === 'bottom' && (last || target)) { + target = target || last + target.scrollTop = target.scrollHeight + } + } + if (swapSpec.show) { + var target = null + if (swapSpec.showTarget) { + let targetStr = swapSpec.showTarget + if (swapSpec.showTarget === 'window') { + targetStr = 'body' + } + target = asElement(querySelectorExt(first, targetStr)) + } + if (swapSpec.show === 'top' && (first || target)) { + target = target || first + // @ts-ignore For some reason tsc doesn't recognize "instant" as a valid option for now + target.scrollIntoView({ block: 'start', behavior: htmx.config.scrollBehavior }) + } + if (swapSpec.show === 'bottom' && (last || target)) { + target = target || last + // @ts-ignore For some reason tsc doesn't recognize "instant" as a valid option for now + target.scrollIntoView({ block: 'end', behavior: htmx.config.scrollBehavior }) + } + } + } + + /** + * @param {Element} elt + * @param {string} attr + * @param {boolean=} evalAsDefault + * @param {Object=} values + * @returns {Object} + */ + function getValuesForElement(elt, attr, evalAsDefault, values) { + if (values == null) { + values = {} + } + if (elt == null) { + return values + } + const attributeValue = getAttributeValue(elt, attr) + if (attributeValue) { + let str = attributeValue.trim() + let evaluateValue = evalAsDefault + if (str === 'unset') { + return null + } + if (str.indexOf('javascript:') === 0) { + str = str.substr(11) + evaluateValue = true + } else if (str.indexOf('js:') === 0) { + str = str.substr(3) + evaluateValue = true + } + if (str.indexOf('{') !== 0) { + str = '{' + str + '}' + } + let varsValues + if (evaluateValue) { + varsValues = maybeEval(elt, function() { return Function('return (' + str + ')')() }, {}) + } else { + varsValues = parseJSON(str) + } + for (const key in varsValues) { + if (varsValues.hasOwnProperty(key)) { + if (values[key] == null) { + values[key] = varsValues[key] + } + } + } + } + return getValuesForElement(asElement(parentElt(elt)), attr, evalAsDefault, values) + } + + /** + * @param {EventTarget|string} elt + * @param {() => any} toEval + * @param {any=} defaultVal + * @returns {any} + */ + function maybeEval(elt, toEval, defaultVal) { + if (htmx.config.allowEval) { + return toEval() + } else { + triggerErrorEvent(elt, 'htmx:evalDisallowedError') + return defaultVal + } + } + + /** + * @param {Element} elt + * @param {*?} expressionVars + * @returns + */ + function getHXVarsForElement(elt, expressionVars) { + return getValuesForElement(elt, 'hx-vars', true, expressionVars) + } + + /** + * @param {Element} elt + * @param {*?} expressionVars + * @returns + */ + function getHXValsForElement(elt, expressionVars) { + return getValuesForElement(elt, 'hx-vals', false, expressionVars) + } + + /** + * @param {Element} elt + * @returns {FormData} + */ + function getExpressionVars(elt) { + return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)) + } + + /** + * @param {XMLHttpRequest} xhr + * @param {string} header + * @param {string|null} headerValue + */ + function safelySetHeaderValue(xhr, header, headerValue) { + if (headerValue !== null) { + try { + xhr.setRequestHeader(header, headerValue) + } catch (e) { + // On an exception, try to set the header URI encoded instead + xhr.setRequestHeader(header, encodeURIComponent(headerValue)) + xhr.setRequestHeader(header + '-URI-AutoEncoded', 'true') + } + } + } + + /** + * @param {XMLHttpRequest} xhr + * @return {string} + */ + function getPathFromResponse(xhr) { + // NB: IE11 does not support this stuff + if (xhr.responseURL && typeof (URL) !== 'undefined') { + try { + const url = new URL(xhr.responseURL) + return url.pathname + url.search + } catch (e) { + triggerErrorEvent(getDocument().body, 'htmx:badResponseUrl', { url: xhr.responseURL }) + } + } + } + + /** + * @param {XMLHttpRequest} xhr + * @param {RegExp} regexp + * @return {boolean} + */ + function hasHeader(xhr, regexp) { + return regexp.test(xhr.getAllResponseHeaders()) + } + + /** + * Issues an htmx-style AJAX request + * + * @see https://htmx.org/api/#ajax + * + * @param {HttpVerb} verb + * @param {string} path the URL path to make the AJAX + * @param {Element|string|HtmxAjaxHelperContext} context the element to target (defaults to the **body**) | a selector for the target | a context object that contains any of the following + * @return {Promise<void>} Promise that resolves immediately if no request is sent, or when the request is complete + */ + function ajaxHelper(verb, path, context) { + verb = (/** @type HttpVerb */(verb.toLowerCase())) + if (context) { + if (context instanceof Element || typeof context === 'string') { + return issueAjaxRequest(verb, path, null, null, { + targetOverride: resolveTarget(context), + returnPromise: true + }) + } else { + return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, + { + handler: context.handler, + headers: context.headers, + values: context.values, + targetOverride: resolveTarget(context.target), + swapOverride: context.swap, + select: context.select, + returnPromise: true + }) + } + } else { + return issueAjaxRequest(verb, path, null, null, { + returnPromise: true + }) + } + } + + /** + * @param {Element} elt + * @return {Element[]} + */ + function hierarchyForElt(elt) { + const arr = [] + while (elt) { + arr.push(elt) + elt = elt.parentElement + } + return arr + } + + /** + * @param {Element} elt + * @param {string} path + * @param {HtmxRequestConfig} requestConfig + * @return {boolean} + */ + function verifyPath(elt, path, requestConfig) { + let sameHost + let url + if (typeof URL === 'function') { + url = new URL(path, document.location.href) + const origin = document.location.origin + sameHost = origin === url.origin + } else { + // IE11 doesn't support URL + url = path + sameHost = startsWith(path, document.location.origin) + } - //=========================================== - // Next resolve via DOM values - //=========================================== - var requestPath = responseInfo.pathInfo.finalRequestPath; - var responsePath = responseInfo.pathInfo.responsePath; - - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url"); - var elementIsBoosted = getInternalData(elt).boosted; - - var saveType = null; - var path = null; - - if (pushUrl) { - saveType = "push"; - path = pushUrl; - } else if (replaceUrl) { - saveType = "replace"; - path = replaceUrl; - } else if (elementIsBoosted) { - saveType = "push"; - path = responsePath || requestPath; // if there is no response path, go with the original request path - } + if (htmx.config.selfRequestsOnly) { + if (!sameHost) { + return false + } + } + return triggerEvent(elt, 'htmx:validateUrl', mergeObjects({ url, sameHost }, requestConfig)) + } + + /** + * @param {Object|FormData} obj + * @return {FormData} + */ + function formDataFromObject(obj) { + if (obj instanceof FormData) return obj + const formData = new FormData() + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + if (typeof obj[key].forEach === 'function') { + obj[key].forEach(function(v) { formData.append(key, v) }) + } else if (typeof obj[key] === 'object') { + formData.append(key, JSON.stringify(obj[key])) + } else { + formData.append(key, obj[key]) + } + } + } + return formData + } + + /** + * @param {FormData} formData + * @param {string} name + * @param {Array} array + * @returns {Array} + */ + function formDataArrayProxy(formData, name, array) { + // mutating the array should mutate the underlying form data + return new Proxy(array, { + get: function(target, key) { + if (typeof key === 'number') return target[key] + if (key === 'length') return target.length + if (key === 'push') { + return function(value) { + target.push(value) + formData.append(name, value) + } + } + if (typeof target[key] === 'function') { + return function() { + target[key].apply(target, arguments) + formData.delete(name) + target.forEach(function(v) { formData.append(name, v) }) + } + } + + if (target[key] && target[key].length === 1) { + return target[key][0] + } else { + return target[key] + } + }, + set: function(target, index, value) { + target[index] = value + formData.delete(name) + target.forEach(function(v) { formData.append(name, v) }) + return true + } + }) + } + + /** + * @param {FormData} formData + * @returns {Object} + */ + function formDataProxy(formData) { + return new Proxy(formData, { + get: function(target, name) { + if (typeof name === 'symbol') { + // Forward symbol calls to the FormData itself directly + return Reflect.get(target, name) + } + if (name === 'toJSON') { + // Support JSON.stringify call on proxy + return () => Object.fromEntries(formData) + } + if (name in target) { + // Wrap in function with apply to correctly bind the FormData context, as a direct call would result in an illegal invocation error + if (typeof target[name] === 'function') { + return function() { + return formData[name].apply(formData, arguments) + } + } else { + return target[name] + } + } + const array = formData.getAll(name) + // Those 2 undefined & single value returns are for retro-compatibility as we weren't using FormData before + if (array.length === 0) { + return undefined + } else if (array.length === 1) { + return array[0] + } else { + return formDataArrayProxy(target, name, array) + } + }, + set: function(target, name, value) { + if (typeof name !== 'string') { + return false + } + target.delete(name) + if (typeof value.forEach === 'function') { + value.forEach(function(v) { target.append(name, v) }) + } else { + target.append(name, value) + } + return true + }, + deleteProperty: function(target, name) { + if (typeof name === 'string') { + target.delete(name) + } + return true + }, + // Support Object.assign call from proxy + ownKeys: function(target) { + return Reflect.ownKeys(Object.fromEntries(target)) + }, + getOwnPropertyDescriptor: function(target, prop) { + return Reflect.getOwnPropertyDescriptor(Object.fromEntries(target), prop) + } + }) + } + + /** + * @param {HttpVerb} verb + * @param {string} path + * @param {Element} elt + * @param {Event} event + * @param {HtmxAjaxEtc} [etc] + * @param {boolean} [confirmed] + * @return {Promise<void>} + */ + function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { + let resolve = null + let reject = null + etc = etc != null ? etc : {} + if (etc.returnPromise && typeof Promise !== 'undefined') { + var promise = new Promise(function(_resolve, _reject) { + resolve = _resolve + reject = _reject + }) + } + if (elt == null) { + elt = getDocument().body + } + const responseHandler = etc.handler || handleAjaxResponse + const select = etc.select || null - if (path) { - // false indicates no push, return empty object - if (path === "false") { - return {}; - } + if (!bodyContains(elt)) { + // do not issue requests for elements removed from the DOM + maybeCall(resolve) + return promise + } + const target = etc.targetOverride || asElement(getTarget(elt)) + if (target == null || target == DUMMY_ELT) { + triggerErrorEvent(elt, 'htmx:targetError', { target: getAttributeValue(elt, 'hx-target') }) + maybeCall(reject) + return promise + } - // true indicates we want to follow wherever the server ended up sending us - if (path === "true") { - path = responsePath || requestPath; // if there is no response path, go with the original request path - } + let eltData = getInternalData(elt) + const submitter = eltData.lastButtonClicked - // restore any anchor associated with the request - if (responseInfo.pathInfo.anchor && - path.indexOf("#") === -1) { - path = path + "#" + responseInfo.pathInfo.anchor; - } + if (submitter) { + const buttonPath = getRawAttribute(submitter, 'formaction') + if (buttonPath != null) { + path = buttonPath + } - return { - type:saveType, - path: path - } - } else { - return {}; - } + const buttonVerb = getRawAttribute(submitter, 'formmethod') + if (buttonVerb != null) { + // ignore buttons with formmethod="dialog" + if (buttonVerb.toLowerCase() !== 'dialog') { + verb = (/** @type HttpVerb */(buttonVerb)) } + } + } - function handleAjaxResponse(elt, responseInfo) { - var xhr = responseInfo.xhr; - var target = responseInfo.target; - var etc = responseInfo.etc; - var requestConfig = responseInfo.requestConfig; - var select = responseInfo.select; + const confirmQuestion = getClosestAttributeValue(elt, 'hx-confirm') + // allow event-based confirmation w/ a callback + if (confirmed === undefined) { + const issueRequest = function(skipConfirmation) { + return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation) + } + const confirmDetails = { target, elt, path, verb, triggeringEvent: event, etc, issueRequest, question: confirmQuestion } + if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { + maybeCall(resolve) + return promise + } + } - if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; + let syncElt = elt + let syncStrategy = getClosestAttributeValue(elt, 'hx-sync') + let queueStrategy = null + let abortable = false + if (syncStrategy) { + const syncStrings = syncStrategy.split(':') + const selector = syncStrings[0].trim() + if (selector === 'this') { + syncElt = findThisElement(elt, 'hx-sync') + } else { + syncElt = asElement(querySelectorExt(elt, selector)) + } + // default to the drop strategy + syncStrategy = (syncStrings[1] || 'drop').trim() + eltData = getInternalData(syncElt) + if (syncStrategy === 'drop' && eltData.xhr && eltData.abortable !== true) { + maybeCall(resolve) + return promise + } else if (syncStrategy === 'abort') { + if (eltData.xhr) { + maybeCall(resolve) + return promise + } else { + abortable = true + } + } else if (syncStrategy === 'replace') { + triggerEvent(syncElt, 'htmx:abort') // abort the current request and continue + } else if (syncStrategy.indexOf('queue') === 0) { + const queueStrArray = syncStrategy.split(' ') + queueStrategy = (queueStrArray[1] || 'last').trim() + } + } - if (hasHeader(xhr, /HX-Trigger:/i)) { - handleTrigger(xhr, "HX-Trigger", elt); - } + if (eltData.xhr) { + if (eltData.abortable) { + triggerEvent(syncElt, 'htmx:abort') // abort the current request and continue + } else { + if (queueStrategy == null) { + if (event) { + const eventData = getInternalData(event) + if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { + queueStrategy = eventData.triggerSpec.queue + } + } + if (queueStrategy == null) { + queueStrategy = 'last' + } + } + if (eltData.queuedRequests == null) { + eltData.queuedRequests = [] + } + if (queueStrategy === 'first' && eltData.queuedRequests.length === 0) { + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } else if (queueStrategy === 'all') { + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } else if (queueStrategy === 'last') { + eltData.queuedRequests = [] // dump existing queue + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } + maybeCall(resolve) + return promise + } + } - if (hasHeader(xhr, /HX-Location:/i)) { - saveCurrentPageToHistory(); - var redirectPath = xhr.getResponseHeader("HX-Location"); - var swapSpec; - if (redirectPath.indexOf("{") === 0) { - swapSpec = parseJSON(redirectPath); - // what's the best way to throw an error if the user didn't include this - redirectPath = swapSpec['path']; - delete swapSpec['path']; - } - ajaxHelper('GET', redirectPath, swapSpec).then(function(){ - pushUrlIntoHistory(redirectPath); - }); - return; - } + const xhr = new XMLHttpRequest() + eltData.xhr = xhr + eltData.abortable = abortable + const endRequestLock = function() { + eltData.xhr = null + eltData.abortable = false + if (eltData.queuedRequests != null && + eltData.queuedRequests.length > 0) { + const queuedRequest = eltData.queuedRequests.shift() + queuedRequest() + } + } + const promptQuestion = getClosestAttributeValue(elt, 'hx-prompt') + if (promptQuestion) { + var promptResponse = prompt(promptQuestion) + // prompt returns null if cancelled and empty string if accepted with no entry + if (promptResponse === null || + !triggerEvent(elt, 'htmx:prompt', { prompt: promptResponse, target })) { + maybeCall(resolve) + endRequestLock() + return promise + } + } - var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh"); + if (confirmQuestion && !confirmed) { + if (!confirm(confirmQuestion)) { + maybeCall(resolve) + endRequestLock() + return promise + } + } - if (hasHeader(xhr, /HX-Redirect:/i)) { - location.href = xhr.getResponseHeader("HX-Redirect"); - shouldRefresh && location.reload(); - return; - } + let headers = getHeaders(elt, target, promptResponse) - if (shouldRefresh) { - location.reload(); - return; - } + if (verb !== 'get' && !usesFormData(elt)) { + headers['Content-Type'] = 'application/x-www-form-urlencoded' + } - if (hasHeader(xhr,/HX-Retarget:/i)) { - if (xhr.getResponseHeader("HX-Retarget") === "this") { - responseInfo.target = elt; - } else { - responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget")); - } - } + if (etc.headers) { + headers = mergeObjects(headers, etc.headers) + } + const results = getInputValues(elt, verb) + let errors = results.errors + const rawFormData = results.formData + if (etc.values) { + overrideFormData(rawFormData, formDataFromObject(etc.values)) + } + const expressionVars = formDataFromObject(getExpressionVars(elt)) + const allFormData = overrideFormData(rawFormData, expressionVars) + let filteredFormData = filterValues(allFormData, elt) - var historyUpdate = determineHistoryUpdates(elt, responseInfo); - - // by default htmx only swaps on 200 return codes and does not swap - // on 204 'No Content' - // this can be ovverriden by responding to the htmx:beforeSwap event and - // overriding the detail.shouldSwap property - var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; - var serverResponse = xhr.response; - var isError = xhr.status >= 400; - var ignoreTitle = htmx.config.ignoreTitle - var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo); - if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; - - target = beforeSwapDetails.target; // allow re-targeting - serverResponse = beforeSwapDetails.serverResponse; // allow updating content - isError = beforeSwapDetails.isError; // allow updating error - ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title - - responseInfo.target = target; // Make updated target available to response events - responseInfo.failed = isError; // Make failed property available to response events - responseInfo.successful = !isError; // Make successful property available to response events - - if (beforeSwapDetails.shouldSwap) { - if (xhr.status === 286) { - cancelPolling(elt); - } + if (htmx.config.getCacheBusterParam && verb === 'get') { + filteredFormData.set('org.htmx.cache-buster', getRawAttribute(target, 'id') || 'true') + } - withExtensions(elt, function (extension) { - serverResponse = extension.transformResponse(serverResponse, xhr, elt); - }); + // behavior of anchors w/ empty href is to use the current URL + if (path == null || path === '') { + path = getDocument().location.href + } - // Save current page if there will be a history update - if (historyUpdate.type) { - saveCurrentPageToHistory(); - } + /** + * @type {Object} + * @property {boolean} [credentials] + * @property {number} [timeout] + * @property {boolean} [noHeaders] + */ + const requestAttrValues = getValuesForElement(elt, 'hx-request') + + const eltIsBoosted = getInternalData(elt).boosted + + let useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + + /** @type HtmxRequestConfig */ + const requestConfig = { + boosted: eltIsBoosted, + useUrlParams, + formData: filteredFormData, + parameters: formDataProxy(filteredFormData), + unfilteredFormData: allFormData, + unfilteredParameters: formDataProxy(allFormData), + headers, + target, + verb, + errors, + withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, + timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, + path, + triggeringEvent: event + } - var swapOverride = etc.swapOverride; - if (hasHeader(xhr,/HX-Reswap:/i)) { - swapOverride = xhr.getResponseHeader("HX-Reswap"); - } - var swapSpec = getSwapSpecification(elt, swapOverride); + if (!triggerEvent(elt, 'htmx:configRequest', requestConfig)) { + maybeCall(resolve) + endRequestLock() + return promise + } - if (swapSpec.hasOwnProperty('ignoreTitle')) { - ignoreTitle = swapSpec.ignoreTitle; - } + // copy out in case the object was overwritten + path = requestConfig.path + verb = requestConfig.verb + headers = requestConfig.headers + filteredFormData = formDataFromObject(requestConfig.parameters) + errors = requestConfig.errors + useUrlParams = requestConfig.useUrlParams + + if (errors && errors.length > 0) { + triggerEvent(elt, 'htmx:validation:halted', requestConfig) + maybeCall(resolve) + endRequestLock() + return promise + } - target.classList.add(htmx.config.swappingClass); - - // optional transition API promise callbacks - var settleResolve = null; - var settleReject = null; - - var doSwap = function () { - try { - var activeElt = document.activeElement; - var selectionInfo = {}; - try { - selectionInfo = { - elt: activeElt, - // @ts-ignore - start: activeElt ? activeElt.selectionStart : null, - // @ts-ignore - end: activeElt ? activeElt.selectionEnd : null - }; - } catch (e) { - // safari issue - see https://github.com/microsoft/playwright/issues/5894 - } - - var selectOverride; - if (select) { - selectOverride = select; - } - - if (hasHeader(xhr, /HX-Reselect:/i)) { - selectOverride = xhr.getResponseHeader("HX-Reselect"); - } - - // if we need to save history, do so, before swapping so that relative resources have the correct base URL - if (historyUpdate.type) { - triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)); - if (historyUpdate.type === "push") { - pushUrlIntoHistory(historyUpdate.path); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path}); - } else { - replaceUrlInHistory(historyUpdate.path); - triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path}); - } - } - - var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride); - - if (selectionInfo.elt && - !bodyContains(selectionInfo.elt) && - getRawAttribute(selectionInfo.elt, "id")) { - var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id")); - var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; - if (newActiveElt) { - // @ts-ignore - if (selectionInfo.start && newActiveElt.setSelectionRange) { - // @ts-ignore - try { - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); - } catch (e) { - // the setSelectionRange method is present on fields that don't support it, so just let this fail - } - } - newActiveElt.focus(focusOptions); - } - } - - target.classList.remove(htmx.config.swappingClass); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.add(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSwap', responseInfo); - }); - - if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); - } - - var doSettle = function () { - forEach(settleInfo.tasks, function (task) { - task.call(); - }); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.remove(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSettle', responseInfo); - }); - - if (responseInfo.pathInfo.anchor) { - var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor); - if(anchorTarget) { - anchorTarget.scrollIntoView({block:'start', behavior: "auto"}); - } - } - - if(settleInfo.title && !ignoreTitle) { - var titleElt = find("title"); - if(titleElt) { - titleElt.innerHTML = settleInfo.title; - } else { - window.document.title = settleInfo.title; - } - } - - updateScrollState(settleInfo.elts, swapSpec); - - if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); - } - maybeCall(settleResolve); - } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'htmx:swapError', responseInfo); - maybeCall(settleReject); - throw e; - } - }; - - var shouldTransition = htmx.config.globalViewTransitions - if(swapSpec.hasOwnProperty('transition')){ - shouldTransition = swapSpec.transition; - } + const splitPath = path.split('#') + const pathNoAnchor = splitPath[0] + const anchor = splitPath[1] + + let finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor + const hasValues = !filteredFormData.keys().next().done + if (hasValues) { + if (finalPath.indexOf('?') < 0) { + finalPath += '?' + } else { + finalPath += '&' + } + finalPath += urlEncode(filteredFormData) + if (anchor) { + finalPath += '#' + anchor + } + } + } - if(shouldTransition && - triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && - typeof Promise !== "undefined" && document.startViewTransition){ - var settlePromise = new Promise(function (_resolve, _reject) { - settleResolve = _resolve; - settleReject = _reject; - }); - // wrap the original doSwap() in a call to startViewTransition() - var innerDoSwap = doSwap; - doSwap = function() { - document.startViewTransition(function () { - innerDoSwap(); - return settlePromise; - }); - } - } + if (!verifyPath(elt, finalPath, requestConfig)) { + triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) + maybeCall(reject) + return promise + } + xhr.open(verb.toUpperCase(), finalPath, true) + xhr.overrideMimeType('text/html') + xhr.withCredentials = requestConfig.withCredentials + xhr.timeout = requestConfig.timeout - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); - } - } - if (isError) { - triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo)); - } + // request headers + if (requestAttrValues.noHeaders) { + // ignore all headers + } else { + for (const header in headers) { + if (headers.hasOwnProperty(header)) { + const headerValue = headers[header] + safelySetHeaderValue(xhr, header, headerValue) } + } + } - //==================================================================== - // Extensions API - //==================================================================== - - /** @type {Object<string, import("./htmx").HtmxExtension>} */ - var extensions = {}; - - /** - * extensionBase defines the default functions for all extensions. - * @returns {import("./htmx").HtmxExtension} - */ - function extensionBase() { - return { - init: function(api) {return null;}, - onEvent : function(name, evt) {return true;}, - transformResponse : function(text, xhr, elt) {return text;}, - isInlineSwap : function(swapStyle) {return false;}, - handleSwap : function(swapStyle, target, fragment, settleInfo) {return false;}, - encodeParameters : function(xhr, parameters, elt) {return null;} - } - } + /** @type {HtmxResponseInfo} */ + const responseInfo = { + xhr, + target, + requestConfig, + etc, + boosted: eltIsBoosted, + select, + pathInfo: { + requestPath: path, + finalRequestPath: finalPath, + responsePath: null, + anchor + } + } - /** - * defineExtension initializes the extension and adds it to the htmx registry - * - * @param {string} name - * @param {import("./htmx").HtmxExtension} extension - */ - function defineExtension(name, extension) { - if(extension.init) { - extension.init(internalAPI) - } - extensions[name] = mergeObjects(extensionBase(), extension); - } + xhr.onload = function() { + try { + const hierarchy = hierarchyForElt(elt) + responseInfo.pathInfo.responsePath = getPathFromResponse(xhr) + responseHandler(elt, responseInfo) + removeRequestIndicators(indicators, disableElts) + triggerEvent(elt, 'htmx:afterRequest', responseInfo) + triggerEvent(elt, 'htmx:afterOnLoad', responseInfo) + // if the body no longer contains the element, trigger the event on the closest parent + // remaining in the DOM + if (!bodyContains(elt)) { + let secondaryTriggerElt = null + while (hierarchy.length > 0 && secondaryTriggerElt == null) { + const parentEltInHierarchy = hierarchy.shift() + if (bodyContains(parentEltInHierarchy)) { + secondaryTriggerElt = parentEltInHierarchy + } + } + if (secondaryTriggerElt) { + triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo) + triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo) + } + } + maybeCall(resolve) + endRequestLock() + } catch (e) { + triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({ error: e }, responseInfo)) + throw e + } + } + xhr.onerror = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:sendError', responseInfo) + maybeCall(reject) + endRequestLock() + } + xhr.onabort = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo) + maybeCall(reject) + endRequestLock() + } + xhr.ontimeout = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:timeout', responseInfo) + maybeCall(reject) + endRequestLock() + } + if (!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)) { + maybeCall(resolve) + endRequestLock() + return promise + } + var indicators = addRequestIndicatorClasses(elt) + var disableElts = disableElements(elt) + + forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { + forEach([xhr, xhr.upload], function(target) { + target.addEventListener(eventName, function(event) { + triggerEvent(elt, 'htmx:xhr:' + eventName, { + lengthComputable: event.lengthComputable, + loaded: event.loaded, + total: event.total + }) + }) + }) + }) + triggerEvent(elt, 'htmx:beforeSend', responseInfo) + const params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredFormData) + xhr.send(params) + return promise + } + + /** + * @typedef {Object} HtmxHistoryUpdate + * @property {string|null} [type] + * @property {string|null} [path] + */ + + /** + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + * @return {HtmxHistoryUpdate} + */ + function determineHistoryUpdates(elt, responseInfo) { + const xhr = responseInfo.xhr + + //= ========================================== + // First consult response headers + //= ========================================== + let pathFromHeaders = null + let typeFromHeaders = null + if (hasHeader(xhr, /HX-Push:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Push') + typeFromHeaders = 'push' + } else if (hasHeader(xhr, /HX-Push-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Push-Url') + typeFromHeaders = 'push' + } else if (hasHeader(xhr, /HX-Replace-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Replace-Url') + typeFromHeaders = 'replace' + } - /** - * removeExtension removes an extension from the htmx registry - * - * @param {string} name - */ - function removeExtension(name) { - delete extensions[name]; + // if there was a response header, that has priority + if (pathFromHeaders) { + if (pathFromHeaders === 'false') { + return {} + } else { + return { + type: typeFromHeaders, + path: pathFromHeaders } + } + } - /** - * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element - * - * @param {HTMLElement} elt - * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn - * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore - */ - function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + //= ========================================== + // Next resolve via DOM values + //= ========================================== + const requestPath = responseInfo.pathInfo.finalRequestPath + const responsePath = responseInfo.pathInfo.responsePath + + const pushUrl = getClosestAttributeValue(elt, 'hx-push-url') + const replaceUrl = getClosestAttributeValue(elt, 'hx-replace-url') + const elementIsBoosted = getInternalData(elt).boosted + + let saveType = null + let path = null + + if (pushUrl) { + saveType = 'push' + path = pushUrl + } else if (replaceUrl) { + saveType = 'replace' + path = replaceUrl + } else if (elementIsBoosted) { + saveType = 'push' + path = responsePath || requestPath // if there is no response path, go with the original request path + } - if (elt == undefined) { - return extensionsToReturn; - } - if (extensionsToReturn == undefined) { - extensionsToReturn = []; - } - if (extensionsToIgnore == undefined) { - extensionsToIgnore = []; - } - var extensionsForElement = getAttributeValue(elt, "hx-ext"); - if (extensionsForElement) { - forEach(extensionsForElement.split(","), function(extensionName){ - extensionName = extensionName.replace(/ /g, ''); - if (extensionName.slice(0, 7) == "ignore:") { - extensionsToIgnore.push(extensionName.slice(7)); - return; - } - if (extensionsToIgnore.indexOf(extensionName) < 0) { - var extension = extensions[extensionName]; - if (extension && extensionsToReturn.indexOf(extension) < 0) { - extensionsToReturn.push(extension); - } - } - }); - } - return getExtensions(parentElt(elt), extensionsToReturn, extensionsToIgnore); - } + if (path) { + // false indicates no push, return empty object + if (path === 'false') { + return {} + } + + // true indicates we want to follow wherever the server ended up sending us + if (path === 'true') { + path = responsePath || requestPath // if there is no response path, go with the original request path + } + + // restore any anchor associated with the request + if (responseInfo.pathInfo.anchor && path.indexOf('#') === -1) { + path = path + '#' + responseInfo.pathInfo.anchor + } + + return { + type: saveType, + path + } + } else { + return {} + } + } + + /** + * @param {HtmxResponseHandlingConfig} responseHandlingConfig + * @param {number} status + * @return {boolean} + */ + function codeMatches(responseHandlingConfig, status) { + var regExp = new RegExp(responseHandlingConfig.code) + return regExp.test(status.toString(10)) + } + + /** + * @param {XMLHttpRequest} xhr + * @return {HtmxResponseHandlingConfig} + */ + function resolveResponseHandling(xhr) { + for (var i = 0; i < htmx.config.responseHandling.length; i++) { + /** @type HtmxResponseHandlingConfig */ + var responseHandlingElement = htmx.config.responseHandling[i] + if (codeMatches(responseHandlingElement, xhr.status)) { + return responseHandlingElement + } + } + // no matches, return no swap + return { + swap: false + } + } + + /** + * @param {string} title + */ + function handleTitle(title) { + if (title) { + const titleElt = find('title') + if (titleElt) { + titleElt.innerHTML = title + } else { + window.document.title = title + } + } + } + + /** + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + */ + function handleAjaxResponse(elt, responseInfo) { + const xhr = responseInfo.xhr + let target = responseInfo.target + const etc = responseInfo.etc + const responseInfoSelect = responseInfo.select + + if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return + + if (hasHeader(xhr, /HX-Trigger:/i)) { + handleTriggerHeader(xhr, 'HX-Trigger', elt) + } - //==================================================================== - // Initialization - //==================================================================== - var isReady = false - getDocument().addEventListener('DOMContentLoaded', function() { - isReady = true - }) + if (hasHeader(xhr, /HX-Location:/i)) { + saveCurrentPageToHistory() + let redirectPath = xhr.getResponseHeader('HX-Location') + /** @type {HtmxAjaxHelperContext&{path:string}} */ + var redirectSwapSpec + if (redirectPath.indexOf('{') === 0) { + redirectSwapSpec = parseJSON(redirectPath) + // what's the best way to throw an error if the user didn't include this + redirectPath = redirectSwapSpec.path + delete redirectSwapSpec.path + } + ajaxHelper('get', redirectPath, redirectSwapSpec).then(function() { + pushUrlIntoHistory(redirectPath) + }) + return + } - /** - * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. - * - * This function uses isReady because there is no realiable way to ask the browswer whether - * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded - * firing and readystate=complete. - */ - function ready(fn) { - // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by - // some means other than the initial page load. - if (isReady || getDocument().readyState === 'complete') { - fn(); - } else { - getDocument().addEventListener('DOMContentLoaded', fn); - } - } + const shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && xhr.getResponseHeader('HX-Refresh') === 'true' - function insertIndicatorStyles() { - if (htmx.config.includeIndicatorStyles !== false) { - getDocument().head.insertAdjacentHTML("beforeend", - "<style>\ - ." + htmx.config.indicatorClass + "{opacity:0}\ - ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ - ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ - </style>"); - } - } + if (hasHeader(xhr, /HX-Redirect:/i)) { + location.href = xhr.getResponseHeader('HX-Redirect') + shouldRefresh && location.reload() + return + } - function getMetaConfig() { - var element = getDocument().querySelector('meta[name="htmx-config"]'); - if (element) { - // @ts-ignore - return parseJSON(element.content); - } else { - return null; - } - } + if (shouldRefresh) { + location.reload() + return + } - function mergeMetaConfig() { - var metaConfig = getMetaConfig(); - if (metaConfig) { - htmx.config = mergeObjects(htmx.config , metaConfig) - } - } + if (hasHeader(xhr, /HX-Retarget:/i)) { + if (xhr.getResponseHeader('HX-Retarget') === 'this') { + responseInfo.target = elt + } else { + responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget'))) + } + } - // initialize the document - ready(function () { - mergeMetaConfig(); - insertIndicatorStyles(); - var body = getDocument().body; - processNode(body); - var restoredElts = getDocument().querySelectorAll( - "[hx-trigger='restored'],[data-hx-trigger='restored']" - ); - body.addEventListener("htmx:abort", function (evt) { - var target = evt.target; - var internalData = getInternalData(target); - if (internalData && internalData.xhr) { - internalData.xhr.abort(); - } - }); - /** @type {(ev: PopStateEvent) => any} */ - const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null; - /** @type {(ev: PopStateEvent) => any} */ - window.onpopstate = function (event) { - if (event.state && event.state.htmx) { - restoreHistory(); - forEach(restoredElts, function(elt){ - triggerEvent(elt, 'htmx:restored', { - 'document': getDocument(), - 'triggerEvent': triggerEvent - }); - }); - } else { - if (originalPopstate) { - originalPopstate(event); - } - } - }; - setTimeout(function () { - triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event - body = null; // kill reference for gc - }, 0); + const historyUpdate = determineHistoryUpdates(elt, responseInfo) + + const responseHandling = resolveResponseHandling(xhr) + const shouldSwap = responseHandling.swap + let isError = !!responseHandling.error + let ignoreTitle = htmx.config.ignoreTitle || responseHandling.ignoreTitle + let selectOverride = responseHandling.select + if (responseHandling.target) { + responseInfo.target = asElement(querySelectorExt(elt, responseHandling.target)) + } + var swapOverride = etc.swapOverride + if (swapOverride == null && responseHandling.swapOverride) { + swapOverride = responseHandling.swapOverride + } + + // response headers override response handling config + if (hasHeader(xhr, /HX-Retarget:/i)) { + if (xhr.getResponseHeader('HX-Retarget') === 'this') { + responseInfo.target = elt + } else { + responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget'))) + } + } + if (hasHeader(xhr, /HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader('HX-Reswap') + } + + var serverResponse = xhr.response + /** @type HtmxBeforeSwapDetails */ + var beforeSwapDetails = mergeObjects({ + shouldSwap, + serverResponse, + isError, + ignoreTitle, + selectOverride + }, responseInfo) + + if (responseHandling.event && !triggerEvent(target, responseHandling.event, beforeSwapDetails)) return + + if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return + + target = beforeSwapDetails.target // allow re-targeting + serverResponse = beforeSwapDetails.serverResponse // allow updating content + isError = beforeSwapDetails.isError // allow updating error + ignoreTitle = beforeSwapDetails.ignoreTitle // allow updating ignoring title + selectOverride = beforeSwapDetails.selectOverride // allow updating select override + + responseInfo.target = target // Make updated target available to response events + responseInfo.failed = isError // Make failed property available to response events + responseInfo.successful = !isError // Make successful property available to response events + + if (beforeSwapDetails.shouldSwap) { + if (xhr.status === 286) { + cancelPolling(elt) + } + + withExtensions(elt, function(extension) { + serverResponse = extension.transformResponse(serverResponse, xhr, elt) + }) + + // Save current page if there will be a history update + if (historyUpdate.type) { + saveCurrentPageToHistory() + } + + if (hasHeader(xhr, /HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader('HX-Reswap') + } + var swapSpec = getSwapSpecification(elt, swapOverride) + + if (!swapSpec.hasOwnProperty('ignoreTitle')) { + swapSpec.ignoreTitle = ignoreTitle + } + + target.classList.add(htmx.config.swappingClass) + + // optional transition API promise callbacks + let settleResolve = null + let settleReject = null + + if (responseInfoSelect) { + selectOverride = responseInfoSelect + } + + if (hasHeader(xhr, /HX-Reselect:/i)) { + selectOverride = xhr.getResponseHeader('HX-Reselect') + } + + const selectOOB = getClosestAttributeValue(elt, 'hx-select-oob') + const select = getClosestAttributeValue(elt, 'hx-select') + + let doSwap = function() { + try { + // if we need to save history, do so, before swapping so that relative resources have the correct base URL + if (historyUpdate.type) { + triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)) + if (historyUpdate.type === 'push') { + pushUrlIntoHistory(historyUpdate.path) + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', { path: historyUpdate.path }) + } else { + replaceUrlInHistory(historyUpdate.path) + triggerEvent(getDocument().body, 'htmx:replacedInHistory', { path: historyUpdate.path }) + } + } + + swap(target, serverResponse, swapSpec, { + select: selectOverride || select, + selectOOB, + eventInfo: responseInfo, + anchor: responseInfo.pathInfo.anchor, + contextElement: elt, + afterSwapCallback: function() { + if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { + let finalElt = elt + if (!bodyContains(elt)) { + finalElt = getDocument().body + } + handleTriggerHeader(xhr, 'HX-Trigger-After-Swap', finalElt) + } + }, + afterSettleCallback: function() { + if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { + let finalElt = elt + if (!bodyContains(elt)) { + finalElt = getDocument().body + } + handleTriggerHeader(xhr, 'HX-Trigger-After-Settle', finalElt) + } + maybeCall(settleResolve) + } + }) + } catch (e) { + triggerErrorEvent(elt, 'htmx:swapError', responseInfo) + maybeCall(settleReject) + throw e + } + } + + let shouldTransition = htmx.config.globalViewTransitions + if (swapSpec.hasOwnProperty('transition')) { + shouldTransition = swapSpec.transition + } + + if (shouldTransition && + triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && + typeof Promise !== 'undefined' && + // @ts-ignore experimental feature atm + document.startViewTransition) { + const settlePromise = new Promise(function(_resolve, _reject) { + settleResolve = _resolve + settleReject = _reject }) + // wrap the original doSwap() in a call to startViewTransition() + const innerDoSwap = doSwap + doSwap = function() { + // @ts-ignore experimental feature atm + document.startViewTransition(function() { + innerDoSwap() + return settlePromise + }) + } + } + + if (swapSpec.swapDelay > 0) { + getWindow().setTimeout(doSwap, swapSpec.swapDelay) + } else { + doSwap() + } + } + if (isError) { + triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({ error: 'Response Status Error Code ' + xhr.status + ' from ' + responseInfo.pathInfo.requestPath }, responseInfo)) + } + } + + //= =================================================================== + // Extensions API + //= =================================================================== + + /** @type {Object<string, HtmxExtension>} */ + const extensions = {} + + /** + * extensionBase defines the default functions for all extensions. + * @returns {HtmxExtension} + */ + function extensionBase() { + return { + init: function(api) { return null }, + getSelectors: function() { return null }, + onEvent: function(name, evt) { return true }, + transformResponse: function(text, xhr, elt) { return text }, + isInlineSwap: function(swapStyle) { return false }, + handleSwap: function(swapStyle, target, fragment, settleInfo) { return false }, + encodeParameters: function(xhr, parameters, elt) { return null } + } + } + + /** + * defineExtension initializes the extension and adds it to the htmx registry + * + * @see https://htmx.org/api/#defineExtension + * + * @param {string} name the extension name + * @param {HtmxExtension} extension the extension definition + */ + function defineExtension(name, extension) { + if (extension.init) { + extension.init(internalAPI) + } + extensions[name] = mergeObjects(extensionBase(), extension) + } + + /** + * removeExtension removes an extension from the htmx registry + * + * @see https://htmx.org/api/#removeExtension + * + * @param {string} name + */ + function removeExtension(name) { + delete extensions[name] + } + + /** + * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element + * + * @param {Element} elt + * @param {HtmxExtension[]=} extensionsToReturn + * @param {string[]=} extensionsToIgnore + * @returns {HtmxExtension[]} + */ + function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + if (extensionsToReturn == undefined) { + extensionsToReturn = [] + } + if (elt == undefined) { + return extensionsToReturn + } + if (extensionsToIgnore == undefined) { + extensionsToIgnore = [] + } + const extensionsForElement = getAttributeValue(elt, 'hx-ext') + if (extensionsForElement) { + forEach(extensionsForElement.split(','), function(extensionName) { + extensionName = extensionName.replace(/ /g, '') + if (extensionName.slice(0, 7) == 'ignore:') { + extensionsToIgnore.push(extensionName.slice(7)) + return + } + if (extensionsToIgnore.indexOf(extensionName) < 0) { + const extension = extensions[extensionName] + if (extension && extensionsToReturn.indexOf(extension) < 0) { + extensionsToReturn.push(extension) + } + } + }) + } + return getExtensions(asElement(parentElt(elt)), extensionsToReturn, extensionsToIgnore) + } + + //= =================================================================== + // Initialization + //= =================================================================== + var isReady = false + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true + }) + + /** + * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. + * + * This function uses isReady because there is no reliable way to ask the browser whether + * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded + * firing and readystate=complete. + */ + function ready(fn) { + // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by + // some means other than the initial page load. + if (isReady || getDocument().readyState === 'complete') { + fn() + } else { + getDocument().addEventListener('DOMContentLoaded', fn) + } + } + + function insertIndicatorStyles() { + if (htmx.config.includeIndicatorStyles !== false) { + const nonceAttribute = htmx.config.inlineStyleNonce ? ` nonce="${htmx.config.inlineStyleNonce}"` : '' + getDocument().head.insertAdjacentHTML('beforeend', + '<style' + nonceAttribute + '>\ + .' + htmx.config.indicatorClass + '{opacity:0}\ + .' + htmx.config.requestClass + ' .' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\ + .' + htmx.config.requestClass + '.' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\ + </style>') + } + } + + function getMetaConfig() { + /** @type HTMLMetaElement */ + const element = getDocument().querySelector('meta[name="htmx-config"]') + if (element) { + return parseJSON(element.content) + } else { + return null + } + } - return htmx; + function mergeMetaConfig() { + const metaConfig = getMetaConfig() + if (metaConfig) { + htmx.config = mergeObjects(htmx.config, metaConfig) + } + } + + // initialize the document + ready(function() { + mergeMetaConfig() + insertIndicatorStyles() + let body = getDocument().body + processNode(body) + const restoredElts = getDocument().querySelectorAll( + "[hx-trigger='restored'],[data-hx-trigger='restored']" + ) + body.addEventListener('htmx:abort', function(evt) { + const target = evt.target + const internalData = getInternalData(target) + if (internalData && internalData.xhr) { + internalData.xhr.abort() + } + }) + /** @type {(ev: PopStateEvent) => any} */ + const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null + /** @type {(ev: PopStateEvent) => any} */ + window.onpopstate = function(event) { + if (event.state && event.state.htmx) { + restoreHistory() + forEach(restoredElts, function(elt) { + triggerEvent(elt, 'htmx:restored', { + document: getDocument(), + triggerEvent + }) + }) + } else { + if (originalPopstate) { + originalPopstate(event) + } + } } -)() -})); + getWindow().setTimeout(function() { + triggerEvent(body, 'htmx:load', {}) // give ready handlers a chance to load up before firing this event + body = null // kill reference for gc + }, 0) + }) + + return htmx +})() + +/** @typedef {'get'|'head'|'post'|'put'|'delete'|'connect'|'options'|'trace'|'patch'} HttpVerb */ + +/** + * @typedef {Object} SwapOptions + * @property {string} [select] + * @property {string} [selectOOB] + * @property {*} [eventInfo] + * @property {string} [anchor] + * @property {Element} [contextElement] + * @property {swapCallback} [afterSwapCallback] + * @property {swapCallback} [afterSettleCallback] + */ + +/** + * @callback swapCallback + */ + +/** + * @typedef {'innerHTML' | 'outerHTML' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'delete' | 'none' | string} HtmxSwapStyle + */ + +/** + * @typedef HtmxSwapSpecification + * @property {HtmxSwapStyle} swapStyle + * @property {number} swapDelay + * @property {number} settleDelay + * @property {boolean} [transition] + * @property {boolean} [ignoreTitle] + * @property {string} [head] + * @property {'top' | 'bottom'} [scroll] + * @property {string} [scrollTarget] + * @property {string} [show] + * @property {string} [showTarget] + * @property {boolean} [focusScroll] + */ + +/** + * @typedef {((this:Node, evt:Event) => boolean) & {source: string}} ConditionalFunction + */ + +/** + * @typedef {Object} HtmxTriggerSpecification + * @property {string} trigger + * @property {number} [pollInterval] + * @property {ConditionalFunction} [eventFilter] + * @property {boolean} [changed] + * @property {boolean} [once] + * @property {boolean} [consume] + * @property {number} [delay] + * @property {string} [from] + * @property {string} [target] + * @property {number} [throttle] + * @property {string} [queue] + * @property {string} [root] + * @property {string} [threshold] + */ + +/** + * @typedef {{elt: Element, message: string, validity: ValidityState}} HtmxElementValidationError + */ + +/** + * @typedef {Record<string, string>} HtmxHeaderSpecification + * @property {'true'} HX-Request + * @property {string|null} HX-Trigger + * @property {string|null} HX-Trigger-Name + * @property {string|null} HX-Target + * @property {string} HX-Current-URL + * @property {string} [HX-Prompt] + * @property {'true'} [HX-Boosted] + * @property {string} [Content-Type] + * @property {'true'} [HX-History-Restore-Request] + */ + +/** @typedef HtmxAjaxHelperContext + * @property {Element|string} [source] + * @property {Event} [event] + * @property {HtmxAjaxHandler} [handler] + * @property {Element|string} target + * @property {HtmxSwapStyle} [swap] + * @property {Object|FormData} [values] + * @property {Record<string,string>} [headers] + * @property {string} [select] + */ + +/** + * @typedef {Object} HtmxRequestConfig + * @property {boolean} boosted + * @property {boolean} useUrlParams + * @property {FormData} formData + * @property {Object} parameters formData proxy + * @property {FormData} unfilteredFormData + * @property {Object} unfilteredParameters unfilteredFormData proxy + * @property {HtmxHeaderSpecification} headers + * @property {Element} target + * @property {HttpVerb} verb + * @property {HtmxElementValidationError[]} errors + * @property {boolean} withCredentials + * @property {number} timeout + * @property {string} path + * @property {Event} triggeringEvent + */ + +/** + * @typedef {Object} HtmxResponseInfo + * @property {XMLHttpRequest} xhr + * @property {Element} target + * @property {HtmxRequestConfig} requestConfig + * @property {HtmxAjaxEtc} etc + * @property {boolean} boosted + * @property {string} select + * @property {{requestPath: string, finalRequestPath: string, responsePath: string|null, anchor: string}} pathInfo + * @property {boolean} [failed] + * @property {boolean} [successful] + */ + +/** + * @typedef {Object} HtmxAjaxEtc + * @property {boolean} [returnPromise] + * @property {HtmxAjaxHandler} [handler] + * @property {string} [select] + * @property {Element} [targetOverride] + * @property {HtmxSwapStyle} [swapOverride] + * @property {Record<string,string>} [headers] + * @property {Object|FormData} [values] + * @property {boolean} [credentials] + * @property {number} [timeout] + */ + +/** + * @typedef {Object} HtmxResponseHandlingConfig + * @property {string} [code] + * @property {boolean} swap + * @property {boolean} [error] + * @property {boolean} [ignoreTitle] + * @property {string} [select] + * @property {string} [target] + * @property {string} [swapOverride] + * @property {string} [event] + */ + +/** + * @typedef {HtmxResponseInfo & {shouldSwap: boolean, serverResponse: any, isError: boolean, ignoreTitle: boolean, selectOverride:string}} HtmxBeforeSwapDetails + */ + +/** + * @callback HtmxAjaxHandler + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + */ + +/** + * @typedef {(() => void)} HtmxSettleTask + */ + +/** + * @typedef {Object} HtmxSettleInfo + * @property {HtmxSettleTask[]} tasks + * @property {Element[]} elts + * @property {string} [title] + */ + +/** + * @typedef {Object} HtmxExtension + * @see https://htmx.org/extensions/#defining + * @property {(api: any) => void} init + * @property {(name: string, event: Event|CustomEvent) => boolean} onEvent + * @property {(text: string, xhr: XMLHttpRequest, elt: Element) => string} transformResponse + * @property {(swapStyle: HtmxSwapStyle) => boolean} isInlineSwap + * @property {(swapStyle: HtmxSwapStyle, target: Element, fragment: Node, settleInfo: HtmxSettleInfo) => boolean} handleSwap + * @property {(xhr: XMLHttpRequest, parameters: FormData, elt: Element) => *|string|null} encodeParameters + */ diff --git a/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.min.js b/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.min.js index 53bbdf6..d66acce 100644 --- a/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.min.js +++ b/code/ch5_partials/ch5_starter_video_collector/static/js/htmx.min.js @@ -1,4 +1,2 @@ -// /////////////////////////////////////////////////////////////////// -// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js -// -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(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 a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/<body/.test(e)}function l(e){var t=!N(e);var r=A(e);var n=e;if(r==="head"){n=n.replace(S,"")}if(Q.config.useTemplateFragments&&t){var i=a("<body><template>"+n+"</template></body>",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a("<table>"+n+"</table>",1);case"col":return a("<table><colgroup>"+n+"</colgroup></table>",2);case"tr":return a("<table><tbody>"+n+"</tbody></table>",2);case"td":case"th":return a("<table><tbody><tr>"+n+"</tr></tbody></table>",3);case"script":case"style":return a("<div>"+n+"</div>",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function oe(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function X(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var Y=function(e,t){var r=re().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function we(t,r){oe(t.attributes,function(e){if(!r.hasAttribute(e.name)&&be(e.name)){t.removeAttribute(e.name)}});oe(r.attributes,function(e){if(be(e.name)){t.setAttribute(e.name,e.value)}})}function Se(e,t){var r=Fr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){b(e)}}return e==="outerHTML"}function Ee(e,i,a){var t="#"+ee(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a<i.length;a++){var o=i[a].split(":",2);var s=o[0].trim();if(s.indexOf("#")===0){s=s.substring(1)}var l=o[1]||"true";var u=t.querySelector("#"+s);if(u){Ee(l,u,r)}}}oe(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=te(e,"hx-swap-oob");if(t!=null){Ee(t,e,r)}})}function Re(e){oe(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=te(e,"id");var r=re().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function Te(o,e,s){oe(e.querySelectorAll("[id]"),function(e){var t=ee(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Le(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=He(n.name,t);t=He(n.value,t)}}}return t}function Ae(e){var t=ae(e);if(t.onHandlers){for(var r=0;r<t.onHandlers.length;r++){const n=t.onHandlers[r];e.removeEventListener(n.event,n.listener)}delete t.onHandlers}}function Ne(e){var t=ae(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){oe(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}Ae(e);oe(Object.keys(t),function(e){delete t[e]})}function p(e){ce(e,"htmx:beforeCleanupElement");Ne(e);if(e.children){oe(e.children,function(e){p(e)})}}function Ie(t,e,r){if(t.tagName==="BODY"){return Ue(t,e,r)}else{var n;var i=t.previousSibling;m(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}p(t);u(t).removeChild(t)}}function ke(e,t,r){return m(e,e.firstChild,t,r)}function Pe(e,t,r){return m(u(e),e,t,r)}function Me(e,t,r){return m(e,null,t,r)}function Xe(e,t,r){return m(u(e),e.nextSibling,t,r)}function De(e,t,r){p(e);return u(e).removeChild(e)}function Ue(e,t,r){var n=e.firstChild;m(e,n,t,r);if(n){while(n.nextSibling){p(n.nextSibling);e.removeChild(n.nextSibling)}p(n);e.removeChild(n)}}function Be(e,t,r){var n=r||ne(e,"hx-select");if(n){var i=re().createDocumentFragment();oe(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function Fe(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Ie(r,n,i);return;case"afterbegin":ke(r,n,i);return;case"beforebegin":Pe(r,n,i);return;case"beforeend":Me(r,n,i);return;case"afterend":Xe(r,n,i);return;case"delete":De(r,n,i);return;default:var a=Fr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Oe(f))}}}return}}catch(e){b(e)}}if(e==="innerHTML"){Ue(r,n,i)}else{Fe(Q.config.defaultSwapStyle,t,r,n,i)}}}function Ve(e){if(e.indexOf("<title")>-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){ce(r,s[l].trim(),[])}}}var ze=/\s/;var x=/[\s,]/;var $e=/[_$a-zA-Z]/;var We=/[_$a-zA-Z0-9]/;var Ge=['"',"'","/"];var Je=/[^\s]/;var Ze=/[{(]/;var Ke=/[})]/;function Ye(e){var t=[];var r=0;while(r<e.length){if($e.exec(e.charAt(r))){var n=r;while(We.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ge.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function Qe(e,t,r){return $e.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function et(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){xt(e,a[1],0)}if(a[0]==="send"){bt(e)}}}function xt(s,r,n){if(!se(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=Q.createWebSocket(r);t.onerror=function(e){fe(s,"htmx:wsError",{error:e,socket:t});yt(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a<i.length;a++){var o=i[a];Ee(te(o,"hx-swap-oob")||"true",o,r)}nr(r.tasks)})}function yt(e){if(!se(e)){ae(e).webSocket.close();return true}}function bt(u){var f=c(u,function(e){return ae(e).webSocket!=null});if(f){u.addEventListener(it(u)[0].trigger,function(e){var t=ae(f).webSocket;var r=xr(u,f);var n=dr(u,"post");var i=n.errors;var a=n.values;var o=Hr(u);var s=le(a,o);var l=yr(s,u);l["HEADERS"]=r;if(i&&i.length>0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){Et(e,a[1])}if(a[0]==="swap"){Ct(e,a[1])}}}function Et(t,e){var r=Q.createEventSource(e);r.onerror=function(e){fe(t,"htmx:sseError",{error:e,source:r});Tt(t)};ae(t).sseEventSource=r}function Ct(a,o){var s=c(a,Ot);if(s){var l=ae(s).sseEventSource;var u=function(e){if(Tt(s)){return}if(!se(a)){l.removeEventListener(o,u);return}var t=e.data;R(a,function(e){t=e.transformResponse(t,null,a)});var r=wr(a);var n=ye(a);var i=T(a);je(r.swapStyle,n,a,t,i);nr(i.tasks);ce(a,"htmx:sseMessage",e)};ae(a).sseListener=u;l.addEventListener(o,u)}else{fe(a,"htmx:noSSESourceError")}}function Rt(e,t,r){var n=c(e,Ot);if(n){var i=ae(n).sseEventSource;var a=function(){if(!Tt(n)){if(se(e)){t(e)}else{i.removeEventListener(r,a)}}};ae(e).sseListener=a;i.addEventListener(r,a)}else{fe(e,"htmx:noSSESourceError")}}function Tt(e){if(!se(e)){ae(e).sseEventSource.close();return true}}function Ot(e){return ae(e).sseEventSource!=null}function qt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n>0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){ce(n,"intersect");break}}},i);a.observe(n);ht(n,r,t,e)}else if(e.trigger==="load"){if(!ct(e,n,Wt("load",{elt:n}))){qt(n,r,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r<t.length;r++){var n=t[r].name;if(s(n,"hx-on:")||s(n,"data-hx-on:")||s(n,"hx-on-")||s(n,"data-hx-on-")){return true}}return false}function kt(e){var t=null;var r=[];if(It(e)){r.push(e)}if(document.evaluate){var n=document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]',e);while(t=n.iterateNext())r.push(t)}else{var i=e.getElementsByTagName("*");for(var a=0;a<i.length;a++){if(It(i[a])){r.push(i[a])}}}return r}function Pt(e){if(e.querySelectorAll){var t=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";var r=e.querySelectorAll(i+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Mt(e){var t=v(e.target,"button, input[type='submit']");var r=Dt(e);if(r){r.lastButtonClicked=t}}function Xt(e){var t=Dt(e);if(t){t.lastButtonClicked=null}}function Dt(e){var t=v(e.target,"button, input[type='submit']");if(!t){return}var r=g("#"+ee(t,"form"))||v(t,"form");if(!r){return}return ae(r)}function Ut(e){e.addEventListener("click",Mt);e.addEventListener("focusin",Mt);e.addEventListener("focusout",Xt)}function Bt(e){var t=Ye(e);var r=0;for(var n=0;n<t.length;n++){const i=t[n];if(i==="{"){r++}else if(i==="}"){r--}}return r}function Ft(t,e,r){var n=ae(t);if(!Array.isArray(n.onHandlers)){n.onHandlers=[]}var i;var a=function(e){return Tr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Vt(e){var t=te(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;t<e.attributes.length;t++){var r=e.attributes[t].name;var n=e.attributes[t].value;if(s(r,"hx-on")||s(r,"data-hx-on")){var i=r.indexOf("-on")+3;var a=r.slice(i,i+1);if(a==="-"||a===":"){var o=r.slice(i+1);if(s(o,":")){o="htmx"+o}else if(s(o,"-")){o="htmx:"+o.slice(1)}else if(s(o,"htmx-")){o="htmx:"+o.slice(5)}Ft(e,o,n)}}}}function _t(t){if(v(t,Q.config.disableSelector)){p(t);return}var r=ae(t);if(r.initHash!==Le(t)){Ne(t);r.initHash=Le(t);Vt(t);ce(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=it(t);var n=Ht(t,r,e);if(!n){if(ne(t,"hx-boost")==="true"){lt(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){Lt(t,e,r,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&o(t,"form")){Ut(t)}var i=te(t,"hx-sse");if(i){St(t,r,i)}var a=te(t,"hx-ws");if(a){pt(t,r,a)}ce(t,"htmx:afterProcessNode")}}function zt(e){e=g(e);if(v(e,Q.config.disableSelector)){p(e);return}_t(e);oe(Pt(e),function(e){_t(e)});oe(kt(e),jt)}function $t(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=re().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function fe(e,t,r){ce(e,t,le({error:t},r))}function Gt(e){return e==="htmx:afterProcessNode"}function R(e,t){oe(Fr(e),function(e){try{t(e)}catch(e){b(e)}})}function b(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ce(e,t,r){e=g(e);if(r==null){r={}}r["elt"]=e;var n=Wt(t,r);if(Q.logger&&!Gt(t)){Q.logger(e,t,r)}if(r.error){b(r.error);ce(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=$t(t);if(i&&a!==t){var o=Wt(a,n.detail);i=i&&e.dispatchEvent(o)}R(e,function(e){i=i&&(e.onEvent(t,n)!==false&&!n.defaultPrevented)});return i}var Jt=location.pathname+location.search;function Zt(){var e=re().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||re().body}function Kt(e,t,r,n){if(!U()){return}if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}e=B(e);var i=E(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};ce(re().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Qt(e){var t=Q.config.requestClass;var r=e.cloneNode(true);oe(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function er(){var e=Zt();var t=Jt||location.pathname+location.search;var r;try{r=re().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){r=re().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!r){ce(re().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Kt(t,Qt(e),re().title,window.scrollY)}if(Q.config.historyEnabled)history.replaceState({htmx:true},re().title,window.location.href)}function tr(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(G(e,"&")||G(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Jt=e}function rr(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Jt=e}function nr(e){oe(e,function(e){e.call()})}function ir(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};ce(re().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",re().location.href);e.onload=function(){if(this.status>=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function fr(e){if(e.name===""||e.name==null||e.disabled||v(e,"fieldset[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 cr(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function hr(t,r,n,e,i){if(e==null||ur(t,e)){return}else{t.push(e)}if(fr(e)){var a=ee(e,"name");var o=e.value;if(e.multiple&&e.tagName==="SELECT"){o=M(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=M(e.files)}cr(a,o,r);if(i){vr(e,n)}}if(h(e,"form")){var s=e.elements;oe(s,function(e){hr(t,r,n,e,i)})}}function vr(e,t){if(e.willValidate){ce(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});ce(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function dr(e,t){var r=[];var n={};var i={};var a=[];var o=ae(e);if(o.lastButtonClicked&&!se(o.lastButtonClicked)){o.lastButtonClicked=null}var s=h(e,"form")&&e.noValidate!==true||te(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){hr(r,i,a,v(e,"form"),s)}hr(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=ee(l,"name");cr(u,l.value,i)}var f=pe(e,"hx-include");oe(f,function(e){hr(r,n,a,e,s);if(!h(e,"form")){oe(e.querySelectorAll(rt),function(e){hr(r,n,a,e,s)})}});n=le(n,i);return{errors:a,values:n}}function gr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function mr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t=gr(t,r,e)})}else{t=gr(t,r,n)}}}return t}function pr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function xr(e,t,r){var n={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":re().location.href};Rr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ae(e).boosted){n["HX-Boosted"]="true"}return n}function yr(t,e){var r=ne(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){oe(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};oe(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function br(e){return ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=d(o.substr(5))}else if(o.indexOf("settle:")===0){n["settleDelay"]=d(o.substr(7))}else if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}else if(o.indexOf("ignoreTitle:")===0){n["ignoreTitle"]=o.substr(12)==="true"}else if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","<style> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file +// v2.0.0 from https://github.com/bigskysoftware/htmx/releases +var htmx=function(){"use strict";const Q={onLoad:null,process:null,on:null,off:null,trigger:null,ajax:null,find:null,findAll:null,closest:null,values:function(e,t){const n=cn(e,t||"post");return n.values},remove:null,addClass:null,removeClass:null,toggleClass:null,takeClass:null,swap:null,defineExtension:null,removeExtension:null,logAll:null,logNone:null,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",inlineStyleNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",scrollBehavior:"instant",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get","delete"],selfRequestsOnly:true,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null,disableInheritance:false,responseHandling:[{code:"204",swap:false},{code:"[23]..",swap:true},{code:"[45]..",swap:false,error:true}],allowNestedOobSwaps:true},parseInterval:null,_:null,version:"2.0.0"};Q.onLoad=$;Q.process=Dt;Q.on=be;Q.off=we;Q.trigger=he;Q.ajax=Hn;Q.find=r;Q.findAll=p;Q.closest=g;Q.remove=K;Q.addClass=W;Q.removeClass=o;Q.toggleClass=Y;Q.takeClass=ge;Q.swap=ze;Q.defineExtension=Un;Q.removeExtension=Bn;Q.logAll=z;Q.logNone=J;Q.parseInterval=d;Q._=_;const n={addTriggerHandler:Et,bodyContains:le,canAccessLocalStorage:j,findThisElement:Ee,filterValues:dn,swap:ze,hasAttribute:s,getAttributeValue:te,getClosestAttributeValue:re,getClosestMatch:T,getExpressionVars:Cn,getHeaders:hn,getInputValues:cn,getInternalData:ie,getSwapSpecification:pn,getTriggerSpecs:lt,getTarget:Ce,makeFragment:D,mergeObjects:ue,makeSettleInfo:xn,oobSwap:Te,querySelectorExt:fe,settleImmediately:Gt,shouldCancel:dt,triggerEvent:he,triggerErrorEvent:ae,withExtensions:Ut};const v=["get","post","put","delete","patch"];const R=v.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");const O=e("head");function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e instanceof Element&&e.getAttribute(t)}function s(e,t){return!!e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){const t=e.parentElement;if(!t&&e.parentNode instanceof ShadowRoot)return e.parentNode;return t}function ne(){return document}function H(e,t){return e.getRootNode?e.getRootNode({composed:t}):ne()}function T(e,t){while(e&&!t(e)){e=u(e)}return e||null}function q(e,t,n){const r=te(t,n);const o=te(t,"hx-disinherit");var i=te(t,"hx-inherit");if(e!==t){if(Q.config.disableInheritance){if(i&&(i==="*"||i.split(" ").indexOf(n)>=0)){return r}else{return null}}if(o&&(o==="*"||o.split(" ").indexOf(n)>=0)){return"unset"}}return r}function re(t,n){let r=null;T(t,function(e){return!!(r=q(t,ce(e),n))});if(r!=="unset"){return r}}function a(e,t){const n=e instanceof Element&&(e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector);return!!n&&n.call(e,t)}function L(e){const t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;const n=t.exec(e);if(n){return n[1].toLowerCase()}else{return""}}function N(e){const t=new DOMParser;return t.parseFromString(e,"text/html")}function A(e,t){while(t.childNodes.length>0){e.append(t.childNodes[0])}}function I(e){const t=ne().createElement("script");se(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}return t}function P(e){return e.matches("script")&&(e.type==="text/javascript"||e.type==="module"||e.type==="")}function k(e){Array.from(e.querySelectorAll("script")).forEach(e=>{if(P(e)){const t=I(e);const n=e.parentNode;try{n.insertBefore(t,e)}catch(e){w(e)}finally{e.remove()}}})}function D(e){const t=e.replace(O,"");const n=L(t);let r;if(n==="html"){r=new DocumentFragment;const i=N(e);A(r,i.body);r.title=i.title}else if(n==="body"){r=new DocumentFragment;const i=N(t);A(r,i.body);r.title=i.title}else{const i=N('<body><template class="internal-htmx-wrapper">'+t+"</template></body>");r=i.querySelector("template").content;r.title=i.title;var o=r.querySelector("title");if(o&&o.parentNode===r){o.remove();r.title=o.innerText}}if(r){if(Q.config.allowScriptTags){k(r)}else{r.querySelectorAll("script").forEach(e=>e.remove())}}return r}function oe(e){if(e){e()}}function t(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function M(e){return typeof e==="function"}function X(e){return t(e,"Object")}function ie(e){const t="htmx-internal-data";let n=e[t];if(!n){n=e[t]={}}return n}function F(t){const n=[];if(t){for(let e=0;e<t.length;e++){n.push(t[e])}}return n}function se(t,n){if(t){for(let e=0;e<t.length;e++){n(t[e])}}}function U(e){const t=e.getBoundingClientRect();const n=t.top;const r=t.bottom;return n<window.innerHeight&&r>=0}function le(e){const t=e.getRootNode&&e.getRootNode();if(t&&t instanceof window.ShadowRoot){return ne().body.contains(t.host)}else{return ne().body.contains(e)}}function B(e){return e.trim().split(/\s+/)}function ue(e,t){for(const n in t){if(t.hasOwnProperty(n)){e[n]=t[n]}}return e}function S(e){try{return JSON.parse(e)}catch(e){w(e);return null}}function j(){const e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function V(t){try{const e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function _(e){return vn(ne().body,function(){return eval(e)})}function $(t){const e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function z(){Q.logger=function(e,t,n){if(console){console.log(t,e,n)}}}function J(){Q.logger=null}function r(e,t){if(typeof e!=="string"){return e.querySelector(t)}else{return r(ne(),e)}}function p(e,t){if(typeof e!=="string"){return e.querySelectorAll(t)}else{return p(ne(),e)}}function E(){return window}function K(e,t){e=y(e);if(t){E().setTimeout(function(){K(e);e=null},t)}else{u(e).removeChild(e)}}function ce(e){return e instanceof Element?e:null}function G(e){return e instanceof HTMLElement?e:null}function Z(e){return typeof e==="string"?e:null}function h(e){return e instanceof Element||e instanceof Document||e instanceof DocumentFragment?e:null}function W(e,t,n){e=ce(y(e));if(!e){return}if(n){E().setTimeout(function(){W(e,t);e=null},n)}else{e.classList&&e.classList.add(t)}}function o(e,t,n){let r=ce(y(e));if(!r){return}if(n){E().setTimeout(function(){o(r,t);r=null},n)}else{if(r.classList){r.classList.remove(t);if(r.classList.length===0){r.removeAttribute("class")}}}}function Y(e,t){e=y(e);e.classList.toggle(t)}function ge(e,t){e=y(e);se(e.parentElement.children,function(e){o(e,t)});W(ce(e),t)}function g(e,t){e=ce(y(e));if(e&&e.closest){return e.closest(t)}else{do{if(e==null||a(e,t)){return e}}while(e=e&&ce(u(e)));return null}}function l(e,t){return e.substring(0,t.length)===t}function pe(e,t){return e.substring(e.length-t.length)===t}function i(e){const t=e.trim();if(l(t,"<")&&pe(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function m(e,t,n){e=y(e);if(t.indexOf("closest ")===0){return[g(ce(e),i(t.substr(8)))]}else if(t.indexOf("find ")===0){return[r(h(e),i(t.substr(5)))]}else if(t==="next"){return[ce(e).nextElementSibling]}else if(t.indexOf("next ")===0){return[me(e,i(t.substr(5)),!!n)]}else if(t==="previous"){return[ce(e).previousElementSibling]}else if(t.indexOf("previous ")===0){return[ye(e,i(t.substr(9)),!!n)]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else if(t==="root"){return[H(e,!!n)]}else if(t.indexOf("global ")===0){return m(e,t.slice(7),true)}else{return F(h(H(e,!!n)).querySelectorAll(i(t)))}}var me=function(t,e,n){const r=h(H(t,n)).querySelectorAll(e);for(let e=0;e<r.length;e++){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_PRECEDING){return o}}};var ye=function(t,e,n){const r=h(H(t,n)).querySelectorAll(e);for(let e=r.length-1;e>=0;e--){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_FOLLOWING){return o}}};function fe(e,t){if(typeof e!=="string"){return m(e,t)[0]}else{return m(ne().body,e)[0]}}function y(e,t){if(typeof e==="string"){return r(h(t)||document,e)}else{return e}}function xe(e,t,n){if(M(t)){return{target:ne().body,event:Z(e),listener:t}}else{return{target:y(e),event:Z(t),listener:n}}}function be(t,n,r){_n(function(){const e=xe(t,n,r);e.target.addEventListener(e.event,e.listener)});const e=M(n);return e?n:r}function we(t,n,r){_n(function(){const e=xe(t,n,r);e.target.removeEventListener(e.event,e.listener)});return M(n)?n:r}const ve=ne().createElement("output");function Se(e,t){const n=re(e,t);if(n){if(n==="this"){return[Ee(e,t)]}else{const r=m(e,n);if(r.length===0){w('The selector "'+n+'" on '+t+" returned no matches!");return[ve]}else{return r}}}}function Ee(e,t){return ce(T(e,function(e){return te(ce(e),t)!=null}))}function Ce(e){const t=re(e,"hx-target");if(t){if(t==="this"){return Ee(e,"hx-target")}else{return fe(e,t)}}else{const n=ie(e);if(n.boosted){return ne().body}else{return e}}}function Re(t){const n=Q.config.attributesToSettle;for(let e=0;e<n.length;e++){if(t===n[e]){return true}}return false}function Oe(t,n){se(t.attributes,function(e){if(!n.hasAttribute(e.name)&&Re(e.name)){t.removeAttribute(e.name)}});se(n.attributes,function(e){if(Re(e.name)){t.setAttribute(e.name,e.value)}})}function He(t,e){const n=jn(e);for(let e=0;e<n.length;e++){const r=n[e];try{if(r.isInlineSwap(t)){return true}}catch(e){w(e)}}return t==="outerHTML"}function Te(e,o,i){let t="#"+ee(o,"id");let s="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){s=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{s=e}const n=ne().querySelectorAll(t);if(n){se(n,function(e){let t;const n=o.cloneNode(true);t=ne().createDocumentFragment();t.appendChild(n);if(!He(s,e)){t=h(n)}const r={shouldSwap:true,target:e,fragment:t};if(!he(e,"htmx:oobBeforeSwap",r))return;e=r.target;if(r.shouldSwap){_e(s,e,e,t,i)}se(i.elts,function(e){he(e,"htmx:oobAfterSwap",r)})});o.parentNode.removeChild(o)}else{o.parentNode.removeChild(o);ae(ne().body,"htmx:oobErrorNoTarget",{content:o})}return e}function qe(e){se(p(e,"[hx-preserve], [data-hx-preserve]"),function(e){const t=te(e,"id");const n=ne().getElementById(t);if(n!=null){e.parentNode.replaceChild(n,e)}})}function Le(l,e,u){se(e.querySelectorAll("[id]"),function(t){const n=ee(t,"id");if(n&&n.length>0){const r=n.replace("'","\\'");const o=t.tagName.replace(":","\\:");const e=h(l);const i=e&&e.querySelector(o+"[id='"+r+"']");if(i&&i!==e){const s=t.cloneNode();Oe(t,i);u.tasks.push(function(){Oe(t,s)})}}})}function Ne(e){return function(){o(e,Q.config.addedClass);Dt(ce(e));Ae(h(e));he(e,"htmx:load")}}function Ae(e){const t="[autofocus]";const n=G(a(e,t)?e:e.querySelector(t));if(n!=null){n.focus()}}function c(e,t,n,r){Le(e,n,r);while(n.childNodes.length>0){const o=n.firstChild;W(ce(o),Q.config.addedClass);e.insertBefore(o,t);if(o.nodeType!==Node.TEXT_NODE&&o.nodeType!==Node.COMMENT_NODE){r.tasks.push(Ne(o))}}}function Ie(e,t){let n=0;while(n<e.length){t=(t<<5)-t+e.charCodeAt(n++)|0}return t}function Pe(t){let n=0;if(t.attributes){for(let e=0;e<t.attributes.length;e++){const r=t.attributes[e];if(r.value){n=Ie(r.name,n);n=Ie(r.value,n)}}}return n}function ke(t){const n=ie(t);if(n.onHandlers){for(let e=0;e<n.onHandlers.length;e++){const r=n.onHandlers[e];we(t,r.event,r.listener)}delete n.onHandlers}}function De(e){const t=ie(e);if(t.timeout){clearTimeout(t.timeout)}if(t.listenerInfos){se(t.listenerInfos,function(e){if(e.on){we(e.on,e.trigger,e.listener)}})}ke(e);se(Object.keys(t),function(e){delete t[e]})}function f(e){he(e,"htmx:beforeCleanupElement");De(e);if(e.children){se(e.children,function(e){f(e)})}}function Me(t,e,n){let r;const o=t.previousSibling;c(u(t),t,e,n);if(o==null){r=u(t).firstChild}else{r=o.nextSibling}n.elts=n.elts.filter(function(e){return e!==t});while(r&&r!==t){if(r instanceof Element){n.elts.push(r);r=r.nextElementSibling}else{r=null}}f(t);if(t instanceof Element){t.remove()}else{t.parentNode.removeChild(t)}}function Xe(e,t,n){return c(e,e.firstChild,t,n)}function Fe(e,t,n){return c(u(e),e,t,n)}function Ue(e,t,n){return c(e,null,t,n)}function Be(e,t,n){return c(u(e),e.nextSibling,t,n)}function je(e){f(e);return u(e).removeChild(e)}function Ve(e,t,n){const r=e.firstChild;c(e,r,t,n);if(r){while(r.nextSibling){f(r.nextSibling);e.removeChild(r.nextSibling)}f(r);e.removeChild(r)}}function _e(t,e,n,r,o){switch(t){case"none":return;case"outerHTML":Me(n,r,o);return;case"afterbegin":Xe(n,r,o);return;case"beforebegin":Fe(n,r,o);return;case"beforeend":Ue(n,r,o);return;case"afterend":Be(n,r,o);return;case"delete":je(n);return;default:var i=jn(e);for(let e=0;e<i.length;e++){const s=i[e];try{const l=s.handleSwap(t,n,r,o);if(l){if(typeof l.length!=="undefined"){for(let e=0;e<l.length;e++){const u=l[e];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){o.tasks.push(Ne(u))}}}return}}catch(e){w(e)}}if(t==="innerHTML"){Ve(n,r,o)}else{_e(Q.config.defaultSwapStyle,e,n,r,o)}}}function $e(e,n){se(p(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){if(Q.config.allowNestedOobSwaps||e.parentElement===null){const t=te(e,"hx-swap-oob");if(t!=null){Te(t,e,n)}}else{e.removeAttribute("hx-swap-oob");e.removeAttribute("data-hx-swap-oob")}})}function ze(e,t,r,o){if(!o){o={}}e=y(e);const n=document.activeElement;let i={};try{i={elt:n,start:n?n.selectionStart:null,end:n?n.selectionEnd:null}}catch(e){}const s=xn(e);if(r.swapStyle==="textContent"){e.textContent=t}else{let n=D(t);s.title=n.title;if(o.selectOOB){const u=o.selectOOB.split(",");for(let t=0;t<u.length;t++){const c=u[t].split(":",2);let e=c[0].trim();if(e.indexOf("#")===0){e=e.substring(1)}const f=c[1]||"true";const a=n.querySelector("#"+e);if(a){Te(f,a,s)}}}$e(n,s);se(p(n,"template"),function(e){$e(e.content,s);if(e.content.childElementCount===0){e.remove()}});if(o.select){const h=ne().createDocumentFragment();se(n.querySelectorAll(o.select),function(e){h.appendChild(e)});n=h}qe(n);_e(r.swapStyle,o.contextElement,e,n,s)}if(i.elt&&!le(i.elt)&&ee(i.elt,"id")){const d=document.getElementById(ee(i.elt,"id"));const g={preventScroll:r.focusScroll!==undefined?!r.focusScroll:!Q.config.defaultFocusScroll};if(d){if(i.start&&d.setSelectionRange){try{d.setSelectionRange(i.start,i.end)}catch(e){}}d.focus(g)}}e.classList.remove(Q.config.swappingClass);se(s.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}he(e,"htmx:afterSwap",o.eventInfo)});if(o.afterSwapCallback){o.afterSwapCallback()}if(!r.ignoreTitle){Dn(s.title)}const l=function(){se(s.tasks,function(e){e.call()});se(s.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}he(e,"htmx:afterSettle",o.eventInfo)});if(o.anchor){const e=ce(y("#"+o.anchor));if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}bn(s.elts,r);if(o.afterSettleCallback){o.afterSettleCallback()}};if(r.settleDelay>0){E().setTimeout(l,r.settleDelay)}else{l()}}function Je(e,t,n){const r=e.getResponseHeader(t);if(r.indexOf("{")===0){const o=S(r);for(const i in o){if(o.hasOwnProperty(i)){let e=o[i];if(!X(e)){e={value:e}}he(n,i,e)}}}else{const s=r.split(",");for(let e=0;e<s.length;e++){he(n,s[e].trim(),[])}}}const Ke=/\s/;const x=/[\s,]/;const Ge=/[_$a-zA-Z]/;const Ze=/[_$a-zA-Z0-9]/;const We=['"',"'","/"];const Ye=/[^\s]/;const Qe=/[{(]/;const et=/[})]/;function tt(e){const t=[];let n=0;while(n<e.length){if(Ge.exec(e.charAt(n))){var r=n;while(Ze.exec(e.charAt(n+1))){n++}t.push(e.substr(r,n-r+1))}else if(We.indexOf(e.charAt(n))!==-1){const o=e.charAt(n);var r=n;n++;while(n<e.length&&e.charAt(n)!==o){if(e.charAt(n)==="\\"){n++}n++}t.push(e.substr(r,n-r+1))}else{const i=e.charAt(n);t.push(i)}n++}return t}function nt(e,t,n){return Ge.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==n&&t!=="."}function rt(r,o,i){if(o[0]==="["){o.shift();let e=1;let t=" return (function("+i+"){ return (";let n=null;while(o.length>0){const s=o[0];if(s==="]"){e--;if(e===0){if(n===null){t=t+"true"}o.shift();t+=")})";try{const l=vn(r,function(){return Function(t)()},function(){return true});l.source=t;return l}catch(e){ae(ne().body,"htmx:syntax:error",{error:e,source:t});return null}}}else if(s==="["){e++}if(nt(s,n,i)){t+="(("+i+"."+s+") ? ("+i+"."+s+") : (window."+s+"))"}else{t=t+s}n=o.shift()}}}function b(e,t){let n="";while(e.length>0&&!t.test(e[0])){n+=e.shift()}return n}function ot(e){let t;if(e.length>0&&Qe.test(e[0])){e.shift();t=b(e,et).trim();e.shift()}else{t=b(e,x)}return t}const it="input, textarea, select";function st(e,t,n){const r=[];const o=tt(t);do{b(o,Ye);const l=o.length;const u=b(o,/[,\[\s]/);if(u!==""){if(u==="every"){const c={trigger:"every"};b(o,Ye);c.pollInterval=d(b(o,/[,\[\s]/));b(o,Ye);var i=rt(e,o,"event");if(i){c.eventFilter=i}r.push(c)}else{const f={trigger:u};var i=rt(e,o,"event");if(i){f.eventFilter=i}while(o.length>0&&o[0]!==","){b(o,Ye);const a=o.shift();if(a==="changed"){f.changed=true}else if(a==="once"){f.once=true}else if(a==="consume"){f.consume=true}else if(a==="delay"&&o[0]===":"){o.shift();f.delay=d(b(o,x))}else if(a==="from"&&o[0]===":"){o.shift();if(Qe.test(o[0])){var s=ot(o)}else{var s=b(o,x);if(s==="closest"||s==="find"||s==="next"||s==="previous"){o.shift();const h=ot(o);if(h.length>0){s+=" "+h}}}f.from=s}else if(a==="target"&&o[0]===":"){o.shift();f.target=ot(o)}else if(a==="throttle"&&o[0]===":"){o.shift();f.throttle=d(b(o,x))}else if(a==="queue"&&o[0]===":"){o.shift();f.queue=b(o,x)}else if(a==="root"&&o[0]===":"){o.shift();f[a]=ot(o)}else if(a==="threshold"&&o[0]===":"){o.shift();f[a]=b(o,x)}else{ae(e,"htmx:syntax:error",{token:o.shift()})}}r.push(f)}}if(o.length===l){ae(e,"htmx:syntax:error",{token:o.shift()})}b(o,Ye)}while(o[0]===","&&o.shift());if(n){n[t]=r}return r}function lt(e){const t=te(e,"hx-trigger");let n=[];if(t){const r=Q.config.triggerSpecsCache;n=r&&r[t]||st(e,t,r)}if(n.length>0){return n}else if(a(e,"form")){return[{trigger:"submit"}]}else if(a(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(a(e,it)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function ut(e){ie(e).cancelled=true}function ct(e,t,n){const r=ie(e);r.timeout=E().setTimeout(function(){if(le(e)&&r.cancelled!==true){if(!pt(n,e,Xt("hx:poll:trigger",{triggerSpec:n,target:e}))){t(e)}ct(e,t,n)}},n.pollInterval)}function ft(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function at(e){return g(e,Q.config.disableSelector)}function ht(t,n,e){if(t instanceof HTMLAnchorElement&&ft(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){n.boosted=true;let r,o;if(t.tagName==="A"){r="get";o=ee(t,"href")}else{const i=ee(t,"method");r=i?i.toLowerCase():"get";if(r==="get"){}o=ee(t,"action")}e.forEach(function(e){mt(t,function(e,t){const n=ce(e);if(at(n)){f(n);return}de(r,o,n,t)},n,e,true)})}}function dt(e,t){const n=ce(t);if(!n){return false}if(e.type==="submit"||e.type==="click"){if(n.tagName==="FORM"){return true}if(a(n,'input[type="submit"], button')&&g(n,"form")!==null){return true}if(n instanceof HTMLAnchorElement&&n.href&&(n.getAttribute("href")==="#"||n.getAttribute("href").indexOf("#")!==0)){return true}}return false}function gt(e,t){return ie(e).boosted&&e instanceof HTMLAnchorElement&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function pt(e,t,n){const r=e.eventFilter;if(r){try{return r.call(t,n)!==true}catch(e){const o=r.source;ae(ne().body,"htmx:eventFilter:error",{error:e,source:o});return true}}return false}function mt(s,l,e,u,c){const f=ie(s);let t;if(u.from){t=m(s,u.from)}else{t=[s]}if(u.changed){t.forEach(function(e){const t=ie(e);t.lastValue=e.value})}se(t,function(o){const i=function(e){if(!le(s)){o.removeEventListener(u.trigger,i);return}if(gt(s,e)){return}if(c||dt(e,s)){e.preventDefault()}if(pt(u,s,e)){return}const t=ie(e);t.triggerSpec=u;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(s)<0){t.handledFor.push(s);if(u.consume){e.stopPropagation()}if(u.target&&e.target){if(!a(ce(e.target),u.target)){return}}if(u.once){if(f.triggeredOnce){return}else{f.triggeredOnce=true}}if(u.changed){const n=ie(o);const r=o.value;if(n.lastValue===r){return}n.lastValue=r}if(f.delayed){clearTimeout(f.delayed)}if(f.throttle){return}if(u.throttle>0){if(!f.throttle){l(s,e);f.throttle=E().setTimeout(function(){f.throttle=null},u.throttle)}}else if(u.delay>0){f.delayed=E().setTimeout(function(){l(s,e)},u.delay)}else{he(s,"htmx:trigger");l(s,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:u.trigger,listener:i,on:o});o.addEventListener(u.trigger,i)})}let yt=false;let xt=null;function bt(){if(!xt){xt=function(){yt=true};window.addEventListener("scroll",xt);setInterval(function(){if(yt){yt=false;se(ne().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"),function(e){wt(e)})}},200)}}function wt(e){if(!s(e,"data-hx-revealed")&&U(e)){e.setAttribute("data-hx-revealed","true");const t=ie(e);if(t.initHash){he(e,"revealed")}else{e.addEventListener("htmx:afterProcessNode",function(){he(e,"revealed")},{once:true})}}}function vt(e,t,n,r){const o=function(){if(!n.loaded){n.loaded=true;t(e)}};if(r>0){E().setTimeout(o,r)}else{o()}}function St(t,n,e){let i=false;se(v,function(r){if(s(t,"hx-"+r)){const o=te(t,"hx-"+r);i=true;n.path=o;n.verb=r;e.forEach(function(e){Et(t,e,n,function(e,t){const n=ce(e);if(g(n,Q.config.disableSelector)){f(n);return}de(r,o,n,t)})})}});return i}function Et(r,e,t,n){if(e.trigger==="revealed"){bt();mt(r,n,t,e);wt(ce(r))}else if(e.trigger==="intersect"){const o={};if(e.root){o.root=fe(r,e.root)}if(e.threshold){o.threshold=parseFloat(e.threshold)}const i=new IntersectionObserver(function(t){for(let e=0;e<t.length;e++){const n=t[e];if(n.isIntersecting){he(r,"intersect");break}}},o);i.observe(ce(r));mt(ce(r),n,t,e)}else if(e.trigger==="load"){if(!pt(e,r,Xt("load",{elt:r}))){vt(ce(r),n,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ct(ce(r),n,e)}else{mt(r,n,t,e)}}function Ct(e){const t=ce(e);if(!t){return false}const n=t.attributes;for(let e=0;e<n.length;e++){const r=n[e].name;if(l(r,"hx-on:")||l(r,"data-hx-on:")||l(r,"hx-on-")||l(r,"data-hx-on-")){return true}}return false}const Rt=(new XPathEvaluator).createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]');function Ot(e,t){if(Ct(e)){t.push(ce(e))}const n=Rt.evaluate(e);let r=null;while(r=n.iterateNext())t.push(ce(r))}function Ht(e){const t=[];if(e instanceof DocumentFragment){for(const n of e.childNodes){Ot(n,t)}}else{Ot(e,t)}return t}function Tt(e){if(e.querySelectorAll){const n=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";const r=[];for(const i in Xn){const s=Xn[i];if(s.getSelectors){var t=s.getSelectors();if(t){r.push(t)}}}const o=e.querySelectorAll(R+n+", form, [type='submit'],"+" [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]"+r.flat().map(e=>", "+e).join(""));return o}else{return[]}}function qt(e){const t=g(ce(e.target),"button, input[type='submit']");const n=Nt(e);if(n){n.lastButtonClicked=t}}function Lt(e){const t=Nt(e);if(t){t.lastButtonClicked=null}}function Nt(e){const t=g(ce(e.target),"button, input[type='submit']");if(!t){return}const n=y("#"+ee(t,"form"),t.getRootNode())||g(t,"form");if(!n){return}return ie(n)}function At(e){e.addEventListener("click",qt);e.addEventListener("focusin",qt);e.addEventListener("focusout",Lt)}function It(t,e,n){const r=ie(t);if(!Array.isArray(r.onHandlers)){r.onHandlers=[]}let o;const i=function(e){vn(t,function(){if(at(t)){return}if(!o){o=new Function("event",n)}o.call(t,e)})};t.addEventListener(e,i);r.onHandlers.push({event:e,listener:i})}function Pt(t){ke(t);for(let e=0;e<t.attributes.length;e++){const n=t.attributes[e].name;const r=t.attributes[e].value;if(l(n,"hx-on")||l(n,"data-hx-on")){const o=n.indexOf("-on")+3;const i=n.slice(o,o+1);if(i==="-"||i===":"){let e=n.slice(o+1);if(l(e,":")){e="htmx"+e}else if(l(e,"-")){e="htmx:"+e.slice(1)}else if(l(e,"htmx-")){e="htmx:"+e.slice(5)}It(t,e,r)}}}}function kt(t){if(g(t,Q.config.disableSelector)){f(t);return}const n=ie(t);if(n.initHash!==Pe(t)){De(t);n.initHash=Pe(t);he(t,"htmx:beforeProcessNode");if(t.value){n.lastValue=t.value}const e=lt(t);const r=St(t,n,e);if(!r){if(re(t,"hx-boost")==="true"){ht(t,n,e)}else if(s(t,"hx-trigger")){e.forEach(function(e){Et(t,e,n,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&s(t,"form")){At(t)}he(t,"htmx:afterProcessNode")}}function Dt(e){e=y(e);if(g(e,Q.config.disableSelector)){f(e);return}kt(e);se(Tt(e),function(e){kt(e)});se(Ht(e),Pt)}function Mt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Xt(e,t){let n;if(window.CustomEvent&&typeof window.CustomEvent==="function"){n=new CustomEvent(e,{bubbles:true,cancelable:true,composed:true,detail:t})}else{n=ne().createEvent("CustomEvent");n.initCustomEvent(e,true,true,t)}return n}function ae(e,t,n){he(e,t,ue({error:t},n))}function Ft(e){return e==="htmx:afterProcessNode"}function Ut(e,t){se(jn(e),function(e){try{t(e)}catch(e){w(e)}})}function w(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function he(e,t,n){e=y(e);if(n==null){n={}}n.elt=e;const r=Xt(t,n);if(Q.logger&&!Ft(t)){Q.logger(e,t,n)}if(n.error){w(n.error);he(e,"htmx:error",{errorInfo:n})}let o=e.dispatchEvent(r);const i=Mt(t);if(o&&i!==t){const s=Xt(i,r.detail);o=o&&e.dispatchEvent(s)}Ut(ce(e),function(e){o=o&&(e.onEvent(t,r)!==false&&!r.defaultPrevented)});return o}let Bt=location.pathname+location.search;function jt(){const e=ne().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||ne().body}function Vt(t,e){if(!j()){return}const n=$t(e);const r=ne().title;const o=window.scrollY;if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}t=V(t);const i=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e<i.length;e++){if(i[e].url===t){i.splice(e,1);break}}const s={url:t,content:n,title:r,scroll:o};he(ne().body,"htmx:historyItemCreated",{item:s,cache:i});i.push(s);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ae(ne().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function _t(t){if(!j()){return null}t=V(t);const n=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e<n.length;e++){if(n[e].url===t){return n[e]}}return null}function $t(e){const t=Q.config.requestClass;const n=e.cloneNode(true);se(p(n,"."+t),function(e){o(e,t)});return n.innerHTML}function zt(){const e=jt();const t=Bt||location.pathname+location.search;let n;try{n=ne().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){n=ne().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!n){he(ne().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Vt(t,e)}if(Q.config.historyEnabled)history.replaceState({htmx:true},ne().title,window.location.href)}function Jt(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(pe(e,"&")||pe(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Bt=e}function Kt(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Bt=e}function Gt(e){se(e,function(e){e.call(undefined)})}function Zt(o){const e=new XMLHttpRequest;const i={path:o,xhr:e};he(ne().body,"htmx:historyCacheMiss",i);e.open("GET",o,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",ne().location.href);e.onload=function(){if(this.status>=200&&this.status<400){he(ne().body,"htmx:historyCacheMissLoad",i);const e=D(this.response);const t=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;const n=jt();const r=xn(n);Dn(e.title);Ve(n,t,r);Gt(r.tasks);Bt=o;he(ne().body,"htmx:historyRestore",{path:o,cacheMiss:true,serverResponse:this.response})}else{ae(ne().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Wt(e){zt();e=e||location.pathname+location.search;const t=_t(e);if(t){const n=D(t.content);const r=jt();const o=xn(r);Dn(n.title);Ve(r,n,o);Gt(o.tasks);E().setTimeout(function(){window.scrollTo(0,t.scroll)},0);Bt=e;he(ne().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{Zt(e)}}}function Yt(e){let t=Se(e,"hx-indicator");if(t==null){t=[e]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.classList.add.call(e.classList,Q.config.requestClass)});return t}function Qt(e){let t=Se(e,"hx-disabled-elt");if(t==null){t=[]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function en(e,t){se(e,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList.remove.call(e.classList,Q.config.requestClass)}});se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function tn(t,n){for(let e=0;e<t.length;e++){const r=t[e];if(r.isSameNode(n)){return true}}return false}function nn(e){const t=e;if(t.name===""||t.name==null||t.disabled||g(t,"fieldset[disabled]")){return false}if(t.type==="button"||t.type==="submit"||t.tagName==="image"||t.tagName==="reset"||t.tagName==="file"){return false}if(t.type==="checkbox"||t.type==="radio"){return t.checked}return true}function rn(t,e,n){if(t!=null&&e!=null){if(Array.isArray(e)){e.forEach(function(e){n.append(t,e)})}else{n.append(t,e)}}}function on(t,n,r){if(t!=null&&n!=null){let e=r.getAll(t);if(Array.isArray(n)){e=e.filter(e=>n.indexOf(e)<0)}else{e=e.filter(e=>e!==n)}r.delete(t);se(e,e=>r.append(t,e))}}function sn(t,n,r,o,i){if(o==null||tn(t,o)){return}else{t.push(o)}if(nn(o)){const s=ee(o,"name");let e=o.value;if(o instanceof HTMLSelectElement&&o.multiple){e=F(o.querySelectorAll("option:checked")).map(function(e){return e.value})}if(o instanceof HTMLInputElement&&o.files){e=F(o.files)}rn(s,e,n);if(i){ln(o,r)}}if(o instanceof HTMLFormElement){se(o.elements,function(e){if(t.indexOf(e)>=0){on(e.name,e.value,n)}else{t.push(e)}if(i){ln(e,r)}});new FormData(o).forEach(function(e,t){if(e instanceof File&&e.name===""){return}rn(t,e,n)})}}function ln(e,t){const n=e;if(n.willValidate){he(n,"htmx:validation:validate");if(!n.checkValidity()){t.push({elt:n,message:n.validationMessage,validity:n.validity});he(n,"htmx:validation:failed",{message:n.validationMessage,validity:n.validity})}}}function un(t,e){for(const n of e.keys()){t.delete(n);e.getAll(n).forEach(function(e){t.append(n,e)})}return t}function cn(e,t){const n=[];const r=new FormData;const o=new FormData;const i=[];const s=ie(e);if(s.lastButtonClicked&&!le(s.lastButtonClicked)){s.lastButtonClicked=null}let l=e instanceof HTMLFormElement&&e.noValidate!==true||te(e,"hx-validate")==="true";if(s.lastButtonClicked){l=l&&s.lastButtonClicked.formNoValidate!==true}if(t!=="get"){sn(n,o,i,g(e,"form"),l)}sn(n,r,i,e,l);if(s.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){const c=s.lastButtonClicked||e;const f=ee(c,"name");rn(f,c.value,o)}const u=Se(e,"hx-include");se(u,function(e){sn(n,r,i,ce(e),l);if(!a(e,"form")){se(h(e).querySelectorAll(it),function(e){sn(n,r,i,e,l)})}});un(r,o);return{errors:i,formData:r,values:An(r)}}function fn(e,t,n){if(e!==""){e+="&"}if(String(n)==="[object Object]"){n=JSON.stringify(n)}const r=encodeURIComponent(n);e+=encodeURIComponent(t)+"="+r;return e}function an(e){e=Ln(e);let n="";e.forEach(function(e,t){n=fn(n,t,e)});return n}function hn(e,t,n){const r={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":ne().location.href};wn(e,"hx-headers",false,r);if(n!==undefined){r["HX-Prompt"]=n}if(ie(e).boosted){r["HX-Boosted"]="true"}return r}function dn(n,e){const t=re(e,"hx-params");if(t){if(t==="none"){return new FormData}else if(t==="*"){return n}else if(t.indexOf("not ")===0){se(t.substr(4).split(","),function(e){e=e.trim();n.delete(e)});return n}else{const r=new FormData;se(t.split(","),function(t){t=t.trim();if(n.has(t)){n.getAll(t).forEach(function(e){r.append(t,e)})}});return r}}else{return n}}function gn(e){return!!ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function pn(e,t){const n=t||re(e,"hx-swap");const r={swapStyle:ie(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ie(e).boosted&&!gn(e)){r.show="top"}if(n){const s=B(n);if(s.length>0){for(let e=0;e<s.length;e++){const l=s[e];if(l.indexOf("swap:")===0){r.swapDelay=d(l.substr(5))}else if(l.indexOf("settle:")===0){r.settleDelay=d(l.substr(7))}else if(l.indexOf("transition:")===0){r.transition=l.substr(11)==="true"}else if(l.indexOf("ignoreTitle:")===0){r.ignoreTitle=l.substr(12)==="true"}else if(l.indexOf("scroll:")===0){const u=l.substr(7);var o=u.split(":");const c=o.pop();var i=o.length>0?o.join(":"):null;r.scroll=c;r.scrollTarget=i}else if(l.indexOf("show:")===0){const f=l.substr(5);var o=f.split(":");const a=o.pop();var i=o.length>0?o.join(":"):null;r.show=a;r.showTarget=i}else if(l.indexOf("focus-scroll:")===0){const h=l.substr("focus-scroll:".length);r.focusScroll=h=="true"}else if(e==0){r.swapStyle=l}else{w("Unknown modifier in hx-swap: "+l)}}}}return r}function mn(e){return re(e,"hx-encoding")==="multipart/form-data"||a(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function yn(t,n,r){let o=null;Ut(n,function(e){if(o==null){o=e.encodeParameters(t,r,n)}});if(o!=null){return o}else{if(mn(n)){return un(new FormData,Ln(r))}else{return an(r)}}}function xn(e){return{tasks:[],elts:[e]}}function bn(e,t){const n=e[0];const r=e[e.length-1];if(t.scroll){var o=null;if(t.scrollTarget){o=ce(fe(n,t.scrollTarget))}if(t.scroll==="top"&&(n||o)){o=o||n;o.scrollTop=0}if(t.scroll==="bottom"&&(r||o)){o=o||r;o.scrollTop=o.scrollHeight}}if(t.show){var o=null;if(t.showTarget){let e=t.showTarget;if(t.showTarget==="window"){e="body"}o=ce(fe(n,e))}if(t.show==="top"&&(n||o)){o=o||n;o.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(r||o)){o=o||r;o.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function wn(r,e,o,i){if(i==null){i={}}if(r==null){return i}const s=te(r,e);if(s){let e=s.trim();let t=o;if(e==="unset"){return null}if(e.indexOf("javascript:")===0){e=e.substr(11);t=true}else if(e.indexOf("js:")===0){e=e.substr(3);t=true}if(e.indexOf("{")!==0){e="{"+e+"}"}let n;if(t){n=vn(r,function(){return Function("return ("+e+")")()},{})}else{n=S(e)}for(const l in n){if(n.hasOwnProperty(l)){if(i[l]==null){i[l]=n[l]}}}}return wn(ce(u(r)),e,o,i)}function vn(e,t,n){if(Q.config.allowEval){return t()}else{ae(e,"htmx:evalDisallowedError");return n}}function Sn(e,t){return wn(e,"hx-vars",true,t)}function En(e,t){return wn(e,"hx-vals",false,t)}function Cn(e){return ue(Sn(e),En(e))}function Rn(t,n,r){if(r!==null){try{t.setRequestHeader(n,r)}catch(e){t.setRequestHeader(n,encodeURIComponent(r));t.setRequestHeader(n+"-URI-AutoEncoded","true")}}}function On(t){if(t.responseURL&&typeof URL!=="undefined"){try{const e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ae(ne().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function C(e,t){return t.test(e.getAllResponseHeaders())}function Hn(e,t,n){e=e.toLowerCase();if(n){if(n instanceof Element||typeof n==="string"){return de(e,t,null,null,{targetOverride:y(n),returnPromise:true})}else{return de(e,t,y(n.source),n.event,{handler:n.handler,headers:n.headers,values:n.values,targetOverride:y(n.target),swapOverride:n.swap,select:n.select,returnPromise:true})}}else{return de(e,t,null,null,{returnPromise:true})}}function Tn(e){const t=[];while(e){t.push(e);e=e.parentElement}return t}function qn(e,t,n){let r;let o;if(typeof URL==="function"){o=new URL(t,document.location.href);const i=document.location.origin;r=i===o.origin}else{o=t;r=l(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!r){return false}}return he(e,"htmx:validateUrl",ue({url:o,sameHost:r},n))}function Ln(e){if(e instanceof FormData)return e;const t=new FormData;for(const n in e){if(e.hasOwnProperty(n)){if(typeof e[n].forEach==="function"){e[n].forEach(function(e){t.append(n,e)})}else if(typeof e[n]==="object"){t.append(n,JSON.stringify(e[n]))}else{t.append(n,e[n])}}}return t}function Nn(r,o,e){return new Proxy(e,{get:function(t,e){if(typeof e==="number")return t[e];if(e==="length")return t.length;if(e==="push"){return function(e){t.push(e);r.append(o,e)}}if(typeof t[e]==="function"){return function(){t[e].apply(t,arguments);r.delete(o);t.forEach(function(e){r.append(o,e)})}}if(t[e]&&t[e].length===1){return t[e][0]}else{return t[e]}},set:function(e,t,n){e[t]=n;r.delete(o);e.forEach(function(e){r.append(o,e)});return true}})}function An(r){return new Proxy(r,{get:function(e,t){if(typeof t==="symbol"){return Reflect.get(e,t)}if(t==="toJSON"){return()=>Object.fromEntries(r)}if(t in e){if(typeof e[t]==="function"){return function(){return r[t].apply(r,arguments)}}else{return e[t]}}const n=r.getAll(t);if(n.length===0){return undefined}else if(n.length===1){return n[0]}else{return Nn(e,t,n)}},set:function(t,n,e){if(typeof n!=="string"){return false}t.delete(n);if(typeof e.forEach==="function"){e.forEach(function(e){t.append(n,e)})}else{t.append(n,e)}return true},deleteProperty:function(e,t){if(typeof t==="string"){e.delete(t)}return true},ownKeys:function(e){return Reflect.ownKeys(Object.fromEntries(e))},getOwnPropertyDescriptor:function(e,t){return Reflect.getOwnPropertyDescriptor(Object.fromEntries(e),t)}})}function de(t,n,r,o,i,D){let s=null;let l=null;i=i!=null?i:{};if(i.returnPromise&&typeof Promise!=="undefined"){var e=new Promise(function(e,t){s=e;l=t})}if(r==null){r=ne().body}const M=i.handler||Mn;const X=i.select||null;if(!le(r)){oe(s);return e}const u=i.targetOverride||ce(Ce(r));if(u==null||u==ve){ae(r,"htmx:targetError",{target:te(r,"hx-target")});oe(l);return e}let c=ie(r);const f=c.lastButtonClicked;if(f){const L=ee(f,"formaction");if(L!=null){n=L}const N=ee(f,"formmethod");if(N!=null){if(N.toLowerCase()!=="dialog"){t=N}}}const a=re(r,"hx-confirm");if(D===undefined){const K=function(e){return de(t,n,r,o,i,!!e)};const G={target:u,elt:r,path:n,verb:t,triggeringEvent:o,etc:i,issueRequest:K,question:a};if(he(r,"htmx:confirm",G)===false){oe(s);return e}}let h=r;let d=re(r,"hx-sync");let g=null;let F=false;if(d){const A=d.split(":");const I=A[0].trim();if(I==="this"){h=Ee(r,"hx-sync")}else{h=ce(fe(r,I))}d=(A[1]||"drop").trim();c=ie(h);if(d==="drop"&&c.xhr&&c.abortable!==true){oe(s);return e}else if(d==="abort"){if(c.xhr){oe(s);return e}else{F=true}}else if(d==="replace"){he(h,"htmx:abort")}else if(d.indexOf("queue")===0){const Z=d.split(" ");g=(Z[1]||"last").trim()}}if(c.xhr){if(c.abortable){he(h,"htmx:abort")}else{if(g==null){if(o){const P=ie(o);if(P&&P.triggerSpec&&P.triggerSpec.queue){g=P.triggerSpec.queue}}if(g==null){g="last"}}if(c.queuedRequests==null){c.queuedRequests=[]}if(g==="first"&&c.queuedRequests.length===0){c.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="all"){c.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="last"){c.queuedRequests=[];c.queuedRequests.push(function(){de(t,n,r,o,i)})}oe(s);return e}}const p=new XMLHttpRequest;c.xhr=p;c.abortable=F;const m=function(){c.xhr=null;c.abortable=false;if(c.queuedRequests!=null&&c.queuedRequests.length>0){const e=c.queuedRequests.shift();e()}};const U=re(r,"hx-prompt");if(U){var y=prompt(U);if(y===null||!he(r,"htmx:prompt",{prompt:y,target:u})){oe(s);m();return e}}if(a&&!D){if(!confirm(a)){oe(s);m();return e}}let x=hn(r,u,y);if(t!=="get"&&!mn(r)){x["Content-Type"]="application/x-www-form-urlencoded"}if(i.headers){x=ue(x,i.headers)}const B=cn(r,t);let b=B.errors;const j=B.formData;if(i.values){un(j,Ln(i.values))}const V=Ln(Cn(r));const w=un(j,V);let v=dn(w,r);if(Q.config.getCacheBusterParam&&t==="get"){v.set("org.htmx.cache-buster",ee(u,"id")||"true")}if(n==null||n===""){n=ne().location.href}const S=wn(r,"hx-request");const _=ie(r).boosted;let E=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;const C={boosted:_,useUrlParams:E,formData:v,parameters:An(v),unfilteredFormData:w,unfilteredParameters:An(w),headers:x,target:u,verb:t,errors:b,withCredentials:i.credentials||S.credentials||Q.config.withCredentials,timeout:i.timeout||S.timeout||Q.config.timeout,path:n,triggeringEvent:o};if(!he(r,"htmx:configRequest",C)){oe(s);m();return e}n=C.path;t=C.verb;x=C.headers;v=Ln(C.parameters);b=C.errors;E=C.useUrlParams;if(b&&b.length>0){he(r,"htmx:validation:halted",C);oe(s);m();return e}const $=n.split("#");const z=$[0];const R=$[1];let O=n;if(E){O=z;const W=!v.keys().next().done;if(W){if(O.indexOf("?")<0){O+="?"}else{O+="&"}O+=an(v);if(R){O+="#"+R}}}if(!qn(r,O,C)){ae(r,"htmx:invalidPath",C);oe(l);return e}p.open(t.toUpperCase(),O,true);p.overrideMimeType("text/html");p.withCredentials=C.withCredentials;p.timeout=C.timeout;if(S.noHeaders){}else{for(const k in x){if(x.hasOwnProperty(k)){const Y=x[k];Rn(p,k,Y)}}}const H={xhr:p,target:u,requestConfig:C,etc:i,boosted:_,select:X,pathInfo:{requestPath:n,finalRequestPath:O,responsePath:null,anchor:R}};p.onload=function(){try{const t=Tn(r);H.pathInfo.responsePath=On(p);M(r,H);en(T,q);he(r,"htmx:afterRequest",H);he(r,"htmx:afterOnLoad",H);if(!le(r)){let e=null;while(t.length>0&&e==null){const n=t.shift();if(le(n)){e=n}}if(e){he(e,"htmx:afterRequest",H);he(e,"htmx:afterOnLoad",H)}}oe(s);m()}catch(e){ae(r,"htmx:onLoadError",ue({error:e},H));throw e}};p.onerror=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:sendError",H);oe(l);m()};p.onabort=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:sendAbort",H);oe(l);m()};p.ontimeout=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:timeout",H);oe(l);m()};if(!he(r,"htmx:beforeRequest",H)){oe(s);m();return e}var T=Yt(r);var q=Qt(r);se(["loadstart","loadend","progress","abort"],function(t){se([p,p.upload],function(e){e.addEventListener(t,function(e){he(r,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});he(r,"htmx:beforeSend",H);const J=E?null:yn(p,r,v);p.send(J);return e}function In(e,t){const n=t.xhr;let r=null;let o=null;if(C(n,/HX-Push:/i)){r=n.getResponseHeader("HX-Push");o="push"}else if(C(n,/HX-Push-Url:/i)){r=n.getResponseHeader("HX-Push-Url");o="push"}else if(C(n,/HX-Replace-Url:/i)){r=n.getResponseHeader("HX-Replace-Url");o="replace"}if(r){if(r==="false"){return{}}else{return{type:o,path:r}}}const i=t.pathInfo.finalRequestPath;const s=t.pathInfo.responsePath;const l=re(e,"hx-push-url");const u=re(e,"hx-replace-url");const c=ie(e).boosted;let f=null;let a=null;if(l){f="push";a=l}else if(u){f="replace";a=u}else if(c){f="push";a=s||i}if(a){if(a==="false"){return{}}if(a==="true"){a=s||i}if(t.pathInfo.anchor&&a.indexOf("#")===-1){a=a+"#"+t.pathInfo.anchor}return{type:f,path:a}}else{return{}}}function Pn(e,t){var n=new RegExp(e.code);return n.test(t.toString(10))}function kn(e){for(var t=0;t<Q.config.responseHandling.length;t++){var n=Q.config.responseHandling[t];if(Pn(n,e.status)){return n}}return{swap:false}}function Dn(e){if(e){const t=r("title");if(t){t.innerHTML=e}else{window.document.title=e}}}function Mn(o,i){const s=i.xhr;let l=i.target;const e=i.etc;const u=i.select;if(!he(o,"htmx:beforeOnLoad",i))return;if(C(s,/HX-Trigger:/i)){Je(s,"HX-Trigger",o)}if(C(s,/HX-Location:/i)){zt();let e=s.getResponseHeader("HX-Location");var t;if(e.indexOf("{")===0){t=S(e);e=t.path;delete t.path}Hn("get",e,t).then(function(){Jt(e)});return}const n=C(s,/HX-Refresh:/i)&&s.getResponseHeader("HX-Refresh")==="true";if(C(s,/HX-Redirect:/i)){location.href=s.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(C(s,/HX-Retarget:/i)){if(s.getResponseHeader("HX-Retarget")==="this"){i.target=o}else{i.target=ce(fe(o,s.getResponseHeader("HX-Retarget")))}}const c=In(o,i);const r=kn(s);const f=r.swap;let a=!!r.error;let h=Q.config.ignoreTitle||r.ignoreTitle;let d=r.select;if(r.target){i.target=ce(fe(o,r.target))}var g=e.swapOverride;if(g==null&&r.swapOverride){g=r.swapOverride}if(C(s,/HX-Retarget:/i)){if(s.getResponseHeader("HX-Retarget")==="this"){i.target=o}else{i.target=ce(fe(o,s.getResponseHeader("HX-Retarget")))}}if(C(s,/HX-Reswap:/i)){g=s.getResponseHeader("HX-Reswap")}var p=s.response;var m=ue({shouldSwap:f,serverResponse:p,isError:a,ignoreTitle:h,selectOverride:d},i);if(r.event&&!he(l,r.event,m))return;if(!he(l,"htmx:beforeSwap",m))return;l=m.target;p=m.serverResponse;a=m.isError;h=m.ignoreTitle;d=m.selectOverride;i.target=l;i.failed=a;i.successful=!a;if(m.shouldSwap){if(s.status===286){ut(o)}Ut(o,function(e){p=e.transformResponse(p,s,o)});if(c.type){zt()}if(C(s,/HX-Reswap:/i)){g=s.getResponseHeader("HX-Reswap")}var y=pn(o,g);if(!y.hasOwnProperty("ignoreTitle")){y.ignoreTitle=h}l.classList.add(Q.config.swappingClass);let n=null;let r=null;if(u){d=u}if(C(s,/HX-Reselect:/i)){d=s.getResponseHeader("HX-Reselect")}const x=re(o,"hx-select-oob");const b=re(o,"hx-select");let e=function(){try{if(c.type){he(ne().body,"htmx:beforeHistoryUpdate",ue({history:c},i));if(c.type==="push"){Jt(c.path);he(ne().body,"htmx:pushedIntoHistory",{path:c.path})}else{Kt(c.path);he(ne().body,"htmx:replacedInHistory",{path:c.path})}}ze(l,p,y,{select:d||b,selectOOB:x,eventInfo:i,anchor:i.pathInfo.anchor,contextElement:o,afterSwapCallback:function(){if(C(s,/HX-Trigger-After-Swap:/i)){let e=o;if(!le(o)){e=ne().body}Je(s,"HX-Trigger-After-Swap",e)}},afterSettleCallback:function(){if(C(s,/HX-Trigger-After-Settle:/i)){let e=o;if(!le(o)){e=ne().body}Je(s,"HX-Trigger-After-Settle",e)}oe(n)}})}catch(e){ae(o,"htmx:swapError",i);oe(r);throw e}};let t=Q.config.globalViewTransitions;if(y.hasOwnProperty("transition")){t=y.transition}if(t&&he(o,"htmx:beforeTransition",i)&&typeof Promise!=="undefined"&&document.startViewTransition){const w=new Promise(function(e,t){n=e;r=t});const v=e;e=function(){document.startViewTransition(function(){v();return w})}}if(y.swapDelay>0){E().setTimeout(e,y.swapDelay)}else{e()}}if(a){ae(o,"htmx:responseError",ue({error:"Response Status Error Code "+s.status+" from "+i.pathInfo.requestPath},i))}}const Xn={};function Fn(){return{init:function(e){return null},getSelectors:function(){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,n){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,n,r){return false},encodeParameters:function(e,t,n){return null}}}function Un(e,t){if(t.init){t.init(n)}Xn[e]=ue(Fn(),t)}function Bn(e){delete Xn[e]}function jn(e,n,r){if(n==undefined){n=[]}if(e==undefined){return n}if(r==undefined){r=[]}const t=te(e,"hx-ext");if(t){se(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){r.push(e.slice(7));return}if(r.indexOf(e)<0){const t=Xn[e];if(t&&n.indexOf(t)<0){n.push(t)}}})}return jn(ce(u(e)),n,r)}var Vn=false;ne().addEventListener("DOMContentLoaded",function(){Vn=true});function _n(e){if(Vn||ne().readyState==="complete"){e()}else{ne().addEventListener("DOMContentLoaded",e)}}function $n(){if(Q.config.includeIndicatorStyles!==false){const e=Q.config.inlineStyleNonce?` nonce="${Q.config.inlineStyleNonce}"`:"";ne().head.insertAdjacentHTML("beforeend","<style"+e+"> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zn(){const e=ne().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function Jn(){const e=zn();if(e){Q.config=ue(Q.config,e)}}_n(function(){Jn();$n();let e=ne().body;Dt(e);const t=ne().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){const t=e.target;const n=ie(t);if(n&&n.xhr){n.xhr.abort()}});const n=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){Wt();se(t,function(e){he(e,"htmx:restored",{document:ne(),triggerEvent:he})})}else{if(n){n(e)}}};E().setTimeout(function(){he(e,"htmx:load",{});e=null},0)});return Q}(); \ No newline at end of file diff --git a/code/ch5_partials/ch5_starter_video_collector/templates/shared/_layout.html b/code/ch5_partials/ch5_starter_video_collector/templates/shared/_layout.html index b4738bb..d8fe9b9 100644 --- a/code/ch5_partials/ch5_starter_video_collector/templates/shared/_layout.html +++ b/code/ch5_partials/ch5_starter_video_collector/templates/shared/_layout.html @@ -51,7 +51,7 @@ </footer> -<script src="/https/github.com/static/js/htmx.min.js?v=1.5.0"></script> +<script src="/https/github.com/static/js/htmx.min.js?v=2.0.0"></script> <script src="/https/github.com/static/js/jquery-3.5.1.slim.min.js"></script> <script src="/https/github.com/static/js/popper-1.16.1.min.js"></script> diff --git a/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.d.ts b/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.d.ts new file mode 100644 index 0000000..3775459 --- /dev/null +++ b/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.d.ts @@ -0,0 +1,195 @@ +declare namespace htmx { + const onLoad: (callback: (elt: Node) => void) => EventListener; + const process: (elt: string | Element) => void; + const on: (arg1: string | EventTarget, arg2: string | EventListener, arg3?: EventListener) => EventListener; + const off: (arg1: string | EventTarget, arg2: string | EventListener, arg3?: EventListener) => EventListener; + const trigger: (elt: string | EventTarget, eventName: string, detail?: any) => boolean; + const ajax: (verb: HttpVerb, path: string, context: string | Element | HtmxAjaxHelperContext) => Promise<void>; + const find: (eltOrSelector: string | ParentNode, selector?: string) => Element; + const findAll: (eltOrSelector: string | ParentNode, selector?: string) => NodeListOf<Element>; + const closest: (elt: string | Element, selector: string) => Element; + function values(elt: Element, type: HttpVerb): any; + const remove: (elt: Node, delay?: number) => void; + const addClass: (elt: string | Element, clazz: string, delay?: number) => void; + const removeClass: (node: string | Node, clazz: string, delay?: number) => void; + const toggleClass: (elt: string | Element, clazz: string) => void; + const takeClass: (elt: string | Node, clazz: string) => void; + const swap: (target: string | Element, content: string, swapSpec: HtmxSwapSpecification, swapOptions?: SwapOptions) => void; + const defineExtension: (name: string, extension: any) => void; + const removeExtension: (name: string) => void; + const logAll: () => void; + const logNone: () => void; + const logger: any; + namespace config { + const historyEnabled: boolean; + const historyCacheSize: number; + const refreshOnHistoryMiss: boolean; + const defaultSwapStyle: HtmxSwapStyle; + const defaultSwapDelay: number; + const defaultSettleDelay: number; + const includeIndicatorStyles: boolean; + const indicatorClass: string; + const requestClass: string; + const addedClass: string; + const settlingClass: string; + const swappingClass: string; + const allowEval: boolean; + const allowScriptTags: boolean; + const inlineScriptNonce: string; + const inlineStyleNonce: string; + const attributesToSettle: string[]; + const withCredentials: boolean; + const timeout: number; + const wsReconnectDelay: "full-jitter" | ((retryCount: number) => number); + const wsBinaryType: BinaryType; + const disableSelector: string; + const scrollBehavior: 'auto' | 'instant' | 'smooth'; + const defaultFocusScroll: boolean; + const getCacheBusterParam: boolean; + const globalViewTransitions: boolean; + const methodsThatUseUrlParams: (HttpVerb)[]; + const selfRequestsOnly: boolean; + const ignoreTitle: boolean; + const scrollIntoViewOnBoost: boolean; + const triggerSpecsCache: any | null; + const disableInheritance: boolean; + const responseHandling: HtmxResponseHandlingConfig[]; + const allowNestedOobSwaps: boolean; + } + const parseInterval: (str: string) => number; + const _: (str: string) => any; + const version: string; +} +type HttpVerb = 'get' | 'head' | 'post' | 'put' | 'delete' | 'connect' | 'options' | 'trace' | 'patch'; +type SwapOptions = { + select?: string; + selectOOB?: string; + eventInfo?: any; + anchor?: string; + contextElement?: Element; + afterSwapCallback?: swapCallback; + afterSettleCallback?: swapCallback; +}; +type swapCallback = () => any; +type HtmxSwapStyle = 'innerHTML' | 'outerHTML' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'delete' | 'none' | string; +type HtmxSwapSpecification = { + swapStyle: HtmxSwapStyle; + swapDelay: number; + settleDelay: number; + transition?: boolean; + ignoreTitle?: boolean; + head?: string; + scroll?: 'top' | 'bottom'; + scrollTarget?: string; + show?: string; + showTarget?: string; + focusScroll?: boolean; +}; +type ConditionalFunction = ((this: Node, evt: Event) => boolean) & { + source: string; +}; +type HtmxTriggerSpecification = { + trigger: string; + pollInterval?: number; + eventFilter?: ConditionalFunction; + changed?: boolean; + once?: boolean; + consume?: boolean; + delay?: number; + from?: string; + target?: string; + throttle?: number; + queue?: string; + root?: string; + threshold?: string; +}; +type HtmxElementValidationError = { + elt: Element; + message: string; + validity: ValidityState; +}; +type HtmxHeaderSpecification = Record<string, string>; +type HtmxAjaxHelperContext = { + source?: Element | string; + event?: Event; + handler?: HtmxAjaxHandler; + target: Element | string; + swap?: HtmxSwapStyle; + values?: any | FormData; + headers?: Record<string, string>; + select?: string; +}; +type HtmxRequestConfig = { + boosted: boolean; + useUrlParams: boolean; + formData: FormData; + /** + * formData proxy + */ + parameters: any; + unfilteredFormData: FormData; + /** + * unfilteredFormData proxy + */ + unfilteredParameters: any; + headers: HtmxHeaderSpecification; + target: Element; + verb: HttpVerb; + errors: HtmxElementValidationError[]; + withCredentials: boolean; + timeout: number; + path: string; + triggeringEvent: Event; +}; +type HtmxResponseInfo = { + xhr: XMLHttpRequest; + target: Element; + requestConfig: HtmxRequestConfig; + etc: HtmxAjaxEtc; + boosted: boolean; + select: string; + pathInfo: { + requestPath: string; + finalRequestPath: string; + responsePath: string | null; + anchor: string; + }; + failed?: boolean; + successful?: boolean; +}; +type HtmxAjaxEtc = { + returnPromise?: boolean; + handler?: HtmxAjaxHandler; + select?: string; + targetOverride?: Element; + swapOverride?: HtmxSwapStyle; + headers?: Record<string, string>; + values?: any | FormData; + credentials?: boolean; + timeout?: number; +}; +type HtmxResponseHandlingConfig = { + code?: string; + swap: boolean; + error?: boolean; + ignoreTitle?: boolean; + select?: string; + target?: string; + swapOverride?: string; + event?: string; +}; +type HtmxBeforeSwapDetails = HtmxResponseInfo & { + shouldSwap: boolean; + serverResponse: any; + isError: boolean; + ignoreTitle: boolean; + selectOverride: string; +}; +type HtmxAjaxHandler = (elt: Element, responseInfo: HtmxResponseInfo) => any; +type HtmxSettleTask = (() => void); +type HtmxSettleInfo = { + tasks: HtmxSettleTask[]; + elts: Element[]; + title?: string; +}; +type HtmxExtension = any; diff --git a/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.js b/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.js index 86e7668..c57bcd7 100644 --- a/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.js +++ b/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.js @@ -1,3909 +1,5131 @@ -// /////////////////////////////////////////////////////////////////// -// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.js -// - -// UMD insanity -// This code sets up support for (in order) AMD, ES6 modules, and globals. -(function (root, factory) { - //@ts-ignore - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - //@ts-ignore - define([], factory); - } else if (typeof module === 'object' && module.exports) { - // Node. Does not work with strict CommonJS, but - // only CommonJS-like environments that support module.exports, - // like Node. - module.exports = factory(); - } else { - // Browser globals - root.htmx = root.htmx || factory(); - } -}(typeof self !== 'undefined' ? self : this, function () { -return (function () { - 'use strict'; - - // Public API - //** @type {import("./htmx").HtmxApi} */ - // TODO: list all methods in public API - var htmx = { - onLoad: onLoadHelper, - process: processNode, - on: addEventListenerImpl, - off: removeEventListenerImpl, - trigger : triggerEvent, - ajax : ajaxHelper, - find : find, - findAll : findAll, - closest : closest, - values : function(elt, type){ - var inputValues = getInputValues(elt, type || "post"); - return inputValues.values; - }, - remove : removeElement, - addClass : addClassToElement, - removeClass : removeClassFromElement, - toggleClass : toggleClassOnElement, - takeClass : takeClassForElement, - defineExtension : defineExtension, - removeExtension : removeExtension, - logAll : logAll, - logNone : logNone, - logger : null, - config : { - historyEnabled:true, - historyCacheSize:10, - refreshOnHistoryMiss:false, - defaultSwapStyle:'innerHTML', - defaultSwapDelay:0, - defaultSettleDelay:20, - includeIndicatorStyles:true, - indicatorClass:'htmx-indicator', - requestClass:'htmx-request', - addedClass:'htmx-added', - settlingClass:'htmx-settling', - swappingClass:'htmx-swapping', - allowEval:true, - allowScriptTags:true, - inlineScriptNonce:'', - attributesToSettle:["class", "style", "width", "height"], - withCredentials:false, - timeout:0, - wsReconnectDelay: 'full-jitter', - wsBinaryType: 'blob', - disableSelector: "[hx-disable], [data-hx-disable]", - useTemplateFragments: false, - scrollBehavior: 'smooth', - defaultFocusScroll: false, - getCacheBusterParam: false, - globalViewTransitions: false, - methodsThatUseUrlParams: ["get"], - selfRequestsOnly: false, - ignoreTitle: false, - scrollIntoViewOnBoost: true, - triggerSpecsCache: null, - }, - parseInterval:parseInterval, - _:internalEval, - createEventSource: function(url){ - return new EventSource(url, {withCredentials:true}) - }, - createWebSocket: function(url){ - var sock = new WebSocket(url, []); - sock.binaryType = htmx.config.wsBinaryType; - return sock; - }, - version: "1.9.10" - }; - - /** @type {import("./htmx").HtmxInternalApi} */ - var internalAPI = { - addTriggerHandler: addTriggerHandler, - bodyContains: bodyContains, - canAccessLocalStorage: canAccessLocalStorage, - findThisElement: findThisElement, - filterValues: filterValues, - hasAttribute: hasAttribute, - getAttributeValue: getAttributeValue, - getClosestAttributeValue: getClosestAttributeValue, - getClosestMatch: getClosestMatch, - getExpressionVars: getExpressionVars, - getHeaders: getHeaders, - getInputValues: getInputValues, - getInternalData: getInternalData, - getSwapSpecification: getSwapSpecification, - getTriggerSpecs: getTriggerSpecs, - getTarget: getTarget, - makeFragment: makeFragment, - mergeObjects: mergeObjects, - makeSettleInfo: makeSettleInfo, - oobSwap: oobSwap, - querySelectorExt: querySelectorExt, - selectAndSwap: selectAndSwap, - settleImmediately: settleImmediately, - shouldCancel: shouldCancel, - triggerEvent: triggerEvent, - triggerErrorEvent: triggerErrorEvent, - withExtensions: withExtensions, - } - - var VERBS = ['get', 'post', 'put', 'delete', 'patch']; - var VERB_SELECTOR = VERBS.map(function(verb){ - return "[hx-" + verb + "], [data-hx-" + verb + "]" - }).join(", "); - - var HEAD_TAG_REGEX = makeTagRegEx('head'), - TITLE_TAG_REGEX = makeTagRegEx('title'), - SVG_TAGS_REGEX = makeTagRegEx('svg', true); - - //==================================================================== - // Utilities - //==================================================================== - - /** - * @param {string} tag - * @param {boolean} global - * @returns {RegExp} - */ - function makeTagRegEx(tag, global = false) { - return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, - global ? 'gim' : 'im'); - } - - function parseInterval(str) { - if (str == undefined) { - return undefined; - } - - let interval = NaN; - if (str.slice(-2) == "ms") { - interval = parseFloat(str.slice(0, -2)); - } else if (str.slice(-1) == "s") { - interval = parseFloat(str.slice(0, -1)) * 1000; - } else if (str.slice(-1) == "m") { - interval = parseFloat(str.slice(0, -1)) * 1000 * 60; - } else { - interval = parseFloat(str); - } - return isNaN(interval) ? undefined : interval; - } - - /** - * @param {HTMLElement} elt - * @param {string} name - * @returns {(string | null)} - */ - function getRawAttribute(elt, name) { - return elt.getAttribute && elt.getAttribute(name); - } - - // resolve with both hx and data-hx prefixes - function hasAttribute(elt, qualifiedName) { - return elt.hasAttribute && (elt.hasAttribute(qualifiedName) || - elt.hasAttribute("data-" + qualifiedName)); - } - - /** - * - * @param {HTMLElement} elt - * @param {string} qualifiedName - * @returns {(string | null)} - */ - function getAttributeValue(elt, qualifiedName) { - return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); - } - - /** - * @param {HTMLElement} elt - * @returns {HTMLElement | null} - */ - function parentElt(elt) { - return elt.parentElement; - } - - /** - * @returns {Document} - */ - function getDocument() { - return document; - } - - /** - * @param {HTMLElement} elt - * @param {(e:HTMLElement) => boolean} condition - * @returns {HTMLElement | null} - */ - function getClosestMatch(elt, condition) { - while (elt && !condition(elt)) { - elt = parentElt(elt); - } - - return elt ? elt : null; - } - - function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ - var attributeValue = getAttributeValue(ancestor, attributeName); - var disinherit = getAttributeValue(ancestor, "hx-disinherit"); - if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) { - return "unset"; - } else { - return attributeValue - } - } - - /** - * @param {HTMLElement} elt - * @param {string} attributeName - * @returns {string | null} - */ - function getClosestAttributeValue(elt, attributeName) { - var closestAttr = null; - getClosestMatch(elt, function (e) { - return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName); - }); - if (closestAttr !== "unset") { - return closestAttr; - } - } - - /** - * @param {HTMLElement} elt - * @param {string} selector - * @returns {boolean} - */ - function matches(elt, selector) { - // @ts-ignore: non-standard properties for browser compatibility - // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; - return matchesFunction && matchesFunction.call(elt, selector); - } - - /** - * @param {string} str - * @returns {string} - */ - 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 ""; - } - } - - /** - * - * @param {string} resp - * @param {number} depth - * @returns {Element} - */ - function parseHTML(resp, depth) { - var parser = new DOMParser(); - var responseDoc = parser.parseFromString(resp, "text/html"); - - /** @type {Element} */ - var responseNode = responseDoc.body; - while (depth > 0) { - depth--; - // @ts-ignore - responseNode = responseNode.firstChild; - } - if (responseNode == null) { - // @ts-ignore - responseNode = getDocument().createDocumentFragment(); - } - return responseNode; - } - - function aFullPageResponse(resp) { - return /<body/.test(resp) - } +// v2.0.0 from https://github.com/bigskysoftware/htmx/releases + +var htmx = (function() { + 'use strict' + + // Public API + const htmx = { + // Tsc madness here, assigning the functions directly results in an invalid TypeScript output, but reassigning is fine + /* Event processing */ + /** @type {typeof onLoadHelper} */ + onLoad: null, + /** @type {typeof processNode} */ + process: null, + /** @type {typeof addEventListenerImpl} */ + on: null, + /** @type {typeof removeEventListenerImpl} */ + off: null, + /** @type {typeof triggerEvent} */ + trigger: null, + /** @type {typeof ajaxHelper} */ + ajax: null, + /* DOM querying helpers */ + /** @type {typeof find} */ + find: null, + /** @type {typeof findAll} */ + findAll: null, + /** @type {typeof closest} */ + closest: null, + /** + * Returns the input values that would resolve for a given element via the htmx value resolution mechanism + * + * @see https://htmx.org/api/#values + * + * @param {Element} elt the element to resolve values on + * @param {HttpVerb} type the request type (e.g. **get** or **post**) non-GET's will include the enclosing form of the element. Defaults to **post** + * @returns {Object} + */ + values: function(elt, type) { + const inputValues = getInputValues(elt, type || 'post') + return inputValues.values + }, + /* DOM manipulation helpers */ + /** @type {typeof removeElement} */ + remove: null, + /** @type {typeof addClassToElement} */ + addClass: null, + /** @type {typeof removeClassFromElement} */ + removeClass: null, + /** @type {typeof toggleClassOnElement} */ + toggleClass: null, + /** @type {typeof takeClassForElement} */ + takeClass: null, + /** @type {typeof swap} */ + swap: null, + /* Extension entrypoints */ + /** @type {typeof defineExtension} */ + defineExtension: null, + /** @type {typeof removeExtension} */ + removeExtension: null, + /* Debugging */ + /** @type {typeof logAll} */ + logAll: null, + /** @type {typeof logNone} */ + logNone: null, + /* Debugging */ + /** + * The logger htmx uses to log with + * + * @see https://htmx.org/api/#logger + */ + logger: null, + /** + * A property holding the configuration htmx uses at runtime. + * + * Note that using a [meta tag](https://htmx.org/docs/#config) is the preferred mechanism for setting these properties. + * + * @see https://htmx.org/api/#config + */ + config: { + /** + * Whether to use history. + * @type boolean + * @default true + */ + historyEnabled: true, + /** + * The number of pages to keep in **localStorage** for history support. + * @type number + * @default 10 + */ + historyCacheSize: 10, + /** + * @type boolean + * @default false + */ + refreshOnHistoryMiss: false, + /** + * The default swap style to use if **[hx-swap](https://htmx.org/attributes/hx-swap)** is omitted. + * @type HtmxSwapStyle + * @default 'innerHTML' + */ + defaultSwapStyle: 'innerHTML', + /** + * The default delay between receiving a response from the server and doing the swap. + * @type number + * @default 0 + */ + defaultSwapDelay: 0, + /** + * The default delay between completing the content swap and settling attributes. + * @type number + * @default 20 + */ + defaultSettleDelay: 20, + /** + * If true, htmx will inject a small amount of CSS into the page to make indicators invisible unless the **htmx-indicator** class is present. + * @type boolean + * @default true + */ + includeIndicatorStyles: true, + /** + * The class to place on indicators when a request is in flight. + * @type string + * @default 'htmx-indicator' + */ + indicatorClass: 'htmx-indicator', + /** + * The class to place on triggering elements when a request is in flight. + * @type string + * @default 'htmx-request' + */ + requestClass: 'htmx-request', + /** + * The class to temporarily place on elements that htmx has added to the DOM. + * @type string + * @default 'htmx-added' + */ + addedClass: 'htmx-added', + /** + * The class to place on target elements when htmx is in the settling phase. + * @type string + * @default 'htmx-settling' + */ + settlingClass: 'htmx-settling', + /** + * The class to place on target elements when htmx is in the swapping phase. + * @type string + * @default 'htmx-swapping' + */ + swappingClass: 'htmx-swapping', + /** + * Allows the use of eval-like functionality in htmx, to enable **hx-vars**, trigger conditions & script tag evaluation. Can be set to **false** for CSP compatibility. + * @type boolean + * @default true + */ + allowEval: true, + /** + * If set to false, disables the interpretation of script tags. + * @type boolean + * @default true + */ + allowScriptTags: true, + /** + * If set, the nonce will be added to inline scripts. + * @type string + * @default '' + */ + inlineScriptNonce: '', + /** + * If set, the nonce will be added to inline styles. + * @type string + * @default '' + */ + inlineStyleNonce: '', + /** + * The attributes to settle during the settling phase. + * @type string[] + * @default ['class', 'style', 'width', 'height'] + */ + attributesToSettle: ['class', 'style', 'width', 'height'], + /** + * Allow cross-site Access-Control requests using credentials such as cookies, authorization headers or TLS client certificates. + * @type boolean + * @default false + */ + withCredentials: false, + /** + * @type number + * @default 0 + */ + timeout: 0, + /** + * The default implementation of **getWebSocketReconnectDelay** for reconnecting after unexpected connection loss by the event code **Abnormal Closure**, **Service Restart** or **Try Again Later**. + * @type {'full-jitter' | ((retryCount:number) => number)} + * @default "full-jitter" + */ + wsReconnectDelay: 'full-jitter', + /** + * The type of binary data being received over the WebSocket connection + * @type BinaryType + * @default 'blob' + */ + wsBinaryType: 'blob', + /** + * @type string + * @default '[hx-disable], [data-hx-disable]' + */ + disableSelector: '[hx-disable], [data-hx-disable]', + /** + * @type {'auto' | 'instant' | 'smooth'} + * @default 'smooth' + */ + scrollBehavior: 'instant', + /** + * If the focused element should be scrolled into view. + * @type boolean + * @default false + */ + defaultFocusScroll: false, + /** + * If set to true htmx will include a cache-busting parameter in GET requests to avoid caching partial responses by the browser + * @type boolean + * @default false + */ + getCacheBusterParam: false, + /** + * If set to true, htmx will use the View Transition API when swapping in new content. + * @type boolean + * @default false + */ + globalViewTransitions: false, + /** + * htmx will format requests with these methods by encoding their parameters in the URL, not the request body + * @type {(HttpVerb)[]} + * @default ['get', 'delete'] + */ + methodsThatUseUrlParams: ['get', 'delete'], + /** + * If set to true, disables htmx-based requests to non-origin hosts. + * @type boolean + * @default false + */ + selfRequestsOnly: true, + /** + * If set to true htmx will not update the title of the document when a title tag is found in new content + * @type boolean + * @default false + */ + ignoreTitle: false, + /** + * Whether the target of a boosted element is scrolled into the viewport. + * @type boolean + * @default true + */ + scrollIntoViewOnBoost: true, + /** + * The cache to store evaluated trigger specifications into. + * You may define a simple object to use a never-clearing cache, or implement your own system using a [proxy object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Proxy) + * @type {Object|null} + * @default null + */ + triggerSpecsCache: null, + /** @type boolean */ + disableInheritance: false, + /** @type HtmxResponseHandlingConfig[] */ + responseHandling: [ + { code: '204', swap: false }, + { code: '[23]..', swap: true }, + { code: '[45]..', swap: false, error: true } + ], + /** + * Whether to process OOB swaps on elements that are nested within the main response element. + * @type boolean + * @default true + */ + allowNestedOobSwaps: true + }, + /** @type {typeof parseInterval} */ + parseInterval: null, + /** @type {typeof internalEval} */ + _: null, + version: '2.0.0' + } + // Tsc madness part 2 + htmx.onLoad = onLoadHelper + htmx.process = processNode + htmx.on = addEventListenerImpl + htmx.off = removeEventListenerImpl + htmx.trigger = triggerEvent + htmx.ajax = ajaxHelper + htmx.find = find + htmx.findAll = findAll + htmx.closest = closest + htmx.remove = removeElement + htmx.addClass = addClassToElement + htmx.removeClass = removeClassFromElement + htmx.toggleClass = toggleClassOnElement + htmx.takeClass = takeClassForElement + htmx.swap = swap + htmx.defineExtension = defineExtension + htmx.removeExtension = removeExtension + htmx.logAll = logAll + htmx.logNone = logNone + htmx.parseInterval = parseInterval + htmx._ = internalEval + + const internalAPI = { + addTriggerHandler, + bodyContains, + canAccessLocalStorage, + findThisElement, + filterValues, + swap, + hasAttribute, + getAttributeValue, + getClosestAttributeValue, + getClosestMatch, + getExpressionVars, + getHeaders, + getInputValues, + getInternalData, + getSwapSpecification, + getTriggerSpecs, + getTarget, + makeFragment, + mergeObjects, + makeSettleInfo, + oobSwap, + querySelectorExt, + settleImmediately, + shouldCancel, + triggerEvent, + triggerErrorEvent, + withExtensions + } + + const VERBS = ['get', 'post', 'put', 'delete', 'patch'] + const VERB_SELECTOR = VERBS.map(function(verb) { + return '[hx-' + verb + '], [data-hx-' + verb + ']' + }).join(', ') + + const HEAD_TAG_REGEX = makeTagRegEx('head') + + //= =================================================================== + // Utilities + //= =================================================================== + + /** + * @param {string} tag + * @param {boolean} global + * @returns {RegExp} + */ + function makeTagRegEx(tag, global = false) { + return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, + global ? 'gim' : 'im') + } + + /** + * Parses an interval string consistent with the way htmx does. Useful for plugins that have timing-related attributes. + * + * Caution: Accepts an int followed by either **s** or **ms**. All other values use **parseFloat** + * + * @see https://htmx.org/api/#parseInterval + * + * @param {string} str timing string + * @returns {number|undefined} + */ + function parseInterval(str) { + if (str == undefined) { + return undefined + } - /** - * - * @param {string} response - * @returns {Element} - */ - function makeFragment(response) { - var partialResponse = !aFullPageResponse(response); - var startTag = getStartTag(response); - var content = response; - if (startTag === 'head') { - content = content.replace(HEAD_TAG_REGEX, ''); - } - if (htmx.config.useTemplateFragments && partialResponse) { - var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0); - // @ts-ignore type mismatch between DocumentFragment and Element. - // TODO: Are these close enough for htmx to use interchangeably? - return documentFragment.querySelector('template').content; - } - switch (startTag) { - case "thead": - case "tbody": - case "tfoot": - case "colgroup": - case "caption": - return parseHTML("<table>" + content + "</table>", 1); - case "col": - return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2); - case "tr": - return parseHTML("<table><tbody>" + content + "</tbody></table>", 2); - case "td": - case "th": - return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3); - case "script": - case "style": - return parseHTML("<div>" + content + "</div>", 1); - default: - return parseHTML(content, 0); - } - } + let interval = NaN + if (str.slice(-2) == 'ms') { + interval = parseFloat(str.slice(0, -2)) + } else if (str.slice(-1) == 's') { + interval = parseFloat(str.slice(0, -1)) * 1000 + } else if (str.slice(-1) == 'm') { + interval = parseFloat(str.slice(0, -1)) * 1000 * 60 + } else { + interval = parseFloat(str) + } + return isNaN(interval) ? undefined : interval + } + + /** + * @param {Node} elt + * @param {string} name + * @returns {(string | null)} + */ + function getRawAttribute(elt, name) { + return elt instanceof Element && elt.getAttribute(name) + } + + /** + * @param {Element} elt + * @param {string} qualifiedName + * @returns {boolean} + */ + // resolve with both hx and data-hx prefixes + function hasAttribute(elt, qualifiedName) { + return !!elt.hasAttribute && (elt.hasAttribute(qualifiedName) || + elt.hasAttribute('data-' + qualifiedName)) + } + + /** + * + * @param {Node} elt + * @param {string} qualifiedName + * @returns {(string | null)} + */ + function getAttributeValue(elt, qualifiedName) { + return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, 'data-' + qualifiedName) + } + + /** + * @param {Node} elt + * @returns {Node | null} + */ + function parentElt(elt) { + const parent = elt.parentElement + if (!parent && elt.parentNode instanceof ShadowRoot) return elt.parentNode + return parent + } + + /** + * @returns {Document} + */ + function getDocument() { + return document + } + + /** + * @param {Node} elt + * @param {boolean} global + * @returns {Node|Document} + */ + function getRootNode(elt, global) { + return elt.getRootNode ? elt.getRootNode({ composed: global }) : getDocument() + } + + /** + * @param {Node} elt + * @param {(e:Node) => boolean} condition + * @returns {Node | null} + */ + function getClosestMatch(elt, condition) { + while (elt && !condition(elt)) { + elt = parentElt(elt) + } - /** - * @param {Function} func - */ - function maybeCall(func){ - if(func) { - func(); - } + return elt || null + } + + /** + * @param {Element} initialElement + * @param {Element} ancestor + * @param {string} attributeName + * @returns {string|null} + */ + function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName) { + const attributeValue = getAttributeValue(ancestor, attributeName) + const disinherit = getAttributeValue(ancestor, 'hx-disinherit') + var inherit = getAttributeValue(ancestor, 'hx-inherit') + if (initialElement !== ancestor) { + if (htmx.config.disableInheritance) { + if (inherit && (inherit === '*' || inherit.split(' ').indexOf(attributeName) >= 0)) { + return attributeValue + } else { + return null + } + } + if (disinherit && (disinherit === '*' || disinherit.split(' ').indexOf(attributeName) >= 0)) { + return 'unset' + } + } + return attributeValue + } + + /** + * @param {Element} elt + * @param {string} attributeName + * @returns {string | null} + */ + function getClosestAttributeValue(elt, attributeName) { + let closestAttr = null + getClosestMatch(elt, function(e) { + return !!(closestAttr = getAttributeValueWithDisinheritance(elt, asElement(e), attributeName)) + }) + if (closestAttr !== 'unset') { + return closestAttr + } + } + + /** + * @param {Node} elt + * @param {string} selector + * @returns {boolean} + */ + function matches(elt, selector) { + // @ts-ignore: non-standard properties for browser compatibility + // noinspection JSUnresolvedVariable + const matchesFunction = elt instanceof Element && (elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector) + return !!matchesFunction && matchesFunction.call(elt, selector) + } + + /** + * @param {string} str + * @returns {string} + */ + function getStartTag(str) { + const tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i + const match = tagMatcher.exec(str) + if (match) { + return match[1].toLowerCase() + } else { + return '' + } + } + + /** + * @param {string} resp + * @returns {Document} + */ + function parseHTML(resp) { + const parser = new DOMParser() + return parser.parseFromString(resp, 'text/html') + } + + /** + * @param {DocumentFragment} fragment + * @param {Node} elt + */ + function takeChildrenFor(fragment, elt) { + while (elt.childNodes.length > 0) { + fragment.append(elt.childNodes[0]) + } + } + + /** + * @param {HTMLScriptElement} script + * @returns {HTMLScriptElement} + */ + function duplicateScript(script) { + const newScript = getDocument().createElement('script') + forEach(script.attributes, function(attr) { + newScript.setAttribute(attr.name, attr.value) + }) + newScript.textContent = script.textContent + newScript.async = false + if (htmx.config.inlineScriptNonce) { + newScript.nonce = htmx.config.inlineScriptNonce + } + return newScript + } + + /** + * @param {HTMLScriptElement} script + * @returns {boolean} + */ + function isJavaScriptScriptNode(script) { + return script.matches('script') && (script.type === 'text/javascript' || script.type === 'module' || script.type === '') + } + + /** + * we have to make new copies of script tags that we are going to insert because + * SOME browsers (not saying who, but it involves an element and an animal) don't + * execute scripts created in <template> tags when they are inserted into the DOM + * and all the others do lmao + * @param {DocumentFragment} fragment + */ + function normalizeScriptTags(fragment) { + Array.from(fragment.querySelectorAll('script')).forEach(/** @param {HTMLScriptElement} script */ (script) => { + if (isJavaScriptScriptNode(script)) { + const newScript = duplicateScript(script) + const parent = script.parentNode + try { + parent.insertBefore(newScript, script) + } catch (e) { + logError(e) + } finally { + script.remove() + } + } + }) + } + + /** + * @typedef {DocumentFragment & {title?: string}} DocumentFragmentWithTitle + * @description a document fragment representing the response HTML, including + * a `title` property for any title information found + */ + + /** + * @param {string} response HTML + * @returns {DocumentFragmentWithTitle} + */ + function makeFragment(response) { + // strip head tag to determine shape of response we are dealing with + const responseWithNoHead = response.replace(HEAD_TAG_REGEX, '') + const startTag = getStartTag(responseWithNoHead) + /** @type DocumentFragmentWithTitle */ + let fragment + if (startTag === 'html') { + // if it is a full document, parse it and return the body + fragment = /** @type DocumentFragmentWithTitle */ (new DocumentFragment()) + const doc = parseHTML(response) + takeChildrenFor(fragment, doc.body) + fragment.title = doc.title + } else if (startTag === 'body') { + // parse body w/o wrapping in template + fragment = /** @type DocumentFragmentWithTitle */ (new DocumentFragment()) + const doc = parseHTML(responseWithNoHead) + takeChildrenFor(fragment, doc.body) + fragment.title = doc.title + } else { + // otherwise we have non-body partial HTML content, so wrap it in a template to maximize parsing flexibility + const doc = parseHTML('<body><template class="internal-htmx-wrapper">' + responseWithNoHead + '</template></body>') + fragment = /** @type DocumentFragmentWithTitle */ (doc.querySelector('template').content) + // extract title into fragment for later processing + fragment.title = doc.title + + // for legacy reasons we support a title tag at the root level of non-body responses, so we need to handle it + var titleElement = fragment.querySelector('title') + if (titleElement && titleElement.parentNode === fragment) { + titleElement.remove() + fragment.title = titleElement.innerText + } + } + if (fragment) { + if (htmx.config.allowScriptTags) { + normalizeScriptTags(fragment) + } else { + // remove all script tags if scripts are disabled + fragment.querySelectorAll('script').forEach((script) => script.remove()) + } + } + return fragment + } + + /** + * @param {Function} func + */ + function maybeCall(func) { + if (func) { + func() + } + } + + /** + * @param {any} o + * @param {string} type + * @returns + */ + function isType(o, type) { + return Object.prototype.toString.call(o) === '[object ' + type + ']' + } + + /** + * @param {*} o + * @returns {o is Function} + */ + function isFunction(o) { + return typeof o === 'function' + } + + /** + * @param {*} o + * @returns {o is Object} + */ + function isRawObject(o) { + return isType(o, 'Object') + } + + /** + * @typedef {Object} OnHandler + * @property {(keyof HTMLElementEventMap)|string} event + * @property {EventListener} listener + */ + + /** + * @typedef {Object} ListenerInfo + * @property {string} trigger + * @property {EventListener} listener + * @property {EventTarget} on + */ + + /** + * @typedef {Object} HtmxNodeInternalData + * Element data + * @property {number} [initHash] + * @property {boolean} [boosted] + * @property {OnHandler[]} [onHandlers] + * @property {number} [timeout] + * @property {ListenerInfo[]} [listenerInfos] + * @property {boolean} [cancelled] + * @property {boolean} [triggeredOnce] + * @property {number} [delayed] + * @property {number|null} [throttle] + * @property {string} [lastValue] + * @property {boolean} [loaded] + * @property {string} [path] + * @property {string} [verb] + * @property {boolean} [polling] + * @property {HTMLButtonElement|HTMLInputElement|null} [lastButtonClicked] + * @property {number} [requestCount] + * @property {XMLHttpRequest} [xhr] + * @property {(() => void)[]} [queuedRequests] + * @property {boolean} [abortable] + * + * Event data + * @property {HtmxTriggerSpecification} [triggerSpec] + * @property {EventTarget[]} [handledFor] + */ + + /** + * getInternalData retrieves "private" data stored by htmx within an element + * @param {EventTarget|Event} elt + * @returns {HtmxNodeInternalData} + */ + function getInternalData(elt) { + const dataProp = 'htmx-internal-data' + let data = elt[dataProp] + if (!data) { + data = elt[dataProp] = {} + } + return data + } + + /** + * toArray converts an ArrayLike object into a real array. + * @template T + * @param {ArrayLike<T>} arr + * @returns {T[]} + */ + function toArray(arr) { + const returnArr = [] + if (arr) { + for (let i = 0; i < arr.length; i++) { + returnArr.push(arr[i]) + } + } + return returnArr + } + + /** + * @template T + * @param {T[]|NamedNodeMap|HTMLCollection|HTMLFormControlsCollection|ArrayLike<T>} arr + * @param {(T) => void} func + */ + function forEach(arr, func) { + if (arr) { + for (let i = 0; i < arr.length; i++) { + func(arr[i]) + } + } + } + + /** + * @param {Element} el + * @returns {boolean} + */ + function isScrolledIntoView(el) { + const rect = el.getBoundingClientRect() + const elemTop = rect.top + const elemBottom = rect.bottom + return elemTop < window.innerHeight && elemBottom >= 0 + } + + /** + * @param {Node} elt + * @returns {boolean} + */ + function bodyContains(elt) { + // IE Fix + const rootNode = elt.getRootNode && elt.getRootNode() + if (rootNode && rootNode instanceof window.ShadowRoot) { + return getDocument().body.contains(rootNode.host) + } else { + return getDocument().body.contains(elt) + } + } + + /** + * @param {string} trigger + * @returns {string[]} + */ + function splitOnWhitespace(trigger) { + return trigger.trim().split(/\s+/) + } + + /** + * mergeObjects takes all the keys from + * obj2 and duplicates them into obj1 + * @template T1 + * @template T2 + * @param {T1} obj1 + * @param {T2} obj2 + * @returns {T1 & T2} + */ + function mergeObjects(obj1, obj2) { + for (const key in obj2) { + if (obj2.hasOwnProperty(key)) { + // @ts-ignore tsc doesn't seem to properly handle types merging + obj1[key] = obj2[key] + } + } + // @ts-ignore tsc doesn't seem to properly handle types merging + return obj1 + } + + /** + * @param {string} jString + * @returns {any|null} + */ + function parseJSON(jString) { + try { + return JSON.parse(jString) + } catch (error) { + logError(error) + return null + } + } + + /** + * @returns {boolean} + */ + function canAccessLocalStorage() { + const test = 'htmx:localStorageTest' + try { + localStorage.setItem(test, test) + localStorage.removeItem(test) + return true + } catch (e) { + return false + } + } + + /** + * @param {string} path + * @returns {string} + */ + function normalizePath(path) { + try { + const url = new URL(path) + if (url) { + path = url.pathname + url.search + } + // remove trailing slash, unless index page + if (!(/^\/$/.test(path))) { + path = path.replace(/\/+$/, '') + } + return path + } catch (e) { + // be kind to IE11, which doesn't support URL() + return path + } + } + + //= ========================================================================================= + // public API + //= ========================================================================================= + + /** + * @param {string} str + * @returns {any} + */ + function internalEval(str) { + return maybeEval(getDocument().body, function() { + return eval(str) + }) + } + + /** + * Adds a callback for the **htmx:load** event. This can be used to process new content, for example initializing the content with a javascript library + * + * @see https://htmx.org/api/#onLoad + * + * @param {(elt: Node) => void} callback the callback to call on newly loaded content + * @returns {EventListener} + */ + function onLoadHelper(callback) { + const value = htmx.on('htmx:load', /** @param {CustomEvent} evt */ function(evt) { + callback(evt.detail.elt) + }) + return value + } + + /** + * Log all htmx events, useful for debugging. + * + * @see https://htmx.org/api/#logAll + */ + function logAll() { + htmx.logger = function(elt, event, data) { + if (console) { + console.log(event, elt, data) + } + } + } + + function logNone() { + htmx.logger = null + } + + /** + * Finds an element matching the selector + * + * @see https://htmx.org/api/#find + * + * @param {ParentNode|string} eltOrSelector the root element to find the matching element in, inclusive | the selector to match + * @param {string} [selector] the selector to match + * @returns {Element|null} + */ + function find(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return eltOrSelector.querySelector(selector) + } else { + return find(getDocument(), eltOrSelector) + } + } + + /** + * Finds all elements matching the selector + * + * @see https://htmx.org/api/#findAll + * + * @param {ParentNode|string} eltOrSelector the root element to find the matching elements in, inclusive | the selector to match + * @param {string} [selector] the selector to match + * @returns {NodeListOf<Element>} + */ + function findAll(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return eltOrSelector.querySelectorAll(selector) + } else { + return findAll(getDocument(), eltOrSelector) + } + } + + /** + * @returns Window + */ + function getWindow() { + return window + } + + /** + * Removes an element from the DOM + * + * @see https://htmx.org/api/#remove + * + * @param {Node} elt + * @param {number} [delay] + */ + function removeElement(elt, delay) { + elt = resolveTarget(elt) + if (delay) { + getWindow().setTimeout(function() { + removeElement(elt) + elt = null + }, delay) + } else { + parentElt(elt).removeChild(elt) + } + } + + /** + * @param {any} elt + * @return {Element|null} + */ + function asElement(elt) { + return elt instanceof Element ? elt : null + } + + /** + * @param {any} elt + * @return {HTMLElement|null} + */ + function asHtmlElement(elt) { + return elt instanceof HTMLElement ? elt : null + } + + /** + * @param {any} value + * @return {string|null} + */ + function asString(value) { + return typeof value === 'string' ? value : null + } + + /** + * @param {EventTarget} elt + * @return {ParentNode|null} + */ + function asParentNode(elt) { + return elt instanceof Element || elt instanceof Document || elt instanceof DocumentFragment ? elt : null + } + + /** + * This method adds a class to the given element. + * + * @see https://htmx.org/api/#addClass + * + * @param {Element|string} elt the element to add the class to + * @param {string} clazz the class to add + * @param {number} [delay] the delay (in milliseconds) before class is added + */ + function addClassToElement(elt, clazz, delay) { + elt = asElement(resolveTarget(elt)) + if (!elt) { + return + } + if (delay) { + getWindow().setTimeout(function() { + addClassToElement(elt, clazz) + elt = null + }, delay) + } else { + elt.classList && elt.classList.add(clazz) + } + } + + /** + * Removes a class from the given element + * + * @see https://htmx.org/api/#removeClass + * + * @param {Node|string} node element to remove the class from + * @param {string} clazz the class to remove + * @param {number} [delay] the delay (in milliseconds before class is removed) + */ + function removeClassFromElement(node, clazz, delay) { + let elt = asElement(resolveTarget(node)) + if (!elt) { + return + } + if (delay) { + getWindow().setTimeout(function() { + removeClassFromElement(elt, clazz) + elt = null + }, delay) + } else { + if (elt.classList) { + elt.classList.remove(clazz) + // if there are no classes left, remove the class attribute + if (elt.classList.length === 0) { + elt.removeAttribute('class') } + } + } + } + + /** + * Toggles the given class on an element + * + * @see https://htmx.org/api/#toggleClass + * + * @param {Element|string} elt the element to toggle the class on + * @param {string} clazz the class to toggle + */ + function toggleClassOnElement(elt, clazz) { + elt = resolveTarget(elt) + elt.classList.toggle(clazz) + } + + /** + * Takes the given class from its siblings, so that among its siblings, only the given element will have the class. + * + * @see https://htmx.org/api/#takeClass + * + * @param {Node|string} elt the element that will take the class + * @param {string} clazz the class to take + */ + function takeClassForElement(elt, clazz) { + elt = resolveTarget(elt) + forEach(elt.parentElement.children, function(child) { + removeClassFromElement(child, clazz) + }) + addClassToElement(asElement(elt), clazz) + } + + /** + * Finds the closest matching element in the given elements parentage, inclusive of the element + * + * @see https://htmx.org/api/#closest + * + * @param {Element|string} elt the element to find the selector from + * @param {string} selector the selector to find + * @returns {Element|null} + */ + function closest(elt, selector) { + elt = asElement(resolveTarget(elt)) + if (elt && elt.closest) { + return elt.closest(selector) + } else { + // TODO remove when IE goes away + do { + if (elt == null || matches(elt, selector)) { + return elt + } + } + while (elt = elt && asElement(parentElt(elt))) + return null + } + } + + /** + * @param {string} str + * @param {string} prefix + * @returns {boolean} + */ + function startsWith(str, prefix) { + return str.substring(0, prefix.length) === prefix + } + + /** + * @param {string} str + * @param {string} suffix + * @returns {boolean} + */ + function endsWith(str, suffix) { + return str.substring(str.length - suffix.length) === suffix + } + + /** + * @param {string} selector + * @returns {string} + */ + function normalizeSelector(selector) { + const trimmedSelector = selector.trim() + if (startsWith(trimmedSelector, '<') && endsWith(trimmedSelector, '/>')) { + return trimmedSelector.substring(1, trimmedSelector.length - 2) + } else { + return trimmedSelector + } + } + + /** + * @param {Node|Element|Document|string} elt + * @param {string} selector + * @param {boolean=} global + * @returns {(Node|Window)[]} + */ + function querySelectorAllExt(elt, selector, global) { + elt = resolveTarget(elt) + if (selector.indexOf('closest ') === 0) { + return [closest(asElement(elt), normalizeSelector(selector.substr(8)))] + } else if (selector.indexOf('find ') === 0) { + return [find(asParentNode(elt), normalizeSelector(selector.substr(5)))] + } else if (selector === 'next') { + return [asElement(elt).nextElementSibling] + } else if (selector.indexOf('next ') === 0) { + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)), !!global)] + } else if (selector === 'previous') { + return [asElement(elt).previousElementSibling] + } else if (selector.indexOf('previous ') === 0) { + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)), !!global)] + } else if (selector === 'document') { + return [document] + } else if (selector === 'window') { + return [window] + } else if (selector === 'body') { + return [document.body] + } else if (selector === 'root') { + return [getRootNode(elt, !!global)] + } else if (selector.indexOf('global ') === 0) { + return querySelectorAllExt(elt, selector.slice(7), true) + } else { + return toArray(asParentNode(getRootNode(elt, !!global)).querySelectorAll(normalizeSelector(selector))) + } + } + + /** + * @param {Node} start + * @param {string} match + * @param {boolean} global + * @returns {Element} + */ + var scanForwardQuery = function(start, match, global) { + const results = asParentNode(getRootNode(start, global)).querySelectorAll(match) + for (let i = 0; i < results.length; i++) { + const elt = results[i] + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { + return elt + } + } + } + + /** + * @param {Node} start + * @param {string} match + * @param {boolean} global + * @returns {Element} + */ + var scanBackwardsQuery = function(start, match, global) { + const results = asParentNode(getRootNode(start, global)).querySelectorAll(match) + for (let i = results.length - 1; i >= 0; i--) { + const elt = results[i] + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { + return elt + } + } + } + + /** + * @param {Node|string} eltOrSelector + * @param {string=} selector + * @returns {Node|Window} + */ + function querySelectorExt(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return querySelectorAllExt(eltOrSelector, selector)[0] + } else { + return querySelectorAllExt(getDocument().body, eltOrSelector)[0] + } + } + + /** + * @template {EventTarget} T + * @param {T|string} eltOrSelector + * @param {T} [context] + * @returns {Element|T|null} + */ + function resolveTarget(eltOrSelector, context) { + if (typeof eltOrSelector === 'string') { + return find(asParentNode(context) || document, eltOrSelector) + } else { + return eltOrSelector + } + } + + /** + * @typedef {keyof HTMLElementEventMap|string} AnyEventName + */ + + /** + * @typedef {Object} EventArgs + * @property {EventTarget} target + * @property {AnyEventName} event + * @property {EventListener} listener + */ + + /** + * @param {EventTarget|AnyEventName} arg1 + * @param {AnyEventName|EventListener} arg2 + * @param {EventListener} [arg3] + * @returns {EventArgs} + */ + function processEventArgs(arg1, arg2, arg3) { + if (isFunction(arg2)) { + return { + target: getDocument().body, + event: asString(arg1), + listener: arg2 + } + } else { + return { + target: resolveTarget(arg1), + event: asString(arg2), + listener: arg3 + } + } + } + + /** + * Adds an event listener to an element + * + * @see https://htmx.org/api/#on + * + * @param {EventTarget|string} arg1 the element to add the listener to | the event name to add the listener for + * @param {string|EventListener} arg2 the event name to add the listener for | the listener to add + * @param {EventListener} [arg3] the listener to add + * @returns {EventListener} + */ + function addEventListenerImpl(arg1, arg2, arg3) { + ready(function() { + const eventArgs = processEventArgs(arg1, arg2, arg3) + eventArgs.target.addEventListener(eventArgs.event, eventArgs.listener) + }) + const b = isFunction(arg2) + return b ? arg2 : arg3 + } + + /** + * Removes an event listener from an element + * + * @see https://htmx.org/api/#off + * + * @param {EventTarget|string} arg1 the element to remove the listener from | the event name to remove the listener from + * @param {string|EventListener} arg2 the event name to remove the listener from | the listener to remove + * @param {EventListener} [arg3] the listener to remove + * @returns {EventListener} + */ + function removeEventListenerImpl(arg1, arg2, arg3) { + ready(function() { + const eventArgs = processEventArgs(arg1, arg2, arg3) + eventArgs.target.removeEventListener(eventArgs.event, eventArgs.listener) + }) + return isFunction(arg2) ? arg2 : arg3 + } + + //= =================================================================== + // Node processing + //= =================================================================== + + const DUMMY_ELT = getDocument().createElement('output') // dummy element for bad selectors + /** + * @param {Element} elt + * @param {string} attrName + * @returns {(Node|Window)[]} + */ + function findAttributeTargets(elt, attrName) { + const attrTarget = getClosestAttributeValue(elt, attrName) + if (attrTarget) { + if (attrTarget === 'this') { + return [findThisElement(elt, attrName)] + } else { + const result = querySelectorAllExt(elt, attrTarget) + if (result.length === 0) { + logError('The selector "' + attrTarget + '" on ' + attrName + ' returned no matches!') + return [DUMMY_ELT] + } else { + return result + } + } + } + } + + /** + * @param {Element} elt + * @param {string} attribute + * @returns {Element|null} + */ + function findThisElement(elt, attribute) { + return asElement(getClosestMatch(elt, function(elt) { + return getAttributeValue(asElement(elt), attribute) != null + })) + } + + /** + * @param {Element} elt + * @returns {Node|Window|null} + */ + function getTarget(elt) { + const targetStr = getClosestAttributeValue(elt, 'hx-target') + if (targetStr) { + if (targetStr === 'this') { + return findThisElement(elt, 'hx-target') + } else { + return querySelectorExt(elt, targetStr) + } + } else { + const data = getInternalData(elt) + if (data.boosted) { + return getDocument().body + } else { + return elt + } + } + } + + /** + * @param {string} name + * @returns {boolean} + */ + function shouldSettleAttribute(name) { + const attributesToSettle = htmx.config.attributesToSettle + for (let i = 0; i < attributesToSettle.length; i++) { + if (name === attributesToSettle[i]) { + return true + } + } + return false + } + + /** + * @param {Element} mergeTo + * @param {Element} mergeFrom + */ + function cloneAttributes(mergeTo, mergeFrom) { + forEach(mergeTo.attributes, function(attr) { + if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) { + mergeTo.removeAttribute(attr.name) + } + }) + forEach(mergeFrom.attributes, function(attr) { + if (shouldSettleAttribute(attr.name)) { + mergeTo.setAttribute(attr.name, attr.value) + } + }) + } + + /** + * @param {HtmxSwapStyle} swapStyle + * @param {Element} target + * @returns {boolean} + */ + function isInlineSwap(swapStyle, target) { + const extensions = getExtensions(target) + for (let i = 0; i < extensions.length; i++) { + const extension = extensions[i] + try { + if (extension.isInlineSwap(swapStyle)) { + return true + } + } catch (e) { + logError(e) + } + } + return swapStyle === 'outerHTML' + } + + /** + * @param {string} oobValue + * @param {Element} oobElement + * @param {HtmxSettleInfo} settleInfo + * @returns + */ + function oobSwap(oobValue, oobElement, settleInfo) { + let selector = '#' + getRawAttribute(oobElement, 'id') + /** @type HtmxSwapStyle */ + let swapStyle = 'outerHTML' + if (oobValue === 'true') { + // do nothing + } else if (oobValue.indexOf(':') > 0) { + swapStyle = oobValue.substr(0, oobValue.indexOf(':')) + selector = oobValue.substr(oobValue.indexOf(':') + 1, oobValue.length) + } else { + swapStyle = oobValue + } - /** - * @param {any} o - * @param {string} type - * @returns - */ - function isType(o, type) { - return Object.prototype.toString.call(o) === "[object " + type + "]"; - } - - /** - * @param {*} o - * @returns {o is Function} - */ - function isFunction(o) { - return isType(o, "Function"); - } - - /** - * @param {*} o - * @returns {o is Object} - */ - function isRawObject(o) { - return isType(o, "Object"); - } - - /** - * getInternalData retrieves "private" data stored by htmx within an element - * @param {HTMLElement} elt - * @returns {*} - */ - function getInternalData(elt) { - var dataProp = 'htmx-internal-data'; - var data = elt[dataProp]; - if (!data) { - data = elt[dataProp] = {}; - } - return data; - } - - /** - * toArray converts an ArrayLike object into a real array. - * @param {ArrayLike} arr - * @returns {any[]} - */ - function toArray(arr) { - var returnArr = []; - if (arr) { - for (var i = 0; i < arr.length; i++) { - returnArr.push(arr[i]); - } - } - return returnArr + const targets = getDocument().querySelectorAll(selector) + if (targets) { + forEach( + targets, + function(target) { + let fragment + const oobElementClone = oobElement.cloneNode(true) + fragment = getDocument().createDocumentFragment() + fragment.appendChild(oobElementClone) + if (!isInlineSwap(swapStyle, target)) { + fragment = asParentNode(oobElementClone) // if this is not an inline swap, we use the content of the node, not the node itself + } + + const beforeSwapDetails = { shouldSwap: true, target, fragment } + if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return + + target = beforeSwapDetails.target // allow re-targeting + if (beforeSwapDetails.shouldSwap) { + swapWithStyle(swapStyle, target, target, fragment, settleInfo) + } + forEach(settleInfo.elts, function(elt) { + triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails) + }) + } + ) + oobElement.parentNode.removeChild(oobElement) + } else { + oobElement.parentNode.removeChild(oobElement) + triggerErrorEvent(getDocument().body, 'htmx:oobErrorNoTarget', { content: oobElement }) + } + return oobValue + } + + /** + * @param {DocumentFragment} fragment + */ + function handlePreservedElements(fragment) { + forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function(preservedElt) { + const id = getAttributeValue(preservedElt, 'id') + const oldElt = getDocument().getElementById(id) + if (oldElt != null) { + preservedElt.parentNode.replaceChild(oldElt, preservedElt) + } + }) + } + + /** + * @param {Node} parentNode + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function handleAttributes(parentNode, fragment, settleInfo) { + forEach(fragment.querySelectorAll('[id]'), function(newNode) { + const id = getRawAttribute(newNode, 'id') + if (id && id.length > 0) { + const normalizedId = id.replace("'", "\\'") + const normalizedTag = newNode.tagName.replace(':', '\\:') + const parentElt = asParentNode(parentNode) + const oldNode = parentElt && parentElt.querySelector(normalizedTag + "[id='" + normalizedId + "']") + if (oldNode && oldNode !== parentElt) { + const newAttributes = newNode.cloneNode() + cloneAttributes(newNode, oldNode) + settleInfo.tasks.push(function() { + cloneAttributes(newNode, newAttributes) + }) + } + } + }) + } + + /** + * @param {Node} child + * @returns {HtmxSettleTask} + */ + function makeAjaxLoadTask(child) { + return function() { + removeClassFromElement(child, htmx.config.addedClass) + processNode(asElement(child)) + processFocus(asParentNode(child)) + triggerEvent(child, 'htmx:load') + } + } + + /** + * @param {ParentNode} child + */ + function processFocus(child) { + const autofocus = '[autofocus]' + const autoFocusedElt = asHtmlElement(matches(child, autofocus) ? child : child.querySelector(autofocus)) + if (autoFocusedElt != null) { + autoFocusedElt.focus() + } + } + + /** + * @param {Node} parentNode + * @param {Node} insertBefore + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) { + handleAttributes(parentNode, fragment, settleInfo) + while (fragment.childNodes.length > 0) { + const child = fragment.firstChild + addClassToElement(asElement(child), htmx.config.addedClass) + parentNode.insertBefore(child, insertBefore) + if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { + settleInfo.tasks.push(makeAjaxLoadTask(child)) + } + } + } + + /** + * based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, + * derived from Java's string hashcode implementation + * @param {string} string + * @param {number} hash + * @returns {number} + */ + function stringHash(string, hash) { + let char = 0 + while (char < string.length) { + hash = (hash << 5) - hash + string.charCodeAt(char++) | 0 // bitwise or ensures we have a 32-bit int + } + return hash + } + + /** + * @param {Element} elt + * @returns {number} + */ + function attributeHash(elt) { + let hash = 0 + // IE fix + if (elt.attributes) { + for (let i = 0; i < elt.attributes.length; i++) { + const attribute = elt.attributes[i] + if (attribute.value) { // only include attributes w/ actual values (empty is same as non-existent) + hash = stringHash(attribute.name, hash) + hash = stringHash(attribute.value, hash) + } + } + } + return hash + } + + /** + * @param {EventTarget} elt + */ + function deInitOnHandlers(elt) { + const internalData = getInternalData(elt) + if (internalData.onHandlers) { + for (let i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i] + removeEventListenerImpl(elt, handlerInfo.event, handlerInfo.listener) + } + delete internalData.onHandlers + } + } + + /** + * @param {Node} element + */ + function deInitNode(element) { + const internalData = getInternalData(element) + if (internalData.timeout) { + clearTimeout(internalData.timeout) + } + if (internalData.listenerInfos) { + forEach(internalData.listenerInfos, function(info) { + if (info.on) { + removeEventListenerImpl(info.on, info.trigger, info.listener) } - - function forEach(arr, func) { - if (arr) { - for (var i = 0; i < arr.length; i++) { - func(arr[i]); - } - } + }) + } + deInitOnHandlers(element) + forEach(Object.keys(internalData), function(key) { delete internalData[key] }) + } + + /** + * @param {Node} element + */ + function cleanUpElement(element) { + triggerEvent(element, 'htmx:beforeCleanupElement') + deInitNode(element) + // @ts-ignore IE11 code + // noinspection JSUnresolvedReference + if (element.children) { // IE + // @ts-ignore + forEach(element.children, function(child) { cleanUpElement(child) }) + } + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapOuterHTML(target, fragment, settleInfo) { + /** @type {Node} */ + let newElt + const eltBeforeNewContent = target.previousSibling + insertNodesBefore(parentElt(target), target, fragment, settleInfo) + if (eltBeforeNewContent == null) { + newElt = parentElt(target).firstChild + } else { + newElt = eltBeforeNewContent.nextSibling + } + settleInfo.elts = settleInfo.elts.filter(function(e) { return e !== target }) + while (newElt && newElt !== target) { + if (newElt instanceof Element) { + settleInfo.elts.push(newElt) + newElt = newElt.nextElementSibling + } else { + newElt = null + } + } + cleanUpElement(target) + if (target instanceof Element) { + target.remove() + } else { + target.parentNode.removeChild(target) + } + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapAfterBegin(target, fragment, settleInfo) { + return insertNodesBefore(target, target.firstChild, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapBeforeBegin(target, fragment, settleInfo) { + return insertNodesBefore(parentElt(target), target, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapBeforeEnd(target, fragment, settleInfo) { + return insertNodesBefore(target, null, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapAfterEnd(target, fragment, settleInfo) { + return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo) + } + + /** + * @param {Node} target + */ + function swapDelete(target) { + cleanUpElement(target) + return parentElt(target).removeChild(target) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapInnerHTML(target, fragment, settleInfo) { + const firstChild = target.firstChild + insertNodesBefore(target, firstChild, fragment, settleInfo) + if (firstChild) { + while (firstChild.nextSibling) { + cleanUpElement(firstChild.nextSibling) + target.removeChild(firstChild.nextSibling) + } + cleanUpElement(firstChild) + target.removeChild(firstChild) + } + } + + /** + * @param {HtmxSwapStyle} swapStyle + * @param {Element} elt + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapWithStyle(swapStyle, elt, target, fragment, settleInfo) { + switch (swapStyle) { + case 'none': + return + case 'outerHTML': + swapOuterHTML(target, fragment, settleInfo) + return + case 'afterbegin': + swapAfterBegin(target, fragment, settleInfo) + return + case 'beforebegin': + swapBeforeBegin(target, fragment, settleInfo) + return + case 'beforeend': + swapBeforeEnd(target, fragment, settleInfo) + return + case 'afterend': + swapAfterEnd(target, fragment, settleInfo) + return + case 'delete': + swapDelete(target) + return + default: + var extensions = getExtensions(elt) + for (let i = 0; i < extensions.length; i++) { + const ext = extensions[i] + try { + const newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo) + if (newElements) { + if (typeof newElements.length !== 'undefined') { + // if handleSwap returns an array (like) of elements, we handle them + for (let j = 0; j < newElements.length; j++) { + const child = newElements[j] + if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { + settleInfo.tasks.push(makeAjaxLoadTask(child)) + } + } + } + return + } + } catch (e) { + logError(e) + } + } + if (swapStyle === 'innerHTML') { + swapInnerHTML(target, fragment, settleInfo) + } else { + swapWithStyle(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo) } + } + } + + /** + * @param {DocumentFragment} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function findAndSwapOobElements(fragment, settleInfo) { + forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function(oobElement) { + if (htmx.config.allowNestedOobSwaps || oobElement.parentElement === null) { + const oobValue = getAttributeValue(oobElement, 'hx-swap-oob') + if (oobValue != null) { + oobSwap(oobValue, oobElement, settleInfo) + } + } else { + oobElement.removeAttribute('hx-swap-oob') + oobElement.removeAttribute('data-hx-swap-oob') + } + }) + } + + /** + * Implements complete swapping pipeline, including: focus and selection preservation, + * title updates, scroll, OOB swapping, normal swapping and settling + * @param {string|Element} target + * @param {string} content + * @param {HtmxSwapSpecification} swapSpec + * @param {SwapOptions} [swapOptions] + */ + function swap(target, content, swapSpec, swapOptions) { + if (!swapOptions) { + swapOptions = {} + } - function isScrolledIntoView(el) { - var rect = el.getBoundingClientRect(); - var elemTop = rect.top; - var elemBottom = rect.bottom; - return elemTop < window.innerHeight && elemBottom >= 0; - } + target = resolveTarget(target) + + // preserve focus and selection + const activeElt = document.activeElement + let selectionInfo = {} + try { + selectionInfo = { + elt: activeElt, + // @ts-ignore + start: activeElt ? activeElt.selectionStart : null, + // @ts-ignore + end: activeElt ? activeElt.selectionEnd : null + } + } catch (e) { + // safari issue - see https://github.com/microsoft/playwright/issues/5894 + } + const settleInfo = makeSettleInfo(target) - function bodyContains(elt) { - // IE Fix - if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) { - return getDocument().body.contains(elt.getRootNode().host); - } else { - return getDocument().body.contains(elt); - } - } + // For text content swaps, don't parse the response as HTML, just insert it + if (swapSpec.swapStyle === 'textContent') { + target.textContent = content + // Otherwise, make the fragment and process it + } else { + let fragment = makeFragment(content) + + settleInfo.title = fragment.title + + // select-oob swaps + if (swapOptions.selectOOB) { + const oobSelectValues = swapOptions.selectOOB.split(',') + for (let i = 0; i < oobSelectValues.length; i++) { + const oobSelectValue = oobSelectValues[i].split(':', 2) + let id = oobSelectValue[0].trim() + if (id.indexOf('#') === 0) { + id = id.substring(1) + } + const oobValue = oobSelectValue[1] || 'true' + const oobElement = fragment.querySelector('#' + id) + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo) + } + } + } + // oob swaps + findAndSwapOobElements(fragment, settleInfo) + forEach(findAll(fragment, 'template'), /** @param {HTMLTemplateElement} template */function(template) { + findAndSwapOobElements(template.content, settleInfo) + if (template.content.childElementCount === 0) { + // Avoid polluting the DOM with empty templates that were only used to encapsulate oob swap + template.remove() + } + }) + + // normal swap + if (swapOptions.select) { + const newFragment = getDocument().createDocumentFragment() + forEach(fragment.querySelectorAll(swapOptions.select), function(node) { + newFragment.appendChild(node) + }) + fragment = newFragment + } + handlePreservedElements(fragment) + swapWithStyle(swapSpec.swapStyle, swapOptions.contextElement, target, fragment, settleInfo) + } - function splitOnWhitespace(trigger) { - return trigger.trim().split(/\s+/); - } + // apply saved focus and selection information to swapped content + if (selectionInfo.elt && + !bodyContains(selectionInfo.elt) && + getRawAttribute(selectionInfo.elt, 'id')) { + const newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, 'id')) + const focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll } + if (newActiveElt) { + // @ts-ignore + if (selectionInfo.start && newActiveElt.setSelectionRange) { + try { + // @ts-ignore + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end) + } catch (e) { + // the setSelectionRange method is present on fields that don't support it, so just let this fail + } + } + newActiveElt.focus(focusOptions) + } + } - /** - * mergeObjects takes all of the keys from - * obj2 and duplicates them into obj1 - * @param {Object} obj1 - * @param {Object} obj2 - * @returns {Object} - */ - function mergeObjects(obj1, obj2) { - for (var key in obj2) { - if (obj2.hasOwnProperty(key)) { - obj1[key] = obj2[key]; - } - } - return obj1; - } + target.classList.remove(htmx.config.swappingClass) + forEach(settleInfo.elts, function(elt) { + if (elt.classList) { + elt.classList.add(htmx.config.settlingClass) + } + triggerEvent(elt, 'htmx:afterSwap', swapOptions.eventInfo) + }) + if (swapOptions.afterSwapCallback) { + swapOptions.afterSwapCallback() + } - function parseJSON(jString) { - try { - return JSON.parse(jString); - } catch(error) { - logError(error); - return null; - } - } + // merge in new title after swap but before settle + if (!swapSpec.ignoreTitle) { + handleTitle(settleInfo.title) + } - function canAccessLocalStorage() { - var test = 'htmx:localStorageTest'; - try { - localStorage.setItem(test, test); - localStorage.removeItem(test); - return true; - } catch(e) { - return false; - } - } + // settle + const doSettle = function() { + forEach(settleInfo.tasks, function(task) { + task.call() + }) + forEach(settleInfo.elts, function(elt) { + if (elt.classList) { + elt.classList.remove(htmx.config.settlingClass) + } + triggerEvent(elt, 'htmx:afterSettle', swapOptions.eventInfo) + }) + + if (swapOptions.anchor) { + const anchorTarget = asElement(resolveTarget('#' + swapOptions.anchor)) + if (anchorTarget) { + anchorTarget.scrollIntoView({ block: 'start', behavior: 'auto' }) + } + } + + updateScrollState(settleInfo.elts, swapSpec) + if (swapOptions.afterSettleCallback) { + swapOptions.afterSettleCallback() + } + } - function normalizePath(path) { + if (swapSpec.settleDelay > 0) { + getWindow().setTimeout(doSettle, swapSpec.settleDelay) + } else { + doSettle() + } + } + + /** + * @param {XMLHttpRequest} xhr + * @param {string} header + * @param {EventTarget} elt + */ + function handleTriggerHeader(xhr, header, elt) { + const triggerBody = xhr.getResponseHeader(header) + if (triggerBody.indexOf('{') === 0) { + const triggers = parseJSON(triggerBody) + for (const eventName in triggers) { + if (triggers.hasOwnProperty(eventName)) { + let detail = triggers[eventName] + if (!isRawObject(detail)) { + detail = { value: detail } + } + triggerEvent(elt, eventName, detail) + } + } + } else { + const eventNames = triggerBody.split(',') + for (let i = 0; i < eventNames.length; i++) { + triggerEvent(elt, eventNames[i].trim(), []) + } + } + } + + const WHITESPACE = /\s/ + const WHITESPACE_OR_COMMA = /[\s,]/ + const SYMBOL_START = /[_$a-zA-Z]/ + const SYMBOL_CONT = /[_$a-zA-Z0-9]/ + const STRINGISH_START = ['"', "'", '/'] + const NOT_WHITESPACE = /[^\s]/ + const COMBINED_SELECTOR_START = /[{(]/ + const COMBINED_SELECTOR_END = /[})]/ + + /** + * @param {string} str + * @returns {string[]} + */ + function tokenizeString(str) { + /** @type string[] */ + const tokens = [] + let position = 0 + while (position < str.length) { + if (SYMBOL_START.exec(str.charAt(position))) { + var startPosition = position + while (SYMBOL_CONT.exec(str.charAt(position + 1))) { + position++ + } + tokens.push(str.substr(startPosition, position - startPosition + 1)) + } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) { + const startChar = str.charAt(position) + var startPosition = position + position++ + while (position < str.length && str.charAt(position) !== startChar) { + if (str.charAt(position) === '\\') { + position++ + } + position++ + } + tokens.push(str.substr(startPosition, position - startPosition + 1)) + } else { + const symbol = str.charAt(position) + tokens.push(symbol) + } + position++ + } + return tokens + } + + /** + * @param {string} token + * @param {string|null} last + * @param {string} paramName + * @returns {boolean} + */ + function isPossibleRelativeReference(token, last, paramName) { + return SYMBOL_START.exec(token.charAt(0)) && + token !== 'true' && + token !== 'false' && + token !== 'this' && + token !== paramName && + last !== '.' + } + + /** + * @param {EventTarget|string} elt + * @param {string[]} tokens + * @param {string} paramName + * @returns {ConditionalFunction|null} + */ + function maybeGenerateConditional(elt, tokens, paramName) { + if (tokens[0] === '[') { + tokens.shift() + let bracketCount = 1 + let conditionalSource = ' return (function(' + paramName + '){ return (' + let last = null + while (tokens.length > 0) { + const token = tokens[0] + // @ts-ignore For some reason tsc doesn't understand the shift call, and thinks we're comparing the same value here, i.e. '[' vs ']' + if (token === ']') { + bracketCount-- + if (bracketCount === 0) { + if (last === null) { + conditionalSource = conditionalSource + 'true' + } + tokens.shift() + conditionalSource += ')})' try { - var url = new URL(path); - if (url) { - path = url.pathname + url.search; - } - // remove trailing slash, unless index page - if (!(/^\/$/.test(path))) { - path = path.replace(/\/+$/, ''); - } - return path; + const conditionFunction = maybeEval(elt, function() { + return Function(conditionalSource)() + }, + function() { return true }) + conditionFunction.source = conditionalSource + return conditionFunction } catch (e) { - // be kind to IE11, which doesn't support URL() - return path; - } - } - - //========================================================================================== - // public API - //========================================================================================== - - function internalEval(str){ - return maybeEval(getDocument().body, function () { - return eval(str); - }); - } - - function onLoadHelper(callback) { - var value = htmx.on("htmx:load", function(evt) { - callback(evt.detail.elt); - }); - return value; - } - - function logAll(){ - htmx.logger = function(elt, event, data) { - if(console) { - console.log(event, elt, data); - } - } - } - - function logNone() { - htmx.logger = null - } - - function find(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelector(selector); - } else { - return find(getDocument(), eltOrSelector); - } - } - - function findAll(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelectorAll(selector); - } else { - return findAll(getDocument(), eltOrSelector); - } - } - - function removeElement(elt, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - removeElement(elt); - elt = null; - }, delay); - } else { - elt.parentElement.removeChild(elt); - } - } - - function addClassToElement(elt, clazz, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - addClassToElement(elt, clazz); - elt = null; - }, delay); - } else { - elt.classList && elt.classList.add(clazz); - } - } - - function removeClassFromElement(elt, clazz, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - removeClassFromElement(elt, clazz); - elt = null; - }, delay); - } else { - if (elt.classList) { - elt.classList.remove(clazz); - // if there are no classes left, remove the class attribute - if (elt.classList.length === 0) { - elt.removeAttribute("class"); - } - } - } - } - - function toggleClassOnElement(elt, clazz) { - elt = resolveTarget(elt); - elt.classList.toggle(clazz); - } - - function takeClassForElement(elt, clazz) { - elt = resolveTarget(elt); - forEach(elt.parentElement.children, function(child){ - removeClassFromElement(child, clazz); - }) - addClassToElement(elt, clazz); - } - - function closest(elt, selector) { - elt = resolveTarget(elt); - if (elt.closest) { - return elt.closest(selector); - } else { - // TODO remove when IE goes away - do{ - if (elt == null || matches(elt, selector)){ - return elt; - } - } - while (elt = elt && parentElt(elt)); - return null; - } - } - - function startsWith(str, prefix) { - return str.substring(0, prefix.length) === prefix - } - - function endsWith(str, suffix) { - return str.substring(str.length - suffix.length) === suffix - } - - function normalizeSelector(selector) { - var trimmedSelector = selector.trim(); - if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) { - return trimmedSelector.substring(1, trimmedSelector.length - 2); - } else { - return trimmedSelector; - } - } - - function querySelectorAllExt(elt, selector) { - if (selector.indexOf("closest ") === 0) { - return [closest(elt, normalizeSelector(selector.substr(8)))]; - } else if (selector.indexOf("find ") === 0) { - return [find(elt, normalizeSelector(selector.substr(5)))]; - } else if (selector === "next") { - return [elt.nextElementSibling] - } else if (selector.indexOf("next ") === 0) { - return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; - } else if (selector === "previous") { - return [elt.previousElementSibling] - } else if (selector.indexOf("previous ") === 0) { - return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; - } else if (selector === 'document') { - return [document]; - } else if (selector === 'window') { - return [window]; - } else if (selector === 'body') { - return [document.body]; - } else { - return getDocument().querySelectorAll(normalizeSelector(selector)); - } - } - - var scanForwardQuery = function(start, match) { - var results = getDocument().querySelectorAll(match); - for (var i = 0; i < results.length; i++) { - var elt = results[i]; - if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { - return elt; - } - } - } - - var scanBackwardsQuery = function(start, match) { - var results = getDocument().querySelectorAll(match); - for (var i = results.length - 1; i >= 0; i--) { - var elt = results[i]; - if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { - return elt; - } - } - } - - function querySelectorExt(eltOrSelector, selector) { - if (selector) { - return querySelectorAllExt(eltOrSelector, selector)[0]; - } else { - return querySelectorAllExt(getDocument().body, eltOrSelector)[0]; - } - } - - function resolveTarget(arg2) { - if (isType(arg2, 'String')) { - return find(arg2); - } else { - return arg2; - } - } - - function processEventArgs(arg1, arg2, arg3) { - if (isFunction(arg2)) { - return { - target: getDocument().body, - event: arg1, - listener: arg2 - } - } else { - return { - target: resolveTarget(arg1), - event: arg2, - listener: arg3 - } - } - - } - - function addEventListenerImpl(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 removeEventListenerImpl(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 - //==================================================================== - - var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors - function findAttributeTargets(elt, attrName) { - var attrTarget = getClosestAttributeValue(elt, attrName); - if (attrTarget) { - if (attrTarget === "this") { - return [findThisElement(elt, attrName)]; - } else { - var result = querySelectorAllExt(elt, attrTarget); - if (result.length === 0) { - logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!"); - return [DUMMY_ELT] - } else { - return result; - } - } - } - } - - function findThisElement(elt, attribute){ - return getClosestMatch(elt, function (elt) { - return getAttributeValue(elt, attribute) != null; - }) - } - - function getTarget(elt) { - var targetStr = getClosestAttributeValue(elt, "hx-target"); - if (targetStr) { - if (targetStr === "this") { - return findThisElement(elt,'hx-target'); - } else { - return querySelectorExt(elt, targetStr) - } - } else { - var data = getInternalData(elt); - if (data.boosted) { - return getDocument().body; - } else { - return elt; - } - } - } - - function shouldSettleAttribute(name) { - var attributesToSettle = htmx.config.attributesToSettle; - for (var i = 0; i < attributesToSettle.length; i++) { - if (name === attributesToSettle[i]) { - return true; - } - } - return false; - } - - function cloneAttributes(mergeTo, mergeFrom) { - forEach(mergeTo.attributes, function (attr) { - if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) { - mergeTo.removeAttribute(attr.name) - } - }); - forEach(mergeFrom.attributes, function (attr) { - if (shouldSettleAttribute(attr.name)) { - mergeTo.setAttribute(attr.name, attr.value); - } - }); - } - - function isInlineSwap(swapStyle, target) { - var extensions = getExtensions(target); - for (var i = 0; i < extensions.length; i++) { - var extension = extensions[i]; - try { - if (extension.isInlineSwap(swapStyle)) { - return true; - } - } catch(e) { - logError(e); - } - } - return swapStyle === "outerHTML"; - } - - /** - * - * @param {string} oobValue - * @param {HTMLElement} oobElement - * @param {*} settleInfo - * @returns - */ - function oobSwap(oobValue, oobElement, settleInfo) { - var selector = "#" + getRawAttribute(oobElement, "id"); - var swapStyle = "outerHTML"; - if (oobValue === "true") { - // do nothing - } else if (oobValue.indexOf(":") > 0) { - swapStyle = oobValue.substr(0, oobValue.indexOf(":")); - selector = oobValue.substr(oobValue.indexOf(":") + 1, oobValue.length); - } else { - swapStyle = oobValue; - } - - var targets = getDocument().querySelectorAll(selector); - if (targets) { - forEach( - targets, - function (target) { - var fragment; - var oobElementClone = oobElement.cloneNode(true); - fragment = getDocument().createDocumentFragment(); - fragment.appendChild(oobElementClone); - if (!isInlineSwap(swapStyle, target)) { - fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself - } - - var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment }; - if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return; - - target = beforeSwapDetails.target; // allow re-targeting - if (beforeSwapDetails['shouldSwap']){ - swap(swapStyle, target, target, fragment, settleInfo); - } - forEach(settleInfo.elts, function (elt) { - triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails); - }); - } - ); - oobElement.parentNode.removeChild(oobElement); - } else { - oobElement.parentNode.removeChild(oobElement); - triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}); - } - return oobValue; - } - - function handleOutOfBandSwaps(elt, fragment, settleInfo) { - var oobSelects = getClosestAttributeValue(elt, "hx-select-oob"); - if (oobSelects) { - var oobSelectValues = oobSelects.split(","); - for (var i = 0; i < oobSelectValues.length; i++) { - var oobSelectValue = oobSelectValues[i].split(":", 2); - var id = oobSelectValue[0].trim(); - if (id.indexOf("#") === 0) { - id = id.substring(1); - } - var oobValue = oobSelectValue[1] || "true"; - var oobElement = fragment.querySelector("#" + id); - if (oobElement) { - oobSwap(oobValue, oobElement, settleInfo); - } - } - } - forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) { - var oobValue = getAttributeValue(oobElement, "hx-swap-oob"); - if (oobValue != null) { - oobSwap(oobValue, oobElement, settleInfo); - } - }); - } - - function handlePreservedElements(fragment) { - forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function (preservedElt) { - var id = getAttributeValue(preservedElt, "id"); - var oldElt = getDocument().getElementById(id); - if (oldElt != null) { - preservedElt.parentNode.replaceChild(oldElt, preservedElt); - } - }); - } - - function handleAttributes(parentNode, fragment, settleInfo) { - forEach(fragment.querySelectorAll("[id]"), function (newNode) { - var id = getRawAttribute(newNode, "id") - if (id && id.length > 0) { - var normalizedId = id.replace("'", "\\'"); - var normalizedTag = newNode.tagName.replace(':', '\\:'); - var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']"); - if (oldNode && oldNode !== parentNode) { - var newAttributes = newNode.cloneNode(); - cloneAttributes(newNode, oldNode); - settleInfo.tasks.push(function () { - cloneAttributes(newNode, newAttributes); - }); - } - } - }); - } - - function makeAjaxLoadTask(child) { - return function () { - removeClassFromElement(child, htmx.config.addedClass); - processNode(child); - processScripts(child); - processFocus(child) - triggerEvent(child, 'htmx:load'); - }; - } - - function processFocus(child) { - var autofocus = "[autofocus]"; - var autoFocusedElt = matches(child, autofocus) ? child : child.querySelector(autofocus) - if (autoFocusedElt != null) { - autoFocusedElt.focus(); - } - } - - function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) { - handleAttributes(parentNode, fragment, settleInfo); - while(fragment.childNodes.length > 0){ - var child = fragment.firstChild; - addClassToElement(child, htmx.config.addedClass); - parentNode.insertBefore(child, insertBefore); - if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { - settleInfo.tasks.push(makeAjaxLoadTask(child)); - } - } - } - - // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, - // derived from Java's string hashcode implementation - function stringHash(string, hash) { - var char = 0; - while (char < string.length){ - hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int - } - return hash; - } - - function attributeHash(elt) { - var hash = 0; - // IE fix - if (elt.attributes) { - for (var i = 0; i < elt.attributes.length; i++) { - var attribute = elt.attributes[i]; - if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent) - hash = stringHash(attribute.name, hash); - hash = stringHash(attribute.value, hash); - } - } - } - return hash; - } - - function deInitOnHandlers(elt) { - var internalData = getInternalData(elt); - if (internalData.onHandlers) { - for (var i = 0; i < internalData.onHandlers.length; i++) { - const handlerInfo = internalData.onHandlers[i]; - elt.removeEventListener(handlerInfo.event, handlerInfo.listener); - } - delete internalData.onHandlers - } - } - - function deInitNode(element) { - var internalData = getInternalData(element); - if (internalData.timeout) { - clearTimeout(internalData.timeout); - } - if (internalData.webSocket) { - internalData.webSocket.close(); - } - if (internalData.sseEventSource) { - internalData.sseEventSource.close(); - } - if (internalData.listenerInfos) { - forEach(internalData.listenerInfos, function (info) { - if (info.on) { - info.on.removeEventListener(info.trigger, info.listener); - } - }); - } - deInitOnHandlers(element); - forEach(Object.keys(internalData), function(key) { delete internalData[key] }); - } - - function cleanUpElement(element) { - triggerEvent(element, "htmx:beforeCleanupElement") - deInitNode(element); - if (element.children) { // IE - forEach(element.children, function(child) { cleanUpElement(child) }); - } - } - - function swapOuterHTML(target, fragment, settleInfo) { - if (target.tagName === "BODY") { - return swapInnerHTML(target, fragment, settleInfo); - } else { - // @type {HTMLElement} - var newElt - var eltBeforeNewContent = target.previousSibling; - insertNodesBefore(parentElt(target), target, fragment, settleInfo); - if (eltBeforeNewContent == null) { - newElt = parentElt(target).firstChild; - } else { - newElt = eltBeforeNewContent.nextSibling; - } - settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target }); - while(newElt && newElt !== target) { - if (newElt.nodeType === Node.ELEMENT_NODE) { - settleInfo.elts.push(newElt); - } - newElt = newElt.nextElementSibling; - } - cleanUpElement(target); - parentElt(target).removeChild(target); - } - } - - function swapAfterBegin(target, fragment, settleInfo) { - return insertNodesBefore(target, target.firstChild, fragment, settleInfo); - } - - function swapBeforeBegin(target, fragment, settleInfo) { - return insertNodesBefore(parentElt(target), target, fragment, settleInfo); - } - - function swapBeforeEnd(target, fragment, settleInfo) { - return insertNodesBefore(target, null, fragment, settleInfo); - } - - function swapAfterEnd(target, fragment, settleInfo) { - return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo); - } - function swapDelete(target, fragment, settleInfo) { - cleanUpElement(target); - return parentElt(target).removeChild(target); - } - - function swapInnerHTML(target, fragment, settleInfo) { - var firstChild = target.firstChild; - insertNodesBefore(target, firstChild, fragment, settleInfo); - if (firstChild) { - while (firstChild.nextSibling) { - cleanUpElement(firstChild.nextSibling) - target.removeChild(firstChild.nextSibling); - } - cleanUpElement(firstChild) - target.removeChild(firstChild); - } - } - - function maybeSelectFromResponse(elt, fragment, selectOverride) { - var selector = selectOverride || getClosestAttributeValue(elt, "hx-select"); - if (selector) { - var newFragment = getDocument().createDocumentFragment(); - forEach(fragment.querySelectorAll(selector), function (node) { - newFragment.appendChild(node); - }); - fragment = newFragment; - } - return fragment; - } - - function swap(swapStyle, elt, target, fragment, settleInfo) { - switch (swapStyle) { - case "none": - return; - case "outerHTML": - swapOuterHTML(target, fragment, settleInfo); - return; - case "afterbegin": - swapAfterBegin(target, fragment, settleInfo); - return; - case "beforebegin": - swapBeforeBegin(target, fragment, settleInfo); - return; - case "beforeend": - swapBeforeEnd(target, fragment, settleInfo); - return; - case "afterend": - swapAfterEnd(target, fragment, settleInfo); - return; - case "delete": - swapDelete(target, fragment, settleInfo); - return; - default: - var extensions = getExtensions(elt); - for (var i = 0; i < extensions.length; i++) { - var ext = extensions[i]; - try { - var newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo); - if (newElements) { - if (typeof newElements.length !== 'undefined') { - // if handleSwap returns an array (like) of elements, we handle them - for (var j = 0; j < newElements.length; j++) { - var child = newElements[j]; - if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { - settleInfo.tasks.push(makeAjaxLoadTask(child)); - } - } - } - return; - } - } catch (e) { - logError(e); - } - } - if (swapStyle === "innerHTML") { - swapInnerHTML(target, fragment, settleInfo); - } else { - swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo); - } - } - } - - function findTitle(content) { - if (content.indexOf('<title') > -1) { - var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, ''); - var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX); - if (result) { - return result[2]; - } - } - } - - function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) { - settleInfo.title = findTitle(responseText); - var fragment = makeFragment(responseText); - if (fragment) { - handleOutOfBandSwaps(elt, fragment, settleInfo); - fragment = maybeSelectFromResponse(elt, fragment, selectOverride); - handlePreservedElements(fragment); - return swap(swapStyle, elt, target, fragment, settleInfo); - } - } - - function handleTrigger(xhr, header, elt) { - var triggerBody = xhr.getResponseHeader(header); - if (triggerBody.indexOf("{") === 0) { - var triggers = parseJSON(triggerBody); - for (var eventName in triggers) { - if (triggers.hasOwnProperty(eventName)) { - var detail = triggers[eventName]; - if (!isRawObject(detail)) { - detail = {"value": detail} - } - triggerEvent(elt, eventName, detail); - } - } - } else { - var eventNames = triggerBody.split(",") - for (var i = 0; i < eventNames.length; i++) { - triggerEvent(elt, eventNames[i].trim(), []); - } - } - } - - var WHITESPACE = /\s/; - var WHITESPACE_OR_COMMA = /[\s,]/; - var SYMBOL_START = /[_$a-zA-Z]/; - var SYMBOL_CONT = /[_$a-zA-Z0-9]/; - var STRINGISH_START = ['"', "'", "/"]; - var NOT_WHITESPACE = /[^\s]/; - var COMBINED_SELECTOR_START = /[{(]/; - var COMBINED_SELECTOR_END = /[})]/; - function tokenizeString(str) { - var tokens = []; - var position = 0; - while (position < str.length) { - if(SYMBOL_START.exec(str.charAt(position))) { - var startPosition = position; - while (SYMBOL_CONT.exec(str.charAt(position + 1))) { - position++; - } - tokens.push(str.substr(startPosition, position - startPosition + 1)); - } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) { - var startChar = str.charAt(position); - var startPosition = position; - position++; - while (position < str.length && str.charAt(position) !== startChar ) { - if (str.charAt(position) === "\\") { - position++; - } - position++; - } - tokens.push(str.substr(startPosition, position - startPosition + 1)); - } else { - var symbol = str.charAt(position); - tokens.push(symbol); - } - position++; - } - return tokens; - } - - function isPossibleRelativeReference(token, last, paramName) { - return SYMBOL_START.exec(token.charAt(0)) && - token !== "true" && - token !== "false" && - token !== "this" && - token !== paramName && - last !== "."; - } - - function maybeGenerateConditional(elt, tokens, paramName) { - if (tokens[0] === '[') { - tokens.shift(); - var bracketCount = 1; - var conditionalSource = " return (function(" + paramName + "){ return ("; - var last = null; - while (tokens.length > 0) { - var token = tokens[0]; - if (token === "]") { - bracketCount--; - if (bracketCount === 0) { - if (last === null) { - conditionalSource = conditionalSource + "true"; - } - tokens.shift(); - conditionalSource += ")})"; - try { - var conditionFunction = maybeEval(elt,function () { - return Function(conditionalSource)(); - }, - function(){return true}) - conditionFunction.source = conditionalSource; - return conditionFunction; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:syntax:error", {error:e, source:conditionalSource}) - return null; - } - } - } else if (token === "[") { - bracketCount++; - } - if (isPossibleRelativeReference(token, last, paramName)) { - conditionalSource += "((" + paramName + "." + token + ") ? (" + paramName + "." + token + ") : (window." + token + "))"; - } else { - conditionalSource = conditionalSource + token; - } - last = tokens.shift(); - } - } - } - - function consumeUntil(tokens, match) { - var result = ""; - while (tokens.length > 0 && !match.test(tokens[0])) { - result += tokens.shift(); - } - return result; - } - - function consumeCSSSelector(tokens) { - var result; - if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { - tokens.shift(); - result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim(); - tokens.shift(); - } else { - result = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } - return result; - } - - var INPUT_SELECTOR = 'input, textarea, select'; - - /** - * @param {HTMLElement} elt - * @param {string} explicitTrigger - * @param {cache} cache for trigger specs - * @returns {import("./htmx").HtmxTriggerSpecification[]} - */ - function parseAndCacheTrigger(elt, explicitTrigger, cache) { - var triggerSpecs = []; - var tokens = tokenizeString(explicitTrigger); - do { - consumeUntil(tokens, NOT_WHITESPACE); - var initialLength = tokens.length; - var trigger = consumeUntil(tokens, /[,\[\s]/); - if (trigger !== "") { - if (trigger === "every") { - var every = {trigger: 'every'}; - consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); - consumeUntil(tokens, NOT_WHITESPACE); - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - every.eventFilter = eventFilter; - } - triggerSpecs.push(every); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); - } else { - var triggerSpec = {trigger: trigger}; - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - triggerSpec.eventFilter = eventFilter; - } - while (tokens.length > 0 && tokens[0] !== ",") { - consumeUntil(tokens, NOT_WHITESPACE) - var token = tokens.shift(); - if (token === "changed") { - triggerSpec.changed = true; - } else if (token === "once") { - triggerSpec.once = true; - } else if (token === "consume") { - triggerSpec.consume = true; - } else if (token === "delay" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "from" && tokens[0] === ":") { - tokens.shift(); - if (COMBINED_SELECTOR_START.test(tokens[0])) { - var from_arg = consumeCSSSelector(tokens); - } else { - var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); - if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") { - tokens.shift(); - var selector = consumeCSSSelector(tokens); - // `next` and `previous` allow a selector-less syntax - if (selector.length > 0) { - from_arg += " " + selector; - } - } - } - triggerSpec.from = from_arg; - } else if (token === "target" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.target = consumeCSSSelector(tokens); - } else if (token === "throttle" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "queue" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if (token === "root" && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeCSSSelector(tokens); - } else if (token === "threshold" && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - } - triggerSpecs.push(triggerSpec); - } - } - if (tokens.length === initialLength) { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - consumeUntil(tokens, NOT_WHITESPACE); - } while (tokens[0] === "," && tokens.shift()) - if (cache) { - cache[explicitTrigger] = triggerSpecs - } - return triggerSpecs - } - - /** - * @param {HTMLElement} elt - * @returns {import("./htmx").HtmxTriggerSpecification[]} - */ - function getTriggerSpecs(elt) { - var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); - var triggerSpecs = []; - if (explicitTrigger) { - var cache = htmx.config.triggerSpecsCache - triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) - } - - if (triggerSpecs.length > 0) { - return triggerSpecs; - } else if (matches(elt, 'form')) { - return [{trigger: 'submit'}]; - } else if (matches(elt, 'input[type="button"], input[type="submit"]')){ - return [{trigger: 'click'}]; - } else if (matches(elt, INPUT_SELECTOR)) { - return [{trigger: 'change'}]; - } else { - return [{trigger: 'click'}]; - } - } - - function cancelPolling(elt) { - getInternalData(elt).cancelled = true; - } - - function processPolling(elt, handler, spec) { - var nodeData = getInternalData(elt); - nodeData.timeout = setTimeout(function () { - if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { - triggerSpec: spec, - target: elt - }))) { - handler(elt); - } - processPolling(elt, handler, spec); - } - }, spec.pollInterval); - } - - function isLocalLink(elt) { - return location.hostname === elt.hostname && - getRawAttribute(elt,'href') && - getRawAttribute(elt,'href').indexOf("#") !== 0; - } - - function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || 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"; - if (verb === "get") { - } - path = getRawAttribute(elt, 'action'); - } - triggerSpecs.forEach(function(triggerSpec) { - addEventListener(elt, function(elt, evt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return - } - issueAjaxRequest(verb, path, elt, evt) - }, nodeData, triggerSpec, true); - }); - } - } - - /** - * - * @param {Event} evt - * @param {HTMLElement} elt - * @returns - */ - function shouldCancel(evt, elt) { - if (evt.type === "submit" || evt.type === "click") { - if (elt.tagName === "FORM") { - return true; - } - if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { - return true; - } - if (elt.tagName === "A" && elt.href && - (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) { - return true; - } - } - return false; - } - - function ignoreBoostedAnchorCtrlClick(elt, evt) { - return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); - } - - function maybeFilterEvent(triggerSpec, elt, evt) { - var eventFilter = triggerSpec.eventFilter; - if(eventFilter){ - try { - return eventFilter.call(elt, evt) !== true; - } catch(e) { - triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); - return true; - } - } - return false; - } - - function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { - var elementData = getInternalData(elt); - var eltsToListenOn; - if (triggerSpec.from) { - eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); - } else { - eltsToListenOn = [elt]; - } - // store the initial values of the elements, so we can tell if they change - if (triggerSpec.changed) { - eltsToListenOn.forEach(function (eltToListenOn) { - var eltToListenOnData = getInternalData(eltToListenOn); - eltToListenOnData.lastValue = eltToListenOn.value; - }) - } - forEach(eltsToListenOn, function (eltToListenOn) { - var eventListener = function (evt) { - if (!bodyContains(elt)) { - eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); - return; - } - if (ignoreBoostedAnchorCtrlClick(elt, evt)) { - return; - } - if (explicitCancel || shouldCancel(evt, elt)) { - evt.preventDefault(); - } - if (maybeFilterEvent(triggerSpec, elt, evt)) { - return; - } - var eventData = getInternalData(evt); - eventData.triggerSpec = triggerSpec; - if (eventData.handledFor == null) { - eventData.handledFor = []; - } - if (eventData.handledFor.indexOf(elt) < 0) { - eventData.handledFor.push(elt); - if (triggerSpec.consume) { - evt.stopPropagation(); - } - if (triggerSpec.target && evt.target) { - if (!matches(evt.target, triggerSpec.target)) { - return; - } - } - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } - } - if (triggerSpec.changed) { - var eltToListenOnData = getInternalData(eltToListenOn) - if (eltToListenOnData.lastValue === eltToListenOn.value) { - return; - } - eltToListenOnData.lastValue = eltToListenOn.value - } - if (elementData.delayed) { - clearTimeout(elementData.delayed); - } - if (elementData.throttle) { - return; - } - - if (triggerSpec.throttle > 0) { - if (!elementData.throttle) { - handler(elt, evt); - elementData.throttle = setTimeout(function () { - elementData.throttle = null; - }, triggerSpec.throttle); - } - } else if (triggerSpec.delay > 0) { - elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); - } else { - triggerEvent(elt, 'htmx:trigger') - handler(elt, evt); - } - } - }; - if (nodeData.listenerInfos == null) { - nodeData.listenerInfos = []; - } - nodeData.listenerInfos.push({ - trigger: triggerSpec.trigger, - listener: eventListener, - on: eltToListenOn - }) - eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); - }); - } - - var windowIsScrolling = false // used by initScrollHandler - var scrollHandler = null; - function initScrollHandler() { - if (!scrollHandler) { - scrollHandler = function() { - windowIsScrolling = true - }; - window.addEventListener("scroll", scrollHandler) - setInterval(function() { - if (windowIsScrolling) { - windowIsScrolling = false; - forEach(getDocument().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"), function (elt) { - maybeReveal(elt); - }) - } - }, 200); - } - } - - function maybeReveal(elt) { - if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { - elt.setAttribute('data-hx-revealed', 'true'); - var nodeData = getInternalData(elt); - if (nodeData.initHash) { - triggerEvent(elt, 'revealed'); - } else { - // if the node isn't initialized, wait for it before triggering the request - elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true}); - } - } - } - - //==================================================================== - // Web Sockets - //==================================================================== - - function processWebSocketInfo(elt, nodeData, info) { - var values = splitOnWhitespace(info); - for (var i = 0; i < values.length; i++) { - var value = values[i].split(/:(.+)/); - if (value[0] === "connect") { - ensureWebSocket(elt, value[1], 0); - } - if (value[0] === "send") { - processWebSocketSend(elt); - } - } - } - - function ensureWebSocket(elt, wssSource, retryCount) { - if (!bodyContains(elt)) { - return; // stop ensuring websocket connection when socket bearing element ceases to exist - } - - if (wssSource.indexOf("/") == 0) { // complete absolute paths only - var base_part = location.hostname + (location.port ? ':'+location.port: ''); - if (location.protocol == 'https:') { - wssSource = "wss://" + base_part + wssSource; - } else if (location.protocol == 'http:') { - wssSource = "ws://" + base_part + wssSource; - } - } - var socket = htmx.createWebSocket(wssSource); - socket.onerror = function (e) { - triggerErrorEvent(elt, "htmx:wsError", {error:e, socket:socket}); - maybeCloseWebSocketSource(elt); - }; - - socket.onclose = function (e) { - if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later - var delay = getWebSocketReconnectDelay(retryCount); - setTimeout(function() { - ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout - }, delay); - } - }; - socket.onopen = function (e) { - retryCount = 0; - } - - getInternalData(elt).webSocket = socket; - socket.addEventListener('message', function (event) { - if (maybeCloseWebSocketSource(elt)) { - return; - } - - var response = event.data; - withExtensions(elt, function(extension){ - response = extension.transformResponse(response, null, elt); - }); - - var settleInfo = makeSettleInfo(elt); - var fragment = makeFragment(response); - var children = toArray(fragment.children); - for (var i = 0; i < children.length; i++) { - var child = children[i]; - oobSwap(getAttributeValue(child, "hx-swap-oob") || "true", child, settleInfo); - } - - settleImmediately(settleInfo.tasks); - }); - } - - function maybeCloseWebSocketSource(elt) { - if (!bodyContains(elt)) { - getInternalData(elt).webSocket.close(); - return true; - } - } - - function processWebSocketSend(elt) { - var webSocketSourceElt = getClosestMatch(elt, function (parent) { - return getInternalData(parent).webSocket != null; - }); - if (webSocketSourceElt) { - elt.addEventListener(getTriggerSpecs(elt)[0].trigger, function (evt) { - var webSocket = getInternalData(webSocketSourceElt).webSocket; - var headers = getHeaders(elt, webSocketSourceElt); - var results = getInputValues(elt, 'post'); - var errors = results.errors; - var rawParameters = results.values; - var expressionVars = getExpressionVars(elt); - var allParameters = mergeObjects(rawParameters, expressionVars); - var filteredParameters = filterValues(allParameters, elt); - filteredParameters['HEADERS'] = headers; - if (errors && errors.length > 0) { - triggerEvent(elt, 'htmx:validation:halted', errors); - return; - } - webSocket.send(JSON.stringify(filteredParameters)); - if(shouldCancel(evt, elt)){ - evt.preventDefault(); - } - }); - } else { - triggerErrorEvent(elt, "htmx:noWebSocketSourceError"); - } - } - - function getWebSocketReconnectDelay(retryCount) { - var delay = htmx.config.wsReconnectDelay; - if (typeof delay === 'function') { - // @ts-ignore - return delay(retryCount); - } - if (delay === 'full-jitter') { - var exp = Math.min(retryCount, 6); - var maxDelay = 1000 * Math.pow(2, exp); - return maxDelay * Math.random(); - } - logError('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"'); - } - - //==================================================================== - // Server Sent Events - //==================================================================== - - function processSSEInfo(elt, nodeData, info) { - var values = splitOnWhitespace(info); - for (var i = 0; i < values.length; i++) { - var value = values[i].split(/:(.+)/); - if (value[0] === "connect") { - processSSESource(elt, value[1]); - } - - if ((value[0] === "swap")) { - processSSESwap(elt, value[1]) - } - } - } - - function processSSESource(elt, sseSrc) { - var source = htmx.createEventSource(sseSrc); - source.onerror = function (e) { - triggerErrorEvent(elt, "htmx:sseError", {error:e, source:source}); - maybeCloseSSESource(elt); - }; - getInternalData(elt).sseEventSource = source; - } - - function processSSESwap(elt, sseEventName) { - var sseSourceElt = getClosestMatch(elt, hasEventSource); - if (sseSourceElt) { - var sseEventSource = getInternalData(sseSourceElt).sseEventSource; - var sseListener = function (event) { - if (maybeCloseSSESource(sseSourceElt)) { - return; - } - if (!bodyContains(elt)) { - sseEventSource.removeEventListener(sseEventName, sseListener); - return; - } - - /////////////////////////// - // TODO: merge this code with AJAX and WebSockets code in the future. - - var response = event.data; - withExtensions(elt, function(extension){ - response = extension.transformResponse(response, null, elt); - }); - - var swapSpec = getSwapSpecification(elt) - var target = getTarget(elt) - var settleInfo = makeSettleInfo(elt); - - selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) - settleImmediately(settleInfo.tasks) - triggerEvent(elt, "htmx:sseMessage", event) - }; - - getInternalData(elt).sseListener = sseListener; - sseEventSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "htmx:noSSESourceError"); - } - } - - function processSSETrigger(elt, handler, sseEventName) { - var sseSourceElt = getClosestMatch(elt, hasEventSource); - if (sseSourceElt) { - var sseEventSource = getInternalData(sseSourceElt).sseEventSource; - var sseListener = function () { - if (!maybeCloseSSESource(sseSourceElt)) { - if (bodyContains(elt)) { - handler(elt); - } else { - sseEventSource.removeEventListener(sseEventName, sseListener); - } - } - }; - getInternalData(elt).sseListener = sseListener; - sseEventSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "htmx:noSSESourceError"); - } - } - - function maybeCloseSSESource(elt) { - if (!bodyContains(elt)) { - getInternalData(elt).sseEventSource.close(); - return true; - } - } - - function hasEventSource(node) { - return getInternalData(node).sseEventSource != null; - } - - //==================================================================== - - function loadImmediately(elt, handler, nodeData, delay) { - var load = function(){ - if (!nodeData.loaded) { - nodeData.loaded = true; - handler(elt); - } - } - if (delay > 0) { - setTimeout(load, delay); - } else { - load(); - } - } - - function processVerbs(elt, nodeData, triggerSpecs) { - var explicitAction = false; - forEach(VERBS, function (verb) { - if (hasAttribute(elt,'hx-' + verb)) { - var path = getAttributeValue(elt, 'hx-' + verb); - explicitAction = true; - nodeData.path = path; - nodeData.verb = verb; - triggerSpecs.forEach(function(triggerSpec) { - addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return - } - issueAjaxRequest(verb, path, elt, evt) - }) - }); - } - }); - return explicitAction; - } - - function addTriggerHandler(elt, triggerSpec, nodeData, handler) { - if (triggerSpec.sseEvent) { - processSSETrigger(elt, handler, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - addEventListener(elt, handler, nodeData, triggerSpec); - maybeReveal(elt); - } else if (triggerSpec.trigger === "intersect") { - var observerOptions = {}; - if (triggerSpec.root) { - observerOptions.root = querySelectorExt(elt, triggerSpec.root) - } - if (triggerSpec.threshold) { - observerOptions.threshold = parseFloat(triggerSpec.threshold); - } - var observer = new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - if (entry.isIntersecting) { - triggerEvent(elt, "intersect"); - break; - } - } - }, observerOptions); - observer.observe(elt); - addEventListener(elt, handler, nodeData, triggerSpec); - } else if (triggerSpec.trigger === "load") { - if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { - loadImmediately(elt, handler, nodeData, triggerSpec.delay); - } - } else if (triggerSpec.pollInterval > 0) { - nodeData.polling = true; - processPolling(elt, handler, triggerSpec); - } else { - addEventListener(elt, handler, nodeData, triggerSpec); - } - } - - function evalScript(script) { - if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) { - var newScript = getDocument().createElement("script"); - forEach(script.attributes, function (attr) { - newScript.setAttribute(attr.name, attr.value); - }); - newScript.textContent = script.textContent; - newScript.async = false; - if (htmx.config.inlineScriptNonce) { - newScript.nonce = htmx.config.inlineScriptNonce; - } - var parent = script.parentElement; - - try { - parent.insertBefore(newScript, script); - } catch (e) { - logError(e); - } finally { - // remove old script element, but only if it is still in DOM - if (script.parentElement) { - script.parentElement.removeChild(script); - } - } - } - } - - function processScripts(elt) { - if (matches(elt, "script")) { - evalScript(elt); - } - forEach(findAll(elt, "script"), function (script) { - evalScript(script); - }); - } - - function shouldProcessHxOn(elt) { - var attributes = elt.attributes - for (var j = 0; j < attributes.length; j++) { - var attrName = attributes[j].name - if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") || - startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) { - return true - } - } - return false - } - - function findHxOnWildcardElements(elt) { - var node = null - var elements = [] - - if (shouldProcessHxOn(elt)) { - elements.push(elt) - } - - if (document.evaluate) { - var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + - ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt) - while (node = iter.iterateNext()) elements.push(node) - } else { - var allElements = elt.getElementsByTagName("*") - for (var i = 0; i < allElements.length; i++) { - if (shouldProcessHxOn(allElements[i])) { - elements.push(allElements[i]) - } - } - } - - return elements - } - - function findElementsToProcess(elt) { - if (elt.querySelectorAll) { - var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; - var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]"); - return results; - } else { - return []; - } - } - - // Handle submit buttons/inputs that have the form attribute set - // see https://developer.mozilla.org/docs/Web/HTML/Element/button - function maybeSetLastButtonClicked(evt) { - var elt = closest(evt.target, "button, input[type='submit']"); - var internalData = getRelatedFormData(evt) - if (internalData) { - internalData.lastButtonClicked = elt; - } - }; - function maybeUnsetLastButtonClicked(evt){ - var internalData = getRelatedFormData(evt) - if (internalData) { - internalData.lastButtonClicked = null; - } - } - function getRelatedFormData(evt) { - var elt = closest(evt.target, "button, input[type='submit']"); - if (!elt) { - return; - } - var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form'); - if (!form) { - return; - } - return getInternalData(form); - } - function initButtonTracking(elt) { - // need to handle both click and focus in: - // focusin - in case someone tabs in to a button and hits the space bar - // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 - elt.addEventListener('click', maybeSetLastButtonClicked) - elt.addEventListener('focusin', maybeSetLastButtonClicked) - elt.addEventListener('focusout', maybeUnsetLastButtonClicked) - } - - function countCurlies(line) { - var tokens = tokenizeString(line); - var netCurlies = 0; - for (var i = 0; i < tokens.length; i++) { - const token = tokens[i]; - if (token === "{") { - netCurlies++; - } else if (token === "}") { - netCurlies--; - } - } - return netCurlies; - } - - function addHxOnEventHandler(elt, eventName, code) { - var nodeData = getInternalData(elt); - if (!Array.isArray(nodeData.onHandlers)) { - nodeData.onHandlers = []; - } - var func; - var listener = function (e) { - return maybeEval(elt, function() { - if (!func) { - func = new Function("event", code); - } - func.call(elt, e); - }); - }; - elt.addEventListener(eventName, listener); - nodeData.onHandlers.push({event:eventName, listener:listener}); - } - - function processHxOn(elt) { - var hxOnValue = getAttributeValue(elt, 'hx-on'); - if (hxOnValue) { - var handlers = {} - var lines = hxOnValue.split("\n"); - var currentEvent = null; - var curlyCount = 0; - while (lines.length > 0) { - var line = lines.shift(); - var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/); - if (curlyCount === 0 && match) { - line.split(":") - currentEvent = match[1].slice(0, -1); // strip last colon - handlers[currentEvent] = match[2]; - } else { - handlers[currentEvent] += line; - } - curlyCount += countCurlies(line); - } - - for (var eventName in handlers) { - addHxOnEventHandler(elt, eventName, handlers[eventName]); - } - } - } - - function processHxOnWildcard(elt) { - // wipe any previous on handlers so that this function takes precedence - deInitOnHandlers(elt) - - for (var i = 0; i < elt.attributes.length; i++) { - var name = elt.attributes[i].name - var value = elt.attributes[i].value - if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) { - var afterOnPosition = name.indexOf("-on") + 3; - var nextChar = name.slice(afterOnPosition, afterOnPosition + 1); - if (nextChar === "-" || nextChar === ":") { - var eventName = name.slice(afterOnPosition + 1); - // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support - if (startsWith(eventName, ":")) { - eventName = "htmx" + eventName - } else if (startsWith(eventName, "-")) { - eventName = "htmx:" + eventName.slice(1); - } else if (startsWith(eventName, "htmx-")) { - eventName = "htmx:" + eventName.slice(5); - } - - addHxOnEventHandler(elt, eventName, value) - } - } - } - } - - function initNode(elt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return; - } - var nodeData = getInternalData(elt); - if (nodeData.initHash !== attributeHash(elt)) { - // clean up any previously processed info - deInitNode(elt); - - nodeData.initHash = attributeHash(elt); - - processHxOn(elt); - - triggerEvent(elt, "htmx:beforeProcessNode") - - if (elt.value) { - nodeData.lastValue = elt.value; - } - - var triggerSpecs = getTriggerSpecs(elt); - var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs); - - if (!hasExplicitHttpAction) { - if (getClosestAttributeValue(elt, "hx-boost") === "true") { - boostElement(elt, nodeData, triggerSpecs); - } else if (hasAttribute(elt, 'hx-trigger')) { - triggerSpecs.forEach(function (triggerSpec) { - // For "naked" triggers, don't do anything at all - addTriggerHandler(elt, triggerSpec, nodeData, function () { - }) - }) - } - } - - // Handle submit buttons/inputs that have the form attribute set - // see https://developer.mozilla.org/docs/Web/HTML/Element/button - if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) { - initButtonTracking(elt) - } - - var sseInfo = getAttributeValue(elt, 'hx-sse'); - if (sseInfo) { - processSSEInfo(elt, nodeData, sseInfo); - } - - var wsInfo = getAttributeValue(elt, 'hx-ws'); - if (wsInfo) { - processWebSocketInfo(elt, nodeData, wsInfo); - } - triggerEvent(elt, "htmx:afterProcessNode"); - } - } - - function processNode(elt) { - elt = resolveTarget(elt); - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return; - } - initNode(elt); - forEach(findElementsToProcess(elt), function(child) { initNode(child) }); - // Because it happens second, the new way of adding onHandlers superseeds the old one - // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored - forEach(findHxOnWildcardElements(elt), processHxOnWildcard); - } - - //==================================================================== - // Event/Log Support - //==================================================================== - - function kebabEventName(str) { - return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase(); - } - - 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({error:eventName}, detail)); - } - - function ignoreEventForLogging(eventName) { - return eventName === "htmx:afterProcessNode" - } - - /** - * `withExtensions` locates all active extensions for a provided element, then - * executes the provided function using each of the active extensions. It should - * be called internally at every extendable execution point in htmx. - * - * @param {HTMLElement} elt - * @param {(extension:import("./htmx").HtmxExtension) => void} toDo - * @returns void - */ - function withExtensions(elt, toDo) { - forEach(getExtensions(elt), function(extension){ - try { - toDo(extension); - } catch (e) { - logError(e); - } - }); - } - - function logError(msg) { - if(console.error) { - console.error(msg); - } else if (console.log) { - console.log("ERROR: ", msg); - } - } - - function triggerEvent(elt, eventName, detail) { - elt = resolveTarget(elt); - if (detail == null) { - detail = {}; - } - detail["elt"] = elt; - var event = makeEvent(eventName, detail); - if (htmx.logger && !ignoreEventForLogging(eventName)) { - htmx.logger(elt, eventName, detail); - } - if (detail.error) { - logError(detail.error); - triggerEvent(elt, "htmx:error", {errorInfo:detail}) - } - var eventResult = elt.dispatchEvent(event); - var kebabName = kebabEventName(eventName); - if (eventResult && kebabName !== eventName) { - var kebabedEvent = makeEvent(kebabName, event.detail); - eventResult = eventResult && elt.dispatchEvent(kebabedEvent) - } - withExtensions(elt, function (extension) { - eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) - }); - return eventResult; - } - - //==================================================================== - // History Support - //==================================================================== - var currentPathForHistory = location.pathname+location.search; - - function getHistoryElement() { - var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]'); - return historyElt || getDocument().body; - } - - function saveToHistoryCache(url, content, title, scroll) { - if (!canAccessLocalStorage()) { - return; - } - - if (htmx.config.historyCacheSize <= 0) { - // make sure that an eventually already existing cache is purged - localStorage.removeItem("htmx-history-cache"); - return; - } - - url = normalizePath(url); - - var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - historyCache.splice(i, 1); - break; - } - } - var newHistoryItem = {url:url, content: content, title:title, scroll:scroll}; - triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache}) - historyCache.push(newHistoryItem) - while (historyCache.length > htmx.config.historyCacheSize) { - historyCache.shift(); - } - while(historyCache.length > 0){ - try { - localStorage.setItem("htmx-history-cache", JSON.stringify(historyCache)); - break; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:historyCacheError", {cause:e, cache: historyCache}) - historyCache.shift(); // shrink the cache and retry - } - } - } - - function getCachedHistory(url) { - if (!canAccessLocalStorage()) { - return null; - } - - url = normalizePath(url); - - var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - return historyCache[i]; - } - } - return null; - } - - function cleanInnerHtmlForHistory(elt) { - var className = htmx.config.requestClass; - var clone = elt.cloneNode(true); - forEach(findAll(clone, "." + className), function(child){ - removeClassFromElement(child, className); - }); - return clone.innerHTML; - } - - function saveCurrentPageToHistory() { - var elt = getHistoryElement(); - var path = currentPathForHistory || location.pathname+location.search; - - // Allow history snapshot feature to be disabled where hx-history="false" - // is present *anywhere* in the current document we're about to save, - // so we can prevent privileged data entering the cache. - // The page will still be reachable as a history entry, but htmx will fetch it - // live from the server onpopstate rather than look in the localStorage cache - var disableHistoryCache - try { - disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') - } catch (e) { - // IE11: insensitive modifier not supported so fallback to case sensitive selector - disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') - } - if (!disableHistoryCache) { - triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt}); - saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); - } - - if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href); - } - - function pushUrlIntoHistory(path) { - // remove the cache buster parameter, if any - if (htmx.config.getCacheBusterParam) { - path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') - if (endsWith(path, '&') || endsWith(path, "?")) { - path = path.slice(0, -1); - } - } - if(htmx.config.historyEnabled) { - history.pushState({htmx:true}, "", path); - } - currentPathForHistory = path; - } - - function replaceUrlInHistory(path) { - if(htmx.config.historyEnabled) history.replaceState({htmx:true}, "", path); - currentPathForHistory = path; - } - - function settleImmediately(tasks) { - forEach(tasks, function (task) { - task.call(); - }); - } - - function loadHistoryFromServer(path) { - var request = new XMLHttpRequest(); - var details = {path: path, xhr:request}; - triggerEvent(getDocument().body, "htmx:historyCacheMiss", details); - request.open('GET', path, true); - request.setRequestHeader("HX-Request", "true"); - request.setRequestHeader("HX-History-Restore-Request", "true"); - request.setRequestHeader("HX-Current-URL", getDocument().location.href); - request.onload = function () { - if (this.status >= 200 && this.status < 400) { - triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); - var fragment = makeFragment(this.response); - // @ts-ignore - fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; - var historyElement = getHistoryElement(); - var settleInfo = makeSettleInfo(historyElement); - var title = findTitle(this.response); - if (title) { - var titleElt = find("title"); - if (titleElt) { - titleElt.innerHTML = title; - } else { - window.document.title = title; - } - } - // @ts-ignore - swapInnerHTML(historyElement, fragment, settleInfo) - settleImmediately(settleInfo.tasks); - currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response}); - } else { - triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details); - } - }; - request.send(); - } - - function restoreHistory(path) { - saveCurrentPageToHistory(); - path = path || location.pathname+location.search; - var cached = getCachedHistory(path); - if (cached) { - var fragment = makeFragment(cached.content); - var historyElement = getHistoryElement(); - var settleInfo = makeSettleInfo(historyElement); - swapInnerHTML(historyElement, fragment, settleInfo) - settleImmediately(settleInfo.tasks); - document.title = cached.title; - setTimeout(function () { - window.scrollTo(0, cached.scroll); - }, 0); // next 'tick', so browser has time to render layout - currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); - } else { - if (htmx.config.refreshOnHistoryMiss) { - - // @ts-ignore: optional parameter in reload() function throws error - window.location.reload(true); - } else { - loadHistoryFromServer(path); - } - } - } - - function addRequestIndicatorClasses(elt) { - var indicators = findAttributeTargets(elt, 'hx-indicator'); - if (indicators == null) { - indicators = [elt]; - } - forEach(indicators, function (ic) { - var internalData = getInternalData(ic); - internalData.requestCount = (internalData.requestCount || 0) + 1; - ic.classList["add"].call(ic.classList, htmx.config.requestClass); - }); - return indicators; - } - - function disableElements(elt) { - var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt'); - if (disabledElts == null) { - disabledElts = []; - } - forEach(disabledElts, function (disabledElement) { - var internalData = getInternalData(disabledElement); - internalData.requestCount = (internalData.requestCount || 0) + 1; - disabledElement.setAttribute("disabled", ""); - }); - return disabledElts; - } - - function removeRequestIndicators(indicators, disabled) { - forEach(indicators, function (ic) { - var internalData = getInternalData(ic); - internalData.requestCount = (internalData.requestCount || 0) - 1; - if (internalData.requestCount === 0) { - ic.classList["remove"].call(ic.classList, htmx.config.requestClass); - } - }); - forEach(disabled, function (disabledElement) { - var internalData = getInternalData(disabledElement); - internalData.requestCount = (internalData.requestCount || 0) - 1; - if (internalData.requestCount === 0) { - disabledElement.removeAttribute('disabled'); - } - }); - } - - //==================================================================== - // 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 || closest(elt, "fieldset[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 addValueToValues(name, value, values) { - // This is a little ugly because both the current value of the named value in the form - // and the new value could be arrays, so we have to handle all four cases :/ - if (name != null && value != null) { - var current = values[name]; - if (current === undefined) { - values[name] = value; - } else if (Array.isArray(current)) { - if (Array.isArray(value)) { - values[name] = current.concat(value); - } else { - current.push(value); - } - } else { - if (Array.isArray(value)) { - values[name] = [current].concat(value); - } else { - values[name] = [current, value]; - } - } - } - } - - function processInputValue(processed, values, errors, elt, validate) { - if (elt == null || haveSeenNode(processed, elt)) { - return; - } else { - processed.push(elt); - } - if (shouldInclude(elt)) { - var name = getRawAttribute(elt,"name"); - var value = elt.value; - if (elt.multiple && elt.tagName === "SELECT") { - value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value }); - } - // include file inputs - if (elt.files) { - value = toArray(elt.files); - } - addValueToValues(name, value, values); - if (validate) { - validateElement(elt, errors); - } - } - if (matches(elt, 'form')) { - var inputs = elt.elements; - forEach(inputs, function(input) { - processInputValue(processed, values, errors, input, validate); - }); - } - } - - function validateElement(element, errors) { - if (element.willValidate) { - triggerEvent(element, "htmx:validation:validate") - if (!element.checkValidity()) { - errors.push({elt: element, message:element.validationMessage, validity:element.validity}); - triggerEvent(element, "htmx:validation:failed", {message:element.validationMessage, validity:element.validity}) - } - } - } - - /** - * @param {HTMLElement} elt - * @param {string} verb - */ - function getInputValues(elt, verb) { - var processed = []; - var values = {}; - var formValues = {}; - var errors = []; - var internalData = getInternalData(elt); - if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { - internalData.lastButtonClicked = null - } - - // only validate when form is directly submitted and novalidate or formnovalidate are not set - // or if the element has an explicit hx-validate="true" on it - var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true"; - if (internalData.lastButtonClicked) { - validate = validate && internalData.lastButtonClicked.formNoValidate !== true; - } - - // for a non-GET include the closest form - if (verb !== 'get') { - processInputValue(processed, formValues, errors, closest(elt, 'form'), validate); - } - - // include the element itself - processInputValue(processed, values, errors, elt, validate); - - // if a button or submit was clicked last, include its value - if (internalData.lastButtonClicked || elt.tagName === "BUTTON" || - (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) { - var button = internalData.lastButtonClicked || elt - var name = getRawAttribute(button, "name") - addValueToValues(name, button.value, formValues) - } - - // include any explicit includes - var includes = findAttributeTargets(elt, "hx-include"); - forEach(includes, function(node) { - processInputValue(processed, values, errors, node, validate); - // if a non-form is included, include any input values within it - if (!matches(node, 'form')) { - forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { - processInputValue(processed, values, errors, descendant, validate); - }) - } - }); - - // form values take precedence, overriding the regular values - values = mergeObjects(values, formValues); - - return {errors:errors, values:values}; - } - - function appendParam(returnStr, name, realValue) { - if (returnStr !== "") { - returnStr += "&"; - } - if (String(realValue) === "[object Object]") { - realValue = JSON.stringify(realValue); - } - var s = encodeURIComponent(realValue); - returnStr += encodeURIComponent(name) + "=" + s; - 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; - } - - function makeFormData(values) { - var formData = new FormData(); - for (var name in values) { - if (values.hasOwnProperty(name)) { - var value = values[name]; - if (Array.isArray(value)) { - forEach(value, function(v) { - formData.append(name, v); - }); - } else { - formData.append(name, value); - } - } - } - return formData; - } - - //==================================================================== - // Ajax - //==================================================================== - - /** - * @param {HTMLElement} elt - * @param {HTMLElement} target - * @param {string} prompt - * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification - */ - function getHeaders(elt, target, prompt) { - var headers = { - "HX-Request" : "true", - "HX-Trigger" : getRawAttribute(elt, "id"), - "HX-Trigger-Name" : getRawAttribute(elt, "name"), - "HX-Target" : getAttributeValue(target, "id"), - "HX-Current-URL" : getDocument().location.href, - } - getValuesForElement(elt, "hx-headers", false, headers) - if (prompt !== undefined) { - headers["HX-Prompt"] = prompt; - } - if (getInternalData(elt).boosted) { - headers["HX-Boosted"] = "true"; - } - return headers; - } - - /** - * filterValues takes an object containing form input values - * and returns a new object that only contains keys that are - * specified by the closest "hx-params" attribute - * @param {Object} inputValues - * @param {HTMLElement} elt - * @returns {Object} - */ - function filterValues(inputValues, elt) { - var paramsValue = getClosestAttributeValue(elt, "hx-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 isAnchorLink(elt) { - return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0 - } - - /** - * - * @param {HTMLElement} elt - * @param {string} swapInfoOverride - * @returns {import("./htmx").HtmxSwapSpecification} - */ - function getSwapSpecification(elt, swapInfoOverride) { - var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap"); - var swapSpec = { - "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, - "swapDelay" : htmx.config.defaultSwapDelay, - "settleDelay" : htmx.config.defaultSettleDelay - } - if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { - swapSpec["show"] = "top" - } - if (swapInfo) { - var split = splitOnWhitespace(swapInfo); - if (split.length > 0) { - for (var i = 0; i < split.length; i++) { - var value = split[i]; - if (value.indexOf("swap:") === 0) { - swapSpec["swapDelay"] = parseInterval(value.substr(5)); - } else if (value.indexOf("settle:") === 0) { - swapSpec["settleDelay"] = parseInterval(value.substr(7)); - } else if (value.indexOf("transition:") === 0) { - swapSpec["transition"] = value.substr(11) === "true"; - } else if (value.indexOf("ignoreTitle:") === 0) { - swapSpec["ignoreTitle"] = value.substr(12) === "true"; - } else if (value.indexOf("scroll:") === 0) { - var scrollSpec = value.substr(7); - var splitSpec = scrollSpec.split(":"); - var scrollVal = splitSpec.pop(); - var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; - swapSpec["scroll"] = scrollVal; - swapSpec["scrollTarget"] = selectorVal; - } else if (value.indexOf("show:") === 0) { - var showSpec = value.substr(5); - var splitSpec = showSpec.split(":"); - var showVal = splitSpec.pop(); - var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; - swapSpec["show"] = showVal; - swapSpec["showTarget"] = selectorVal; - } else if (value.indexOf("focus-scroll:") === 0) { - var focusScrollVal = value.substr("focus-scroll:".length); - swapSpec["focusScroll"] = focusScrollVal == "true"; - } else if (i == 0) { - swapSpec["swapStyle"] = value; - } else { - logError('Unknown modifier in hx-swap: ' + value); - } - } - } - } - return swapSpec; - } - - function usesFormData(elt) { - return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || - (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data"); - } - - function encodeParamsForBody(xhr, elt, filteredParameters) { - var encodedParameters = null; - withExtensions(elt, function (extension) { - if (encodedParameters == null) { - encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt); - } - }); - if (encodedParameters != null) { - return encodedParameters; - } else { - if (usesFormData(elt)) { - return makeFormData(filteredParameters); - } else { - return urlEncode(filteredParameters); - } - } - } - - /** - * - * @param {Element} target - * @returns {import("./htmx").HtmxSettleInfo} - */ - function makeSettleInfo(target) { - return {tasks: [], elts: [target]}; - } - - function updateScrollState(content, swapSpec) { - var first = content[0]; - var last = content[content.length - 1]; - if (swapSpec.scroll) { - var target = null; - if (swapSpec.scrollTarget) { - target = querySelectorExt(first, swapSpec.scrollTarget); - } - if (swapSpec.scroll === "top" && (first || target)) { - target = target || first; - target.scrollTop = 0; - } - if (swapSpec.scroll === "bottom" && (last || target)) { - target = target || last; - target.scrollTop = target.scrollHeight; - } - } - if (swapSpec.show) { - var target = null; - if (swapSpec.showTarget) { - var targetStr = swapSpec.showTarget; - if (swapSpec.showTarget === "window") { - targetStr = "body"; - } - target = querySelectorExt(first, targetStr); - } - if (swapSpec.show === "top" && (first || target)) { - target = target || first; - target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior}); - } - if (swapSpec.show === "bottom" && (last || target)) { - target = target || last; - target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior}); - } - } - } - - /** - * @param {HTMLElement} elt - * @param {string} attr - * @param {boolean=} evalAsDefault - * @param {Object=} values - * @returns {Object} - */ - function getValuesForElement(elt, attr, evalAsDefault, values) { - if (values == null) { - values = {}; - } - if (elt == null) { - return values; - } - var attributeValue = getAttributeValue(elt, attr); - if (attributeValue) { - var str = attributeValue.trim(); - var evaluateValue = evalAsDefault; - if (str === "unset") { - return null; - } - if (str.indexOf("javascript:") === 0) { - str = str.substr(11); - evaluateValue = true; - } else if (str.indexOf("js:") === 0) { - str = str.substr(3); - evaluateValue = true; - } - if (str.indexOf('{') !== 0) { - str = "{" + str + "}"; - } - var varsValues; - if (evaluateValue) { - varsValues = maybeEval(elt,function () {return Function("return (" + str + ")")();}, {}); - } else { - varsValues = parseJSON(str); - } - for (var key in varsValues) { - if (varsValues.hasOwnProperty(key)) { - if (values[key] == null) { - values[key] = varsValues[key]; - } - } - } - } - return getValuesForElement(parentElt(elt), attr, evalAsDefault, values); - } - - function maybeEval(elt, toEval, defaultVal) { - if (htmx.config.allowEval) { - return toEval(); - } else { - triggerErrorEvent(elt, 'htmx:evalDisallowedError'); - return defaultVal; - } - } - - /** - * @param {HTMLElement} elt - * @param {*} expressionVars - * @returns - */ - function getHXVarsForElement(elt, expressionVars) { - return getValuesForElement(elt, "hx-vars", true, expressionVars); - } - - /** - * @param {HTMLElement} elt - * @param {*} expressionVars - * @returns - */ - function getHXValsForElement(elt, expressionVars) { - return getValuesForElement(elt, "hx-vals", false, expressionVars); - } - - /** - * @param {HTMLElement} elt - * @returns {Object} - */ - function getExpressionVars(elt) { - return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)); - } - - function safelySetHeaderValue(xhr, header, headerValue) { - if (headerValue !== null) { - try { - xhr.setRequestHeader(header, headerValue); - } catch (e) { - // On an exception, try to set the header URI encoded instead - xhr.setRequestHeader(header, encodeURIComponent(headerValue)); - xhr.setRequestHeader(header + "-URI-AutoEncoded", "true"); - } - } - } - - function getPathFromResponse(xhr) { - // NB: IE11 does not support this stuff - if (xhr.responseURL && typeof(URL) !== "undefined") { - try { - var url = new URL(xhr.responseURL); - return url.pathname + url.search; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:badResponseUrl", {url: xhr.responseURL}); - } - } - } - - function hasHeader(xhr, regexp) { - return regexp.test(xhr.getAllResponseHeaders()) - } - - function ajaxHelper(verb, path, context) { - verb = verb.toLowerCase(); - if (context) { - if (context instanceof Element || isType(context, 'String')) { - return issueAjaxRequest(verb, path, null, null, { - targetOverride: resolveTarget(context), - returnPromise: true - }); - } else { - return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, - { - handler : context.handler, - headers : context.headers, - values : context.values, - targetOverride: resolveTarget(context.target), - swapOverride: context.swap, - select: context.select, - returnPromise: true - }); - } - } else { - return issueAjaxRequest(verb, path, null, null, { - returnPromise: true - }); - } - } - - function hierarchyForElt(elt) { - var arr = []; - while (elt) { - arr.push(elt); - elt = elt.parentElement; - } - return arr; - } - - function verifyPath(elt, path, requestConfig) { - var sameHost - var url - if (typeof URL === "function") { - url = new URL(path, document.location.href); - var origin = document.location.origin; - sameHost = origin === url.origin; - } else { - // IE11 doesn't support URL - url = path - sameHost = startsWith(path, document.location.origin) - } - - if (htmx.config.selfRequestsOnly) { - if (!sameHost) { - return false; - } - } - return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig)); - } - - function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { - var resolve = null; - var reject = null; - etc = etc != null ? etc : {}; - if(etc.returnPromise && typeof Promise !== "undefined"){ - var promise = new Promise(function (_resolve, _reject) { - resolve = _resolve; - reject = _reject; - }); - } - if(elt == null) { - elt = getDocument().body; - } - var responseHandler = etc.handler || handleAjaxResponse; - var select = etc.select || null; - - if (!bodyContains(elt)) { - // do not issue requests for elements removed from the DOM - maybeCall(resolve); - return promise; - } - var target = etc.targetOverride || getTarget(elt); - if (target == null || target == DUMMY_ELT) { - triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); - maybeCall(reject); - return promise; - } - - var eltData = getInternalData(elt); - var submitter = eltData.lastButtonClicked; - - if (submitter) { - var buttonPath = getRawAttribute(submitter, "formaction"); - if (buttonPath != null) { - path = buttonPath; - } - - var buttonVerb = getRawAttribute(submitter, "formmethod") - if (buttonVerb != null) { - // ignore buttons with formmethod="dialog" - if (buttonVerb.toLowerCase() !== "dialog") { - verb = buttonVerb; - } - } - } - - var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); - // allow event-based confirmation w/ a callback - if (confirmed === undefined) { - var issueRequest = function(skipConfirmation) { - return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation); - } - var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion}; - if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { - maybeCall(resolve); - return promise; - } - } - - var syncElt = elt; - var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); - var queueStrategy = null; - var abortable = false; - if (syncStrategy) { - var syncStrings = syncStrategy.split(":"); - var selector = syncStrings[0].trim(); - if (selector === "this") { - syncElt = findThisElement(elt, 'hx-sync'); - } else { - syncElt = querySelectorExt(elt, selector); - } - // default to the drop strategy - syncStrategy = (syncStrings[1] || 'drop').trim(); - eltData = getInternalData(syncElt); - if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { - maybeCall(resolve); - return promise; - } else if (syncStrategy === "abort") { - if (eltData.xhr) { - maybeCall(resolve); - return promise; - } else { - abortable = true; - } - } else if (syncStrategy === "replace") { - triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue - } else if (syncStrategy.indexOf("queue") === 0) { - var queueStrArray = syncStrategy.split(" "); - queueStrategy = (queueStrArray[1] || "last").trim(); - } - } - - if (eltData.xhr) { - if (eltData.abortable) { - triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue - } else { - if(queueStrategy == null){ - if (event) { - var eventData = getInternalData(event); - if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { - queueStrategy = eventData.triggerSpec.queue; - } - } - if (queueStrategy == null) { - queueStrategy = "last"; - } - } - if (eltData.queuedRequests == null) { - eltData.queuedRequests = []; - } - if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } else if (queueStrategy === "all") { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } else if (queueStrategy === "last") { - eltData.queuedRequests = []; // dump existing queue - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } - maybeCall(resolve); - return promise; - } - } - - var xhr = new XMLHttpRequest(); - eltData.xhr = xhr; - eltData.abortable = abortable; - var endRequestLock = function(){ - eltData.xhr = null; - eltData.abortable = false; - if (eltData.queuedRequests != null && - eltData.queuedRequests.length > 0) { - var queuedRequest = eltData.queuedRequests.shift(); - queuedRequest(); - } - } - var promptQuestion = getClosestAttributeValue(elt, "hx-prompt"); - if (promptQuestion) { - var promptResponse = prompt(promptQuestion); - // prompt returns null if cancelled and empty string if accepted with no entry - if (promptResponse === null || - !triggerEvent(elt, 'htmx:prompt', {prompt: promptResponse, target:target})) { - maybeCall(resolve); - endRequestLock(); - return promise; - } + triggerErrorEvent(getDocument().body, 'htmx:syntax:error', { error: e, source: conditionalSource }) + return null } + } + } else if (token === '[') { + bracketCount++ + } + if (isPossibleRelativeReference(token, last, paramName)) { + conditionalSource += '((' + paramName + '.' + token + ') ? (' + paramName + '.' + token + ') : (window.' + token + '))' + } else { + conditionalSource = conditionalSource + token + } + last = tokens.shift() + } + } + } + + /** + * @param {string[]} tokens + * @param {RegExp} match + * @returns {string} + */ + function consumeUntil(tokens, match) { + let result = '' + while (tokens.length > 0 && !match.test(tokens[0])) { + result += tokens.shift() + } + return result + } + + /** + * @param {string[]} tokens + * @returns {string} + */ + function consumeCSSSelector(tokens) { + let result + if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { + tokens.shift() + result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim() + tokens.shift() + } else { + result = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } + return result + } + + const INPUT_SELECTOR = 'input, textarea, select' + + /** + * @param {Element} elt + * @param {string} explicitTrigger + * @param {Object} cache for trigger specs + * @returns {HtmxTriggerSpecification[]} + */ + function parseAndCacheTrigger(elt, explicitTrigger, cache) { + /** @type HtmxTriggerSpecification[] */ + const triggerSpecs = [] + const tokens = tokenizeString(explicitTrigger) + do { + consumeUntil(tokens, NOT_WHITESPACE) + const initialLength = tokens.length + const trigger = consumeUntil(tokens, /[,\[\s]/) + if (trigger !== '') { + if (trigger === 'every') { + /** @type HtmxTriggerSpecification */ + const every = { trigger: 'every' } + consumeUntil(tokens, NOT_WHITESPACE) + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)) + consumeUntil(tokens, NOT_WHITESPACE) + var eventFilter = maybeGenerateConditional(elt, tokens, 'event') + if (eventFilter) { + every.eventFilter = eventFilter + } + triggerSpecs.push(every) + } else { + /** @type HtmxTriggerSpecification */ + const triggerSpec = { trigger } + var eventFilter = maybeGenerateConditional(elt, tokens, 'event') + if (eventFilter) { + triggerSpec.eventFilter = eventFilter + } + while (tokens.length > 0 && tokens[0] !== ',') { + consumeUntil(tokens, NOT_WHITESPACE) + const token = tokens.shift() + if (token === 'changed') { + triggerSpec.changed = true + } else if (token === 'once') { + triggerSpec.once = true + } else if (token === 'consume') { + triggerSpec.consume = true + } else if (token === 'delay' && tokens[0] === ':') { + tokens.shift() + triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)) + } else if (token === 'from' && tokens[0] === ':') { + tokens.shift() + if (COMBINED_SELECTOR_START.test(tokens[0])) { + var from_arg = consumeCSSSelector(tokens) + } else { + var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA) + if (from_arg === 'closest' || from_arg === 'find' || from_arg === 'next' || from_arg === 'previous') { + tokens.shift() + const selector = consumeCSSSelector(tokens) + // `next` and `previous` allow a selector-less syntax + if (selector.length > 0) { + from_arg += ' ' + selector + } + } + } + triggerSpec.from = from_arg + } else if (token === 'target' && tokens[0] === ':') { + tokens.shift() + triggerSpec.target = consumeCSSSelector(tokens) + } else if (token === 'throttle' && tokens[0] === ':') { + tokens.shift() + triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)) + } else if (token === 'queue' && tokens[0] === ':') { + tokens.shift() + triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } else if (token === 'root' && tokens[0] === ':') { + tokens.shift() + triggerSpec[token] = consumeCSSSelector(tokens) + } else if (token === 'threshold' && tokens[0] === ':') { + tokens.shift() + triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } else { + triggerErrorEvent(elt, 'htmx:syntax:error', { token: tokens.shift() }) + } + } + triggerSpecs.push(triggerSpec) + } + } + if (tokens.length === initialLength) { + triggerErrorEvent(elt, 'htmx:syntax:error', { token: tokens.shift() }) + } + consumeUntil(tokens, NOT_WHITESPACE) + } while (tokens[0] === ',' && tokens.shift()) + if (cache) { + cache[explicitTrigger] = triggerSpecs + } + return triggerSpecs + } + + /** + * @param {Element} elt + * @returns {HtmxTriggerSpecification[]} + */ + function getTriggerSpecs(elt) { + const explicitTrigger = getAttributeValue(elt, 'hx-trigger') + let triggerSpecs = [] + if (explicitTrigger) { + const cache = htmx.config.triggerSpecsCache + triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) + } - if (confirmQuestion && !confirmed) { - if(!confirm(confirmQuestion)) { - maybeCall(resolve); - endRequestLock() - return promise; - } + if (triggerSpecs.length > 0) { + return triggerSpecs + } else if (matches(elt, 'form')) { + return [{ trigger: 'submit' }] + } else if (matches(elt, 'input[type="button"], input[type="submit"]')) { + return [{ trigger: 'click' }] + } else if (matches(elt, INPUT_SELECTOR)) { + return [{ trigger: 'change' }] + } else { + return [{ trigger: 'click' }] + } + } + + /** + * @param {Element} elt + */ + function cancelPolling(elt) { + getInternalData(elt).cancelled = true + } + + /** + * @param {Element} elt + * @param {TriggerHandler} handler + * @param {HtmxTriggerSpecification} spec + */ + function processPolling(elt, handler, spec) { + const nodeData = getInternalData(elt) + nodeData.timeout = getWindow().setTimeout(function() { + if (bodyContains(elt) && nodeData.cancelled !== true) { + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { + handler(elt) + } + processPolling(elt, handler, spec) + } + }, spec.pollInterval) + } + + /** + * @param {HTMLAnchorElement} elt + * @returns {boolean} + */ + function isLocalLink(elt) { + return location.hostname === elt.hostname && + getRawAttribute(elt, 'href') && + getRawAttribute(elt, 'href').indexOf('#') !== 0 + } + + /** + * @param {Element} elt + */ + function eltIsDisabled(elt) { + return closest(elt, htmx.config.disableSelector) + } + + /** + * @param {Element} elt + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification[]} triggerSpecs + */ + function boostElement(elt, nodeData, triggerSpecs) { + if ((elt instanceof HTMLAnchorElement && isLocalLink(elt) && (elt.target === '' || elt.target === '_self')) || elt.tagName === 'FORM') { + nodeData.boosted = true + let verb, path + if (elt.tagName === 'A') { + verb = 'get' + path = getRawAttribute(elt, 'href') + } else { + const rawAttribute = getRawAttribute(elt, 'method') + verb = rawAttribute ? rawAttribute.toLowerCase() : 'get' + if (verb === 'get') { + } + path = getRawAttribute(elt, 'action') + } + triggerSpecs.forEach(function(triggerSpec) { + addEventListener(elt, function(node, evt) { + const elt = asElement(node) + if (eltIsDisabled(elt)) { + cleanUpElement(elt) + return + } + issueAjaxRequest(verb, path, elt, evt) + }, nodeData, triggerSpec, true) + }) + } + } + + /** + * @param {Event} evt + * @param {Node} node + * @returns {boolean} + */ + function shouldCancel(evt, node) { + const elt = asElement(node) + if (!elt) { + return false + } + if (evt.type === 'submit' || evt.type === 'click') { + if (elt.tagName === 'FORM') { + return true + } + if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { + return true + } + if (elt instanceof HTMLAnchorElement && elt.href && + (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf('#') !== 0)) { + return true + } + } + return false + } + + /** + * @param {Node} elt + * @param {Event|MouseEvent|KeyboardEvent|TouchEvent} evt + * @returns {boolean} + */ + function ignoreBoostedAnchorCtrlClick(elt, evt) { + return getInternalData(elt).boosted && elt instanceof HTMLAnchorElement && evt.type === 'click' && + // @ts-ignore this will resolve to undefined for events that don't define those properties, which is fine + (evt.ctrlKey || evt.metaKey) + } + + /** + * @param {HtmxTriggerSpecification} triggerSpec + * @param {Node} elt + * @param {Event} evt + * @returns {boolean} + */ + function maybeFilterEvent(triggerSpec, elt, evt) { + const eventFilter = triggerSpec.eventFilter + if (eventFilter) { + try { + return eventFilter.call(elt, evt) !== true + } catch (e) { + const source = eventFilter.source + triggerErrorEvent(getDocument().body, 'htmx:eventFilter:error', { error: e, source }) + return true + } + } + return false + } + + /** + * @param {Node} elt + * @param {TriggerHandler} handler + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification} triggerSpec + * @param {boolean} [explicitCancel] + */ + function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { + const elementData = getInternalData(elt) + /** @type {(Node|Window)[]} */ + let eltsToListenOn + if (triggerSpec.from) { + eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from) + } else { + eltsToListenOn = [elt] + } + // store the initial values of the elements, so we can tell if they change + if (triggerSpec.changed) { + eltsToListenOn.forEach(function(eltToListenOn) { + const eltToListenOnData = getInternalData(eltToListenOn) + // @ts-ignore value will be undefined for non-input elements, which is fine + eltToListenOnData.lastValue = eltToListenOn.value + }) + } + forEach(eltsToListenOn, function(eltToListenOn) { + /** @type EventListener */ + const eventListener = function(evt) { + if (!bodyContains(elt)) { + eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener) + return + } + if (ignoreBoostedAnchorCtrlClick(elt, evt)) { + return + } + if (explicitCancel || shouldCancel(evt, elt)) { + evt.preventDefault() + } + if (maybeFilterEvent(triggerSpec, elt, evt)) { + return + } + const eventData = getInternalData(evt) + eventData.triggerSpec = triggerSpec + if (eventData.handledFor == null) { + eventData.handledFor = [] + } + if (eventData.handledFor.indexOf(elt) < 0) { + eventData.handledFor.push(elt) + if (triggerSpec.consume) { + evt.stopPropagation() + } + if (triggerSpec.target && evt.target) { + if (!matches(asElement(evt.target), triggerSpec.target)) { + return + } + } + if (triggerSpec.once) { + if (elementData.triggeredOnce) { + return + } else { + elementData.triggeredOnce = true + } + } + if (triggerSpec.changed) { + const eltToListenOnData = getInternalData(eltToListenOn) + // @ts-ignore value will be undefined for non-input elements, which is fine + const value = eltToListenOn.value + if (eltToListenOnData.lastValue === value) { + return + } + eltToListenOnData.lastValue = value + } + if (elementData.delayed) { + clearTimeout(elementData.delayed) + } + if (elementData.throttle) { + return + } + + if (triggerSpec.throttle > 0) { + if (!elementData.throttle) { + handler(elt, evt) + elementData.throttle = getWindow().setTimeout(function() { + elementData.throttle = null + }, triggerSpec.throttle) + } + } else if (triggerSpec.delay > 0) { + elementData.delayed = getWindow().setTimeout(function() { handler(elt, evt) }, triggerSpec.delay) + } else { + triggerEvent(elt, 'htmx:trigger') + handler(elt, evt) + } + } + } + if (nodeData.listenerInfos == null) { + nodeData.listenerInfos = [] + } + nodeData.listenerInfos.push({ + trigger: triggerSpec.trigger, + listener: eventListener, + on: eltToListenOn + }) + eltToListenOn.addEventListener(triggerSpec.trigger, eventListener) + }) + } + + let windowIsScrolling = false // used by initScrollHandler + let scrollHandler = null + function initScrollHandler() { + if (!scrollHandler) { + scrollHandler = function() { + windowIsScrolling = true + } + window.addEventListener('scroll', scrollHandler) + setInterval(function() { + if (windowIsScrolling) { + windowIsScrolling = false + forEach(getDocument().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"), function(elt) { + maybeReveal(elt) + }) + } + }, 200) + } + } + + /** + * @param {Element} elt + */ + function maybeReveal(elt) { + if (!hasAttribute(elt, 'data-hx-revealed') && isScrolledIntoView(elt)) { + elt.setAttribute('data-hx-revealed', 'true') + const nodeData = getInternalData(elt) + if (nodeData.initHash) { + triggerEvent(elt, 'revealed') + } else { + // if the node isn't initialized, wait for it before triggering the request + elt.addEventListener('htmx:afterProcessNode', function() { triggerEvent(elt, 'revealed') }, { once: true }) + } + } + } + + //= =================================================================== + + /** + * @param {Element} elt + * @param {TriggerHandler} handler + * @param {HtmxNodeInternalData} nodeData + * @param {number} delay + */ + function loadImmediately(elt, handler, nodeData, delay) { + const load = function() { + if (!nodeData.loaded) { + nodeData.loaded = true + handler(elt) + } + } + if (delay > 0) { + getWindow().setTimeout(load, delay) + } else { + load() + } + } + + /** + * @param {Element} elt + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification[]} triggerSpecs + * @returns {boolean} + */ + function processVerbs(elt, nodeData, triggerSpecs) { + let explicitAction = false + forEach(VERBS, function(verb) { + if (hasAttribute(elt, 'hx-' + verb)) { + const path = getAttributeValue(elt, 'hx-' + verb) + explicitAction = true + nodeData.path = path + nodeData.verb = verb + triggerSpecs.forEach(function(triggerSpec) { + addTriggerHandler(elt, triggerSpec, nodeData, function(node, evt) { + const elt = asElement(node) + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return } + issueAjaxRequest(verb, path, elt, evt) + }) + }) + } + }) + return explicitAction + } + + /** + * @callback TriggerHandler + * @param {Node} elt + * @param {Event} [evt] + */ + + /** + * @param {Node} elt + * @param {HtmxTriggerSpecification} triggerSpec + * @param {HtmxNodeInternalData} nodeData + * @param {TriggerHandler} handler + */ + function addTriggerHandler(elt, triggerSpec, nodeData, handler) { + if (triggerSpec.trigger === 'revealed') { + initScrollHandler() + addEventListener(elt, handler, nodeData, triggerSpec) + maybeReveal(asElement(elt)) + } else if (triggerSpec.trigger === 'intersect') { + const observerOptions = {} + if (triggerSpec.root) { + observerOptions.root = querySelectorExt(elt, triggerSpec.root) + } + if (triggerSpec.threshold) { + observerOptions.threshold = parseFloat(triggerSpec.threshold) + } + const observer = new IntersectionObserver(function(entries) { + for (let i = 0; i < entries.length; i++) { + const entry = entries[i] + if (entry.isIntersecting) { + triggerEvent(elt, 'intersect') + break + } + } + }, observerOptions) + observer.observe(asElement(elt)) + addEventListener(asElement(elt), handler, nodeData, triggerSpec) + } else if (triggerSpec.trigger === 'load') { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent('load', { elt }))) { + loadImmediately(asElement(elt), handler, nodeData, triggerSpec.delay) + } + } else if (triggerSpec.pollInterval > 0) { + nodeData.polling = true + processPolling(asElement(elt), handler, triggerSpec) + } else { + addEventListener(elt, handler, nodeData, triggerSpec) + } + } + + /** + * @param {Node} node + * @returns {boolean} + */ + function shouldProcessHxOn(node) { + const elt = asElement(node) + if (!elt) { + return false + } + const attributes = elt.attributes + for (let j = 0; j < attributes.length; j++) { + const attrName = attributes[j].name + if (startsWith(attrName, 'hx-on:') || startsWith(attrName, 'data-hx-on:') || + startsWith(attrName, 'hx-on-') || startsWith(attrName, 'data-hx-on-')) { + return true + } + } + return false + } + + /** + * @param {Node} elt + * @returns {Element[]} + */ + const HX_ON_QUERY = new XPathEvaluator() + .createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + + ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]') + + function processHXOnRoot(elt, elements) { + if (shouldProcessHxOn(elt)) { + elements.push(asElement(elt)) + } + const iter = HX_ON_QUERY.evaluate(elt) + let node = null + while (node = iter.iterateNext()) elements.push(asElement(node)) + } + + function findHxOnWildcardElements(elt) { + /** @type {Element[]} */ + const elements = [] + if (elt instanceof DocumentFragment) { + for (const child of elt.childNodes) { + processHXOnRoot(child, elements) + } + } else { + processHXOnRoot(elt, elements) + } + return elements + } + + /** + * @param {Element} elt + * @returns {NodeListOf<Element>|[]} + */ + function findElementsToProcess(elt) { + if (elt.querySelectorAll) { + const boostedSelector = ', [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]' + + const extensionSelectors = [] + for (const e in extensions) { + const extension = extensions[e] + if (extension.getSelectors) { + var selectors = extension.getSelectors() + if (selectors) { + extensionSelectors.push(selectors) + } + } + } + + const results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit']," + + ' [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]' + extensionSelectors.flat().map(s => ', ' + s).join('')) + + return results + } else { + return [] + } + } + + /** + * Handle submit buttons/inputs that have the form attribute set + * see https://developer.mozilla.org/docs/Web/HTML/Element/button + * @param {Event} evt + */ + function maybeSetLastButtonClicked(evt) { + const elt = /** @type {HTMLButtonElement|HTMLInputElement} */ (closest(asElement(evt.target), "button, input[type='submit']")) + const internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = elt + } + } + + /** + * @param {Event} evt + */ + function maybeUnsetLastButtonClicked(evt) { + const internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = null + } + } + + /** + * @param {Event} evt + * @returns {HtmxNodeInternalData|undefined} + */ + function getRelatedFormData(evt) { + const elt = closest(asElement(evt.target), "button, input[type='submit']") + if (!elt) { + return + } + const form = resolveTarget('#' + getRawAttribute(elt, 'form'), elt.getRootNode()) || closest(elt, 'form') + if (!form) { + return + } + return getInternalData(form) + } + + /** + * @param {EventTarget} elt + */ + function initButtonTracking(elt) { + // need to handle both click and focus in: + // focusin - in case someone tabs in to a button and hits the space bar + // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + elt.addEventListener('click', maybeSetLastButtonClicked) + elt.addEventListener('focusin', maybeSetLastButtonClicked) + elt.addEventListener('focusout', maybeUnsetLastButtonClicked) + } + + /** + * @param {Element} elt + * @param {string} eventName + * @param {string} code + */ + function addHxOnEventHandler(elt, eventName, code) { + const nodeData = getInternalData(elt) + if (!Array.isArray(nodeData.onHandlers)) { + nodeData.onHandlers = [] + } + let func + /** @type EventListener */ + const listener = function(e) { + maybeEval(elt, function() { + if (eltIsDisabled(elt)) { + return + } + if (!func) { + func = new Function('event', code) + } + func.call(elt, e) + }) + } + elt.addEventListener(eventName, listener) + nodeData.onHandlers.push({ event: eventName, listener }) + } + + /** + * @param {Element} elt + */ + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (let i = 0; i < elt.attributes.length; i++) { + const name = elt.attributes[i].name + const value = elt.attributes[i].value + if (startsWith(name, 'hx-on') || startsWith(name, 'data-hx-on')) { + const afterOnPosition = name.indexOf('-on') + 3 + const nextChar = name.slice(afterOnPosition, afterOnPosition + 1) + if (nextChar === '-' || nextChar === ':') { + let eventName = name.slice(afterOnPosition + 1) + // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support + if (startsWith(eventName, ':')) { + eventName = 'htmx' + eventName + } else if (startsWith(eventName, '-')) { + eventName = 'htmx:' + eventName.slice(1) + } else if (startsWith(eventName, 'htmx-')) { + eventName = 'htmx:' + eventName.slice(5) + } + + addHxOnEventHandler(elt, eventName, value) + } + } + } + } + + /** + * @param {Element|HTMLInputElement} elt + */ + function initNode(elt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + const nodeData = getInternalData(elt) + if (nodeData.initHash !== attributeHash(elt)) { + // clean up any previously processed info + deInitNode(elt) + + nodeData.initHash = attributeHash(elt) + + triggerEvent(elt, 'htmx:beforeProcessNode') + + // @ts-ignore value will be undefined for non-input elements, which is fine + if (elt.value) { + // @ts-ignore + nodeData.lastValue = elt.value + } + + const triggerSpecs = getTriggerSpecs(elt) + const hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs) + + if (!hasExplicitHttpAction) { + if (getClosestAttributeValue(elt, 'hx-boost') === 'true') { + boostElement(elt, nodeData, triggerSpecs) + } else if (hasAttribute(elt, 'hx-trigger')) { + triggerSpecs.forEach(function(triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function() { + }) + }) + } + } + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + if (elt.tagName === 'FORM' || (getRawAttribute(elt, 'type') === 'submit' && hasAttribute(elt, 'form'))) { + initButtonTracking(elt) + } - var headers = getHeaders(elt, target, promptResponse); - - if (verb !== 'get' && !usesFormData(elt)) { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; - } + triggerEvent(elt, 'htmx:afterProcessNode') + } + } + + /** + * Processes new content, enabling htmx behavior. This can be useful if you have content that is added to the DOM outside of the normal htmx request cycle but still want htmx attributes to work. + * + * @see https://htmx.org/api/#process + * + * @param {Element|string} elt element to process + */ + function processNode(elt) { + elt = resolveTarget(elt) + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + initNode(elt) + forEach(findElementsToProcess(elt), function(child) { initNode(child) }) + forEach(findHxOnWildcardElements(elt), processHxOnWildcard) + } + + //= =================================================================== + // Event/Log Support + //= =================================================================== + + /** + * @param {string} str + * @returns {string} + */ + function kebabEventName(str) { + return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase() + } + + /** + * @param {string} eventName + * @param {any} detail + * @returns {CustomEvent} + */ + function makeEvent(eventName, detail) { + let evt + if (window.CustomEvent && typeof window.CustomEvent === 'function') { + // TODO: `composed: true` here is a hack to make global event handlers work with events in shadow DOM + // This breaks expected encapsulation but needs to be here until decided otherwise by core devs + evt = new CustomEvent(eventName, { bubbles: true, cancelable: true, composed: true, detail }) + } else { + evt = getDocument().createEvent('CustomEvent') + evt.initCustomEvent(eventName, true, true, detail) + } + return evt + } + + /** + * @param {EventTarget|string} elt + * @param {string} eventName + * @param {any=} detail + */ + function triggerErrorEvent(elt, eventName, detail) { + triggerEvent(elt, eventName, mergeObjects({ error: eventName }, detail)) + } + + /** + * @param {string} eventName + * @returns {boolean} + */ + function ignoreEventForLogging(eventName) { + return eventName === 'htmx:afterProcessNode' + } + + /** + * `withExtensions` locates all active extensions for a provided element, then + * executes the provided function using each of the active extensions. It should + * be called internally at every extendable execution point in htmx. + * + * @param {Element} elt + * @param {(extension:HtmxExtension) => void} toDo + * @returns void + */ + function withExtensions(elt, toDo) { + forEach(getExtensions(elt), function(extension) { + try { + toDo(extension) + } catch (e) { + logError(e) + } + }) + } + + function logError(msg) { + if (console.error) { + console.error(msg) + } else if (console.log) { + console.log('ERROR: ', msg) + } + } + + /** + * Triggers a given event on an element + * + * @see https://htmx.org/api/#trigger + * + * @param {EventTarget|string} elt the element to trigger the event on + * @param {string} eventName the name of the event to trigger + * @param {any=} detail details for the event + * @returns {boolean} + */ + function triggerEvent(elt, eventName, detail) { + elt = resolveTarget(elt) + if (detail == null) { + detail = {} + } + detail.elt = elt + const event = makeEvent(eventName, detail) + if (htmx.logger && !ignoreEventForLogging(eventName)) { + htmx.logger(elt, eventName, detail) + } + if (detail.error) { + logError(detail.error) + triggerEvent(elt, 'htmx:error', { errorInfo: detail }) + } + let eventResult = elt.dispatchEvent(event) + const kebabName = kebabEventName(eventName) + if (eventResult && kebabName !== eventName) { + const kebabedEvent = makeEvent(kebabName, event.detail) + eventResult = eventResult && elt.dispatchEvent(kebabedEvent) + } + withExtensions(asElement(elt), function(extension) { + eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) + }) + return eventResult + } + + //= =================================================================== + // History Support + //= =================================================================== + let currentPathForHistory = location.pathname + location.search + + /** + * @returns {Element} + */ + function getHistoryElement() { + const historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]') + return historyElt || getDocument().body + } + + /** + * @param {string} url + * @param {Element} rootElt + */ + function saveToHistoryCache(url, rootElt) { + if (!canAccessLocalStorage()) { + return + } - if (etc.headers) { - headers = mergeObjects(headers, etc.headers); - } - var results = getInputValues(elt, verb); - var errors = results.errors; - var rawParameters = results.values; - if (etc.values) { - rawParameters = mergeObjects(rawParameters, etc.values); - } - var expressionVars = getExpressionVars(elt); - var allParameters = mergeObjects(rawParameters, expressionVars); - var filteredParameters = filterValues(allParameters, elt); + // get state to save + const innerHTML = cleanInnerHtmlForHistory(rootElt) + const title = getDocument().title + const scroll = window.scrollY - if (htmx.config.getCacheBusterParam && verb === 'get') { - filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true"; - } + if (htmx.config.historyCacheSize <= 0) { + // make sure that an eventually already existing cache is purged + localStorage.removeItem('htmx-history-cache') + return + } - // behavior of anchors w/ empty href is to use the current URL - if (path == null || path === "") { - path = getDocument().location.href; - } + url = normalizePath(url) + const historyCache = parseJSON(localStorage.getItem('htmx-history-cache')) || [] + for (let i = 0; i < historyCache.length; i++) { + if (historyCache[i].url === url) { + historyCache.splice(i, 1) + break + } + } - var requestAttrValues = getValuesForElement(elt, 'hx-request'); + /** @type HtmxHistoryItem */ + const newHistoryItem = { url, content: innerHTML, title, scroll } - var eltIsBoosted = getInternalData(elt).boosted; + triggerEvent(getDocument().body, 'htmx:historyItemCreated', { item: newHistoryItem, cache: historyCache }) - var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + historyCache.push(newHistoryItem) + while (historyCache.length > htmx.config.historyCacheSize) { + historyCache.shift() + } - var requestConfig = { - boosted: eltIsBoosted, - useUrlParams: useUrlParams, - parameters: filteredParameters, - unfilteredParameters: allParameters, - headers:headers, - target:target, - verb:verb, - errors:errors, - withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, - timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, - path:path, - triggeringEvent:event - }; + // keep trying to save the cache until it succeeds or is empty + while (historyCache.length > 0) { + try { + localStorage.setItem('htmx-history-cache', JSON.stringify(historyCache)) + break + } catch (e) { + triggerErrorEvent(getDocument().body, 'htmx:historyCacheError', { cause: e, cache: historyCache }) + historyCache.shift() // shrink the cache and retry + } + } + } + + /** + * @typedef {Object} HtmxHistoryItem + * @property {string} url + * @property {string} content + * @property {string} title + * @property {number} scroll + */ + + /** + * @param {string} url + * @returns {HtmxHistoryItem|null} + */ + function getCachedHistory(url) { + if (!canAccessLocalStorage()) { + return null + } - if(!triggerEvent(elt, 'htmx:configRequest', requestConfig)){ - maybeCall(resolve); - endRequestLock(); - return promise; - } + url = normalizePath(url) - // copy out in case the object was overwritten - path = requestConfig.path; - verb = requestConfig.verb; - headers = requestConfig.headers; - filteredParameters = requestConfig.parameters; - errors = requestConfig.errors; - useUrlParams = requestConfig.useUrlParams; - - if(errors && errors.length > 0){ - triggerEvent(elt, 'htmx:validation:halted', requestConfig) - maybeCall(resolve); - endRequestLock(); - return promise; - } + const historyCache = parseJSON(localStorage.getItem('htmx-history-cache')) || [] + for (let i = 0; i < historyCache.length; i++) { + if (historyCache[i].url === url) { + return historyCache[i] + } + } + return null + } + + /** + * @param {Element} elt + * @returns {string} + */ + function cleanInnerHtmlForHistory(elt) { + const className = htmx.config.requestClass + const clone = /** @type Element */ (elt.cloneNode(true)) + forEach(findAll(clone, '.' + className), function(child) { + removeClassFromElement(child, className) + }) + return clone.innerHTML + } + + function saveCurrentPageToHistory() { + const elt = getHistoryElement() + const path = currentPathForHistory || location.pathname + location.search + + // Allow history snapshot feature to be disabled where hx-history="false" + // is present *anywhere* in the current document we're about to save, + // so we can prevent privileged data entering the cache. + // The page will still be reachable as a history entry, but htmx will fetch it + // live from the server onpopstate rather than look in the localStorage cache + let disableHistoryCache + try { + disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') + } catch (e) { + // IE11: insensitive modifier not supported so fallback to case sensitive selector + disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') + } + if (!disableHistoryCache) { + triggerEvent(getDocument().body, 'htmx:beforeHistorySave', { path, historyElt: elt }) + saveToHistoryCache(path, elt) + } - var splitPath = path.split("#"); - var pathNoAnchor = splitPath[0]; - var anchor = splitPath[1]; - - var finalPath = path - if (useUrlParams) { - finalPath = pathNoAnchor; - var values = Object.keys(filteredParameters).length !== 0; - if (values) { - if (finalPath.indexOf("?") < 0) { - finalPath += "?"; - } else { - finalPath += "&"; - } - finalPath += urlEncode(filteredParameters); - if (anchor) { - finalPath += "#" + anchor; - } - } - } + if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, getDocument().title, window.location.href) + } + + /** + * @param {string} path + */ + function pushUrlIntoHistory(path) { + // remove the cache buster parameter, if any + if (htmx.config.getCacheBusterParam) { + path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') + if (endsWith(path, '&') || endsWith(path, '?')) { + path = path.slice(0, -1) + } + } + if (htmx.config.historyEnabled) { + history.pushState({ htmx: true }, '', path) + } + currentPathForHistory = path + } + + /** + * @param {string} path + */ + function replaceUrlInHistory(path) { + if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, '', path) + currentPathForHistory = path + } + + /** + * @param {HtmxSettleTask[]} tasks + */ + function settleImmediately(tasks) { + forEach(tasks, function(task) { + task.call(undefined) + }) + } + + /** + * @param {string} path + */ + function loadHistoryFromServer(path) { + const request = new XMLHttpRequest() + const details = { path, xhr: request } + triggerEvent(getDocument().body, 'htmx:historyCacheMiss', details) + request.open('GET', path, true) + request.setRequestHeader('HX-Request', 'true') + request.setRequestHeader('HX-History-Restore-Request', 'true') + request.setRequestHeader('HX-Current-URL', getDocument().location.href) + request.onload = function() { + if (this.status >= 200 && this.status < 400) { + triggerEvent(getDocument().body, 'htmx:historyCacheMissLoad', details) + const fragment = makeFragment(this.response) + /** @type ParentNode */ + const content = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment + const historyElement = getHistoryElement() + const settleInfo = makeSettleInfo(historyElement) + handleTitle(fragment.title) + + swapInnerHTML(historyElement, content, settleInfo) + settleImmediately(settleInfo.tasks) + currentPathForHistory = path + triggerEvent(getDocument().body, 'htmx:historyRestore', { path, cacheMiss: true, serverResponse: this.response }) + } else { + triggerErrorEvent(getDocument().body, 'htmx:historyCacheMissLoadError', details) + } + } + request.send() + } + + /** + * @param {string} [path] + */ + function restoreHistory(path) { + saveCurrentPageToHistory() + path = path || location.pathname + location.search + const cached = getCachedHistory(path) + if (cached) { + const fragment = makeFragment(cached.content) + const historyElement = getHistoryElement() + const settleInfo = makeSettleInfo(historyElement) + handleTitle(fragment.title) + swapInnerHTML(historyElement, fragment, settleInfo) + settleImmediately(settleInfo.tasks) + getWindow().setTimeout(function() { + window.scrollTo(0, cached.scroll) + }, 0) // next 'tick', so browser has time to render layout + currentPathForHistory = path + triggerEvent(getDocument().body, 'htmx:historyRestore', { path, item: cached }) + } else { + if (htmx.config.refreshOnHistoryMiss) { + // @ts-ignore: optional parameter in reload() function throws error + // noinspection JSUnresolvedReference + window.location.reload(true) + } else { + loadHistoryFromServer(path) + } + } + } + + /** + * @param {Element} elt + * @returns {Element[]} + */ + function addRequestIndicatorClasses(elt) { + let indicators = /** @type Element[] */ (findAttributeTargets(elt, 'hx-indicator')) + if (indicators == null) { + indicators = [elt] + } + forEach(indicators, function(ic) { + const internalData = getInternalData(ic) + internalData.requestCount = (internalData.requestCount || 0) + 1 + ic.classList.add.call(ic.classList, htmx.config.requestClass) + }) + return indicators + } + + /** + * @param {Element} elt + * @returns {Element[]} + */ + function disableElements(elt) { + let disabledElts = /** @type Element[] */ (findAttributeTargets(elt, 'hx-disabled-elt')) + if (disabledElts == null) { + disabledElts = [] + } + forEach(disabledElts, function(disabledElement) { + const internalData = getInternalData(disabledElement) + internalData.requestCount = (internalData.requestCount || 0) + 1 + disabledElement.setAttribute('disabled', '') + }) + return disabledElts + } + + /** + * @param {Element[]} indicators + * @param {Element[]} disabled + */ + function removeRequestIndicators(indicators, disabled) { + forEach(indicators, function(ic) { + const internalData = getInternalData(ic) + internalData.requestCount = (internalData.requestCount || 0) - 1 + if (internalData.requestCount === 0) { + ic.classList.remove.call(ic.classList, htmx.config.requestClass) + } + }) + forEach(disabled, function(disabledElement) { + const internalData = getInternalData(disabledElement) + internalData.requestCount = (internalData.requestCount || 0) - 1 + if (internalData.requestCount === 0) { + disabledElement.removeAttribute('disabled') + } + }) + } + + //= =================================================================== + // Input Value Processing + //= =================================================================== + + /** + * @param {Element[]} processed + * @param {Element} elt + * @returns {boolean} + */ + function haveSeenNode(processed, elt) { + for (let i = 0; i < processed.length; i++) { + const node = processed[i] + if (node.isSameNode(elt)) { + return true + } + } + return false + } + + /** + * @param {Element} element + * @return {boolean} + */ + function shouldInclude(element) { + // Cast to trick tsc, undefined values will work fine here + const elt = /** @type {HTMLInputElement} */ (element) + if (elt.name === '' || elt.name == null || elt.disabled || closest(elt, 'fieldset[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 + } + + /** @param {string} name + * @param {string|Array|FormDataEntryValue} value + * @param {FormData} formData */ + function addValueToFormData(name, value, formData) { + if (name != null && value != null) { + if (Array.isArray(value)) { + value.forEach(function(v) { formData.append(name, v) }) + } else { + formData.append(name, value) + } + } + } + + /** @param {string} name + * @param {string|Array} value + * @param {FormData} formData */ + function removeValueFromFormData(name, value, formData) { + if (name != null && value != null) { + let values = formData.getAll(name) + if (Array.isArray(value)) { + values = values.filter(v => value.indexOf(v) < 0) + } else { + values = values.filter(v => v !== value) + } + formData.delete(name) + forEach(values, v => formData.append(name, v)) + } + } + + /** + * @param {Element[]} processed + * @param {FormData} formData + * @param {HtmxElementValidationError[]} errors + * @param {Element|HTMLInputElement|HTMLSelectElement|HTMLFormElement} elt + * @param {boolean} validate + */ + function processInputValue(processed, formData, errors, elt, validate) { + if (elt == null || haveSeenNode(processed, elt)) { + return + } else { + processed.push(elt) + } + if (shouldInclude(elt)) { + const name = getRawAttribute(elt, 'name') + // @ts-ignore value will be undefined for non-input elements, which is fine + let value = elt.value + if (elt instanceof HTMLSelectElement && elt.multiple) { + value = toArray(elt.querySelectorAll('option:checked')).map(function(e) { return (/** @type HTMLOptionElement */(e)).value }) + } + // include file inputs + if (elt instanceof HTMLInputElement && elt.files) { + value = toArray(elt.files) + } + addValueToFormData(name, value, formData) + if (validate) { + validateElement(elt, errors) + } + } + if (elt instanceof HTMLFormElement) { + forEach(elt.elements, function(input) { + if (processed.indexOf(input) >= 0) { + // The input has already been processed and added to the values, but the FormData that will be + // constructed right after on the form, will include it once again. So remove that input's value + // now to avoid duplicates + removeValueFromFormData(input.name, input.value, formData) + } else { + processed.push(input) + } + if (validate) { + validateElement(input, errors) + } + }) + new FormData(elt).forEach(function(value, name) { + if (value instanceof File && value.name === '') { + return // ignore no-name files + } + addValueToFormData(name, value, formData) + }) + } + } + + /** + * + * @param {Element} elt + * @param {HtmxElementValidationError[]} errors + */ + function validateElement(elt, errors) { + const element = /** @type {HTMLElement & ElementInternals} */ (elt) + if (element.willValidate) { + triggerEvent(element, 'htmx:validation:validate') + if (!element.checkValidity()) { + errors.push({ elt: element, message: element.validationMessage, validity: element.validity }) + triggerEvent(element, 'htmx:validation:failed', { message: element.validationMessage, validity: element.validity }) + } + } + } + + /** + * Override values in the one FormData with those from another. + * @param {FormData} receiver the formdata that will be mutated + * @param {FormData} donor the formdata that will provide the overriding values + * @returns {FormData} the {@linkcode receiver} + */ + function overrideFormData(receiver, donor) { + for (const key of donor.keys()) { + receiver.delete(key) + donor.getAll(key).forEach(function(value) { + receiver.append(key, value) + }) + } + return receiver + } + + /** + * @param {Element|HTMLFormElement} elt + * @param {HttpVerb} verb + * @returns {{errors: HtmxElementValidationError[], formData: FormData, values: Object}} + */ + function getInputValues(elt, verb) { + /** @type Element[] */ + const processed = [] + const formData = new FormData() + const priorityFormData = new FormData() + /** @type HtmxElementValidationError[] */ + const errors = [] + const internalData = getInternalData(elt) + if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { + internalData.lastButtonClicked = null + } - if (!verifyPath(elt, finalPath, requestConfig)) { - triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) - maybeCall(reject); - return promise; - }; + // only validate when form is directly submitted and novalidate or formnovalidate are not set + // or if the element has an explicit hx-validate="true" on it + let validate = (elt instanceof HTMLFormElement && elt.noValidate !== true) || getAttributeValue(elt, 'hx-validate') === 'true' + if (internalData.lastButtonClicked) { + validate = validate && internalData.lastButtonClicked.formNoValidate !== true + } - xhr.open(verb.toUpperCase(), finalPath, true); - xhr.overrideMimeType("text/html"); - xhr.withCredentials = requestConfig.withCredentials; - xhr.timeout = requestConfig.timeout; + // for a non-GET include the closest form + if (verb !== 'get') { + processInputValue(processed, priorityFormData, errors, closest(elt, 'form'), validate) + } - // request headers - if (requestAttrValues.noHeaders) { - // ignore all headers - } else { - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - var headerValue = headers[header]; - safelySetHeaderValue(xhr, header, headerValue); - } - } - } + // include the element itself + processInputValue(processed, formData, errors, elt, validate) - var responseInfo = { - xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select, - pathInfo: { - requestPath: path, - finalRequestPath: finalPath, - anchor: anchor - } - }; - - xhr.onload = function () { - try { - var hierarchy = hierarchyForElt(elt); - responseInfo.pathInfo.responsePath = getPathFromResponse(xhr); - responseHandler(elt, responseInfo); - removeRequestIndicators(indicators, disableElts); - triggerEvent(elt, 'htmx:afterRequest', responseInfo); - triggerEvent(elt, 'htmx:afterOnLoad', responseInfo); - // if the body no longer contains the element, trigger the event on the closest parent - // remaining in the DOM - if (!bodyContains(elt)) { - var secondaryTriggerElt = null; - while (hierarchy.length > 0 && secondaryTriggerElt == null) { - var parentEltInHierarchy = hierarchy.shift(); - if (bodyContains(parentEltInHierarchy)) { - secondaryTriggerElt = parentEltInHierarchy; - } - } - if (secondaryTriggerElt) { - triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo); - triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo); - } - } - maybeCall(resolve); - endRequestLock(); - } catch (e) { - triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({error:e}, responseInfo)); - throw e; - } - } - xhr.onerror = function () { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:sendError', responseInfo); - maybeCall(reject); - endRequestLock(); - } - xhr.onabort = function() { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo); - maybeCall(reject); - endRequestLock(); - } - xhr.ontimeout = function() { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:timeout', responseInfo); - maybeCall(reject); - endRequestLock(); - } - if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){ - maybeCall(resolve); - endRequestLock() - return promise - } - var indicators = addRequestIndicatorClasses(elt); - var disableElts = disableElements(elt); - - forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { - forEach([xhr, xhr.upload], function (target) { - target.addEventListener(eventName, function(event){ - triggerEvent(elt, "htmx:xhr:" + eventName, { - lengthComputable:event.lengthComputable, - loaded:event.loaded, - total:event.total - }); - }) - }); - }); - triggerEvent(elt, 'htmx:beforeSend', responseInfo); - var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) - xhr.send(params); - return promise; - } - - function determineHistoryUpdates(elt, responseInfo) { - - var xhr = responseInfo.xhr; - - //=========================================== - // First consult response headers - //=========================================== - var pathFromHeaders = null; - var typeFromHeaders = null; - if (hasHeader(xhr,/HX-Push:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Push"); - typeFromHeaders = "push"; - } else if (hasHeader(xhr,/HX-Push-Url:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Push-Url"); - typeFromHeaders = "push"; - } else if (hasHeader(xhr,/HX-Replace-Url:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url"); - typeFromHeaders = "replace"; - } + // if a button or submit was clicked last, include its value + if (internalData.lastButtonClicked || elt.tagName === 'BUTTON' || + (elt.tagName === 'INPUT' && getRawAttribute(elt, 'type') === 'submit')) { + const button = internalData.lastButtonClicked || (/** @type HTMLInputElement|HTMLButtonElement */(elt)) + const name = getRawAttribute(button, 'name') + addValueToFormData(name, button.value, priorityFormData) + } - // if there was a response header, that has priority - if (pathFromHeaders) { - if (pathFromHeaders === "false") { - return {} - } else { - return { - type: typeFromHeaders, - path : pathFromHeaders - } - } - } + // include any explicit includes + const includes = findAttributeTargets(elt, 'hx-include') + forEach(includes, function(node) { + processInputValue(processed, formData, errors, asElement(node), validate) + // if a non-form is included, include any input values within it + if (!matches(node, 'form')) { + forEach(asParentNode(node).querySelectorAll(INPUT_SELECTOR), function(descendant) { + processInputValue(processed, formData, errors, descendant, validate) + }) + } + }) + + // values from a <form> take precedence, overriding the regular values + overrideFormData(formData, priorityFormData) + + return { errors, formData, values: formDataProxy(formData) } + } + + /** + * @param {string} returnStr + * @param {string} name + * @param {any} realValue + * @returns {string} + */ + function appendParam(returnStr, name, realValue) { + if (returnStr !== '') { + returnStr += '&' + } + if (String(realValue) === '[object Object]') { + realValue = JSON.stringify(realValue) + } + const s = encodeURIComponent(realValue) + returnStr += encodeURIComponent(name) + '=' + s + return returnStr + } + + /** + * @param {FormData|Object} values + * @returns string + */ + function urlEncode(values) { + values = formDataFromObject(values) + let returnStr = '' + values.forEach(function(value, key) { + returnStr = appendParam(returnStr, key, value) + }) + return returnStr + } + + //= =================================================================== + // Ajax + //= =================================================================== + + /** + * @param {Element} elt + * @param {Element} target + * @param {string} prompt + * @returns {HtmxHeaderSpecification} + */ + function getHeaders(elt, target, prompt) { + /** @type HtmxHeaderSpecification */ + const headers = { + 'HX-Request': 'true', + 'HX-Trigger': getRawAttribute(elt, 'id'), + 'HX-Trigger-Name': getRawAttribute(elt, 'name'), + 'HX-Target': getAttributeValue(target, 'id'), + 'HX-Current-URL': getDocument().location.href + } + getValuesForElement(elt, 'hx-headers', false, headers) + if (prompt !== undefined) { + headers['HX-Prompt'] = prompt + } + if (getInternalData(elt).boosted) { + headers['HX-Boosted'] = 'true' + } + return headers + } + + /** + * filterValues takes an object containing form input values + * and returns a new object that only contains keys that are + * specified by the closest "hx-params" attribute + * @param {FormData} inputValues + * @param {Element} elt + * @returns {FormData} + */ + function filterValues(inputValues, elt) { + const paramsValue = getClosestAttributeValue(elt, 'hx-params') + if (paramsValue) { + if (paramsValue === 'none') { + return new FormData() + } else if (paramsValue === '*') { + return inputValues + } else if (paramsValue.indexOf('not ') === 0) { + forEach(paramsValue.substr(4).split(','), function(name) { + name = name.trim() + inputValues.delete(name) + }) + return inputValues + } else { + const newValues = new FormData() + forEach(paramsValue.split(','), function(name) { + name = name.trim() + if (inputValues.has(name)) { + inputValues.getAll(name).forEach(function(value) { newValues.append(name, value) }) + } + }) + return newValues + } + } else { + return inputValues + } + } + + /** + * @param {Element} elt + * @return {boolean} + */ + function isAnchorLink(elt) { + return !!getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf('#') >= 0 + } + + /** + * @param {Element} elt + * @param {HtmxSwapStyle} [swapInfoOverride] + * @returns {HtmxSwapSpecification} + */ + function getSwapSpecification(elt, swapInfoOverride) { + const swapInfo = swapInfoOverride || getClosestAttributeValue(elt, 'hx-swap') + /** @type HtmxSwapSpecification */ + const swapSpec = { + swapStyle: getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, + swapDelay: htmx.config.defaultSwapDelay, + settleDelay: htmx.config.defaultSettleDelay + } + if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { + swapSpec.show = 'top' + } + if (swapInfo) { + const split = splitOnWhitespace(swapInfo) + if (split.length > 0) { + for (let i = 0; i < split.length; i++) { + const value = split[i] + if (value.indexOf('swap:') === 0) { + swapSpec.swapDelay = parseInterval(value.substr(5)) + } else if (value.indexOf('settle:') === 0) { + swapSpec.settleDelay = parseInterval(value.substr(7)) + } else if (value.indexOf('transition:') === 0) { + swapSpec.transition = value.substr(11) === 'true' + } else if (value.indexOf('ignoreTitle:') === 0) { + swapSpec.ignoreTitle = value.substr(12) === 'true' + } else if (value.indexOf('scroll:') === 0) { + const scrollSpec = value.substr(7) + var splitSpec = scrollSpec.split(':') + const scrollVal = splitSpec.pop() + var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null + // @ts-ignore + swapSpec.scroll = scrollVal + swapSpec.scrollTarget = selectorVal + } else if (value.indexOf('show:') === 0) { + const showSpec = value.substr(5) + var splitSpec = showSpec.split(':') + const showVal = splitSpec.pop() + var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null + swapSpec.show = showVal + swapSpec.showTarget = selectorVal + } else if (value.indexOf('focus-scroll:') === 0) { + const focusScrollVal = value.substr('focus-scroll:'.length) + swapSpec.focusScroll = focusScrollVal == 'true' + } else if (i == 0) { + swapSpec.swapStyle = value + } else { + logError('Unknown modifier in hx-swap: ' + value) + } + } + } + } + return swapSpec + } + + /** + * @param {Element} elt + * @return {boolean} + */ + function usesFormData(elt) { + return getClosestAttributeValue(elt, 'hx-encoding') === 'multipart/form-data' || + (matches(elt, 'form') && getRawAttribute(elt, 'enctype') === 'multipart/form-data') + } + + /** + * @param {XMLHttpRequest} xhr + * @param {Element} elt + * @param {FormData} filteredParameters + * @returns {*|string|null} + */ + function encodeParamsForBody(xhr, elt, filteredParameters) { + let encodedParameters = null + withExtensions(elt, function(extension) { + if (encodedParameters == null) { + encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt) + } + }) + if (encodedParameters != null) { + return encodedParameters + } else { + if (usesFormData(elt)) { + // Force conversion to an actual FormData object in case filteredParameters is a formDataProxy + // See https://github.com/bigskysoftware/htmx/issues/2317 + return overrideFormData(new FormData(), formDataFromObject(filteredParameters)) + } else { + return urlEncode(filteredParameters) + } + } + } + + /** + * + * @param {Element} target + * @returns {HtmxSettleInfo} + */ + function makeSettleInfo(target) { + return { tasks: [], elts: [target] } + } + + /** + * @param {Element[]} content + * @param {HtmxSwapSpecification} swapSpec + */ + function updateScrollState(content, swapSpec) { + const first = content[0] + const last = content[content.length - 1] + if (swapSpec.scroll) { + var target = null + if (swapSpec.scrollTarget) { + target = asElement(querySelectorExt(first, swapSpec.scrollTarget)) + } + if (swapSpec.scroll === 'top' && (first || target)) { + target = target || first + target.scrollTop = 0 + } + if (swapSpec.scroll === 'bottom' && (last || target)) { + target = target || last + target.scrollTop = target.scrollHeight + } + } + if (swapSpec.show) { + var target = null + if (swapSpec.showTarget) { + let targetStr = swapSpec.showTarget + if (swapSpec.showTarget === 'window') { + targetStr = 'body' + } + target = asElement(querySelectorExt(first, targetStr)) + } + if (swapSpec.show === 'top' && (first || target)) { + target = target || first + // @ts-ignore For some reason tsc doesn't recognize "instant" as a valid option for now + target.scrollIntoView({ block: 'start', behavior: htmx.config.scrollBehavior }) + } + if (swapSpec.show === 'bottom' && (last || target)) { + target = target || last + // @ts-ignore For some reason tsc doesn't recognize "instant" as a valid option for now + target.scrollIntoView({ block: 'end', behavior: htmx.config.scrollBehavior }) + } + } + } + + /** + * @param {Element} elt + * @param {string} attr + * @param {boolean=} evalAsDefault + * @param {Object=} values + * @returns {Object} + */ + function getValuesForElement(elt, attr, evalAsDefault, values) { + if (values == null) { + values = {} + } + if (elt == null) { + return values + } + const attributeValue = getAttributeValue(elt, attr) + if (attributeValue) { + let str = attributeValue.trim() + let evaluateValue = evalAsDefault + if (str === 'unset') { + return null + } + if (str.indexOf('javascript:') === 0) { + str = str.substr(11) + evaluateValue = true + } else if (str.indexOf('js:') === 0) { + str = str.substr(3) + evaluateValue = true + } + if (str.indexOf('{') !== 0) { + str = '{' + str + '}' + } + let varsValues + if (evaluateValue) { + varsValues = maybeEval(elt, function() { return Function('return (' + str + ')')() }, {}) + } else { + varsValues = parseJSON(str) + } + for (const key in varsValues) { + if (varsValues.hasOwnProperty(key)) { + if (values[key] == null) { + values[key] = varsValues[key] + } + } + } + } + return getValuesForElement(asElement(parentElt(elt)), attr, evalAsDefault, values) + } + + /** + * @param {EventTarget|string} elt + * @param {() => any} toEval + * @param {any=} defaultVal + * @returns {any} + */ + function maybeEval(elt, toEval, defaultVal) { + if (htmx.config.allowEval) { + return toEval() + } else { + triggerErrorEvent(elt, 'htmx:evalDisallowedError') + return defaultVal + } + } + + /** + * @param {Element} elt + * @param {*?} expressionVars + * @returns + */ + function getHXVarsForElement(elt, expressionVars) { + return getValuesForElement(elt, 'hx-vars', true, expressionVars) + } + + /** + * @param {Element} elt + * @param {*?} expressionVars + * @returns + */ + function getHXValsForElement(elt, expressionVars) { + return getValuesForElement(elt, 'hx-vals', false, expressionVars) + } + + /** + * @param {Element} elt + * @returns {FormData} + */ + function getExpressionVars(elt) { + return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)) + } + + /** + * @param {XMLHttpRequest} xhr + * @param {string} header + * @param {string|null} headerValue + */ + function safelySetHeaderValue(xhr, header, headerValue) { + if (headerValue !== null) { + try { + xhr.setRequestHeader(header, headerValue) + } catch (e) { + // On an exception, try to set the header URI encoded instead + xhr.setRequestHeader(header, encodeURIComponent(headerValue)) + xhr.setRequestHeader(header + '-URI-AutoEncoded', 'true') + } + } + } + + /** + * @param {XMLHttpRequest} xhr + * @return {string} + */ + function getPathFromResponse(xhr) { + // NB: IE11 does not support this stuff + if (xhr.responseURL && typeof (URL) !== 'undefined') { + try { + const url = new URL(xhr.responseURL) + return url.pathname + url.search + } catch (e) { + triggerErrorEvent(getDocument().body, 'htmx:badResponseUrl', { url: xhr.responseURL }) + } + } + } + + /** + * @param {XMLHttpRequest} xhr + * @param {RegExp} regexp + * @return {boolean} + */ + function hasHeader(xhr, regexp) { + return regexp.test(xhr.getAllResponseHeaders()) + } + + /** + * Issues an htmx-style AJAX request + * + * @see https://htmx.org/api/#ajax + * + * @param {HttpVerb} verb + * @param {string} path the URL path to make the AJAX + * @param {Element|string|HtmxAjaxHelperContext} context the element to target (defaults to the **body**) | a selector for the target | a context object that contains any of the following + * @return {Promise<void>} Promise that resolves immediately if no request is sent, or when the request is complete + */ + function ajaxHelper(verb, path, context) { + verb = (/** @type HttpVerb */(verb.toLowerCase())) + if (context) { + if (context instanceof Element || typeof context === 'string') { + return issueAjaxRequest(verb, path, null, null, { + targetOverride: resolveTarget(context), + returnPromise: true + }) + } else { + return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, + { + handler: context.handler, + headers: context.headers, + values: context.values, + targetOverride: resolveTarget(context.target), + swapOverride: context.swap, + select: context.select, + returnPromise: true + }) + } + } else { + return issueAjaxRequest(verb, path, null, null, { + returnPromise: true + }) + } + } + + /** + * @param {Element} elt + * @return {Element[]} + */ + function hierarchyForElt(elt) { + const arr = [] + while (elt) { + arr.push(elt) + elt = elt.parentElement + } + return arr + } + + /** + * @param {Element} elt + * @param {string} path + * @param {HtmxRequestConfig} requestConfig + * @return {boolean} + */ + function verifyPath(elt, path, requestConfig) { + let sameHost + let url + if (typeof URL === 'function') { + url = new URL(path, document.location.href) + const origin = document.location.origin + sameHost = origin === url.origin + } else { + // IE11 doesn't support URL + url = path + sameHost = startsWith(path, document.location.origin) + } - //=========================================== - // Next resolve via DOM values - //=========================================== - var requestPath = responseInfo.pathInfo.finalRequestPath; - var responsePath = responseInfo.pathInfo.responsePath; - - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url"); - var elementIsBoosted = getInternalData(elt).boosted; - - var saveType = null; - var path = null; - - if (pushUrl) { - saveType = "push"; - path = pushUrl; - } else if (replaceUrl) { - saveType = "replace"; - path = replaceUrl; - } else if (elementIsBoosted) { - saveType = "push"; - path = responsePath || requestPath; // if there is no response path, go with the original request path - } + if (htmx.config.selfRequestsOnly) { + if (!sameHost) { + return false + } + } + return triggerEvent(elt, 'htmx:validateUrl', mergeObjects({ url, sameHost }, requestConfig)) + } + + /** + * @param {Object|FormData} obj + * @return {FormData} + */ + function formDataFromObject(obj) { + if (obj instanceof FormData) return obj + const formData = new FormData() + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + if (typeof obj[key].forEach === 'function') { + obj[key].forEach(function(v) { formData.append(key, v) }) + } else if (typeof obj[key] === 'object') { + formData.append(key, JSON.stringify(obj[key])) + } else { + formData.append(key, obj[key]) + } + } + } + return formData + } + + /** + * @param {FormData} formData + * @param {string} name + * @param {Array} array + * @returns {Array} + */ + function formDataArrayProxy(formData, name, array) { + // mutating the array should mutate the underlying form data + return new Proxy(array, { + get: function(target, key) { + if (typeof key === 'number') return target[key] + if (key === 'length') return target.length + if (key === 'push') { + return function(value) { + target.push(value) + formData.append(name, value) + } + } + if (typeof target[key] === 'function') { + return function() { + target[key].apply(target, arguments) + formData.delete(name) + target.forEach(function(v) { formData.append(name, v) }) + } + } + + if (target[key] && target[key].length === 1) { + return target[key][0] + } else { + return target[key] + } + }, + set: function(target, index, value) { + target[index] = value + formData.delete(name) + target.forEach(function(v) { formData.append(name, v) }) + return true + } + }) + } + + /** + * @param {FormData} formData + * @returns {Object} + */ + function formDataProxy(formData) { + return new Proxy(formData, { + get: function(target, name) { + if (typeof name === 'symbol') { + // Forward symbol calls to the FormData itself directly + return Reflect.get(target, name) + } + if (name === 'toJSON') { + // Support JSON.stringify call on proxy + return () => Object.fromEntries(formData) + } + if (name in target) { + // Wrap in function with apply to correctly bind the FormData context, as a direct call would result in an illegal invocation error + if (typeof target[name] === 'function') { + return function() { + return formData[name].apply(formData, arguments) + } + } else { + return target[name] + } + } + const array = formData.getAll(name) + // Those 2 undefined & single value returns are for retro-compatibility as we weren't using FormData before + if (array.length === 0) { + return undefined + } else if (array.length === 1) { + return array[0] + } else { + return formDataArrayProxy(target, name, array) + } + }, + set: function(target, name, value) { + if (typeof name !== 'string') { + return false + } + target.delete(name) + if (typeof value.forEach === 'function') { + value.forEach(function(v) { target.append(name, v) }) + } else { + target.append(name, value) + } + return true + }, + deleteProperty: function(target, name) { + if (typeof name === 'string') { + target.delete(name) + } + return true + }, + // Support Object.assign call from proxy + ownKeys: function(target) { + return Reflect.ownKeys(Object.fromEntries(target)) + }, + getOwnPropertyDescriptor: function(target, prop) { + return Reflect.getOwnPropertyDescriptor(Object.fromEntries(target), prop) + } + }) + } + + /** + * @param {HttpVerb} verb + * @param {string} path + * @param {Element} elt + * @param {Event} event + * @param {HtmxAjaxEtc} [etc] + * @param {boolean} [confirmed] + * @return {Promise<void>} + */ + function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { + let resolve = null + let reject = null + etc = etc != null ? etc : {} + if (etc.returnPromise && typeof Promise !== 'undefined') { + var promise = new Promise(function(_resolve, _reject) { + resolve = _resolve + reject = _reject + }) + } + if (elt == null) { + elt = getDocument().body + } + const responseHandler = etc.handler || handleAjaxResponse + const select = etc.select || null - if (path) { - // false indicates no push, return empty object - if (path === "false") { - return {}; - } + if (!bodyContains(elt)) { + // do not issue requests for elements removed from the DOM + maybeCall(resolve) + return promise + } + const target = etc.targetOverride || asElement(getTarget(elt)) + if (target == null || target == DUMMY_ELT) { + triggerErrorEvent(elt, 'htmx:targetError', { target: getAttributeValue(elt, 'hx-target') }) + maybeCall(reject) + return promise + } - // true indicates we want to follow wherever the server ended up sending us - if (path === "true") { - path = responsePath || requestPath; // if there is no response path, go with the original request path - } + let eltData = getInternalData(elt) + const submitter = eltData.lastButtonClicked - // restore any anchor associated with the request - if (responseInfo.pathInfo.anchor && - path.indexOf("#") === -1) { - path = path + "#" + responseInfo.pathInfo.anchor; - } + if (submitter) { + const buttonPath = getRawAttribute(submitter, 'formaction') + if (buttonPath != null) { + path = buttonPath + } - return { - type:saveType, - path: path - } - } else { - return {}; - } + const buttonVerb = getRawAttribute(submitter, 'formmethod') + if (buttonVerb != null) { + // ignore buttons with formmethod="dialog" + if (buttonVerb.toLowerCase() !== 'dialog') { + verb = (/** @type HttpVerb */(buttonVerb)) } + } + } - function handleAjaxResponse(elt, responseInfo) { - var xhr = responseInfo.xhr; - var target = responseInfo.target; - var etc = responseInfo.etc; - var requestConfig = responseInfo.requestConfig; - var select = responseInfo.select; + const confirmQuestion = getClosestAttributeValue(elt, 'hx-confirm') + // allow event-based confirmation w/ a callback + if (confirmed === undefined) { + const issueRequest = function(skipConfirmation) { + return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation) + } + const confirmDetails = { target, elt, path, verb, triggeringEvent: event, etc, issueRequest, question: confirmQuestion } + if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { + maybeCall(resolve) + return promise + } + } - if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; + let syncElt = elt + let syncStrategy = getClosestAttributeValue(elt, 'hx-sync') + let queueStrategy = null + let abortable = false + if (syncStrategy) { + const syncStrings = syncStrategy.split(':') + const selector = syncStrings[0].trim() + if (selector === 'this') { + syncElt = findThisElement(elt, 'hx-sync') + } else { + syncElt = asElement(querySelectorExt(elt, selector)) + } + // default to the drop strategy + syncStrategy = (syncStrings[1] || 'drop').trim() + eltData = getInternalData(syncElt) + if (syncStrategy === 'drop' && eltData.xhr && eltData.abortable !== true) { + maybeCall(resolve) + return promise + } else if (syncStrategy === 'abort') { + if (eltData.xhr) { + maybeCall(resolve) + return promise + } else { + abortable = true + } + } else if (syncStrategy === 'replace') { + triggerEvent(syncElt, 'htmx:abort') // abort the current request and continue + } else if (syncStrategy.indexOf('queue') === 0) { + const queueStrArray = syncStrategy.split(' ') + queueStrategy = (queueStrArray[1] || 'last').trim() + } + } - if (hasHeader(xhr, /HX-Trigger:/i)) { - handleTrigger(xhr, "HX-Trigger", elt); - } + if (eltData.xhr) { + if (eltData.abortable) { + triggerEvent(syncElt, 'htmx:abort') // abort the current request and continue + } else { + if (queueStrategy == null) { + if (event) { + const eventData = getInternalData(event) + if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { + queueStrategy = eventData.triggerSpec.queue + } + } + if (queueStrategy == null) { + queueStrategy = 'last' + } + } + if (eltData.queuedRequests == null) { + eltData.queuedRequests = [] + } + if (queueStrategy === 'first' && eltData.queuedRequests.length === 0) { + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } else if (queueStrategy === 'all') { + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } else if (queueStrategy === 'last') { + eltData.queuedRequests = [] // dump existing queue + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } + maybeCall(resolve) + return promise + } + } - if (hasHeader(xhr, /HX-Location:/i)) { - saveCurrentPageToHistory(); - var redirectPath = xhr.getResponseHeader("HX-Location"); - var swapSpec; - if (redirectPath.indexOf("{") === 0) { - swapSpec = parseJSON(redirectPath); - // what's the best way to throw an error if the user didn't include this - redirectPath = swapSpec['path']; - delete swapSpec['path']; - } - ajaxHelper('GET', redirectPath, swapSpec).then(function(){ - pushUrlIntoHistory(redirectPath); - }); - return; - } + const xhr = new XMLHttpRequest() + eltData.xhr = xhr + eltData.abortable = abortable + const endRequestLock = function() { + eltData.xhr = null + eltData.abortable = false + if (eltData.queuedRequests != null && + eltData.queuedRequests.length > 0) { + const queuedRequest = eltData.queuedRequests.shift() + queuedRequest() + } + } + const promptQuestion = getClosestAttributeValue(elt, 'hx-prompt') + if (promptQuestion) { + var promptResponse = prompt(promptQuestion) + // prompt returns null if cancelled and empty string if accepted with no entry + if (promptResponse === null || + !triggerEvent(elt, 'htmx:prompt', { prompt: promptResponse, target })) { + maybeCall(resolve) + endRequestLock() + return promise + } + } - var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh"); + if (confirmQuestion && !confirmed) { + if (!confirm(confirmQuestion)) { + maybeCall(resolve) + endRequestLock() + return promise + } + } - if (hasHeader(xhr, /HX-Redirect:/i)) { - location.href = xhr.getResponseHeader("HX-Redirect"); - shouldRefresh && location.reload(); - return; - } + let headers = getHeaders(elt, target, promptResponse) - if (shouldRefresh) { - location.reload(); - return; - } + if (verb !== 'get' && !usesFormData(elt)) { + headers['Content-Type'] = 'application/x-www-form-urlencoded' + } - if (hasHeader(xhr,/HX-Retarget:/i)) { - if (xhr.getResponseHeader("HX-Retarget") === "this") { - responseInfo.target = elt; - } else { - responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget")); - } - } + if (etc.headers) { + headers = mergeObjects(headers, etc.headers) + } + const results = getInputValues(elt, verb) + let errors = results.errors + const rawFormData = results.formData + if (etc.values) { + overrideFormData(rawFormData, formDataFromObject(etc.values)) + } + const expressionVars = formDataFromObject(getExpressionVars(elt)) + const allFormData = overrideFormData(rawFormData, expressionVars) + let filteredFormData = filterValues(allFormData, elt) - var historyUpdate = determineHistoryUpdates(elt, responseInfo); - - // by default htmx only swaps on 200 return codes and does not swap - // on 204 'No Content' - // this can be ovverriden by responding to the htmx:beforeSwap event and - // overriding the detail.shouldSwap property - var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; - var serverResponse = xhr.response; - var isError = xhr.status >= 400; - var ignoreTitle = htmx.config.ignoreTitle - var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo); - if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; - - target = beforeSwapDetails.target; // allow re-targeting - serverResponse = beforeSwapDetails.serverResponse; // allow updating content - isError = beforeSwapDetails.isError; // allow updating error - ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title - - responseInfo.target = target; // Make updated target available to response events - responseInfo.failed = isError; // Make failed property available to response events - responseInfo.successful = !isError; // Make successful property available to response events - - if (beforeSwapDetails.shouldSwap) { - if (xhr.status === 286) { - cancelPolling(elt); - } + if (htmx.config.getCacheBusterParam && verb === 'get') { + filteredFormData.set('org.htmx.cache-buster', getRawAttribute(target, 'id') || 'true') + } - withExtensions(elt, function (extension) { - serverResponse = extension.transformResponse(serverResponse, xhr, elt); - }); + // behavior of anchors w/ empty href is to use the current URL + if (path == null || path === '') { + path = getDocument().location.href + } - // Save current page if there will be a history update - if (historyUpdate.type) { - saveCurrentPageToHistory(); - } + /** + * @type {Object} + * @property {boolean} [credentials] + * @property {number} [timeout] + * @property {boolean} [noHeaders] + */ + const requestAttrValues = getValuesForElement(elt, 'hx-request') + + const eltIsBoosted = getInternalData(elt).boosted + + let useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + + /** @type HtmxRequestConfig */ + const requestConfig = { + boosted: eltIsBoosted, + useUrlParams, + formData: filteredFormData, + parameters: formDataProxy(filteredFormData), + unfilteredFormData: allFormData, + unfilteredParameters: formDataProxy(allFormData), + headers, + target, + verb, + errors, + withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, + timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, + path, + triggeringEvent: event + } - var swapOverride = etc.swapOverride; - if (hasHeader(xhr,/HX-Reswap:/i)) { - swapOverride = xhr.getResponseHeader("HX-Reswap"); - } - var swapSpec = getSwapSpecification(elt, swapOverride); + if (!triggerEvent(elt, 'htmx:configRequest', requestConfig)) { + maybeCall(resolve) + endRequestLock() + return promise + } - if (swapSpec.hasOwnProperty('ignoreTitle')) { - ignoreTitle = swapSpec.ignoreTitle; - } + // copy out in case the object was overwritten + path = requestConfig.path + verb = requestConfig.verb + headers = requestConfig.headers + filteredFormData = formDataFromObject(requestConfig.parameters) + errors = requestConfig.errors + useUrlParams = requestConfig.useUrlParams + + if (errors && errors.length > 0) { + triggerEvent(elt, 'htmx:validation:halted', requestConfig) + maybeCall(resolve) + endRequestLock() + return promise + } - target.classList.add(htmx.config.swappingClass); - - // optional transition API promise callbacks - var settleResolve = null; - var settleReject = null; - - var doSwap = function () { - try { - var activeElt = document.activeElement; - var selectionInfo = {}; - try { - selectionInfo = { - elt: activeElt, - // @ts-ignore - start: activeElt ? activeElt.selectionStart : null, - // @ts-ignore - end: activeElt ? activeElt.selectionEnd : null - }; - } catch (e) { - // safari issue - see https://github.com/microsoft/playwright/issues/5894 - } - - var selectOverride; - if (select) { - selectOverride = select; - } - - if (hasHeader(xhr, /HX-Reselect:/i)) { - selectOverride = xhr.getResponseHeader("HX-Reselect"); - } - - // if we need to save history, do so, before swapping so that relative resources have the correct base URL - if (historyUpdate.type) { - triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)); - if (historyUpdate.type === "push") { - pushUrlIntoHistory(historyUpdate.path); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path}); - } else { - replaceUrlInHistory(historyUpdate.path); - triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path}); - } - } - - var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride); - - if (selectionInfo.elt && - !bodyContains(selectionInfo.elt) && - getRawAttribute(selectionInfo.elt, "id")) { - var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id")); - var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; - if (newActiveElt) { - // @ts-ignore - if (selectionInfo.start && newActiveElt.setSelectionRange) { - // @ts-ignore - try { - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); - } catch (e) { - // the setSelectionRange method is present on fields that don't support it, so just let this fail - } - } - newActiveElt.focus(focusOptions); - } - } - - target.classList.remove(htmx.config.swappingClass); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.add(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSwap', responseInfo); - }); - - if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); - } - - var doSettle = function () { - forEach(settleInfo.tasks, function (task) { - task.call(); - }); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.remove(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSettle', responseInfo); - }); - - if (responseInfo.pathInfo.anchor) { - var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor); - if(anchorTarget) { - anchorTarget.scrollIntoView({block:'start', behavior: "auto"}); - } - } - - if(settleInfo.title && !ignoreTitle) { - var titleElt = find("title"); - if(titleElt) { - titleElt.innerHTML = settleInfo.title; - } else { - window.document.title = settleInfo.title; - } - } - - updateScrollState(settleInfo.elts, swapSpec); - - if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); - } - maybeCall(settleResolve); - } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'htmx:swapError', responseInfo); - maybeCall(settleReject); - throw e; - } - }; - - var shouldTransition = htmx.config.globalViewTransitions - if(swapSpec.hasOwnProperty('transition')){ - shouldTransition = swapSpec.transition; - } + const splitPath = path.split('#') + const pathNoAnchor = splitPath[0] + const anchor = splitPath[1] + + let finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor + const hasValues = !filteredFormData.keys().next().done + if (hasValues) { + if (finalPath.indexOf('?') < 0) { + finalPath += '?' + } else { + finalPath += '&' + } + finalPath += urlEncode(filteredFormData) + if (anchor) { + finalPath += '#' + anchor + } + } + } - if(shouldTransition && - triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && - typeof Promise !== "undefined" && document.startViewTransition){ - var settlePromise = new Promise(function (_resolve, _reject) { - settleResolve = _resolve; - settleReject = _reject; - }); - // wrap the original doSwap() in a call to startViewTransition() - var innerDoSwap = doSwap; - doSwap = function() { - document.startViewTransition(function () { - innerDoSwap(); - return settlePromise; - }); - } - } + if (!verifyPath(elt, finalPath, requestConfig)) { + triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) + maybeCall(reject) + return promise + } + xhr.open(verb.toUpperCase(), finalPath, true) + xhr.overrideMimeType('text/html') + xhr.withCredentials = requestConfig.withCredentials + xhr.timeout = requestConfig.timeout - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); - } - } - if (isError) { - triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo)); - } + // request headers + if (requestAttrValues.noHeaders) { + // ignore all headers + } else { + for (const header in headers) { + if (headers.hasOwnProperty(header)) { + const headerValue = headers[header] + safelySetHeaderValue(xhr, header, headerValue) } + } + } - //==================================================================== - // Extensions API - //==================================================================== - - /** @type {Object<string, import("./htmx").HtmxExtension>} */ - var extensions = {}; - - /** - * extensionBase defines the default functions for all extensions. - * @returns {import("./htmx").HtmxExtension} - */ - function extensionBase() { - return { - init: function(api) {return null;}, - onEvent : function(name, evt) {return true;}, - transformResponse : function(text, xhr, elt) {return text;}, - isInlineSwap : function(swapStyle) {return false;}, - handleSwap : function(swapStyle, target, fragment, settleInfo) {return false;}, - encodeParameters : function(xhr, parameters, elt) {return null;} - } - } + /** @type {HtmxResponseInfo} */ + const responseInfo = { + xhr, + target, + requestConfig, + etc, + boosted: eltIsBoosted, + select, + pathInfo: { + requestPath: path, + finalRequestPath: finalPath, + responsePath: null, + anchor + } + } - /** - * defineExtension initializes the extension and adds it to the htmx registry - * - * @param {string} name - * @param {import("./htmx").HtmxExtension} extension - */ - function defineExtension(name, extension) { - if(extension.init) { - extension.init(internalAPI) - } - extensions[name] = mergeObjects(extensionBase(), extension); - } + xhr.onload = function() { + try { + const hierarchy = hierarchyForElt(elt) + responseInfo.pathInfo.responsePath = getPathFromResponse(xhr) + responseHandler(elt, responseInfo) + removeRequestIndicators(indicators, disableElts) + triggerEvent(elt, 'htmx:afterRequest', responseInfo) + triggerEvent(elt, 'htmx:afterOnLoad', responseInfo) + // if the body no longer contains the element, trigger the event on the closest parent + // remaining in the DOM + if (!bodyContains(elt)) { + let secondaryTriggerElt = null + while (hierarchy.length > 0 && secondaryTriggerElt == null) { + const parentEltInHierarchy = hierarchy.shift() + if (bodyContains(parentEltInHierarchy)) { + secondaryTriggerElt = parentEltInHierarchy + } + } + if (secondaryTriggerElt) { + triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo) + triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo) + } + } + maybeCall(resolve) + endRequestLock() + } catch (e) { + triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({ error: e }, responseInfo)) + throw e + } + } + xhr.onerror = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:sendError', responseInfo) + maybeCall(reject) + endRequestLock() + } + xhr.onabort = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo) + maybeCall(reject) + endRequestLock() + } + xhr.ontimeout = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:timeout', responseInfo) + maybeCall(reject) + endRequestLock() + } + if (!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)) { + maybeCall(resolve) + endRequestLock() + return promise + } + var indicators = addRequestIndicatorClasses(elt) + var disableElts = disableElements(elt) + + forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { + forEach([xhr, xhr.upload], function(target) { + target.addEventListener(eventName, function(event) { + triggerEvent(elt, 'htmx:xhr:' + eventName, { + lengthComputable: event.lengthComputable, + loaded: event.loaded, + total: event.total + }) + }) + }) + }) + triggerEvent(elt, 'htmx:beforeSend', responseInfo) + const params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredFormData) + xhr.send(params) + return promise + } + + /** + * @typedef {Object} HtmxHistoryUpdate + * @property {string|null} [type] + * @property {string|null} [path] + */ + + /** + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + * @return {HtmxHistoryUpdate} + */ + function determineHistoryUpdates(elt, responseInfo) { + const xhr = responseInfo.xhr + + //= ========================================== + // First consult response headers + //= ========================================== + let pathFromHeaders = null + let typeFromHeaders = null + if (hasHeader(xhr, /HX-Push:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Push') + typeFromHeaders = 'push' + } else if (hasHeader(xhr, /HX-Push-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Push-Url') + typeFromHeaders = 'push' + } else if (hasHeader(xhr, /HX-Replace-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Replace-Url') + typeFromHeaders = 'replace' + } - /** - * removeExtension removes an extension from the htmx registry - * - * @param {string} name - */ - function removeExtension(name) { - delete extensions[name]; + // if there was a response header, that has priority + if (pathFromHeaders) { + if (pathFromHeaders === 'false') { + return {} + } else { + return { + type: typeFromHeaders, + path: pathFromHeaders } + } + } - /** - * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element - * - * @param {HTMLElement} elt - * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn - * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore - */ - function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + //= ========================================== + // Next resolve via DOM values + //= ========================================== + const requestPath = responseInfo.pathInfo.finalRequestPath + const responsePath = responseInfo.pathInfo.responsePath + + const pushUrl = getClosestAttributeValue(elt, 'hx-push-url') + const replaceUrl = getClosestAttributeValue(elt, 'hx-replace-url') + const elementIsBoosted = getInternalData(elt).boosted + + let saveType = null + let path = null + + if (pushUrl) { + saveType = 'push' + path = pushUrl + } else if (replaceUrl) { + saveType = 'replace' + path = replaceUrl + } else if (elementIsBoosted) { + saveType = 'push' + path = responsePath || requestPath // if there is no response path, go with the original request path + } - if (elt == undefined) { - return extensionsToReturn; - } - if (extensionsToReturn == undefined) { - extensionsToReturn = []; - } - if (extensionsToIgnore == undefined) { - extensionsToIgnore = []; - } - var extensionsForElement = getAttributeValue(elt, "hx-ext"); - if (extensionsForElement) { - forEach(extensionsForElement.split(","), function(extensionName){ - extensionName = extensionName.replace(/ /g, ''); - if (extensionName.slice(0, 7) == "ignore:") { - extensionsToIgnore.push(extensionName.slice(7)); - return; - } - if (extensionsToIgnore.indexOf(extensionName) < 0) { - var extension = extensions[extensionName]; - if (extension && extensionsToReturn.indexOf(extension) < 0) { - extensionsToReturn.push(extension); - } - } - }); - } - return getExtensions(parentElt(elt), extensionsToReturn, extensionsToIgnore); - } + if (path) { + // false indicates no push, return empty object + if (path === 'false') { + return {} + } + + // true indicates we want to follow wherever the server ended up sending us + if (path === 'true') { + path = responsePath || requestPath // if there is no response path, go with the original request path + } + + // restore any anchor associated with the request + if (responseInfo.pathInfo.anchor && path.indexOf('#') === -1) { + path = path + '#' + responseInfo.pathInfo.anchor + } + + return { + type: saveType, + path + } + } else { + return {} + } + } + + /** + * @param {HtmxResponseHandlingConfig} responseHandlingConfig + * @param {number} status + * @return {boolean} + */ + function codeMatches(responseHandlingConfig, status) { + var regExp = new RegExp(responseHandlingConfig.code) + return regExp.test(status.toString(10)) + } + + /** + * @param {XMLHttpRequest} xhr + * @return {HtmxResponseHandlingConfig} + */ + function resolveResponseHandling(xhr) { + for (var i = 0; i < htmx.config.responseHandling.length; i++) { + /** @type HtmxResponseHandlingConfig */ + var responseHandlingElement = htmx.config.responseHandling[i] + if (codeMatches(responseHandlingElement, xhr.status)) { + return responseHandlingElement + } + } + // no matches, return no swap + return { + swap: false + } + } + + /** + * @param {string} title + */ + function handleTitle(title) { + if (title) { + const titleElt = find('title') + if (titleElt) { + titleElt.innerHTML = title + } else { + window.document.title = title + } + } + } + + /** + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + */ + function handleAjaxResponse(elt, responseInfo) { + const xhr = responseInfo.xhr + let target = responseInfo.target + const etc = responseInfo.etc + const responseInfoSelect = responseInfo.select + + if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return + + if (hasHeader(xhr, /HX-Trigger:/i)) { + handleTriggerHeader(xhr, 'HX-Trigger', elt) + } - //==================================================================== - // Initialization - //==================================================================== - var isReady = false - getDocument().addEventListener('DOMContentLoaded', function() { - isReady = true - }) + if (hasHeader(xhr, /HX-Location:/i)) { + saveCurrentPageToHistory() + let redirectPath = xhr.getResponseHeader('HX-Location') + /** @type {HtmxAjaxHelperContext&{path:string}} */ + var redirectSwapSpec + if (redirectPath.indexOf('{') === 0) { + redirectSwapSpec = parseJSON(redirectPath) + // what's the best way to throw an error if the user didn't include this + redirectPath = redirectSwapSpec.path + delete redirectSwapSpec.path + } + ajaxHelper('get', redirectPath, redirectSwapSpec).then(function() { + pushUrlIntoHistory(redirectPath) + }) + return + } - /** - * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. - * - * This function uses isReady because there is no realiable way to ask the browswer whether - * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded - * firing and readystate=complete. - */ - function ready(fn) { - // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by - // some means other than the initial page load. - if (isReady || getDocument().readyState === 'complete') { - fn(); - } else { - getDocument().addEventListener('DOMContentLoaded', fn); - } - } + const shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && xhr.getResponseHeader('HX-Refresh') === 'true' - function insertIndicatorStyles() { - if (htmx.config.includeIndicatorStyles !== false) { - getDocument().head.insertAdjacentHTML("beforeend", - "<style>\ - ." + htmx.config.indicatorClass + "{opacity:0}\ - ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ - ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ - </style>"); - } - } + if (hasHeader(xhr, /HX-Redirect:/i)) { + location.href = xhr.getResponseHeader('HX-Redirect') + shouldRefresh && location.reload() + return + } - function getMetaConfig() { - var element = getDocument().querySelector('meta[name="htmx-config"]'); - if (element) { - // @ts-ignore - return parseJSON(element.content); - } else { - return null; - } - } + if (shouldRefresh) { + location.reload() + return + } - function mergeMetaConfig() { - var metaConfig = getMetaConfig(); - if (metaConfig) { - htmx.config = mergeObjects(htmx.config , metaConfig) - } - } + if (hasHeader(xhr, /HX-Retarget:/i)) { + if (xhr.getResponseHeader('HX-Retarget') === 'this') { + responseInfo.target = elt + } else { + responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget'))) + } + } - // initialize the document - ready(function () { - mergeMetaConfig(); - insertIndicatorStyles(); - var body = getDocument().body; - processNode(body); - var restoredElts = getDocument().querySelectorAll( - "[hx-trigger='restored'],[data-hx-trigger='restored']" - ); - body.addEventListener("htmx:abort", function (evt) { - var target = evt.target; - var internalData = getInternalData(target); - if (internalData && internalData.xhr) { - internalData.xhr.abort(); - } - }); - /** @type {(ev: PopStateEvent) => any} */ - const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null; - /** @type {(ev: PopStateEvent) => any} */ - window.onpopstate = function (event) { - if (event.state && event.state.htmx) { - restoreHistory(); - forEach(restoredElts, function(elt){ - triggerEvent(elt, 'htmx:restored', { - 'document': getDocument(), - 'triggerEvent': triggerEvent - }); - }); - } else { - if (originalPopstate) { - originalPopstate(event); - } - } - }; - setTimeout(function () { - triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event - body = null; // kill reference for gc - }, 0); + const historyUpdate = determineHistoryUpdates(elt, responseInfo) + + const responseHandling = resolveResponseHandling(xhr) + const shouldSwap = responseHandling.swap + let isError = !!responseHandling.error + let ignoreTitle = htmx.config.ignoreTitle || responseHandling.ignoreTitle + let selectOverride = responseHandling.select + if (responseHandling.target) { + responseInfo.target = asElement(querySelectorExt(elt, responseHandling.target)) + } + var swapOverride = etc.swapOverride + if (swapOverride == null && responseHandling.swapOverride) { + swapOverride = responseHandling.swapOverride + } + + // response headers override response handling config + if (hasHeader(xhr, /HX-Retarget:/i)) { + if (xhr.getResponseHeader('HX-Retarget') === 'this') { + responseInfo.target = elt + } else { + responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget'))) + } + } + if (hasHeader(xhr, /HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader('HX-Reswap') + } + + var serverResponse = xhr.response + /** @type HtmxBeforeSwapDetails */ + var beforeSwapDetails = mergeObjects({ + shouldSwap, + serverResponse, + isError, + ignoreTitle, + selectOverride + }, responseInfo) + + if (responseHandling.event && !triggerEvent(target, responseHandling.event, beforeSwapDetails)) return + + if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return + + target = beforeSwapDetails.target // allow re-targeting + serverResponse = beforeSwapDetails.serverResponse // allow updating content + isError = beforeSwapDetails.isError // allow updating error + ignoreTitle = beforeSwapDetails.ignoreTitle // allow updating ignoring title + selectOverride = beforeSwapDetails.selectOverride // allow updating select override + + responseInfo.target = target // Make updated target available to response events + responseInfo.failed = isError // Make failed property available to response events + responseInfo.successful = !isError // Make successful property available to response events + + if (beforeSwapDetails.shouldSwap) { + if (xhr.status === 286) { + cancelPolling(elt) + } + + withExtensions(elt, function(extension) { + serverResponse = extension.transformResponse(serverResponse, xhr, elt) + }) + + // Save current page if there will be a history update + if (historyUpdate.type) { + saveCurrentPageToHistory() + } + + if (hasHeader(xhr, /HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader('HX-Reswap') + } + var swapSpec = getSwapSpecification(elt, swapOverride) + + if (!swapSpec.hasOwnProperty('ignoreTitle')) { + swapSpec.ignoreTitle = ignoreTitle + } + + target.classList.add(htmx.config.swappingClass) + + // optional transition API promise callbacks + let settleResolve = null + let settleReject = null + + if (responseInfoSelect) { + selectOverride = responseInfoSelect + } + + if (hasHeader(xhr, /HX-Reselect:/i)) { + selectOverride = xhr.getResponseHeader('HX-Reselect') + } + + const selectOOB = getClosestAttributeValue(elt, 'hx-select-oob') + const select = getClosestAttributeValue(elt, 'hx-select') + + let doSwap = function() { + try { + // if we need to save history, do so, before swapping so that relative resources have the correct base URL + if (historyUpdate.type) { + triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)) + if (historyUpdate.type === 'push') { + pushUrlIntoHistory(historyUpdate.path) + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', { path: historyUpdate.path }) + } else { + replaceUrlInHistory(historyUpdate.path) + triggerEvent(getDocument().body, 'htmx:replacedInHistory', { path: historyUpdate.path }) + } + } + + swap(target, serverResponse, swapSpec, { + select: selectOverride || select, + selectOOB, + eventInfo: responseInfo, + anchor: responseInfo.pathInfo.anchor, + contextElement: elt, + afterSwapCallback: function() { + if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { + let finalElt = elt + if (!bodyContains(elt)) { + finalElt = getDocument().body + } + handleTriggerHeader(xhr, 'HX-Trigger-After-Swap', finalElt) + } + }, + afterSettleCallback: function() { + if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { + let finalElt = elt + if (!bodyContains(elt)) { + finalElt = getDocument().body + } + handleTriggerHeader(xhr, 'HX-Trigger-After-Settle', finalElt) + } + maybeCall(settleResolve) + } + }) + } catch (e) { + triggerErrorEvent(elt, 'htmx:swapError', responseInfo) + maybeCall(settleReject) + throw e + } + } + + let shouldTransition = htmx.config.globalViewTransitions + if (swapSpec.hasOwnProperty('transition')) { + shouldTransition = swapSpec.transition + } + + if (shouldTransition && + triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && + typeof Promise !== 'undefined' && + // @ts-ignore experimental feature atm + document.startViewTransition) { + const settlePromise = new Promise(function(_resolve, _reject) { + settleResolve = _resolve + settleReject = _reject }) + // wrap the original doSwap() in a call to startViewTransition() + const innerDoSwap = doSwap + doSwap = function() { + // @ts-ignore experimental feature atm + document.startViewTransition(function() { + innerDoSwap() + return settlePromise + }) + } + } + + if (swapSpec.swapDelay > 0) { + getWindow().setTimeout(doSwap, swapSpec.swapDelay) + } else { + doSwap() + } + } + if (isError) { + triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({ error: 'Response Status Error Code ' + xhr.status + ' from ' + responseInfo.pathInfo.requestPath }, responseInfo)) + } + } + + //= =================================================================== + // Extensions API + //= =================================================================== + + /** @type {Object<string, HtmxExtension>} */ + const extensions = {} + + /** + * extensionBase defines the default functions for all extensions. + * @returns {HtmxExtension} + */ + function extensionBase() { + return { + init: function(api) { return null }, + getSelectors: function() { return null }, + onEvent: function(name, evt) { return true }, + transformResponse: function(text, xhr, elt) { return text }, + isInlineSwap: function(swapStyle) { return false }, + handleSwap: function(swapStyle, target, fragment, settleInfo) { return false }, + encodeParameters: function(xhr, parameters, elt) { return null } + } + } + + /** + * defineExtension initializes the extension and adds it to the htmx registry + * + * @see https://htmx.org/api/#defineExtension + * + * @param {string} name the extension name + * @param {HtmxExtension} extension the extension definition + */ + function defineExtension(name, extension) { + if (extension.init) { + extension.init(internalAPI) + } + extensions[name] = mergeObjects(extensionBase(), extension) + } + + /** + * removeExtension removes an extension from the htmx registry + * + * @see https://htmx.org/api/#removeExtension + * + * @param {string} name + */ + function removeExtension(name) { + delete extensions[name] + } + + /** + * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element + * + * @param {Element} elt + * @param {HtmxExtension[]=} extensionsToReturn + * @param {string[]=} extensionsToIgnore + * @returns {HtmxExtension[]} + */ + function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + if (extensionsToReturn == undefined) { + extensionsToReturn = [] + } + if (elt == undefined) { + return extensionsToReturn + } + if (extensionsToIgnore == undefined) { + extensionsToIgnore = [] + } + const extensionsForElement = getAttributeValue(elt, 'hx-ext') + if (extensionsForElement) { + forEach(extensionsForElement.split(','), function(extensionName) { + extensionName = extensionName.replace(/ /g, '') + if (extensionName.slice(0, 7) == 'ignore:') { + extensionsToIgnore.push(extensionName.slice(7)) + return + } + if (extensionsToIgnore.indexOf(extensionName) < 0) { + const extension = extensions[extensionName] + if (extension && extensionsToReturn.indexOf(extension) < 0) { + extensionsToReturn.push(extension) + } + } + }) + } + return getExtensions(asElement(parentElt(elt)), extensionsToReturn, extensionsToIgnore) + } + + //= =================================================================== + // Initialization + //= =================================================================== + var isReady = false + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true + }) + + /** + * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. + * + * This function uses isReady because there is no reliable way to ask the browser whether + * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded + * firing and readystate=complete. + */ + function ready(fn) { + // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by + // some means other than the initial page load. + if (isReady || getDocument().readyState === 'complete') { + fn() + } else { + getDocument().addEventListener('DOMContentLoaded', fn) + } + } + + function insertIndicatorStyles() { + if (htmx.config.includeIndicatorStyles !== false) { + const nonceAttribute = htmx.config.inlineStyleNonce ? ` nonce="${htmx.config.inlineStyleNonce}"` : '' + getDocument().head.insertAdjacentHTML('beforeend', + '<style' + nonceAttribute + '>\ + .' + htmx.config.indicatorClass + '{opacity:0}\ + .' + htmx.config.requestClass + ' .' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\ + .' + htmx.config.requestClass + '.' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\ + </style>') + } + } + + function getMetaConfig() { + /** @type HTMLMetaElement */ + const element = getDocument().querySelector('meta[name="htmx-config"]') + if (element) { + return parseJSON(element.content) + } else { + return null + } + } - return htmx; + function mergeMetaConfig() { + const metaConfig = getMetaConfig() + if (metaConfig) { + htmx.config = mergeObjects(htmx.config, metaConfig) + } + } + + // initialize the document + ready(function() { + mergeMetaConfig() + insertIndicatorStyles() + let body = getDocument().body + processNode(body) + const restoredElts = getDocument().querySelectorAll( + "[hx-trigger='restored'],[data-hx-trigger='restored']" + ) + body.addEventListener('htmx:abort', function(evt) { + const target = evt.target + const internalData = getInternalData(target) + if (internalData && internalData.xhr) { + internalData.xhr.abort() + } + }) + /** @type {(ev: PopStateEvent) => any} */ + const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null + /** @type {(ev: PopStateEvent) => any} */ + window.onpopstate = function(event) { + if (event.state && event.state.htmx) { + restoreHistory() + forEach(restoredElts, function(elt) { + triggerEvent(elt, 'htmx:restored', { + document: getDocument(), + triggerEvent + }) + }) + } else { + if (originalPopstate) { + originalPopstate(event) + } + } } -)() -})); + getWindow().setTimeout(function() { + triggerEvent(body, 'htmx:load', {}) // give ready handlers a chance to load up before firing this event + body = null // kill reference for gc + }, 0) + }) + + return htmx +})() + +/** @typedef {'get'|'head'|'post'|'put'|'delete'|'connect'|'options'|'trace'|'patch'} HttpVerb */ + +/** + * @typedef {Object} SwapOptions + * @property {string} [select] + * @property {string} [selectOOB] + * @property {*} [eventInfo] + * @property {string} [anchor] + * @property {Element} [contextElement] + * @property {swapCallback} [afterSwapCallback] + * @property {swapCallback} [afterSettleCallback] + */ + +/** + * @callback swapCallback + */ + +/** + * @typedef {'innerHTML' | 'outerHTML' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'delete' | 'none' | string} HtmxSwapStyle + */ + +/** + * @typedef HtmxSwapSpecification + * @property {HtmxSwapStyle} swapStyle + * @property {number} swapDelay + * @property {number} settleDelay + * @property {boolean} [transition] + * @property {boolean} [ignoreTitle] + * @property {string} [head] + * @property {'top' | 'bottom'} [scroll] + * @property {string} [scrollTarget] + * @property {string} [show] + * @property {string} [showTarget] + * @property {boolean} [focusScroll] + */ + +/** + * @typedef {((this:Node, evt:Event) => boolean) & {source: string}} ConditionalFunction + */ + +/** + * @typedef {Object} HtmxTriggerSpecification + * @property {string} trigger + * @property {number} [pollInterval] + * @property {ConditionalFunction} [eventFilter] + * @property {boolean} [changed] + * @property {boolean} [once] + * @property {boolean} [consume] + * @property {number} [delay] + * @property {string} [from] + * @property {string} [target] + * @property {number} [throttle] + * @property {string} [queue] + * @property {string} [root] + * @property {string} [threshold] + */ + +/** + * @typedef {{elt: Element, message: string, validity: ValidityState}} HtmxElementValidationError + */ + +/** + * @typedef {Record<string, string>} HtmxHeaderSpecification + * @property {'true'} HX-Request + * @property {string|null} HX-Trigger + * @property {string|null} HX-Trigger-Name + * @property {string|null} HX-Target + * @property {string} HX-Current-URL + * @property {string} [HX-Prompt] + * @property {'true'} [HX-Boosted] + * @property {string} [Content-Type] + * @property {'true'} [HX-History-Restore-Request] + */ + +/** @typedef HtmxAjaxHelperContext + * @property {Element|string} [source] + * @property {Event} [event] + * @property {HtmxAjaxHandler} [handler] + * @property {Element|string} target + * @property {HtmxSwapStyle} [swap] + * @property {Object|FormData} [values] + * @property {Record<string,string>} [headers] + * @property {string} [select] + */ + +/** + * @typedef {Object} HtmxRequestConfig + * @property {boolean} boosted + * @property {boolean} useUrlParams + * @property {FormData} formData + * @property {Object} parameters formData proxy + * @property {FormData} unfilteredFormData + * @property {Object} unfilteredParameters unfilteredFormData proxy + * @property {HtmxHeaderSpecification} headers + * @property {Element} target + * @property {HttpVerb} verb + * @property {HtmxElementValidationError[]} errors + * @property {boolean} withCredentials + * @property {number} timeout + * @property {string} path + * @property {Event} triggeringEvent + */ + +/** + * @typedef {Object} HtmxResponseInfo + * @property {XMLHttpRequest} xhr + * @property {Element} target + * @property {HtmxRequestConfig} requestConfig + * @property {HtmxAjaxEtc} etc + * @property {boolean} boosted + * @property {string} select + * @property {{requestPath: string, finalRequestPath: string, responsePath: string|null, anchor: string}} pathInfo + * @property {boolean} [failed] + * @property {boolean} [successful] + */ + +/** + * @typedef {Object} HtmxAjaxEtc + * @property {boolean} [returnPromise] + * @property {HtmxAjaxHandler} [handler] + * @property {string} [select] + * @property {Element} [targetOverride] + * @property {HtmxSwapStyle} [swapOverride] + * @property {Record<string,string>} [headers] + * @property {Object|FormData} [values] + * @property {boolean} [credentials] + * @property {number} [timeout] + */ + +/** + * @typedef {Object} HtmxResponseHandlingConfig + * @property {string} [code] + * @property {boolean} swap + * @property {boolean} [error] + * @property {boolean} [ignoreTitle] + * @property {string} [select] + * @property {string} [target] + * @property {string} [swapOverride] + * @property {string} [event] + */ + +/** + * @typedef {HtmxResponseInfo & {shouldSwap: boolean, serverResponse: any, isError: boolean, ignoreTitle: boolean, selectOverride:string}} HtmxBeforeSwapDetails + */ + +/** + * @callback HtmxAjaxHandler + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + */ + +/** + * @typedef {(() => void)} HtmxSettleTask + */ + +/** + * @typedef {Object} HtmxSettleInfo + * @property {HtmxSettleTask[]} tasks + * @property {Element[]} elts + * @property {string} [title] + */ + +/** + * @typedef {Object} HtmxExtension + * @see https://htmx.org/extensions/#defining + * @property {(api: any) => void} init + * @property {(name: string, event: Event|CustomEvent) => boolean} onEvent + * @property {(text: string, xhr: XMLHttpRequest, elt: Element) => string} transformResponse + * @property {(swapStyle: HtmxSwapStyle) => boolean} isInlineSwap + * @property {(swapStyle: HtmxSwapStyle, target: Element, fragment: Node, settleInfo: HtmxSettleInfo) => boolean} handleSwap + * @property {(xhr: XMLHttpRequest, parameters: FormData, elt: Element) => *|string|null} encodeParameters + */ diff --git a/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.min.js b/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.min.js index 53bbdf6..d66acce 100644 --- a/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.min.js +++ b/code/ch6_active_search/ch6_final_video_collector/static/js/htmx.min.js @@ -1,4 +1,2 @@ -// /////////////////////////////////////////////////////////////////// -// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js -// -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(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 a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/<body/.test(e)}function l(e){var t=!N(e);var r=A(e);var n=e;if(r==="head"){n=n.replace(S,"")}if(Q.config.useTemplateFragments&&t){var i=a("<body><template>"+n+"</template></body>",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a("<table>"+n+"</table>",1);case"col":return a("<table><colgroup>"+n+"</colgroup></table>",2);case"tr":return a("<table><tbody>"+n+"</tbody></table>",2);case"td":case"th":return a("<table><tbody><tr>"+n+"</tr></tbody></table>",3);case"script":case"style":return a("<div>"+n+"</div>",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function oe(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function X(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var Y=function(e,t){var r=re().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function we(t,r){oe(t.attributes,function(e){if(!r.hasAttribute(e.name)&&be(e.name)){t.removeAttribute(e.name)}});oe(r.attributes,function(e){if(be(e.name)){t.setAttribute(e.name,e.value)}})}function Se(e,t){var r=Fr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){b(e)}}return e==="outerHTML"}function Ee(e,i,a){var t="#"+ee(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a<i.length;a++){var o=i[a].split(":",2);var s=o[0].trim();if(s.indexOf("#")===0){s=s.substring(1)}var l=o[1]||"true";var u=t.querySelector("#"+s);if(u){Ee(l,u,r)}}}oe(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=te(e,"hx-swap-oob");if(t!=null){Ee(t,e,r)}})}function Re(e){oe(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=te(e,"id");var r=re().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function Te(o,e,s){oe(e.querySelectorAll("[id]"),function(e){var t=ee(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Le(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=He(n.name,t);t=He(n.value,t)}}}return t}function Ae(e){var t=ae(e);if(t.onHandlers){for(var r=0;r<t.onHandlers.length;r++){const n=t.onHandlers[r];e.removeEventListener(n.event,n.listener)}delete t.onHandlers}}function Ne(e){var t=ae(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){oe(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}Ae(e);oe(Object.keys(t),function(e){delete t[e]})}function p(e){ce(e,"htmx:beforeCleanupElement");Ne(e);if(e.children){oe(e.children,function(e){p(e)})}}function Ie(t,e,r){if(t.tagName==="BODY"){return Ue(t,e,r)}else{var n;var i=t.previousSibling;m(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}p(t);u(t).removeChild(t)}}function ke(e,t,r){return m(e,e.firstChild,t,r)}function Pe(e,t,r){return m(u(e),e,t,r)}function Me(e,t,r){return m(e,null,t,r)}function Xe(e,t,r){return m(u(e),e.nextSibling,t,r)}function De(e,t,r){p(e);return u(e).removeChild(e)}function Ue(e,t,r){var n=e.firstChild;m(e,n,t,r);if(n){while(n.nextSibling){p(n.nextSibling);e.removeChild(n.nextSibling)}p(n);e.removeChild(n)}}function Be(e,t,r){var n=r||ne(e,"hx-select");if(n){var i=re().createDocumentFragment();oe(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function Fe(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Ie(r,n,i);return;case"afterbegin":ke(r,n,i);return;case"beforebegin":Pe(r,n,i);return;case"beforeend":Me(r,n,i);return;case"afterend":Xe(r,n,i);return;case"delete":De(r,n,i);return;default:var a=Fr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Oe(f))}}}return}}catch(e){b(e)}}if(e==="innerHTML"){Ue(r,n,i)}else{Fe(Q.config.defaultSwapStyle,t,r,n,i)}}}function Ve(e){if(e.indexOf("<title")>-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){ce(r,s[l].trim(),[])}}}var ze=/\s/;var x=/[\s,]/;var $e=/[_$a-zA-Z]/;var We=/[_$a-zA-Z0-9]/;var Ge=['"',"'","/"];var Je=/[^\s]/;var Ze=/[{(]/;var Ke=/[})]/;function Ye(e){var t=[];var r=0;while(r<e.length){if($e.exec(e.charAt(r))){var n=r;while(We.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ge.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function Qe(e,t,r){return $e.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function et(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){xt(e,a[1],0)}if(a[0]==="send"){bt(e)}}}function xt(s,r,n){if(!se(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=Q.createWebSocket(r);t.onerror=function(e){fe(s,"htmx:wsError",{error:e,socket:t});yt(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a<i.length;a++){var o=i[a];Ee(te(o,"hx-swap-oob")||"true",o,r)}nr(r.tasks)})}function yt(e){if(!se(e)){ae(e).webSocket.close();return true}}function bt(u){var f=c(u,function(e){return ae(e).webSocket!=null});if(f){u.addEventListener(it(u)[0].trigger,function(e){var t=ae(f).webSocket;var r=xr(u,f);var n=dr(u,"post");var i=n.errors;var a=n.values;var o=Hr(u);var s=le(a,o);var l=yr(s,u);l["HEADERS"]=r;if(i&&i.length>0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){Et(e,a[1])}if(a[0]==="swap"){Ct(e,a[1])}}}function Et(t,e){var r=Q.createEventSource(e);r.onerror=function(e){fe(t,"htmx:sseError",{error:e,source:r});Tt(t)};ae(t).sseEventSource=r}function Ct(a,o){var s=c(a,Ot);if(s){var l=ae(s).sseEventSource;var u=function(e){if(Tt(s)){return}if(!se(a)){l.removeEventListener(o,u);return}var t=e.data;R(a,function(e){t=e.transformResponse(t,null,a)});var r=wr(a);var n=ye(a);var i=T(a);je(r.swapStyle,n,a,t,i);nr(i.tasks);ce(a,"htmx:sseMessage",e)};ae(a).sseListener=u;l.addEventListener(o,u)}else{fe(a,"htmx:noSSESourceError")}}function Rt(e,t,r){var n=c(e,Ot);if(n){var i=ae(n).sseEventSource;var a=function(){if(!Tt(n)){if(se(e)){t(e)}else{i.removeEventListener(r,a)}}};ae(e).sseListener=a;i.addEventListener(r,a)}else{fe(e,"htmx:noSSESourceError")}}function Tt(e){if(!se(e)){ae(e).sseEventSource.close();return true}}function Ot(e){return ae(e).sseEventSource!=null}function qt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n>0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){ce(n,"intersect");break}}},i);a.observe(n);ht(n,r,t,e)}else if(e.trigger==="load"){if(!ct(e,n,Wt("load",{elt:n}))){qt(n,r,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r<t.length;r++){var n=t[r].name;if(s(n,"hx-on:")||s(n,"data-hx-on:")||s(n,"hx-on-")||s(n,"data-hx-on-")){return true}}return false}function kt(e){var t=null;var r=[];if(It(e)){r.push(e)}if(document.evaluate){var n=document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]',e);while(t=n.iterateNext())r.push(t)}else{var i=e.getElementsByTagName("*");for(var a=0;a<i.length;a++){if(It(i[a])){r.push(i[a])}}}return r}function Pt(e){if(e.querySelectorAll){var t=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";var r=e.querySelectorAll(i+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Mt(e){var t=v(e.target,"button, input[type='submit']");var r=Dt(e);if(r){r.lastButtonClicked=t}}function Xt(e){var t=Dt(e);if(t){t.lastButtonClicked=null}}function Dt(e){var t=v(e.target,"button, input[type='submit']");if(!t){return}var r=g("#"+ee(t,"form"))||v(t,"form");if(!r){return}return ae(r)}function Ut(e){e.addEventListener("click",Mt);e.addEventListener("focusin",Mt);e.addEventListener("focusout",Xt)}function Bt(e){var t=Ye(e);var r=0;for(var n=0;n<t.length;n++){const i=t[n];if(i==="{"){r++}else if(i==="}"){r--}}return r}function Ft(t,e,r){var n=ae(t);if(!Array.isArray(n.onHandlers)){n.onHandlers=[]}var i;var a=function(e){return Tr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Vt(e){var t=te(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;t<e.attributes.length;t++){var r=e.attributes[t].name;var n=e.attributes[t].value;if(s(r,"hx-on")||s(r,"data-hx-on")){var i=r.indexOf("-on")+3;var a=r.slice(i,i+1);if(a==="-"||a===":"){var o=r.slice(i+1);if(s(o,":")){o="htmx"+o}else if(s(o,"-")){o="htmx:"+o.slice(1)}else if(s(o,"htmx-")){o="htmx:"+o.slice(5)}Ft(e,o,n)}}}}function _t(t){if(v(t,Q.config.disableSelector)){p(t);return}var r=ae(t);if(r.initHash!==Le(t)){Ne(t);r.initHash=Le(t);Vt(t);ce(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=it(t);var n=Ht(t,r,e);if(!n){if(ne(t,"hx-boost")==="true"){lt(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){Lt(t,e,r,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&o(t,"form")){Ut(t)}var i=te(t,"hx-sse");if(i){St(t,r,i)}var a=te(t,"hx-ws");if(a){pt(t,r,a)}ce(t,"htmx:afterProcessNode")}}function zt(e){e=g(e);if(v(e,Q.config.disableSelector)){p(e);return}_t(e);oe(Pt(e),function(e){_t(e)});oe(kt(e),jt)}function $t(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=re().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function fe(e,t,r){ce(e,t,le({error:t},r))}function Gt(e){return e==="htmx:afterProcessNode"}function R(e,t){oe(Fr(e),function(e){try{t(e)}catch(e){b(e)}})}function b(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ce(e,t,r){e=g(e);if(r==null){r={}}r["elt"]=e;var n=Wt(t,r);if(Q.logger&&!Gt(t)){Q.logger(e,t,r)}if(r.error){b(r.error);ce(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=$t(t);if(i&&a!==t){var o=Wt(a,n.detail);i=i&&e.dispatchEvent(o)}R(e,function(e){i=i&&(e.onEvent(t,n)!==false&&!n.defaultPrevented)});return i}var Jt=location.pathname+location.search;function Zt(){var e=re().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||re().body}function Kt(e,t,r,n){if(!U()){return}if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}e=B(e);var i=E(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};ce(re().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Qt(e){var t=Q.config.requestClass;var r=e.cloneNode(true);oe(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function er(){var e=Zt();var t=Jt||location.pathname+location.search;var r;try{r=re().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){r=re().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!r){ce(re().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Kt(t,Qt(e),re().title,window.scrollY)}if(Q.config.historyEnabled)history.replaceState({htmx:true},re().title,window.location.href)}function tr(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(G(e,"&")||G(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Jt=e}function rr(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Jt=e}function nr(e){oe(e,function(e){e.call()})}function ir(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};ce(re().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",re().location.href);e.onload=function(){if(this.status>=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function fr(e){if(e.name===""||e.name==null||e.disabled||v(e,"fieldset[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 cr(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function hr(t,r,n,e,i){if(e==null||ur(t,e)){return}else{t.push(e)}if(fr(e)){var a=ee(e,"name");var o=e.value;if(e.multiple&&e.tagName==="SELECT"){o=M(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=M(e.files)}cr(a,o,r);if(i){vr(e,n)}}if(h(e,"form")){var s=e.elements;oe(s,function(e){hr(t,r,n,e,i)})}}function vr(e,t){if(e.willValidate){ce(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});ce(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function dr(e,t){var r=[];var n={};var i={};var a=[];var o=ae(e);if(o.lastButtonClicked&&!se(o.lastButtonClicked)){o.lastButtonClicked=null}var s=h(e,"form")&&e.noValidate!==true||te(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){hr(r,i,a,v(e,"form"),s)}hr(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=ee(l,"name");cr(u,l.value,i)}var f=pe(e,"hx-include");oe(f,function(e){hr(r,n,a,e,s);if(!h(e,"form")){oe(e.querySelectorAll(rt),function(e){hr(r,n,a,e,s)})}});n=le(n,i);return{errors:a,values:n}}function gr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function mr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t=gr(t,r,e)})}else{t=gr(t,r,n)}}}return t}function pr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function xr(e,t,r){var n={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":re().location.href};Rr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ae(e).boosted){n["HX-Boosted"]="true"}return n}function yr(t,e){var r=ne(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){oe(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};oe(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function br(e){return ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=d(o.substr(5))}else if(o.indexOf("settle:")===0){n["settleDelay"]=d(o.substr(7))}else if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}else if(o.indexOf("ignoreTitle:")===0){n["ignoreTitle"]=o.substr(12)==="true"}else if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","<style> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file +// v2.0.0 from https://github.com/bigskysoftware/htmx/releases +var htmx=function(){"use strict";const Q={onLoad:null,process:null,on:null,off:null,trigger:null,ajax:null,find:null,findAll:null,closest:null,values:function(e,t){const n=cn(e,t||"post");return n.values},remove:null,addClass:null,removeClass:null,toggleClass:null,takeClass:null,swap:null,defineExtension:null,removeExtension:null,logAll:null,logNone:null,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",inlineStyleNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",scrollBehavior:"instant",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get","delete"],selfRequestsOnly:true,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null,disableInheritance:false,responseHandling:[{code:"204",swap:false},{code:"[23]..",swap:true},{code:"[45]..",swap:false,error:true}],allowNestedOobSwaps:true},parseInterval:null,_:null,version:"2.0.0"};Q.onLoad=$;Q.process=Dt;Q.on=be;Q.off=we;Q.trigger=he;Q.ajax=Hn;Q.find=r;Q.findAll=p;Q.closest=g;Q.remove=K;Q.addClass=W;Q.removeClass=o;Q.toggleClass=Y;Q.takeClass=ge;Q.swap=ze;Q.defineExtension=Un;Q.removeExtension=Bn;Q.logAll=z;Q.logNone=J;Q.parseInterval=d;Q._=_;const n={addTriggerHandler:Et,bodyContains:le,canAccessLocalStorage:j,findThisElement:Ee,filterValues:dn,swap:ze,hasAttribute:s,getAttributeValue:te,getClosestAttributeValue:re,getClosestMatch:T,getExpressionVars:Cn,getHeaders:hn,getInputValues:cn,getInternalData:ie,getSwapSpecification:pn,getTriggerSpecs:lt,getTarget:Ce,makeFragment:D,mergeObjects:ue,makeSettleInfo:xn,oobSwap:Te,querySelectorExt:fe,settleImmediately:Gt,shouldCancel:dt,triggerEvent:he,triggerErrorEvent:ae,withExtensions:Ut};const v=["get","post","put","delete","patch"];const R=v.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");const O=e("head");function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e instanceof Element&&e.getAttribute(t)}function s(e,t){return!!e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){const t=e.parentElement;if(!t&&e.parentNode instanceof ShadowRoot)return e.parentNode;return t}function ne(){return document}function H(e,t){return e.getRootNode?e.getRootNode({composed:t}):ne()}function T(e,t){while(e&&!t(e)){e=u(e)}return e||null}function q(e,t,n){const r=te(t,n);const o=te(t,"hx-disinherit");var i=te(t,"hx-inherit");if(e!==t){if(Q.config.disableInheritance){if(i&&(i==="*"||i.split(" ").indexOf(n)>=0)){return r}else{return null}}if(o&&(o==="*"||o.split(" ").indexOf(n)>=0)){return"unset"}}return r}function re(t,n){let r=null;T(t,function(e){return!!(r=q(t,ce(e),n))});if(r!=="unset"){return r}}function a(e,t){const n=e instanceof Element&&(e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector);return!!n&&n.call(e,t)}function L(e){const t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;const n=t.exec(e);if(n){return n[1].toLowerCase()}else{return""}}function N(e){const t=new DOMParser;return t.parseFromString(e,"text/html")}function A(e,t){while(t.childNodes.length>0){e.append(t.childNodes[0])}}function I(e){const t=ne().createElement("script");se(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}return t}function P(e){return e.matches("script")&&(e.type==="text/javascript"||e.type==="module"||e.type==="")}function k(e){Array.from(e.querySelectorAll("script")).forEach(e=>{if(P(e)){const t=I(e);const n=e.parentNode;try{n.insertBefore(t,e)}catch(e){w(e)}finally{e.remove()}}})}function D(e){const t=e.replace(O,"");const n=L(t);let r;if(n==="html"){r=new DocumentFragment;const i=N(e);A(r,i.body);r.title=i.title}else if(n==="body"){r=new DocumentFragment;const i=N(t);A(r,i.body);r.title=i.title}else{const i=N('<body><template class="internal-htmx-wrapper">'+t+"</template></body>");r=i.querySelector("template").content;r.title=i.title;var o=r.querySelector("title");if(o&&o.parentNode===r){o.remove();r.title=o.innerText}}if(r){if(Q.config.allowScriptTags){k(r)}else{r.querySelectorAll("script").forEach(e=>e.remove())}}return r}function oe(e){if(e){e()}}function t(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function M(e){return typeof e==="function"}function X(e){return t(e,"Object")}function ie(e){const t="htmx-internal-data";let n=e[t];if(!n){n=e[t]={}}return n}function F(t){const n=[];if(t){for(let e=0;e<t.length;e++){n.push(t[e])}}return n}function se(t,n){if(t){for(let e=0;e<t.length;e++){n(t[e])}}}function U(e){const t=e.getBoundingClientRect();const n=t.top;const r=t.bottom;return n<window.innerHeight&&r>=0}function le(e){const t=e.getRootNode&&e.getRootNode();if(t&&t instanceof window.ShadowRoot){return ne().body.contains(t.host)}else{return ne().body.contains(e)}}function B(e){return e.trim().split(/\s+/)}function ue(e,t){for(const n in t){if(t.hasOwnProperty(n)){e[n]=t[n]}}return e}function S(e){try{return JSON.parse(e)}catch(e){w(e);return null}}function j(){const e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function V(t){try{const e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function _(e){return vn(ne().body,function(){return eval(e)})}function $(t){const e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function z(){Q.logger=function(e,t,n){if(console){console.log(t,e,n)}}}function J(){Q.logger=null}function r(e,t){if(typeof e!=="string"){return e.querySelector(t)}else{return r(ne(),e)}}function p(e,t){if(typeof e!=="string"){return e.querySelectorAll(t)}else{return p(ne(),e)}}function E(){return window}function K(e,t){e=y(e);if(t){E().setTimeout(function(){K(e);e=null},t)}else{u(e).removeChild(e)}}function ce(e){return e instanceof Element?e:null}function G(e){return e instanceof HTMLElement?e:null}function Z(e){return typeof e==="string"?e:null}function h(e){return e instanceof Element||e instanceof Document||e instanceof DocumentFragment?e:null}function W(e,t,n){e=ce(y(e));if(!e){return}if(n){E().setTimeout(function(){W(e,t);e=null},n)}else{e.classList&&e.classList.add(t)}}function o(e,t,n){let r=ce(y(e));if(!r){return}if(n){E().setTimeout(function(){o(r,t);r=null},n)}else{if(r.classList){r.classList.remove(t);if(r.classList.length===0){r.removeAttribute("class")}}}}function Y(e,t){e=y(e);e.classList.toggle(t)}function ge(e,t){e=y(e);se(e.parentElement.children,function(e){o(e,t)});W(ce(e),t)}function g(e,t){e=ce(y(e));if(e&&e.closest){return e.closest(t)}else{do{if(e==null||a(e,t)){return e}}while(e=e&&ce(u(e)));return null}}function l(e,t){return e.substring(0,t.length)===t}function pe(e,t){return e.substring(e.length-t.length)===t}function i(e){const t=e.trim();if(l(t,"<")&&pe(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function m(e,t,n){e=y(e);if(t.indexOf("closest ")===0){return[g(ce(e),i(t.substr(8)))]}else if(t.indexOf("find ")===0){return[r(h(e),i(t.substr(5)))]}else if(t==="next"){return[ce(e).nextElementSibling]}else if(t.indexOf("next ")===0){return[me(e,i(t.substr(5)),!!n)]}else if(t==="previous"){return[ce(e).previousElementSibling]}else if(t.indexOf("previous ")===0){return[ye(e,i(t.substr(9)),!!n)]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else if(t==="root"){return[H(e,!!n)]}else if(t.indexOf("global ")===0){return m(e,t.slice(7),true)}else{return F(h(H(e,!!n)).querySelectorAll(i(t)))}}var me=function(t,e,n){const r=h(H(t,n)).querySelectorAll(e);for(let e=0;e<r.length;e++){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_PRECEDING){return o}}};var ye=function(t,e,n){const r=h(H(t,n)).querySelectorAll(e);for(let e=r.length-1;e>=0;e--){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_FOLLOWING){return o}}};function fe(e,t){if(typeof e!=="string"){return m(e,t)[0]}else{return m(ne().body,e)[0]}}function y(e,t){if(typeof e==="string"){return r(h(t)||document,e)}else{return e}}function xe(e,t,n){if(M(t)){return{target:ne().body,event:Z(e),listener:t}}else{return{target:y(e),event:Z(t),listener:n}}}function be(t,n,r){_n(function(){const e=xe(t,n,r);e.target.addEventListener(e.event,e.listener)});const e=M(n);return e?n:r}function we(t,n,r){_n(function(){const e=xe(t,n,r);e.target.removeEventListener(e.event,e.listener)});return M(n)?n:r}const ve=ne().createElement("output");function Se(e,t){const n=re(e,t);if(n){if(n==="this"){return[Ee(e,t)]}else{const r=m(e,n);if(r.length===0){w('The selector "'+n+'" on '+t+" returned no matches!");return[ve]}else{return r}}}}function Ee(e,t){return ce(T(e,function(e){return te(ce(e),t)!=null}))}function Ce(e){const t=re(e,"hx-target");if(t){if(t==="this"){return Ee(e,"hx-target")}else{return fe(e,t)}}else{const n=ie(e);if(n.boosted){return ne().body}else{return e}}}function Re(t){const n=Q.config.attributesToSettle;for(let e=0;e<n.length;e++){if(t===n[e]){return true}}return false}function Oe(t,n){se(t.attributes,function(e){if(!n.hasAttribute(e.name)&&Re(e.name)){t.removeAttribute(e.name)}});se(n.attributes,function(e){if(Re(e.name)){t.setAttribute(e.name,e.value)}})}function He(t,e){const n=jn(e);for(let e=0;e<n.length;e++){const r=n[e];try{if(r.isInlineSwap(t)){return true}}catch(e){w(e)}}return t==="outerHTML"}function Te(e,o,i){let t="#"+ee(o,"id");let s="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){s=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{s=e}const n=ne().querySelectorAll(t);if(n){se(n,function(e){let t;const n=o.cloneNode(true);t=ne().createDocumentFragment();t.appendChild(n);if(!He(s,e)){t=h(n)}const r={shouldSwap:true,target:e,fragment:t};if(!he(e,"htmx:oobBeforeSwap",r))return;e=r.target;if(r.shouldSwap){_e(s,e,e,t,i)}se(i.elts,function(e){he(e,"htmx:oobAfterSwap",r)})});o.parentNode.removeChild(o)}else{o.parentNode.removeChild(o);ae(ne().body,"htmx:oobErrorNoTarget",{content:o})}return e}function qe(e){se(p(e,"[hx-preserve], [data-hx-preserve]"),function(e){const t=te(e,"id");const n=ne().getElementById(t);if(n!=null){e.parentNode.replaceChild(n,e)}})}function Le(l,e,u){se(e.querySelectorAll("[id]"),function(t){const n=ee(t,"id");if(n&&n.length>0){const r=n.replace("'","\\'");const o=t.tagName.replace(":","\\:");const e=h(l);const i=e&&e.querySelector(o+"[id='"+r+"']");if(i&&i!==e){const s=t.cloneNode();Oe(t,i);u.tasks.push(function(){Oe(t,s)})}}})}function Ne(e){return function(){o(e,Q.config.addedClass);Dt(ce(e));Ae(h(e));he(e,"htmx:load")}}function Ae(e){const t="[autofocus]";const n=G(a(e,t)?e:e.querySelector(t));if(n!=null){n.focus()}}function c(e,t,n,r){Le(e,n,r);while(n.childNodes.length>0){const o=n.firstChild;W(ce(o),Q.config.addedClass);e.insertBefore(o,t);if(o.nodeType!==Node.TEXT_NODE&&o.nodeType!==Node.COMMENT_NODE){r.tasks.push(Ne(o))}}}function Ie(e,t){let n=0;while(n<e.length){t=(t<<5)-t+e.charCodeAt(n++)|0}return t}function Pe(t){let n=0;if(t.attributes){for(let e=0;e<t.attributes.length;e++){const r=t.attributes[e];if(r.value){n=Ie(r.name,n);n=Ie(r.value,n)}}}return n}function ke(t){const n=ie(t);if(n.onHandlers){for(let e=0;e<n.onHandlers.length;e++){const r=n.onHandlers[e];we(t,r.event,r.listener)}delete n.onHandlers}}function De(e){const t=ie(e);if(t.timeout){clearTimeout(t.timeout)}if(t.listenerInfos){se(t.listenerInfos,function(e){if(e.on){we(e.on,e.trigger,e.listener)}})}ke(e);se(Object.keys(t),function(e){delete t[e]})}function f(e){he(e,"htmx:beforeCleanupElement");De(e);if(e.children){se(e.children,function(e){f(e)})}}function Me(t,e,n){let r;const o=t.previousSibling;c(u(t),t,e,n);if(o==null){r=u(t).firstChild}else{r=o.nextSibling}n.elts=n.elts.filter(function(e){return e!==t});while(r&&r!==t){if(r instanceof Element){n.elts.push(r);r=r.nextElementSibling}else{r=null}}f(t);if(t instanceof Element){t.remove()}else{t.parentNode.removeChild(t)}}function Xe(e,t,n){return c(e,e.firstChild,t,n)}function Fe(e,t,n){return c(u(e),e,t,n)}function Ue(e,t,n){return c(e,null,t,n)}function Be(e,t,n){return c(u(e),e.nextSibling,t,n)}function je(e){f(e);return u(e).removeChild(e)}function Ve(e,t,n){const r=e.firstChild;c(e,r,t,n);if(r){while(r.nextSibling){f(r.nextSibling);e.removeChild(r.nextSibling)}f(r);e.removeChild(r)}}function _e(t,e,n,r,o){switch(t){case"none":return;case"outerHTML":Me(n,r,o);return;case"afterbegin":Xe(n,r,o);return;case"beforebegin":Fe(n,r,o);return;case"beforeend":Ue(n,r,o);return;case"afterend":Be(n,r,o);return;case"delete":je(n);return;default:var i=jn(e);for(let e=0;e<i.length;e++){const s=i[e];try{const l=s.handleSwap(t,n,r,o);if(l){if(typeof l.length!=="undefined"){for(let e=0;e<l.length;e++){const u=l[e];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){o.tasks.push(Ne(u))}}}return}}catch(e){w(e)}}if(t==="innerHTML"){Ve(n,r,o)}else{_e(Q.config.defaultSwapStyle,e,n,r,o)}}}function $e(e,n){se(p(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){if(Q.config.allowNestedOobSwaps||e.parentElement===null){const t=te(e,"hx-swap-oob");if(t!=null){Te(t,e,n)}}else{e.removeAttribute("hx-swap-oob");e.removeAttribute("data-hx-swap-oob")}})}function ze(e,t,r,o){if(!o){o={}}e=y(e);const n=document.activeElement;let i={};try{i={elt:n,start:n?n.selectionStart:null,end:n?n.selectionEnd:null}}catch(e){}const s=xn(e);if(r.swapStyle==="textContent"){e.textContent=t}else{let n=D(t);s.title=n.title;if(o.selectOOB){const u=o.selectOOB.split(",");for(let t=0;t<u.length;t++){const c=u[t].split(":",2);let e=c[0].trim();if(e.indexOf("#")===0){e=e.substring(1)}const f=c[1]||"true";const a=n.querySelector("#"+e);if(a){Te(f,a,s)}}}$e(n,s);se(p(n,"template"),function(e){$e(e.content,s);if(e.content.childElementCount===0){e.remove()}});if(o.select){const h=ne().createDocumentFragment();se(n.querySelectorAll(o.select),function(e){h.appendChild(e)});n=h}qe(n);_e(r.swapStyle,o.contextElement,e,n,s)}if(i.elt&&!le(i.elt)&&ee(i.elt,"id")){const d=document.getElementById(ee(i.elt,"id"));const g={preventScroll:r.focusScroll!==undefined?!r.focusScroll:!Q.config.defaultFocusScroll};if(d){if(i.start&&d.setSelectionRange){try{d.setSelectionRange(i.start,i.end)}catch(e){}}d.focus(g)}}e.classList.remove(Q.config.swappingClass);se(s.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}he(e,"htmx:afterSwap",o.eventInfo)});if(o.afterSwapCallback){o.afterSwapCallback()}if(!r.ignoreTitle){Dn(s.title)}const l=function(){se(s.tasks,function(e){e.call()});se(s.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}he(e,"htmx:afterSettle",o.eventInfo)});if(o.anchor){const e=ce(y("#"+o.anchor));if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}bn(s.elts,r);if(o.afterSettleCallback){o.afterSettleCallback()}};if(r.settleDelay>0){E().setTimeout(l,r.settleDelay)}else{l()}}function Je(e,t,n){const r=e.getResponseHeader(t);if(r.indexOf("{")===0){const o=S(r);for(const i in o){if(o.hasOwnProperty(i)){let e=o[i];if(!X(e)){e={value:e}}he(n,i,e)}}}else{const s=r.split(",");for(let e=0;e<s.length;e++){he(n,s[e].trim(),[])}}}const Ke=/\s/;const x=/[\s,]/;const Ge=/[_$a-zA-Z]/;const Ze=/[_$a-zA-Z0-9]/;const We=['"',"'","/"];const Ye=/[^\s]/;const Qe=/[{(]/;const et=/[})]/;function tt(e){const t=[];let n=0;while(n<e.length){if(Ge.exec(e.charAt(n))){var r=n;while(Ze.exec(e.charAt(n+1))){n++}t.push(e.substr(r,n-r+1))}else if(We.indexOf(e.charAt(n))!==-1){const o=e.charAt(n);var r=n;n++;while(n<e.length&&e.charAt(n)!==o){if(e.charAt(n)==="\\"){n++}n++}t.push(e.substr(r,n-r+1))}else{const i=e.charAt(n);t.push(i)}n++}return t}function nt(e,t,n){return Ge.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==n&&t!=="."}function rt(r,o,i){if(o[0]==="["){o.shift();let e=1;let t=" return (function("+i+"){ return (";let n=null;while(o.length>0){const s=o[0];if(s==="]"){e--;if(e===0){if(n===null){t=t+"true"}o.shift();t+=")})";try{const l=vn(r,function(){return Function(t)()},function(){return true});l.source=t;return l}catch(e){ae(ne().body,"htmx:syntax:error",{error:e,source:t});return null}}}else if(s==="["){e++}if(nt(s,n,i)){t+="(("+i+"."+s+") ? ("+i+"."+s+") : (window."+s+"))"}else{t=t+s}n=o.shift()}}}function b(e,t){let n="";while(e.length>0&&!t.test(e[0])){n+=e.shift()}return n}function ot(e){let t;if(e.length>0&&Qe.test(e[0])){e.shift();t=b(e,et).trim();e.shift()}else{t=b(e,x)}return t}const it="input, textarea, select";function st(e,t,n){const r=[];const o=tt(t);do{b(o,Ye);const l=o.length;const u=b(o,/[,\[\s]/);if(u!==""){if(u==="every"){const c={trigger:"every"};b(o,Ye);c.pollInterval=d(b(o,/[,\[\s]/));b(o,Ye);var i=rt(e,o,"event");if(i){c.eventFilter=i}r.push(c)}else{const f={trigger:u};var i=rt(e,o,"event");if(i){f.eventFilter=i}while(o.length>0&&o[0]!==","){b(o,Ye);const a=o.shift();if(a==="changed"){f.changed=true}else if(a==="once"){f.once=true}else if(a==="consume"){f.consume=true}else if(a==="delay"&&o[0]===":"){o.shift();f.delay=d(b(o,x))}else if(a==="from"&&o[0]===":"){o.shift();if(Qe.test(o[0])){var s=ot(o)}else{var s=b(o,x);if(s==="closest"||s==="find"||s==="next"||s==="previous"){o.shift();const h=ot(o);if(h.length>0){s+=" "+h}}}f.from=s}else if(a==="target"&&o[0]===":"){o.shift();f.target=ot(o)}else if(a==="throttle"&&o[0]===":"){o.shift();f.throttle=d(b(o,x))}else if(a==="queue"&&o[0]===":"){o.shift();f.queue=b(o,x)}else if(a==="root"&&o[0]===":"){o.shift();f[a]=ot(o)}else if(a==="threshold"&&o[0]===":"){o.shift();f[a]=b(o,x)}else{ae(e,"htmx:syntax:error",{token:o.shift()})}}r.push(f)}}if(o.length===l){ae(e,"htmx:syntax:error",{token:o.shift()})}b(o,Ye)}while(o[0]===","&&o.shift());if(n){n[t]=r}return r}function lt(e){const t=te(e,"hx-trigger");let n=[];if(t){const r=Q.config.triggerSpecsCache;n=r&&r[t]||st(e,t,r)}if(n.length>0){return n}else if(a(e,"form")){return[{trigger:"submit"}]}else if(a(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(a(e,it)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function ut(e){ie(e).cancelled=true}function ct(e,t,n){const r=ie(e);r.timeout=E().setTimeout(function(){if(le(e)&&r.cancelled!==true){if(!pt(n,e,Xt("hx:poll:trigger",{triggerSpec:n,target:e}))){t(e)}ct(e,t,n)}},n.pollInterval)}function ft(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function at(e){return g(e,Q.config.disableSelector)}function ht(t,n,e){if(t instanceof HTMLAnchorElement&&ft(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){n.boosted=true;let r,o;if(t.tagName==="A"){r="get";o=ee(t,"href")}else{const i=ee(t,"method");r=i?i.toLowerCase():"get";if(r==="get"){}o=ee(t,"action")}e.forEach(function(e){mt(t,function(e,t){const n=ce(e);if(at(n)){f(n);return}de(r,o,n,t)},n,e,true)})}}function dt(e,t){const n=ce(t);if(!n){return false}if(e.type==="submit"||e.type==="click"){if(n.tagName==="FORM"){return true}if(a(n,'input[type="submit"], button')&&g(n,"form")!==null){return true}if(n instanceof HTMLAnchorElement&&n.href&&(n.getAttribute("href")==="#"||n.getAttribute("href").indexOf("#")!==0)){return true}}return false}function gt(e,t){return ie(e).boosted&&e instanceof HTMLAnchorElement&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function pt(e,t,n){const r=e.eventFilter;if(r){try{return r.call(t,n)!==true}catch(e){const o=r.source;ae(ne().body,"htmx:eventFilter:error",{error:e,source:o});return true}}return false}function mt(s,l,e,u,c){const f=ie(s);let t;if(u.from){t=m(s,u.from)}else{t=[s]}if(u.changed){t.forEach(function(e){const t=ie(e);t.lastValue=e.value})}se(t,function(o){const i=function(e){if(!le(s)){o.removeEventListener(u.trigger,i);return}if(gt(s,e)){return}if(c||dt(e,s)){e.preventDefault()}if(pt(u,s,e)){return}const t=ie(e);t.triggerSpec=u;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(s)<0){t.handledFor.push(s);if(u.consume){e.stopPropagation()}if(u.target&&e.target){if(!a(ce(e.target),u.target)){return}}if(u.once){if(f.triggeredOnce){return}else{f.triggeredOnce=true}}if(u.changed){const n=ie(o);const r=o.value;if(n.lastValue===r){return}n.lastValue=r}if(f.delayed){clearTimeout(f.delayed)}if(f.throttle){return}if(u.throttle>0){if(!f.throttle){l(s,e);f.throttle=E().setTimeout(function(){f.throttle=null},u.throttle)}}else if(u.delay>0){f.delayed=E().setTimeout(function(){l(s,e)},u.delay)}else{he(s,"htmx:trigger");l(s,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:u.trigger,listener:i,on:o});o.addEventListener(u.trigger,i)})}let yt=false;let xt=null;function bt(){if(!xt){xt=function(){yt=true};window.addEventListener("scroll",xt);setInterval(function(){if(yt){yt=false;se(ne().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"),function(e){wt(e)})}},200)}}function wt(e){if(!s(e,"data-hx-revealed")&&U(e)){e.setAttribute("data-hx-revealed","true");const t=ie(e);if(t.initHash){he(e,"revealed")}else{e.addEventListener("htmx:afterProcessNode",function(){he(e,"revealed")},{once:true})}}}function vt(e,t,n,r){const o=function(){if(!n.loaded){n.loaded=true;t(e)}};if(r>0){E().setTimeout(o,r)}else{o()}}function St(t,n,e){let i=false;se(v,function(r){if(s(t,"hx-"+r)){const o=te(t,"hx-"+r);i=true;n.path=o;n.verb=r;e.forEach(function(e){Et(t,e,n,function(e,t){const n=ce(e);if(g(n,Q.config.disableSelector)){f(n);return}de(r,o,n,t)})})}});return i}function Et(r,e,t,n){if(e.trigger==="revealed"){bt();mt(r,n,t,e);wt(ce(r))}else if(e.trigger==="intersect"){const o={};if(e.root){o.root=fe(r,e.root)}if(e.threshold){o.threshold=parseFloat(e.threshold)}const i=new IntersectionObserver(function(t){for(let e=0;e<t.length;e++){const n=t[e];if(n.isIntersecting){he(r,"intersect");break}}},o);i.observe(ce(r));mt(ce(r),n,t,e)}else if(e.trigger==="load"){if(!pt(e,r,Xt("load",{elt:r}))){vt(ce(r),n,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ct(ce(r),n,e)}else{mt(r,n,t,e)}}function Ct(e){const t=ce(e);if(!t){return false}const n=t.attributes;for(let e=0;e<n.length;e++){const r=n[e].name;if(l(r,"hx-on:")||l(r,"data-hx-on:")||l(r,"hx-on-")||l(r,"data-hx-on-")){return true}}return false}const Rt=(new XPathEvaluator).createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]');function Ot(e,t){if(Ct(e)){t.push(ce(e))}const n=Rt.evaluate(e);let r=null;while(r=n.iterateNext())t.push(ce(r))}function Ht(e){const t=[];if(e instanceof DocumentFragment){for(const n of e.childNodes){Ot(n,t)}}else{Ot(e,t)}return t}function Tt(e){if(e.querySelectorAll){const n=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";const r=[];for(const i in Xn){const s=Xn[i];if(s.getSelectors){var t=s.getSelectors();if(t){r.push(t)}}}const o=e.querySelectorAll(R+n+", form, [type='submit'],"+" [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]"+r.flat().map(e=>", "+e).join(""));return o}else{return[]}}function qt(e){const t=g(ce(e.target),"button, input[type='submit']");const n=Nt(e);if(n){n.lastButtonClicked=t}}function Lt(e){const t=Nt(e);if(t){t.lastButtonClicked=null}}function Nt(e){const t=g(ce(e.target),"button, input[type='submit']");if(!t){return}const n=y("#"+ee(t,"form"),t.getRootNode())||g(t,"form");if(!n){return}return ie(n)}function At(e){e.addEventListener("click",qt);e.addEventListener("focusin",qt);e.addEventListener("focusout",Lt)}function It(t,e,n){const r=ie(t);if(!Array.isArray(r.onHandlers)){r.onHandlers=[]}let o;const i=function(e){vn(t,function(){if(at(t)){return}if(!o){o=new Function("event",n)}o.call(t,e)})};t.addEventListener(e,i);r.onHandlers.push({event:e,listener:i})}function Pt(t){ke(t);for(let e=0;e<t.attributes.length;e++){const n=t.attributes[e].name;const r=t.attributes[e].value;if(l(n,"hx-on")||l(n,"data-hx-on")){const o=n.indexOf("-on")+3;const i=n.slice(o,o+1);if(i==="-"||i===":"){let e=n.slice(o+1);if(l(e,":")){e="htmx"+e}else if(l(e,"-")){e="htmx:"+e.slice(1)}else if(l(e,"htmx-")){e="htmx:"+e.slice(5)}It(t,e,r)}}}}function kt(t){if(g(t,Q.config.disableSelector)){f(t);return}const n=ie(t);if(n.initHash!==Pe(t)){De(t);n.initHash=Pe(t);he(t,"htmx:beforeProcessNode");if(t.value){n.lastValue=t.value}const e=lt(t);const r=St(t,n,e);if(!r){if(re(t,"hx-boost")==="true"){ht(t,n,e)}else if(s(t,"hx-trigger")){e.forEach(function(e){Et(t,e,n,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&s(t,"form")){At(t)}he(t,"htmx:afterProcessNode")}}function Dt(e){e=y(e);if(g(e,Q.config.disableSelector)){f(e);return}kt(e);se(Tt(e),function(e){kt(e)});se(Ht(e),Pt)}function Mt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Xt(e,t){let n;if(window.CustomEvent&&typeof window.CustomEvent==="function"){n=new CustomEvent(e,{bubbles:true,cancelable:true,composed:true,detail:t})}else{n=ne().createEvent("CustomEvent");n.initCustomEvent(e,true,true,t)}return n}function ae(e,t,n){he(e,t,ue({error:t},n))}function Ft(e){return e==="htmx:afterProcessNode"}function Ut(e,t){se(jn(e),function(e){try{t(e)}catch(e){w(e)}})}function w(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function he(e,t,n){e=y(e);if(n==null){n={}}n.elt=e;const r=Xt(t,n);if(Q.logger&&!Ft(t)){Q.logger(e,t,n)}if(n.error){w(n.error);he(e,"htmx:error",{errorInfo:n})}let o=e.dispatchEvent(r);const i=Mt(t);if(o&&i!==t){const s=Xt(i,r.detail);o=o&&e.dispatchEvent(s)}Ut(ce(e),function(e){o=o&&(e.onEvent(t,r)!==false&&!r.defaultPrevented)});return o}let Bt=location.pathname+location.search;function jt(){const e=ne().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||ne().body}function Vt(t,e){if(!j()){return}const n=$t(e);const r=ne().title;const o=window.scrollY;if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}t=V(t);const i=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e<i.length;e++){if(i[e].url===t){i.splice(e,1);break}}const s={url:t,content:n,title:r,scroll:o};he(ne().body,"htmx:historyItemCreated",{item:s,cache:i});i.push(s);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ae(ne().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function _t(t){if(!j()){return null}t=V(t);const n=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e<n.length;e++){if(n[e].url===t){return n[e]}}return null}function $t(e){const t=Q.config.requestClass;const n=e.cloneNode(true);se(p(n,"."+t),function(e){o(e,t)});return n.innerHTML}function zt(){const e=jt();const t=Bt||location.pathname+location.search;let n;try{n=ne().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){n=ne().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!n){he(ne().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Vt(t,e)}if(Q.config.historyEnabled)history.replaceState({htmx:true},ne().title,window.location.href)}function Jt(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(pe(e,"&")||pe(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Bt=e}function Kt(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Bt=e}function Gt(e){se(e,function(e){e.call(undefined)})}function Zt(o){const e=new XMLHttpRequest;const i={path:o,xhr:e};he(ne().body,"htmx:historyCacheMiss",i);e.open("GET",o,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",ne().location.href);e.onload=function(){if(this.status>=200&&this.status<400){he(ne().body,"htmx:historyCacheMissLoad",i);const e=D(this.response);const t=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;const n=jt();const r=xn(n);Dn(e.title);Ve(n,t,r);Gt(r.tasks);Bt=o;he(ne().body,"htmx:historyRestore",{path:o,cacheMiss:true,serverResponse:this.response})}else{ae(ne().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Wt(e){zt();e=e||location.pathname+location.search;const t=_t(e);if(t){const n=D(t.content);const r=jt();const o=xn(r);Dn(n.title);Ve(r,n,o);Gt(o.tasks);E().setTimeout(function(){window.scrollTo(0,t.scroll)},0);Bt=e;he(ne().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{Zt(e)}}}function Yt(e){let t=Se(e,"hx-indicator");if(t==null){t=[e]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.classList.add.call(e.classList,Q.config.requestClass)});return t}function Qt(e){let t=Se(e,"hx-disabled-elt");if(t==null){t=[]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function en(e,t){se(e,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList.remove.call(e.classList,Q.config.requestClass)}});se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function tn(t,n){for(let e=0;e<t.length;e++){const r=t[e];if(r.isSameNode(n)){return true}}return false}function nn(e){const t=e;if(t.name===""||t.name==null||t.disabled||g(t,"fieldset[disabled]")){return false}if(t.type==="button"||t.type==="submit"||t.tagName==="image"||t.tagName==="reset"||t.tagName==="file"){return false}if(t.type==="checkbox"||t.type==="radio"){return t.checked}return true}function rn(t,e,n){if(t!=null&&e!=null){if(Array.isArray(e)){e.forEach(function(e){n.append(t,e)})}else{n.append(t,e)}}}function on(t,n,r){if(t!=null&&n!=null){let e=r.getAll(t);if(Array.isArray(n)){e=e.filter(e=>n.indexOf(e)<0)}else{e=e.filter(e=>e!==n)}r.delete(t);se(e,e=>r.append(t,e))}}function sn(t,n,r,o,i){if(o==null||tn(t,o)){return}else{t.push(o)}if(nn(o)){const s=ee(o,"name");let e=o.value;if(o instanceof HTMLSelectElement&&o.multiple){e=F(o.querySelectorAll("option:checked")).map(function(e){return e.value})}if(o instanceof HTMLInputElement&&o.files){e=F(o.files)}rn(s,e,n);if(i){ln(o,r)}}if(o instanceof HTMLFormElement){se(o.elements,function(e){if(t.indexOf(e)>=0){on(e.name,e.value,n)}else{t.push(e)}if(i){ln(e,r)}});new FormData(o).forEach(function(e,t){if(e instanceof File&&e.name===""){return}rn(t,e,n)})}}function ln(e,t){const n=e;if(n.willValidate){he(n,"htmx:validation:validate");if(!n.checkValidity()){t.push({elt:n,message:n.validationMessage,validity:n.validity});he(n,"htmx:validation:failed",{message:n.validationMessage,validity:n.validity})}}}function un(t,e){for(const n of e.keys()){t.delete(n);e.getAll(n).forEach(function(e){t.append(n,e)})}return t}function cn(e,t){const n=[];const r=new FormData;const o=new FormData;const i=[];const s=ie(e);if(s.lastButtonClicked&&!le(s.lastButtonClicked)){s.lastButtonClicked=null}let l=e instanceof HTMLFormElement&&e.noValidate!==true||te(e,"hx-validate")==="true";if(s.lastButtonClicked){l=l&&s.lastButtonClicked.formNoValidate!==true}if(t!=="get"){sn(n,o,i,g(e,"form"),l)}sn(n,r,i,e,l);if(s.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){const c=s.lastButtonClicked||e;const f=ee(c,"name");rn(f,c.value,o)}const u=Se(e,"hx-include");se(u,function(e){sn(n,r,i,ce(e),l);if(!a(e,"form")){se(h(e).querySelectorAll(it),function(e){sn(n,r,i,e,l)})}});un(r,o);return{errors:i,formData:r,values:An(r)}}function fn(e,t,n){if(e!==""){e+="&"}if(String(n)==="[object Object]"){n=JSON.stringify(n)}const r=encodeURIComponent(n);e+=encodeURIComponent(t)+"="+r;return e}function an(e){e=Ln(e);let n="";e.forEach(function(e,t){n=fn(n,t,e)});return n}function hn(e,t,n){const r={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":ne().location.href};wn(e,"hx-headers",false,r);if(n!==undefined){r["HX-Prompt"]=n}if(ie(e).boosted){r["HX-Boosted"]="true"}return r}function dn(n,e){const t=re(e,"hx-params");if(t){if(t==="none"){return new FormData}else if(t==="*"){return n}else if(t.indexOf("not ")===0){se(t.substr(4).split(","),function(e){e=e.trim();n.delete(e)});return n}else{const r=new FormData;se(t.split(","),function(t){t=t.trim();if(n.has(t)){n.getAll(t).forEach(function(e){r.append(t,e)})}});return r}}else{return n}}function gn(e){return!!ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function pn(e,t){const n=t||re(e,"hx-swap");const r={swapStyle:ie(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ie(e).boosted&&!gn(e)){r.show="top"}if(n){const s=B(n);if(s.length>0){for(let e=0;e<s.length;e++){const l=s[e];if(l.indexOf("swap:")===0){r.swapDelay=d(l.substr(5))}else if(l.indexOf("settle:")===0){r.settleDelay=d(l.substr(7))}else if(l.indexOf("transition:")===0){r.transition=l.substr(11)==="true"}else if(l.indexOf("ignoreTitle:")===0){r.ignoreTitle=l.substr(12)==="true"}else if(l.indexOf("scroll:")===0){const u=l.substr(7);var o=u.split(":");const c=o.pop();var i=o.length>0?o.join(":"):null;r.scroll=c;r.scrollTarget=i}else if(l.indexOf("show:")===0){const f=l.substr(5);var o=f.split(":");const a=o.pop();var i=o.length>0?o.join(":"):null;r.show=a;r.showTarget=i}else if(l.indexOf("focus-scroll:")===0){const h=l.substr("focus-scroll:".length);r.focusScroll=h=="true"}else if(e==0){r.swapStyle=l}else{w("Unknown modifier in hx-swap: "+l)}}}}return r}function mn(e){return re(e,"hx-encoding")==="multipart/form-data"||a(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function yn(t,n,r){let o=null;Ut(n,function(e){if(o==null){o=e.encodeParameters(t,r,n)}});if(o!=null){return o}else{if(mn(n)){return un(new FormData,Ln(r))}else{return an(r)}}}function xn(e){return{tasks:[],elts:[e]}}function bn(e,t){const n=e[0];const r=e[e.length-1];if(t.scroll){var o=null;if(t.scrollTarget){o=ce(fe(n,t.scrollTarget))}if(t.scroll==="top"&&(n||o)){o=o||n;o.scrollTop=0}if(t.scroll==="bottom"&&(r||o)){o=o||r;o.scrollTop=o.scrollHeight}}if(t.show){var o=null;if(t.showTarget){let e=t.showTarget;if(t.showTarget==="window"){e="body"}o=ce(fe(n,e))}if(t.show==="top"&&(n||o)){o=o||n;o.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(r||o)){o=o||r;o.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function wn(r,e,o,i){if(i==null){i={}}if(r==null){return i}const s=te(r,e);if(s){let e=s.trim();let t=o;if(e==="unset"){return null}if(e.indexOf("javascript:")===0){e=e.substr(11);t=true}else if(e.indexOf("js:")===0){e=e.substr(3);t=true}if(e.indexOf("{")!==0){e="{"+e+"}"}let n;if(t){n=vn(r,function(){return Function("return ("+e+")")()},{})}else{n=S(e)}for(const l in n){if(n.hasOwnProperty(l)){if(i[l]==null){i[l]=n[l]}}}}return wn(ce(u(r)),e,o,i)}function vn(e,t,n){if(Q.config.allowEval){return t()}else{ae(e,"htmx:evalDisallowedError");return n}}function Sn(e,t){return wn(e,"hx-vars",true,t)}function En(e,t){return wn(e,"hx-vals",false,t)}function Cn(e){return ue(Sn(e),En(e))}function Rn(t,n,r){if(r!==null){try{t.setRequestHeader(n,r)}catch(e){t.setRequestHeader(n,encodeURIComponent(r));t.setRequestHeader(n+"-URI-AutoEncoded","true")}}}function On(t){if(t.responseURL&&typeof URL!=="undefined"){try{const e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ae(ne().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function C(e,t){return t.test(e.getAllResponseHeaders())}function Hn(e,t,n){e=e.toLowerCase();if(n){if(n instanceof Element||typeof n==="string"){return de(e,t,null,null,{targetOverride:y(n),returnPromise:true})}else{return de(e,t,y(n.source),n.event,{handler:n.handler,headers:n.headers,values:n.values,targetOverride:y(n.target),swapOverride:n.swap,select:n.select,returnPromise:true})}}else{return de(e,t,null,null,{returnPromise:true})}}function Tn(e){const t=[];while(e){t.push(e);e=e.parentElement}return t}function qn(e,t,n){let r;let o;if(typeof URL==="function"){o=new URL(t,document.location.href);const i=document.location.origin;r=i===o.origin}else{o=t;r=l(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!r){return false}}return he(e,"htmx:validateUrl",ue({url:o,sameHost:r},n))}function Ln(e){if(e instanceof FormData)return e;const t=new FormData;for(const n in e){if(e.hasOwnProperty(n)){if(typeof e[n].forEach==="function"){e[n].forEach(function(e){t.append(n,e)})}else if(typeof e[n]==="object"){t.append(n,JSON.stringify(e[n]))}else{t.append(n,e[n])}}}return t}function Nn(r,o,e){return new Proxy(e,{get:function(t,e){if(typeof e==="number")return t[e];if(e==="length")return t.length;if(e==="push"){return function(e){t.push(e);r.append(o,e)}}if(typeof t[e]==="function"){return function(){t[e].apply(t,arguments);r.delete(o);t.forEach(function(e){r.append(o,e)})}}if(t[e]&&t[e].length===1){return t[e][0]}else{return t[e]}},set:function(e,t,n){e[t]=n;r.delete(o);e.forEach(function(e){r.append(o,e)});return true}})}function An(r){return new Proxy(r,{get:function(e,t){if(typeof t==="symbol"){return Reflect.get(e,t)}if(t==="toJSON"){return()=>Object.fromEntries(r)}if(t in e){if(typeof e[t]==="function"){return function(){return r[t].apply(r,arguments)}}else{return e[t]}}const n=r.getAll(t);if(n.length===0){return undefined}else if(n.length===1){return n[0]}else{return Nn(e,t,n)}},set:function(t,n,e){if(typeof n!=="string"){return false}t.delete(n);if(typeof e.forEach==="function"){e.forEach(function(e){t.append(n,e)})}else{t.append(n,e)}return true},deleteProperty:function(e,t){if(typeof t==="string"){e.delete(t)}return true},ownKeys:function(e){return Reflect.ownKeys(Object.fromEntries(e))},getOwnPropertyDescriptor:function(e,t){return Reflect.getOwnPropertyDescriptor(Object.fromEntries(e),t)}})}function de(t,n,r,o,i,D){let s=null;let l=null;i=i!=null?i:{};if(i.returnPromise&&typeof Promise!=="undefined"){var e=new Promise(function(e,t){s=e;l=t})}if(r==null){r=ne().body}const M=i.handler||Mn;const X=i.select||null;if(!le(r)){oe(s);return e}const u=i.targetOverride||ce(Ce(r));if(u==null||u==ve){ae(r,"htmx:targetError",{target:te(r,"hx-target")});oe(l);return e}let c=ie(r);const f=c.lastButtonClicked;if(f){const L=ee(f,"formaction");if(L!=null){n=L}const N=ee(f,"formmethod");if(N!=null){if(N.toLowerCase()!=="dialog"){t=N}}}const a=re(r,"hx-confirm");if(D===undefined){const K=function(e){return de(t,n,r,o,i,!!e)};const G={target:u,elt:r,path:n,verb:t,triggeringEvent:o,etc:i,issueRequest:K,question:a};if(he(r,"htmx:confirm",G)===false){oe(s);return e}}let h=r;let d=re(r,"hx-sync");let g=null;let F=false;if(d){const A=d.split(":");const I=A[0].trim();if(I==="this"){h=Ee(r,"hx-sync")}else{h=ce(fe(r,I))}d=(A[1]||"drop").trim();c=ie(h);if(d==="drop"&&c.xhr&&c.abortable!==true){oe(s);return e}else if(d==="abort"){if(c.xhr){oe(s);return e}else{F=true}}else if(d==="replace"){he(h,"htmx:abort")}else if(d.indexOf("queue")===0){const Z=d.split(" ");g=(Z[1]||"last").trim()}}if(c.xhr){if(c.abortable){he(h,"htmx:abort")}else{if(g==null){if(o){const P=ie(o);if(P&&P.triggerSpec&&P.triggerSpec.queue){g=P.triggerSpec.queue}}if(g==null){g="last"}}if(c.queuedRequests==null){c.queuedRequests=[]}if(g==="first"&&c.queuedRequests.length===0){c.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="all"){c.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="last"){c.queuedRequests=[];c.queuedRequests.push(function(){de(t,n,r,o,i)})}oe(s);return e}}const p=new XMLHttpRequest;c.xhr=p;c.abortable=F;const m=function(){c.xhr=null;c.abortable=false;if(c.queuedRequests!=null&&c.queuedRequests.length>0){const e=c.queuedRequests.shift();e()}};const U=re(r,"hx-prompt");if(U){var y=prompt(U);if(y===null||!he(r,"htmx:prompt",{prompt:y,target:u})){oe(s);m();return e}}if(a&&!D){if(!confirm(a)){oe(s);m();return e}}let x=hn(r,u,y);if(t!=="get"&&!mn(r)){x["Content-Type"]="application/x-www-form-urlencoded"}if(i.headers){x=ue(x,i.headers)}const B=cn(r,t);let b=B.errors;const j=B.formData;if(i.values){un(j,Ln(i.values))}const V=Ln(Cn(r));const w=un(j,V);let v=dn(w,r);if(Q.config.getCacheBusterParam&&t==="get"){v.set("org.htmx.cache-buster",ee(u,"id")||"true")}if(n==null||n===""){n=ne().location.href}const S=wn(r,"hx-request");const _=ie(r).boosted;let E=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;const C={boosted:_,useUrlParams:E,formData:v,parameters:An(v),unfilteredFormData:w,unfilteredParameters:An(w),headers:x,target:u,verb:t,errors:b,withCredentials:i.credentials||S.credentials||Q.config.withCredentials,timeout:i.timeout||S.timeout||Q.config.timeout,path:n,triggeringEvent:o};if(!he(r,"htmx:configRequest",C)){oe(s);m();return e}n=C.path;t=C.verb;x=C.headers;v=Ln(C.parameters);b=C.errors;E=C.useUrlParams;if(b&&b.length>0){he(r,"htmx:validation:halted",C);oe(s);m();return e}const $=n.split("#");const z=$[0];const R=$[1];let O=n;if(E){O=z;const W=!v.keys().next().done;if(W){if(O.indexOf("?")<0){O+="?"}else{O+="&"}O+=an(v);if(R){O+="#"+R}}}if(!qn(r,O,C)){ae(r,"htmx:invalidPath",C);oe(l);return e}p.open(t.toUpperCase(),O,true);p.overrideMimeType("text/html");p.withCredentials=C.withCredentials;p.timeout=C.timeout;if(S.noHeaders){}else{for(const k in x){if(x.hasOwnProperty(k)){const Y=x[k];Rn(p,k,Y)}}}const H={xhr:p,target:u,requestConfig:C,etc:i,boosted:_,select:X,pathInfo:{requestPath:n,finalRequestPath:O,responsePath:null,anchor:R}};p.onload=function(){try{const t=Tn(r);H.pathInfo.responsePath=On(p);M(r,H);en(T,q);he(r,"htmx:afterRequest",H);he(r,"htmx:afterOnLoad",H);if(!le(r)){let e=null;while(t.length>0&&e==null){const n=t.shift();if(le(n)){e=n}}if(e){he(e,"htmx:afterRequest",H);he(e,"htmx:afterOnLoad",H)}}oe(s);m()}catch(e){ae(r,"htmx:onLoadError",ue({error:e},H));throw e}};p.onerror=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:sendError",H);oe(l);m()};p.onabort=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:sendAbort",H);oe(l);m()};p.ontimeout=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:timeout",H);oe(l);m()};if(!he(r,"htmx:beforeRequest",H)){oe(s);m();return e}var T=Yt(r);var q=Qt(r);se(["loadstart","loadend","progress","abort"],function(t){se([p,p.upload],function(e){e.addEventListener(t,function(e){he(r,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});he(r,"htmx:beforeSend",H);const J=E?null:yn(p,r,v);p.send(J);return e}function In(e,t){const n=t.xhr;let r=null;let o=null;if(C(n,/HX-Push:/i)){r=n.getResponseHeader("HX-Push");o="push"}else if(C(n,/HX-Push-Url:/i)){r=n.getResponseHeader("HX-Push-Url");o="push"}else if(C(n,/HX-Replace-Url:/i)){r=n.getResponseHeader("HX-Replace-Url");o="replace"}if(r){if(r==="false"){return{}}else{return{type:o,path:r}}}const i=t.pathInfo.finalRequestPath;const s=t.pathInfo.responsePath;const l=re(e,"hx-push-url");const u=re(e,"hx-replace-url");const c=ie(e).boosted;let f=null;let a=null;if(l){f="push";a=l}else if(u){f="replace";a=u}else if(c){f="push";a=s||i}if(a){if(a==="false"){return{}}if(a==="true"){a=s||i}if(t.pathInfo.anchor&&a.indexOf("#")===-1){a=a+"#"+t.pathInfo.anchor}return{type:f,path:a}}else{return{}}}function Pn(e,t){var n=new RegExp(e.code);return n.test(t.toString(10))}function kn(e){for(var t=0;t<Q.config.responseHandling.length;t++){var n=Q.config.responseHandling[t];if(Pn(n,e.status)){return n}}return{swap:false}}function Dn(e){if(e){const t=r("title");if(t){t.innerHTML=e}else{window.document.title=e}}}function Mn(o,i){const s=i.xhr;let l=i.target;const e=i.etc;const u=i.select;if(!he(o,"htmx:beforeOnLoad",i))return;if(C(s,/HX-Trigger:/i)){Je(s,"HX-Trigger",o)}if(C(s,/HX-Location:/i)){zt();let e=s.getResponseHeader("HX-Location");var t;if(e.indexOf("{")===0){t=S(e);e=t.path;delete t.path}Hn("get",e,t).then(function(){Jt(e)});return}const n=C(s,/HX-Refresh:/i)&&s.getResponseHeader("HX-Refresh")==="true";if(C(s,/HX-Redirect:/i)){location.href=s.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(C(s,/HX-Retarget:/i)){if(s.getResponseHeader("HX-Retarget")==="this"){i.target=o}else{i.target=ce(fe(o,s.getResponseHeader("HX-Retarget")))}}const c=In(o,i);const r=kn(s);const f=r.swap;let a=!!r.error;let h=Q.config.ignoreTitle||r.ignoreTitle;let d=r.select;if(r.target){i.target=ce(fe(o,r.target))}var g=e.swapOverride;if(g==null&&r.swapOverride){g=r.swapOverride}if(C(s,/HX-Retarget:/i)){if(s.getResponseHeader("HX-Retarget")==="this"){i.target=o}else{i.target=ce(fe(o,s.getResponseHeader("HX-Retarget")))}}if(C(s,/HX-Reswap:/i)){g=s.getResponseHeader("HX-Reswap")}var p=s.response;var m=ue({shouldSwap:f,serverResponse:p,isError:a,ignoreTitle:h,selectOverride:d},i);if(r.event&&!he(l,r.event,m))return;if(!he(l,"htmx:beforeSwap",m))return;l=m.target;p=m.serverResponse;a=m.isError;h=m.ignoreTitle;d=m.selectOverride;i.target=l;i.failed=a;i.successful=!a;if(m.shouldSwap){if(s.status===286){ut(o)}Ut(o,function(e){p=e.transformResponse(p,s,o)});if(c.type){zt()}if(C(s,/HX-Reswap:/i)){g=s.getResponseHeader("HX-Reswap")}var y=pn(o,g);if(!y.hasOwnProperty("ignoreTitle")){y.ignoreTitle=h}l.classList.add(Q.config.swappingClass);let n=null;let r=null;if(u){d=u}if(C(s,/HX-Reselect:/i)){d=s.getResponseHeader("HX-Reselect")}const x=re(o,"hx-select-oob");const b=re(o,"hx-select");let e=function(){try{if(c.type){he(ne().body,"htmx:beforeHistoryUpdate",ue({history:c},i));if(c.type==="push"){Jt(c.path);he(ne().body,"htmx:pushedIntoHistory",{path:c.path})}else{Kt(c.path);he(ne().body,"htmx:replacedInHistory",{path:c.path})}}ze(l,p,y,{select:d||b,selectOOB:x,eventInfo:i,anchor:i.pathInfo.anchor,contextElement:o,afterSwapCallback:function(){if(C(s,/HX-Trigger-After-Swap:/i)){let e=o;if(!le(o)){e=ne().body}Je(s,"HX-Trigger-After-Swap",e)}},afterSettleCallback:function(){if(C(s,/HX-Trigger-After-Settle:/i)){let e=o;if(!le(o)){e=ne().body}Je(s,"HX-Trigger-After-Settle",e)}oe(n)}})}catch(e){ae(o,"htmx:swapError",i);oe(r);throw e}};let t=Q.config.globalViewTransitions;if(y.hasOwnProperty("transition")){t=y.transition}if(t&&he(o,"htmx:beforeTransition",i)&&typeof Promise!=="undefined"&&document.startViewTransition){const w=new Promise(function(e,t){n=e;r=t});const v=e;e=function(){document.startViewTransition(function(){v();return w})}}if(y.swapDelay>0){E().setTimeout(e,y.swapDelay)}else{e()}}if(a){ae(o,"htmx:responseError",ue({error:"Response Status Error Code "+s.status+" from "+i.pathInfo.requestPath},i))}}const Xn={};function Fn(){return{init:function(e){return null},getSelectors:function(){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,n){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,n,r){return false},encodeParameters:function(e,t,n){return null}}}function Un(e,t){if(t.init){t.init(n)}Xn[e]=ue(Fn(),t)}function Bn(e){delete Xn[e]}function jn(e,n,r){if(n==undefined){n=[]}if(e==undefined){return n}if(r==undefined){r=[]}const t=te(e,"hx-ext");if(t){se(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){r.push(e.slice(7));return}if(r.indexOf(e)<0){const t=Xn[e];if(t&&n.indexOf(t)<0){n.push(t)}}})}return jn(ce(u(e)),n,r)}var Vn=false;ne().addEventListener("DOMContentLoaded",function(){Vn=true});function _n(e){if(Vn||ne().readyState==="complete"){e()}else{ne().addEventListener("DOMContentLoaded",e)}}function $n(){if(Q.config.includeIndicatorStyles!==false){const e=Q.config.inlineStyleNonce?` nonce="${Q.config.inlineStyleNonce}"`:"";ne().head.insertAdjacentHTML("beforeend","<style"+e+"> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zn(){const e=ne().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function Jn(){const e=zn();if(e){Q.config=ue(Q.config,e)}}_n(function(){Jn();$n();let e=ne().body;Dt(e);const t=ne().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){const t=e.target;const n=ie(t);if(n&&n.xhr){n.xhr.abort()}});const n=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){Wt();se(t,function(e){he(e,"htmx:restored",{document:ne(),triggerEvent:he})})}else{if(n){n(e)}}};E().setTimeout(function(){he(e,"htmx:load",{});e=null},0)});return Q}(); \ No newline at end of file diff --git a/code/ch6_active_search/ch6_final_video_collector/templates/shared/_layout.html b/code/ch6_active_search/ch6_final_video_collector/templates/shared/_layout.html index a13399e..57e80e7 100644 --- a/code/ch6_active_search/ch6_final_video_collector/templates/shared/_layout.html +++ b/code/ch6_active_search/ch6_final_video_collector/templates/shared/_layout.html @@ -52,7 +52,7 @@ </footer> -<script src="/https/github.com/static/js/htmx.min.js?v=1.5.0"></script> +<script src="/https/github.com/static/js/htmx.min.js?v=2.0.0"></script> <script src="/https/github.com/static/js/jquery-3.5.1.slim.min.js"></script> <script src="/https/github.com/static/js/popper-1.16.1.min.js"></script> diff --git a/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.d.ts b/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.d.ts new file mode 100644 index 0000000..3775459 --- /dev/null +++ b/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.d.ts @@ -0,0 +1,195 @@ +declare namespace htmx { + const onLoad: (callback: (elt: Node) => void) => EventListener; + const process: (elt: string | Element) => void; + const on: (arg1: string | EventTarget, arg2: string | EventListener, arg3?: EventListener) => EventListener; + const off: (arg1: string | EventTarget, arg2: string | EventListener, arg3?: EventListener) => EventListener; + const trigger: (elt: string | EventTarget, eventName: string, detail?: any) => boolean; + const ajax: (verb: HttpVerb, path: string, context: string | Element | HtmxAjaxHelperContext) => Promise<void>; + const find: (eltOrSelector: string | ParentNode, selector?: string) => Element; + const findAll: (eltOrSelector: string | ParentNode, selector?: string) => NodeListOf<Element>; + const closest: (elt: string | Element, selector: string) => Element; + function values(elt: Element, type: HttpVerb): any; + const remove: (elt: Node, delay?: number) => void; + const addClass: (elt: string | Element, clazz: string, delay?: number) => void; + const removeClass: (node: string | Node, clazz: string, delay?: number) => void; + const toggleClass: (elt: string | Element, clazz: string) => void; + const takeClass: (elt: string | Node, clazz: string) => void; + const swap: (target: string | Element, content: string, swapSpec: HtmxSwapSpecification, swapOptions?: SwapOptions) => void; + const defineExtension: (name: string, extension: any) => void; + const removeExtension: (name: string) => void; + const logAll: () => void; + const logNone: () => void; + const logger: any; + namespace config { + const historyEnabled: boolean; + const historyCacheSize: number; + const refreshOnHistoryMiss: boolean; + const defaultSwapStyle: HtmxSwapStyle; + const defaultSwapDelay: number; + const defaultSettleDelay: number; + const includeIndicatorStyles: boolean; + const indicatorClass: string; + const requestClass: string; + const addedClass: string; + const settlingClass: string; + const swappingClass: string; + const allowEval: boolean; + const allowScriptTags: boolean; + const inlineScriptNonce: string; + const inlineStyleNonce: string; + const attributesToSettle: string[]; + const withCredentials: boolean; + const timeout: number; + const wsReconnectDelay: "full-jitter" | ((retryCount: number) => number); + const wsBinaryType: BinaryType; + const disableSelector: string; + const scrollBehavior: 'auto' | 'instant' | 'smooth'; + const defaultFocusScroll: boolean; + const getCacheBusterParam: boolean; + const globalViewTransitions: boolean; + const methodsThatUseUrlParams: (HttpVerb)[]; + const selfRequestsOnly: boolean; + const ignoreTitle: boolean; + const scrollIntoViewOnBoost: boolean; + const triggerSpecsCache: any | null; + const disableInheritance: boolean; + const responseHandling: HtmxResponseHandlingConfig[]; + const allowNestedOobSwaps: boolean; + } + const parseInterval: (str: string) => number; + const _: (str: string) => any; + const version: string; +} +type HttpVerb = 'get' | 'head' | 'post' | 'put' | 'delete' | 'connect' | 'options' | 'trace' | 'patch'; +type SwapOptions = { + select?: string; + selectOOB?: string; + eventInfo?: any; + anchor?: string; + contextElement?: Element; + afterSwapCallback?: swapCallback; + afterSettleCallback?: swapCallback; +}; +type swapCallback = () => any; +type HtmxSwapStyle = 'innerHTML' | 'outerHTML' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'delete' | 'none' | string; +type HtmxSwapSpecification = { + swapStyle: HtmxSwapStyle; + swapDelay: number; + settleDelay: number; + transition?: boolean; + ignoreTitle?: boolean; + head?: string; + scroll?: 'top' | 'bottom'; + scrollTarget?: string; + show?: string; + showTarget?: string; + focusScroll?: boolean; +}; +type ConditionalFunction = ((this: Node, evt: Event) => boolean) & { + source: string; +}; +type HtmxTriggerSpecification = { + trigger: string; + pollInterval?: number; + eventFilter?: ConditionalFunction; + changed?: boolean; + once?: boolean; + consume?: boolean; + delay?: number; + from?: string; + target?: string; + throttle?: number; + queue?: string; + root?: string; + threshold?: string; +}; +type HtmxElementValidationError = { + elt: Element; + message: string; + validity: ValidityState; +}; +type HtmxHeaderSpecification = Record<string, string>; +type HtmxAjaxHelperContext = { + source?: Element | string; + event?: Event; + handler?: HtmxAjaxHandler; + target: Element | string; + swap?: HtmxSwapStyle; + values?: any | FormData; + headers?: Record<string, string>; + select?: string; +}; +type HtmxRequestConfig = { + boosted: boolean; + useUrlParams: boolean; + formData: FormData; + /** + * formData proxy + */ + parameters: any; + unfilteredFormData: FormData; + /** + * unfilteredFormData proxy + */ + unfilteredParameters: any; + headers: HtmxHeaderSpecification; + target: Element; + verb: HttpVerb; + errors: HtmxElementValidationError[]; + withCredentials: boolean; + timeout: number; + path: string; + triggeringEvent: Event; +}; +type HtmxResponseInfo = { + xhr: XMLHttpRequest; + target: Element; + requestConfig: HtmxRequestConfig; + etc: HtmxAjaxEtc; + boosted: boolean; + select: string; + pathInfo: { + requestPath: string; + finalRequestPath: string; + responsePath: string | null; + anchor: string; + }; + failed?: boolean; + successful?: boolean; +}; +type HtmxAjaxEtc = { + returnPromise?: boolean; + handler?: HtmxAjaxHandler; + select?: string; + targetOverride?: Element; + swapOverride?: HtmxSwapStyle; + headers?: Record<string, string>; + values?: any | FormData; + credentials?: boolean; + timeout?: number; +}; +type HtmxResponseHandlingConfig = { + code?: string; + swap: boolean; + error?: boolean; + ignoreTitle?: boolean; + select?: string; + target?: string; + swapOverride?: string; + event?: string; +}; +type HtmxBeforeSwapDetails = HtmxResponseInfo & { + shouldSwap: boolean; + serverResponse: any; + isError: boolean; + ignoreTitle: boolean; + selectOverride: string; +}; +type HtmxAjaxHandler = (elt: Element, responseInfo: HtmxResponseInfo) => any; +type HtmxSettleTask = (() => void); +type HtmxSettleInfo = { + tasks: HtmxSettleTask[]; + elts: Element[]; + title?: string; +}; +type HtmxExtension = any; diff --git a/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.js b/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.js index 86e7668..c57bcd7 100644 --- a/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.js +++ b/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.js @@ -1,3909 +1,5131 @@ -// /////////////////////////////////////////////////////////////////// -// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.js -// - -// UMD insanity -// This code sets up support for (in order) AMD, ES6 modules, and globals. -(function (root, factory) { - //@ts-ignore - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - //@ts-ignore - define([], factory); - } else if (typeof module === 'object' && module.exports) { - // Node. Does not work with strict CommonJS, but - // only CommonJS-like environments that support module.exports, - // like Node. - module.exports = factory(); - } else { - // Browser globals - root.htmx = root.htmx || factory(); - } -}(typeof self !== 'undefined' ? self : this, function () { -return (function () { - 'use strict'; - - // Public API - //** @type {import("./htmx").HtmxApi} */ - // TODO: list all methods in public API - var htmx = { - onLoad: onLoadHelper, - process: processNode, - on: addEventListenerImpl, - off: removeEventListenerImpl, - trigger : triggerEvent, - ajax : ajaxHelper, - find : find, - findAll : findAll, - closest : closest, - values : function(elt, type){ - var inputValues = getInputValues(elt, type || "post"); - return inputValues.values; - }, - remove : removeElement, - addClass : addClassToElement, - removeClass : removeClassFromElement, - toggleClass : toggleClassOnElement, - takeClass : takeClassForElement, - defineExtension : defineExtension, - removeExtension : removeExtension, - logAll : logAll, - logNone : logNone, - logger : null, - config : { - historyEnabled:true, - historyCacheSize:10, - refreshOnHistoryMiss:false, - defaultSwapStyle:'innerHTML', - defaultSwapDelay:0, - defaultSettleDelay:20, - includeIndicatorStyles:true, - indicatorClass:'htmx-indicator', - requestClass:'htmx-request', - addedClass:'htmx-added', - settlingClass:'htmx-settling', - swappingClass:'htmx-swapping', - allowEval:true, - allowScriptTags:true, - inlineScriptNonce:'', - attributesToSettle:["class", "style", "width", "height"], - withCredentials:false, - timeout:0, - wsReconnectDelay: 'full-jitter', - wsBinaryType: 'blob', - disableSelector: "[hx-disable], [data-hx-disable]", - useTemplateFragments: false, - scrollBehavior: 'smooth', - defaultFocusScroll: false, - getCacheBusterParam: false, - globalViewTransitions: false, - methodsThatUseUrlParams: ["get"], - selfRequestsOnly: false, - ignoreTitle: false, - scrollIntoViewOnBoost: true, - triggerSpecsCache: null, - }, - parseInterval:parseInterval, - _:internalEval, - createEventSource: function(url){ - return new EventSource(url, {withCredentials:true}) - }, - createWebSocket: function(url){ - var sock = new WebSocket(url, []); - sock.binaryType = htmx.config.wsBinaryType; - return sock; - }, - version: "1.9.10" - }; - - /** @type {import("./htmx").HtmxInternalApi} */ - var internalAPI = { - addTriggerHandler: addTriggerHandler, - bodyContains: bodyContains, - canAccessLocalStorage: canAccessLocalStorage, - findThisElement: findThisElement, - filterValues: filterValues, - hasAttribute: hasAttribute, - getAttributeValue: getAttributeValue, - getClosestAttributeValue: getClosestAttributeValue, - getClosestMatch: getClosestMatch, - getExpressionVars: getExpressionVars, - getHeaders: getHeaders, - getInputValues: getInputValues, - getInternalData: getInternalData, - getSwapSpecification: getSwapSpecification, - getTriggerSpecs: getTriggerSpecs, - getTarget: getTarget, - makeFragment: makeFragment, - mergeObjects: mergeObjects, - makeSettleInfo: makeSettleInfo, - oobSwap: oobSwap, - querySelectorExt: querySelectorExt, - selectAndSwap: selectAndSwap, - settleImmediately: settleImmediately, - shouldCancel: shouldCancel, - triggerEvent: triggerEvent, - triggerErrorEvent: triggerErrorEvent, - withExtensions: withExtensions, - } - - var VERBS = ['get', 'post', 'put', 'delete', 'patch']; - var VERB_SELECTOR = VERBS.map(function(verb){ - return "[hx-" + verb + "], [data-hx-" + verb + "]" - }).join(", "); - - var HEAD_TAG_REGEX = makeTagRegEx('head'), - TITLE_TAG_REGEX = makeTagRegEx('title'), - SVG_TAGS_REGEX = makeTagRegEx('svg', true); - - //==================================================================== - // Utilities - //==================================================================== - - /** - * @param {string} tag - * @param {boolean} global - * @returns {RegExp} - */ - function makeTagRegEx(tag, global = false) { - return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, - global ? 'gim' : 'im'); - } - - function parseInterval(str) { - if (str == undefined) { - return undefined; - } - - let interval = NaN; - if (str.slice(-2) == "ms") { - interval = parseFloat(str.slice(0, -2)); - } else if (str.slice(-1) == "s") { - interval = parseFloat(str.slice(0, -1)) * 1000; - } else if (str.slice(-1) == "m") { - interval = parseFloat(str.slice(0, -1)) * 1000 * 60; - } else { - interval = parseFloat(str); - } - return isNaN(interval) ? undefined : interval; - } - - /** - * @param {HTMLElement} elt - * @param {string} name - * @returns {(string | null)} - */ - function getRawAttribute(elt, name) { - return elt.getAttribute && elt.getAttribute(name); - } - - // resolve with both hx and data-hx prefixes - function hasAttribute(elt, qualifiedName) { - return elt.hasAttribute && (elt.hasAttribute(qualifiedName) || - elt.hasAttribute("data-" + qualifiedName)); - } - - /** - * - * @param {HTMLElement} elt - * @param {string} qualifiedName - * @returns {(string | null)} - */ - function getAttributeValue(elt, qualifiedName) { - return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); - } - - /** - * @param {HTMLElement} elt - * @returns {HTMLElement | null} - */ - function parentElt(elt) { - return elt.parentElement; - } - - /** - * @returns {Document} - */ - function getDocument() { - return document; - } - - /** - * @param {HTMLElement} elt - * @param {(e:HTMLElement) => boolean} condition - * @returns {HTMLElement | null} - */ - function getClosestMatch(elt, condition) { - while (elt && !condition(elt)) { - elt = parentElt(elt); - } - - return elt ? elt : null; - } - - function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ - var attributeValue = getAttributeValue(ancestor, attributeName); - var disinherit = getAttributeValue(ancestor, "hx-disinherit"); - if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) { - return "unset"; - } else { - return attributeValue - } - } - - /** - * @param {HTMLElement} elt - * @param {string} attributeName - * @returns {string | null} - */ - function getClosestAttributeValue(elt, attributeName) { - var closestAttr = null; - getClosestMatch(elt, function (e) { - return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName); - }); - if (closestAttr !== "unset") { - return closestAttr; - } - } - - /** - * @param {HTMLElement} elt - * @param {string} selector - * @returns {boolean} - */ - function matches(elt, selector) { - // @ts-ignore: non-standard properties for browser compatibility - // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; - return matchesFunction && matchesFunction.call(elt, selector); - } - - /** - * @param {string} str - * @returns {string} - */ - 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 ""; - } - } - - /** - * - * @param {string} resp - * @param {number} depth - * @returns {Element} - */ - function parseHTML(resp, depth) { - var parser = new DOMParser(); - var responseDoc = parser.parseFromString(resp, "text/html"); - - /** @type {Element} */ - var responseNode = responseDoc.body; - while (depth > 0) { - depth--; - // @ts-ignore - responseNode = responseNode.firstChild; - } - if (responseNode == null) { - // @ts-ignore - responseNode = getDocument().createDocumentFragment(); - } - return responseNode; - } - - function aFullPageResponse(resp) { - return /<body/.test(resp) - } +// v2.0.0 from https://github.com/bigskysoftware/htmx/releases + +var htmx = (function() { + 'use strict' + + // Public API + const htmx = { + // Tsc madness here, assigning the functions directly results in an invalid TypeScript output, but reassigning is fine + /* Event processing */ + /** @type {typeof onLoadHelper} */ + onLoad: null, + /** @type {typeof processNode} */ + process: null, + /** @type {typeof addEventListenerImpl} */ + on: null, + /** @type {typeof removeEventListenerImpl} */ + off: null, + /** @type {typeof triggerEvent} */ + trigger: null, + /** @type {typeof ajaxHelper} */ + ajax: null, + /* DOM querying helpers */ + /** @type {typeof find} */ + find: null, + /** @type {typeof findAll} */ + findAll: null, + /** @type {typeof closest} */ + closest: null, + /** + * Returns the input values that would resolve for a given element via the htmx value resolution mechanism + * + * @see https://htmx.org/api/#values + * + * @param {Element} elt the element to resolve values on + * @param {HttpVerb} type the request type (e.g. **get** or **post**) non-GET's will include the enclosing form of the element. Defaults to **post** + * @returns {Object} + */ + values: function(elt, type) { + const inputValues = getInputValues(elt, type || 'post') + return inputValues.values + }, + /* DOM manipulation helpers */ + /** @type {typeof removeElement} */ + remove: null, + /** @type {typeof addClassToElement} */ + addClass: null, + /** @type {typeof removeClassFromElement} */ + removeClass: null, + /** @type {typeof toggleClassOnElement} */ + toggleClass: null, + /** @type {typeof takeClassForElement} */ + takeClass: null, + /** @type {typeof swap} */ + swap: null, + /* Extension entrypoints */ + /** @type {typeof defineExtension} */ + defineExtension: null, + /** @type {typeof removeExtension} */ + removeExtension: null, + /* Debugging */ + /** @type {typeof logAll} */ + logAll: null, + /** @type {typeof logNone} */ + logNone: null, + /* Debugging */ + /** + * The logger htmx uses to log with + * + * @see https://htmx.org/api/#logger + */ + logger: null, + /** + * A property holding the configuration htmx uses at runtime. + * + * Note that using a [meta tag](https://htmx.org/docs/#config) is the preferred mechanism for setting these properties. + * + * @see https://htmx.org/api/#config + */ + config: { + /** + * Whether to use history. + * @type boolean + * @default true + */ + historyEnabled: true, + /** + * The number of pages to keep in **localStorage** for history support. + * @type number + * @default 10 + */ + historyCacheSize: 10, + /** + * @type boolean + * @default false + */ + refreshOnHistoryMiss: false, + /** + * The default swap style to use if **[hx-swap](https://htmx.org/attributes/hx-swap)** is omitted. + * @type HtmxSwapStyle + * @default 'innerHTML' + */ + defaultSwapStyle: 'innerHTML', + /** + * The default delay between receiving a response from the server and doing the swap. + * @type number + * @default 0 + */ + defaultSwapDelay: 0, + /** + * The default delay between completing the content swap and settling attributes. + * @type number + * @default 20 + */ + defaultSettleDelay: 20, + /** + * If true, htmx will inject a small amount of CSS into the page to make indicators invisible unless the **htmx-indicator** class is present. + * @type boolean + * @default true + */ + includeIndicatorStyles: true, + /** + * The class to place on indicators when a request is in flight. + * @type string + * @default 'htmx-indicator' + */ + indicatorClass: 'htmx-indicator', + /** + * The class to place on triggering elements when a request is in flight. + * @type string + * @default 'htmx-request' + */ + requestClass: 'htmx-request', + /** + * The class to temporarily place on elements that htmx has added to the DOM. + * @type string + * @default 'htmx-added' + */ + addedClass: 'htmx-added', + /** + * The class to place on target elements when htmx is in the settling phase. + * @type string + * @default 'htmx-settling' + */ + settlingClass: 'htmx-settling', + /** + * The class to place on target elements when htmx is in the swapping phase. + * @type string + * @default 'htmx-swapping' + */ + swappingClass: 'htmx-swapping', + /** + * Allows the use of eval-like functionality in htmx, to enable **hx-vars**, trigger conditions & script tag evaluation. Can be set to **false** for CSP compatibility. + * @type boolean + * @default true + */ + allowEval: true, + /** + * If set to false, disables the interpretation of script tags. + * @type boolean + * @default true + */ + allowScriptTags: true, + /** + * If set, the nonce will be added to inline scripts. + * @type string + * @default '' + */ + inlineScriptNonce: '', + /** + * If set, the nonce will be added to inline styles. + * @type string + * @default '' + */ + inlineStyleNonce: '', + /** + * The attributes to settle during the settling phase. + * @type string[] + * @default ['class', 'style', 'width', 'height'] + */ + attributesToSettle: ['class', 'style', 'width', 'height'], + /** + * Allow cross-site Access-Control requests using credentials such as cookies, authorization headers or TLS client certificates. + * @type boolean + * @default false + */ + withCredentials: false, + /** + * @type number + * @default 0 + */ + timeout: 0, + /** + * The default implementation of **getWebSocketReconnectDelay** for reconnecting after unexpected connection loss by the event code **Abnormal Closure**, **Service Restart** or **Try Again Later**. + * @type {'full-jitter' | ((retryCount:number) => number)} + * @default "full-jitter" + */ + wsReconnectDelay: 'full-jitter', + /** + * The type of binary data being received over the WebSocket connection + * @type BinaryType + * @default 'blob' + */ + wsBinaryType: 'blob', + /** + * @type string + * @default '[hx-disable], [data-hx-disable]' + */ + disableSelector: '[hx-disable], [data-hx-disable]', + /** + * @type {'auto' | 'instant' | 'smooth'} + * @default 'smooth' + */ + scrollBehavior: 'instant', + /** + * If the focused element should be scrolled into view. + * @type boolean + * @default false + */ + defaultFocusScroll: false, + /** + * If set to true htmx will include a cache-busting parameter in GET requests to avoid caching partial responses by the browser + * @type boolean + * @default false + */ + getCacheBusterParam: false, + /** + * If set to true, htmx will use the View Transition API when swapping in new content. + * @type boolean + * @default false + */ + globalViewTransitions: false, + /** + * htmx will format requests with these methods by encoding their parameters in the URL, not the request body + * @type {(HttpVerb)[]} + * @default ['get', 'delete'] + */ + methodsThatUseUrlParams: ['get', 'delete'], + /** + * If set to true, disables htmx-based requests to non-origin hosts. + * @type boolean + * @default false + */ + selfRequestsOnly: true, + /** + * If set to true htmx will not update the title of the document when a title tag is found in new content + * @type boolean + * @default false + */ + ignoreTitle: false, + /** + * Whether the target of a boosted element is scrolled into the viewport. + * @type boolean + * @default true + */ + scrollIntoViewOnBoost: true, + /** + * The cache to store evaluated trigger specifications into. + * You may define a simple object to use a never-clearing cache, or implement your own system using a [proxy object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Proxy) + * @type {Object|null} + * @default null + */ + triggerSpecsCache: null, + /** @type boolean */ + disableInheritance: false, + /** @type HtmxResponseHandlingConfig[] */ + responseHandling: [ + { code: '204', swap: false }, + { code: '[23]..', swap: true }, + { code: '[45]..', swap: false, error: true } + ], + /** + * Whether to process OOB swaps on elements that are nested within the main response element. + * @type boolean + * @default true + */ + allowNestedOobSwaps: true + }, + /** @type {typeof parseInterval} */ + parseInterval: null, + /** @type {typeof internalEval} */ + _: null, + version: '2.0.0' + } + // Tsc madness part 2 + htmx.onLoad = onLoadHelper + htmx.process = processNode + htmx.on = addEventListenerImpl + htmx.off = removeEventListenerImpl + htmx.trigger = triggerEvent + htmx.ajax = ajaxHelper + htmx.find = find + htmx.findAll = findAll + htmx.closest = closest + htmx.remove = removeElement + htmx.addClass = addClassToElement + htmx.removeClass = removeClassFromElement + htmx.toggleClass = toggleClassOnElement + htmx.takeClass = takeClassForElement + htmx.swap = swap + htmx.defineExtension = defineExtension + htmx.removeExtension = removeExtension + htmx.logAll = logAll + htmx.logNone = logNone + htmx.parseInterval = parseInterval + htmx._ = internalEval + + const internalAPI = { + addTriggerHandler, + bodyContains, + canAccessLocalStorage, + findThisElement, + filterValues, + swap, + hasAttribute, + getAttributeValue, + getClosestAttributeValue, + getClosestMatch, + getExpressionVars, + getHeaders, + getInputValues, + getInternalData, + getSwapSpecification, + getTriggerSpecs, + getTarget, + makeFragment, + mergeObjects, + makeSettleInfo, + oobSwap, + querySelectorExt, + settleImmediately, + shouldCancel, + triggerEvent, + triggerErrorEvent, + withExtensions + } + + const VERBS = ['get', 'post', 'put', 'delete', 'patch'] + const VERB_SELECTOR = VERBS.map(function(verb) { + return '[hx-' + verb + '], [data-hx-' + verb + ']' + }).join(', ') + + const HEAD_TAG_REGEX = makeTagRegEx('head') + + //= =================================================================== + // Utilities + //= =================================================================== + + /** + * @param {string} tag + * @param {boolean} global + * @returns {RegExp} + */ + function makeTagRegEx(tag, global = false) { + return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, + global ? 'gim' : 'im') + } + + /** + * Parses an interval string consistent with the way htmx does. Useful for plugins that have timing-related attributes. + * + * Caution: Accepts an int followed by either **s** or **ms**. All other values use **parseFloat** + * + * @see https://htmx.org/api/#parseInterval + * + * @param {string} str timing string + * @returns {number|undefined} + */ + function parseInterval(str) { + if (str == undefined) { + return undefined + } - /** - * - * @param {string} response - * @returns {Element} - */ - function makeFragment(response) { - var partialResponse = !aFullPageResponse(response); - var startTag = getStartTag(response); - var content = response; - if (startTag === 'head') { - content = content.replace(HEAD_TAG_REGEX, ''); - } - if (htmx.config.useTemplateFragments && partialResponse) { - var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0); - // @ts-ignore type mismatch between DocumentFragment and Element. - // TODO: Are these close enough for htmx to use interchangeably? - return documentFragment.querySelector('template').content; - } - switch (startTag) { - case "thead": - case "tbody": - case "tfoot": - case "colgroup": - case "caption": - return parseHTML("<table>" + content + "</table>", 1); - case "col": - return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2); - case "tr": - return parseHTML("<table><tbody>" + content + "</tbody></table>", 2); - case "td": - case "th": - return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3); - case "script": - case "style": - return parseHTML("<div>" + content + "</div>", 1); - default: - return parseHTML(content, 0); - } - } + let interval = NaN + if (str.slice(-2) == 'ms') { + interval = parseFloat(str.slice(0, -2)) + } else if (str.slice(-1) == 's') { + interval = parseFloat(str.slice(0, -1)) * 1000 + } else if (str.slice(-1) == 'm') { + interval = parseFloat(str.slice(0, -1)) * 1000 * 60 + } else { + interval = parseFloat(str) + } + return isNaN(interval) ? undefined : interval + } + + /** + * @param {Node} elt + * @param {string} name + * @returns {(string | null)} + */ + function getRawAttribute(elt, name) { + return elt instanceof Element && elt.getAttribute(name) + } + + /** + * @param {Element} elt + * @param {string} qualifiedName + * @returns {boolean} + */ + // resolve with both hx and data-hx prefixes + function hasAttribute(elt, qualifiedName) { + return !!elt.hasAttribute && (elt.hasAttribute(qualifiedName) || + elt.hasAttribute('data-' + qualifiedName)) + } + + /** + * + * @param {Node} elt + * @param {string} qualifiedName + * @returns {(string | null)} + */ + function getAttributeValue(elt, qualifiedName) { + return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, 'data-' + qualifiedName) + } + + /** + * @param {Node} elt + * @returns {Node | null} + */ + function parentElt(elt) { + const parent = elt.parentElement + if (!parent && elt.parentNode instanceof ShadowRoot) return elt.parentNode + return parent + } + + /** + * @returns {Document} + */ + function getDocument() { + return document + } + + /** + * @param {Node} elt + * @param {boolean} global + * @returns {Node|Document} + */ + function getRootNode(elt, global) { + return elt.getRootNode ? elt.getRootNode({ composed: global }) : getDocument() + } + + /** + * @param {Node} elt + * @param {(e:Node) => boolean} condition + * @returns {Node | null} + */ + function getClosestMatch(elt, condition) { + while (elt && !condition(elt)) { + elt = parentElt(elt) + } - /** - * @param {Function} func - */ - function maybeCall(func){ - if(func) { - func(); - } + return elt || null + } + + /** + * @param {Element} initialElement + * @param {Element} ancestor + * @param {string} attributeName + * @returns {string|null} + */ + function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName) { + const attributeValue = getAttributeValue(ancestor, attributeName) + const disinherit = getAttributeValue(ancestor, 'hx-disinherit') + var inherit = getAttributeValue(ancestor, 'hx-inherit') + if (initialElement !== ancestor) { + if (htmx.config.disableInheritance) { + if (inherit && (inherit === '*' || inherit.split(' ').indexOf(attributeName) >= 0)) { + return attributeValue + } else { + return null + } + } + if (disinherit && (disinherit === '*' || disinherit.split(' ').indexOf(attributeName) >= 0)) { + return 'unset' + } + } + return attributeValue + } + + /** + * @param {Element} elt + * @param {string} attributeName + * @returns {string | null} + */ + function getClosestAttributeValue(elt, attributeName) { + let closestAttr = null + getClosestMatch(elt, function(e) { + return !!(closestAttr = getAttributeValueWithDisinheritance(elt, asElement(e), attributeName)) + }) + if (closestAttr !== 'unset') { + return closestAttr + } + } + + /** + * @param {Node} elt + * @param {string} selector + * @returns {boolean} + */ + function matches(elt, selector) { + // @ts-ignore: non-standard properties for browser compatibility + // noinspection JSUnresolvedVariable + const matchesFunction = elt instanceof Element && (elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector) + return !!matchesFunction && matchesFunction.call(elt, selector) + } + + /** + * @param {string} str + * @returns {string} + */ + function getStartTag(str) { + const tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i + const match = tagMatcher.exec(str) + if (match) { + return match[1].toLowerCase() + } else { + return '' + } + } + + /** + * @param {string} resp + * @returns {Document} + */ + function parseHTML(resp) { + const parser = new DOMParser() + return parser.parseFromString(resp, 'text/html') + } + + /** + * @param {DocumentFragment} fragment + * @param {Node} elt + */ + function takeChildrenFor(fragment, elt) { + while (elt.childNodes.length > 0) { + fragment.append(elt.childNodes[0]) + } + } + + /** + * @param {HTMLScriptElement} script + * @returns {HTMLScriptElement} + */ + function duplicateScript(script) { + const newScript = getDocument().createElement('script') + forEach(script.attributes, function(attr) { + newScript.setAttribute(attr.name, attr.value) + }) + newScript.textContent = script.textContent + newScript.async = false + if (htmx.config.inlineScriptNonce) { + newScript.nonce = htmx.config.inlineScriptNonce + } + return newScript + } + + /** + * @param {HTMLScriptElement} script + * @returns {boolean} + */ + function isJavaScriptScriptNode(script) { + return script.matches('script') && (script.type === 'text/javascript' || script.type === 'module' || script.type === '') + } + + /** + * we have to make new copies of script tags that we are going to insert because + * SOME browsers (not saying who, but it involves an element and an animal) don't + * execute scripts created in <template> tags when they are inserted into the DOM + * and all the others do lmao + * @param {DocumentFragment} fragment + */ + function normalizeScriptTags(fragment) { + Array.from(fragment.querySelectorAll('script')).forEach(/** @param {HTMLScriptElement} script */ (script) => { + if (isJavaScriptScriptNode(script)) { + const newScript = duplicateScript(script) + const parent = script.parentNode + try { + parent.insertBefore(newScript, script) + } catch (e) { + logError(e) + } finally { + script.remove() + } + } + }) + } + + /** + * @typedef {DocumentFragment & {title?: string}} DocumentFragmentWithTitle + * @description a document fragment representing the response HTML, including + * a `title` property for any title information found + */ + + /** + * @param {string} response HTML + * @returns {DocumentFragmentWithTitle} + */ + function makeFragment(response) { + // strip head tag to determine shape of response we are dealing with + const responseWithNoHead = response.replace(HEAD_TAG_REGEX, '') + const startTag = getStartTag(responseWithNoHead) + /** @type DocumentFragmentWithTitle */ + let fragment + if (startTag === 'html') { + // if it is a full document, parse it and return the body + fragment = /** @type DocumentFragmentWithTitle */ (new DocumentFragment()) + const doc = parseHTML(response) + takeChildrenFor(fragment, doc.body) + fragment.title = doc.title + } else if (startTag === 'body') { + // parse body w/o wrapping in template + fragment = /** @type DocumentFragmentWithTitle */ (new DocumentFragment()) + const doc = parseHTML(responseWithNoHead) + takeChildrenFor(fragment, doc.body) + fragment.title = doc.title + } else { + // otherwise we have non-body partial HTML content, so wrap it in a template to maximize parsing flexibility + const doc = parseHTML('<body><template class="internal-htmx-wrapper">' + responseWithNoHead + '</template></body>') + fragment = /** @type DocumentFragmentWithTitle */ (doc.querySelector('template').content) + // extract title into fragment for later processing + fragment.title = doc.title + + // for legacy reasons we support a title tag at the root level of non-body responses, so we need to handle it + var titleElement = fragment.querySelector('title') + if (titleElement && titleElement.parentNode === fragment) { + titleElement.remove() + fragment.title = titleElement.innerText + } + } + if (fragment) { + if (htmx.config.allowScriptTags) { + normalizeScriptTags(fragment) + } else { + // remove all script tags if scripts are disabled + fragment.querySelectorAll('script').forEach((script) => script.remove()) + } + } + return fragment + } + + /** + * @param {Function} func + */ + function maybeCall(func) { + if (func) { + func() + } + } + + /** + * @param {any} o + * @param {string} type + * @returns + */ + function isType(o, type) { + return Object.prototype.toString.call(o) === '[object ' + type + ']' + } + + /** + * @param {*} o + * @returns {o is Function} + */ + function isFunction(o) { + return typeof o === 'function' + } + + /** + * @param {*} o + * @returns {o is Object} + */ + function isRawObject(o) { + return isType(o, 'Object') + } + + /** + * @typedef {Object} OnHandler + * @property {(keyof HTMLElementEventMap)|string} event + * @property {EventListener} listener + */ + + /** + * @typedef {Object} ListenerInfo + * @property {string} trigger + * @property {EventListener} listener + * @property {EventTarget} on + */ + + /** + * @typedef {Object} HtmxNodeInternalData + * Element data + * @property {number} [initHash] + * @property {boolean} [boosted] + * @property {OnHandler[]} [onHandlers] + * @property {number} [timeout] + * @property {ListenerInfo[]} [listenerInfos] + * @property {boolean} [cancelled] + * @property {boolean} [triggeredOnce] + * @property {number} [delayed] + * @property {number|null} [throttle] + * @property {string} [lastValue] + * @property {boolean} [loaded] + * @property {string} [path] + * @property {string} [verb] + * @property {boolean} [polling] + * @property {HTMLButtonElement|HTMLInputElement|null} [lastButtonClicked] + * @property {number} [requestCount] + * @property {XMLHttpRequest} [xhr] + * @property {(() => void)[]} [queuedRequests] + * @property {boolean} [abortable] + * + * Event data + * @property {HtmxTriggerSpecification} [triggerSpec] + * @property {EventTarget[]} [handledFor] + */ + + /** + * getInternalData retrieves "private" data stored by htmx within an element + * @param {EventTarget|Event} elt + * @returns {HtmxNodeInternalData} + */ + function getInternalData(elt) { + const dataProp = 'htmx-internal-data' + let data = elt[dataProp] + if (!data) { + data = elt[dataProp] = {} + } + return data + } + + /** + * toArray converts an ArrayLike object into a real array. + * @template T + * @param {ArrayLike<T>} arr + * @returns {T[]} + */ + function toArray(arr) { + const returnArr = [] + if (arr) { + for (let i = 0; i < arr.length; i++) { + returnArr.push(arr[i]) + } + } + return returnArr + } + + /** + * @template T + * @param {T[]|NamedNodeMap|HTMLCollection|HTMLFormControlsCollection|ArrayLike<T>} arr + * @param {(T) => void} func + */ + function forEach(arr, func) { + if (arr) { + for (let i = 0; i < arr.length; i++) { + func(arr[i]) + } + } + } + + /** + * @param {Element} el + * @returns {boolean} + */ + function isScrolledIntoView(el) { + const rect = el.getBoundingClientRect() + const elemTop = rect.top + const elemBottom = rect.bottom + return elemTop < window.innerHeight && elemBottom >= 0 + } + + /** + * @param {Node} elt + * @returns {boolean} + */ + function bodyContains(elt) { + // IE Fix + const rootNode = elt.getRootNode && elt.getRootNode() + if (rootNode && rootNode instanceof window.ShadowRoot) { + return getDocument().body.contains(rootNode.host) + } else { + return getDocument().body.contains(elt) + } + } + + /** + * @param {string} trigger + * @returns {string[]} + */ + function splitOnWhitespace(trigger) { + return trigger.trim().split(/\s+/) + } + + /** + * mergeObjects takes all the keys from + * obj2 and duplicates them into obj1 + * @template T1 + * @template T2 + * @param {T1} obj1 + * @param {T2} obj2 + * @returns {T1 & T2} + */ + function mergeObjects(obj1, obj2) { + for (const key in obj2) { + if (obj2.hasOwnProperty(key)) { + // @ts-ignore tsc doesn't seem to properly handle types merging + obj1[key] = obj2[key] + } + } + // @ts-ignore tsc doesn't seem to properly handle types merging + return obj1 + } + + /** + * @param {string} jString + * @returns {any|null} + */ + function parseJSON(jString) { + try { + return JSON.parse(jString) + } catch (error) { + logError(error) + return null + } + } + + /** + * @returns {boolean} + */ + function canAccessLocalStorage() { + const test = 'htmx:localStorageTest' + try { + localStorage.setItem(test, test) + localStorage.removeItem(test) + return true + } catch (e) { + return false + } + } + + /** + * @param {string} path + * @returns {string} + */ + function normalizePath(path) { + try { + const url = new URL(path) + if (url) { + path = url.pathname + url.search + } + // remove trailing slash, unless index page + if (!(/^\/$/.test(path))) { + path = path.replace(/\/+$/, '') + } + return path + } catch (e) { + // be kind to IE11, which doesn't support URL() + return path + } + } + + //= ========================================================================================= + // public API + //= ========================================================================================= + + /** + * @param {string} str + * @returns {any} + */ + function internalEval(str) { + return maybeEval(getDocument().body, function() { + return eval(str) + }) + } + + /** + * Adds a callback for the **htmx:load** event. This can be used to process new content, for example initializing the content with a javascript library + * + * @see https://htmx.org/api/#onLoad + * + * @param {(elt: Node) => void} callback the callback to call on newly loaded content + * @returns {EventListener} + */ + function onLoadHelper(callback) { + const value = htmx.on('htmx:load', /** @param {CustomEvent} evt */ function(evt) { + callback(evt.detail.elt) + }) + return value + } + + /** + * Log all htmx events, useful for debugging. + * + * @see https://htmx.org/api/#logAll + */ + function logAll() { + htmx.logger = function(elt, event, data) { + if (console) { + console.log(event, elt, data) + } + } + } + + function logNone() { + htmx.logger = null + } + + /** + * Finds an element matching the selector + * + * @see https://htmx.org/api/#find + * + * @param {ParentNode|string} eltOrSelector the root element to find the matching element in, inclusive | the selector to match + * @param {string} [selector] the selector to match + * @returns {Element|null} + */ + function find(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return eltOrSelector.querySelector(selector) + } else { + return find(getDocument(), eltOrSelector) + } + } + + /** + * Finds all elements matching the selector + * + * @see https://htmx.org/api/#findAll + * + * @param {ParentNode|string} eltOrSelector the root element to find the matching elements in, inclusive | the selector to match + * @param {string} [selector] the selector to match + * @returns {NodeListOf<Element>} + */ + function findAll(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return eltOrSelector.querySelectorAll(selector) + } else { + return findAll(getDocument(), eltOrSelector) + } + } + + /** + * @returns Window + */ + function getWindow() { + return window + } + + /** + * Removes an element from the DOM + * + * @see https://htmx.org/api/#remove + * + * @param {Node} elt + * @param {number} [delay] + */ + function removeElement(elt, delay) { + elt = resolveTarget(elt) + if (delay) { + getWindow().setTimeout(function() { + removeElement(elt) + elt = null + }, delay) + } else { + parentElt(elt).removeChild(elt) + } + } + + /** + * @param {any} elt + * @return {Element|null} + */ + function asElement(elt) { + return elt instanceof Element ? elt : null + } + + /** + * @param {any} elt + * @return {HTMLElement|null} + */ + function asHtmlElement(elt) { + return elt instanceof HTMLElement ? elt : null + } + + /** + * @param {any} value + * @return {string|null} + */ + function asString(value) { + return typeof value === 'string' ? value : null + } + + /** + * @param {EventTarget} elt + * @return {ParentNode|null} + */ + function asParentNode(elt) { + return elt instanceof Element || elt instanceof Document || elt instanceof DocumentFragment ? elt : null + } + + /** + * This method adds a class to the given element. + * + * @see https://htmx.org/api/#addClass + * + * @param {Element|string} elt the element to add the class to + * @param {string} clazz the class to add + * @param {number} [delay] the delay (in milliseconds) before class is added + */ + function addClassToElement(elt, clazz, delay) { + elt = asElement(resolveTarget(elt)) + if (!elt) { + return + } + if (delay) { + getWindow().setTimeout(function() { + addClassToElement(elt, clazz) + elt = null + }, delay) + } else { + elt.classList && elt.classList.add(clazz) + } + } + + /** + * Removes a class from the given element + * + * @see https://htmx.org/api/#removeClass + * + * @param {Node|string} node element to remove the class from + * @param {string} clazz the class to remove + * @param {number} [delay] the delay (in milliseconds before class is removed) + */ + function removeClassFromElement(node, clazz, delay) { + let elt = asElement(resolveTarget(node)) + if (!elt) { + return + } + if (delay) { + getWindow().setTimeout(function() { + removeClassFromElement(elt, clazz) + elt = null + }, delay) + } else { + if (elt.classList) { + elt.classList.remove(clazz) + // if there are no classes left, remove the class attribute + if (elt.classList.length === 0) { + elt.removeAttribute('class') } + } + } + } + + /** + * Toggles the given class on an element + * + * @see https://htmx.org/api/#toggleClass + * + * @param {Element|string} elt the element to toggle the class on + * @param {string} clazz the class to toggle + */ + function toggleClassOnElement(elt, clazz) { + elt = resolveTarget(elt) + elt.classList.toggle(clazz) + } + + /** + * Takes the given class from its siblings, so that among its siblings, only the given element will have the class. + * + * @see https://htmx.org/api/#takeClass + * + * @param {Node|string} elt the element that will take the class + * @param {string} clazz the class to take + */ + function takeClassForElement(elt, clazz) { + elt = resolveTarget(elt) + forEach(elt.parentElement.children, function(child) { + removeClassFromElement(child, clazz) + }) + addClassToElement(asElement(elt), clazz) + } + + /** + * Finds the closest matching element in the given elements parentage, inclusive of the element + * + * @see https://htmx.org/api/#closest + * + * @param {Element|string} elt the element to find the selector from + * @param {string} selector the selector to find + * @returns {Element|null} + */ + function closest(elt, selector) { + elt = asElement(resolveTarget(elt)) + if (elt && elt.closest) { + return elt.closest(selector) + } else { + // TODO remove when IE goes away + do { + if (elt == null || matches(elt, selector)) { + return elt + } + } + while (elt = elt && asElement(parentElt(elt))) + return null + } + } + + /** + * @param {string} str + * @param {string} prefix + * @returns {boolean} + */ + function startsWith(str, prefix) { + return str.substring(0, prefix.length) === prefix + } + + /** + * @param {string} str + * @param {string} suffix + * @returns {boolean} + */ + function endsWith(str, suffix) { + return str.substring(str.length - suffix.length) === suffix + } + + /** + * @param {string} selector + * @returns {string} + */ + function normalizeSelector(selector) { + const trimmedSelector = selector.trim() + if (startsWith(trimmedSelector, '<') && endsWith(trimmedSelector, '/>')) { + return trimmedSelector.substring(1, trimmedSelector.length - 2) + } else { + return trimmedSelector + } + } + + /** + * @param {Node|Element|Document|string} elt + * @param {string} selector + * @param {boolean=} global + * @returns {(Node|Window)[]} + */ + function querySelectorAllExt(elt, selector, global) { + elt = resolveTarget(elt) + if (selector.indexOf('closest ') === 0) { + return [closest(asElement(elt), normalizeSelector(selector.substr(8)))] + } else if (selector.indexOf('find ') === 0) { + return [find(asParentNode(elt), normalizeSelector(selector.substr(5)))] + } else if (selector === 'next') { + return [asElement(elt).nextElementSibling] + } else if (selector.indexOf('next ') === 0) { + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)), !!global)] + } else if (selector === 'previous') { + return [asElement(elt).previousElementSibling] + } else if (selector.indexOf('previous ') === 0) { + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)), !!global)] + } else if (selector === 'document') { + return [document] + } else if (selector === 'window') { + return [window] + } else if (selector === 'body') { + return [document.body] + } else if (selector === 'root') { + return [getRootNode(elt, !!global)] + } else if (selector.indexOf('global ') === 0) { + return querySelectorAllExt(elt, selector.slice(7), true) + } else { + return toArray(asParentNode(getRootNode(elt, !!global)).querySelectorAll(normalizeSelector(selector))) + } + } + + /** + * @param {Node} start + * @param {string} match + * @param {boolean} global + * @returns {Element} + */ + var scanForwardQuery = function(start, match, global) { + const results = asParentNode(getRootNode(start, global)).querySelectorAll(match) + for (let i = 0; i < results.length; i++) { + const elt = results[i] + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { + return elt + } + } + } + + /** + * @param {Node} start + * @param {string} match + * @param {boolean} global + * @returns {Element} + */ + var scanBackwardsQuery = function(start, match, global) { + const results = asParentNode(getRootNode(start, global)).querySelectorAll(match) + for (let i = results.length - 1; i >= 0; i--) { + const elt = results[i] + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { + return elt + } + } + } + + /** + * @param {Node|string} eltOrSelector + * @param {string=} selector + * @returns {Node|Window} + */ + function querySelectorExt(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return querySelectorAllExt(eltOrSelector, selector)[0] + } else { + return querySelectorAllExt(getDocument().body, eltOrSelector)[0] + } + } + + /** + * @template {EventTarget} T + * @param {T|string} eltOrSelector + * @param {T} [context] + * @returns {Element|T|null} + */ + function resolveTarget(eltOrSelector, context) { + if (typeof eltOrSelector === 'string') { + return find(asParentNode(context) || document, eltOrSelector) + } else { + return eltOrSelector + } + } + + /** + * @typedef {keyof HTMLElementEventMap|string} AnyEventName + */ + + /** + * @typedef {Object} EventArgs + * @property {EventTarget} target + * @property {AnyEventName} event + * @property {EventListener} listener + */ + + /** + * @param {EventTarget|AnyEventName} arg1 + * @param {AnyEventName|EventListener} arg2 + * @param {EventListener} [arg3] + * @returns {EventArgs} + */ + function processEventArgs(arg1, arg2, arg3) { + if (isFunction(arg2)) { + return { + target: getDocument().body, + event: asString(arg1), + listener: arg2 + } + } else { + return { + target: resolveTarget(arg1), + event: asString(arg2), + listener: arg3 + } + } + } + + /** + * Adds an event listener to an element + * + * @see https://htmx.org/api/#on + * + * @param {EventTarget|string} arg1 the element to add the listener to | the event name to add the listener for + * @param {string|EventListener} arg2 the event name to add the listener for | the listener to add + * @param {EventListener} [arg3] the listener to add + * @returns {EventListener} + */ + function addEventListenerImpl(arg1, arg2, arg3) { + ready(function() { + const eventArgs = processEventArgs(arg1, arg2, arg3) + eventArgs.target.addEventListener(eventArgs.event, eventArgs.listener) + }) + const b = isFunction(arg2) + return b ? arg2 : arg3 + } + + /** + * Removes an event listener from an element + * + * @see https://htmx.org/api/#off + * + * @param {EventTarget|string} arg1 the element to remove the listener from | the event name to remove the listener from + * @param {string|EventListener} arg2 the event name to remove the listener from | the listener to remove + * @param {EventListener} [arg3] the listener to remove + * @returns {EventListener} + */ + function removeEventListenerImpl(arg1, arg2, arg3) { + ready(function() { + const eventArgs = processEventArgs(arg1, arg2, arg3) + eventArgs.target.removeEventListener(eventArgs.event, eventArgs.listener) + }) + return isFunction(arg2) ? arg2 : arg3 + } + + //= =================================================================== + // Node processing + //= =================================================================== + + const DUMMY_ELT = getDocument().createElement('output') // dummy element for bad selectors + /** + * @param {Element} elt + * @param {string} attrName + * @returns {(Node|Window)[]} + */ + function findAttributeTargets(elt, attrName) { + const attrTarget = getClosestAttributeValue(elt, attrName) + if (attrTarget) { + if (attrTarget === 'this') { + return [findThisElement(elt, attrName)] + } else { + const result = querySelectorAllExt(elt, attrTarget) + if (result.length === 0) { + logError('The selector "' + attrTarget + '" on ' + attrName + ' returned no matches!') + return [DUMMY_ELT] + } else { + return result + } + } + } + } + + /** + * @param {Element} elt + * @param {string} attribute + * @returns {Element|null} + */ + function findThisElement(elt, attribute) { + return asElement(getClosestMatch(elt, function(elt) { + return getAttributeValue(asElement(elt), attribute) != null + })) + } + + /** + * @param {Element} elt + * @returns {Node|Window|null} + */ + function getTarget(elt) { + const targetStr = getClosestAttributeValue(elt, 'hx-target') + if (targetStr) { + if (targetStr === 'this') { + return findThisElement(elt, 'hx-target') + } else { + return querySelectorExt(elt, targetStr) + } + } else { + const data = getInternalData(elt) + if (data.boosted) { + return getDocument().body + } else { + return elt + } + } + } + + /** + * @param {string} name + * @returns {boolean} + */ + function shouldSettleAttribute(name) { + const attributesToSettle = htmx.config.attributesToSettle + for (let i = 0; i < attributesToSettle.length; i++) { + if (name === attributesToSettle[i]) { + return true + } + } + return false + } + + /** + * @param {Element} mergeTo + * @param {Element} mergeFrom + */ + function cloneAttributes(mergeTo, mergeFrom) { + forEach(mergeTo.attributes, function(attr) { + if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) { + mergeTo.removeAttribute(attr.name) + } + }) + forEach(mergeFrom.attributes, function(attr) { + if (shouldSettleAttribute(attr.name)) { + mergeTo.setAttribute(attr.name, attr.value) + } + }) + } + + /** + * @param {HtmxSwapStyle} swapStyle + * @param {Element} target + * @returns {boolean} + */ + function isInlineSwap(swapStyle, target) { + const extensions = getExtensions(target) + for (let i = 0; i < extensions.length; i++) { + const extension = extensions[i] + try { + if (extension.isInlineSwap(swapStyle)) { + return true + } + } catch (e) { + logError(e) + } + } + return swapStyle === 'outerHTML' + } + + /** + * @param {string} oobValue + * @param {Element} oobElement + * @param {HtmxSettleInfo} settleInfo + * @returns + */ + function oobSwap(oobValue, oobElement, settleInfo) { + let selector = '#' + getRawAttribute(oobElement, 'id') + /** @type HtmxSwapStyle */ + let swapStyle = 'outerHTML' + if (oobValue === 'true') { + // do nothing + } else if (oobValue.indexOf(':') > 0) { + swapStyle = oobValue.substr(0, oobValue.indexOf(':')) + selector = oobValue.substr(oobValue.indexOf(':') + 1, oobValue.length) + } else { + swapStyle = oobValue + } - /** - * @param {any} o - * @param {string} type - * @returns - */ - function isType(o, type) { - return Object.prototype.toString.call(o) === "[object " + type + "]"; - } - - /** - * @param {*} o - * @returns {o is Function} - */ - function isFunction(o) { - return isType(o, "Function"); - } - - /** - * @param {*} o - * @returns {o is Object} - */ - function isRawObject(o) { - return isType(o, "Object"); - } - - /** - * getInternalData retrieves "private" data stored by htmx within an element - * @param {HTMLElement} elt - * @returns {*} - */ - function getInternalData(elt) { - var dataProp = 'htmx-internal-data'; - var data = elt[dataProp]; - if (!data) { - data = elt[dataProp] = {}; - } - return data; - } - - /** - * toArray converts an ArrayLike object into a real array. - * @param {ArrayLike} arr - * @returns {any[]} - */ - function toArray(arr) { - var returnArr = []; - if (arr) { - for (var i = 0; i < arr.length; i++) { - returnArr.push(arr[i]); - } - } - return returnArr + const targets = getDocument().querySelectorAll(selector) + if (targets) { + forEach( + targets, + function(target) { + let fragment + const oobElementClone = oobElement.cloneNode(true) + fragment = getDocument().createDocumentFragment() + fragment.appendChild(oobElementClone) + if (!isInlineSwap(swapStyle, target)) { + fragment = asParentNode(oobElementClone) // if this is not an inline swap, we use the content of the node, not the node itself + } + + const beforeSwapDetails = { shouldSwap: true, target, fragment } + if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return + + target = beforeSwapDetails.target // allow re-targeting + if (beforeSwapDetails.shouldSwap) { + swapWithStyle(swapStyle, target, target, fragment, settleInfo) + } + forEach(settleInfo.elts, function(elt) { + triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails) + }) + } + ) + oobElement.parentNode.removeChild(oobElement) + } else { + oobElement.parentNode.removeChild(oobElement) + triggerErrorEvent(getDocument().body, 'htmx:oobErrorNoTarget', { content: oobElement }) + } + return oobValue + } + + /** + * @param {DocumentFragment} fragment + */ + function handlePreservedElements(fragment) { + forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function(preservedElt) { + const id = getAttributeValue(preservedElt, 'id') + const oldElt = getDocument().getElementById(id) + if (oldElt != null) { + preservedElt.parentNode.replaceChild(oldElt, preservedElt) + } + }) + } + + /** + * @param {Node} parentNode + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function handleAttributes(parentNode, fragment, settleInfo) { + forEach(fragment.querySelectorAll('[id]'), function(newNode) { + const id = getRawAttribute(newNode, 'id') + if (id && id.length > 0) { + const normalizedId = id.replace("'", "\\'") + const normalizedTag = newNode.tagName.replace(':', '\\:') + const parentElt = asParentNode(parentNode) + const oldNode = parentElt && parentElt.querySelector(normalizedTag + "[id='" + normalizedId + "']") + if (oldNode && oldNode !== parentElt) { + const newAttributes = newNode.cloneNode() + cloneAttributes(newNode, oldNode) + settleInfo.tasks.push(function() { + cloneAttributes(newNode, newAttributes) + }) + } + } + }) + } + + /** + * @param {Node} child + * @returns {HtmxSettleTask} + */ + function makeAjaxLoadTask(child) { + return function() { + removeClassFromElement(child, htmx.config.addedClass) + processNode(asElement(child)) + processFocus(asParentNode(child)) + triggerEvent(child, 'htmx:load') + } + } + + /** + * @param {ParentNode} child + */ + function processFocus(child) { + const autofocus = '[autofocus]' + const autoFocusedElt = asHtmlElement(matches(child, autofocus) ? child : child.querySelector(autofocus)) + if (autoFocusedElt != null) { + autoFocusedElt.focus() + } + } + + /** + * @param {Node} parentNode + * @param {Node} insertBefore + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) { + handleAttributes(parentNode, fragment, settleInfo) + while (fragment.childNodes.length > 0) { + const child = fragment.firstChild + addClassToElement(asElement(child), htmx.config.addedClass) + parentNode.insertBefore(child, insertBefore) + if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { + settleInfo.tasks.push(makeAjaxLoadTask(child)) + } + } + } + + /** + * based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, + * derived from Java's string hashcode implementation + * @param {string} string + * @param {number} hash + * @returns {number} + */ + function stringHash(string, hash) { + let char = 0 + while (char < string.length) { + hash = (hash << 5) - hash + string.charCodeAt(char++) | 0 // bitwise or ensures we have a 32-bit int + } + return hash + } + + /** + * @param {Element} elt + * @returns {number} + */ + function attributeHash(elt) { + let hash = 0 + // IE fix + if (elt.attributes) { + for (let i = 0; i < elt.attributes.length; i++) { + const attribute = elt.attributes[i] + if (attribute.value) { // only include attributes w/ actual values (empty is same as non-existent) + hash = stringHash(attribute.name, hash) + hash = stringHash(attribute.value, hash) + } + } + } + return hash + } + + /** + * @param {EventTarget} elt + */ + function deInitOnHandlers(elt) { + const internalData = getInternalData(elt) + if (internalData.onHandlers) { + for (let i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i] + removeEventListenerImpl(elt, handlerInfo.event, handlerInfo.listener) + } + delete internalData.onHandlers + } + } + + /** + * @param {Node} element + */ + function deInitNode(element) { + const internalData = getInternalData(element) + if (internalData.timeout) { + clearTimeout(internalData.timeout) + } + if (internalData.listenerInfos) { + forEach(internalData.listenerInfos, function(info) { + if (info.on) { + removeEventListenerImpl(info.on, info.trigger, info.listener) } - - function forEach(arr, func) { - if (arr) { - for (var i = 0; i < arr.length; i++) { - func(arr[i]); - } - } + }) + } + deInitOnHandlers(element) + forEach(Object.keys(internalData), function(key) { delete internalData[key] }) + } + + /** + * @param {Node} element + */ + function cleanUpElement(element) { + triggerEvent(element, 'htmx:beforeCleanupElement') + deInitNode(element) + // @ts-ignore IE11 code + // noinspection JSUnresolvedReference + if (element.children) { // IE + // @ts-ignore + forEach(element.children, function(child) { cleanUpElement(child) }) + } + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapOuterHTML(target, fragment, settleInfo) { + /** @type {Node} */ + let newElt + const eltBeforeNewContent = target.previousSibling + insertNodesBefore(parentElt(target), target, fragment, settleInfo) + if (eltBeforeNewContent == null) { + newElt = parentElt(target).firstChild + } else { + newElt = eltBeforeNewContent.nextSibling + } + settleInfo.elts = settleInfo.elts.filter(function(e) { return e !== target }) + while (newElt && newElt !== target) { + if (newElt instanceof Element) { + settleInfo.elts.push(newElt) + newElt = newElt.nextElementSibling + } else { + newElt = null + } + } + cleanUpElement(target) + if (target instanceof Element) { + target.remove() + } else { + target.parentNode.removeChild(target) + } + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapAfterBegin(target, fragment, settleInfo) { + return insertNodesBefore(target, target.firstChild, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapBeforeBegin(target, fragment, settleInfo) { + return insertNodesBefore(parentElt(target), target, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapBeforeEnd(target, fragment, settleInfo) { + return insertNodesBefore(target, null, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapAfterEnd(target, fragment, settleInfo) { + return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo) + } + + /** + * @param {Node} target + */ + function swapDelete(target) { + cleanUpElement(target) + return parentElt(target).removeChild(target) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapInnerHTML(target, fragment, settleInfo) { + const firstChild = target.firstChild + insertNodesBefore(target, firstChild, fragment, settleInfo) + if (firstChild) { + while (firstChild.nextSibling) { + cleanUpElement(firstChild.nextSibling) + target.removeChild(firstChild.nextSibling) + } + cleanUpElement(firstChild) + target.removeChild(firstChild) + } + } + + /** + * @param {HtmxSwapStyle} swapStyle + * @param {Element} elt + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapWithStyle(swapStyle, elt, target, fragment, settleInfo) { + switch (swapStyle) { + case 'none': + return + case 'outerHTML': + swapOuterHTML(target, fragment, settleInfo) + return + case 'afterbegin': + swapAfterBegin(target, fragment, settleInfo) + return + case 'beforebegin': + swapBeforeBegin(target, fragment, settleInfo) + return + case 'beforeend': + swapBeforeEnd(target, fragment, settleInfo) + return + case 'afterend': + swapAfterEnd(target, fragment, settleInfo) + return + case 'delete': + swapDelete(target) + return + default: + var extensions = getExtensions(elt) + for (let i = 0; i < extensions.length; i++) { + const ext = extensions[i] + try { + const newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo) + if (newElements) { + if (typeof newElements.length !== 'undefined') { + // if handleSwap returns an array (like) of elements, we handle them + for (let j = 0; j < newElements.length; j++) { + const child = newElements[j] + if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { + settleInfo.tasks.push(makeAjaxLoadTask(child)) + } + } + } + return + } + } catch (e) { + logError(e) + } + } + if (swapStyle === 'innerHTML') { + swapInnerHTML(target, fragment, settleInfo) + } else { + swapWithStyle(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo) } + } + } + + /** + * @param {DocumentFragment} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function findAndSwapOobElements(fragment, settleInfo) { + forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function(oobElement) { + if (htmx.config.allowNestedOobSwaps || oobElement.parentElement === null) { + const oobValue = getAttributeValue(oobElement, 'hx-swap-oob') + if (oobValue != null) { + oobSwap(oobValue, oobElement, settleInfo) + } + } else { + oobElement.removeAttribute('hx-swap-oob') + oobElement.removeAttribute('data-hx-swap-oob') + } + }) + } + + /** + * Implements complete swapping pipeline, including: focus and selection preservation, + * title updates, scroll, OOB swapping, normal swapping and settling + * @param {string|Element} target + * @param {string} content + * @param {HtmxSwapSpecification} swapSpec + * @param {SwapOptions} [swapOptions] + */ + function swap(target, content, swapSpec, swapOptions) { + if (!swapOptions) { + swapOptions = {} + } - function isScrolledIntoView(el) { - var rect = el.getBoundingClientRect(); - var elemTop = rect.top; - var elemBottom = rect.bottom; - return elemTop < window.innerHeight && elemBottom >= 0; - } + target = resolveTarget(target) + + // preserve focus and selection + const activeElt = document.activeElement + let selectionInfo = {} + try { + selectionInfo = { + elt: activeElt, + // @ts-ignore + start: activeElt ? activeElt.selectionStart : null, + // @ts-ignore + end: activeElt ? activeElt.selectionEnd : null + } + } catch (e) { + // safari issue - see https://github.com/microsoft/playwright/issues/5894 + } + const settleInfo = makeSettleInfo(target) - function bodyContains(elt) { - // IE Fix - if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) { - return getDocument().body.contains(elt.getRootNode().host); - } else { - return getDocument().body.contains(elt); - } - } + // For text content swaps, don't parse the response as HTML, just insert it + if (swapSpec.swapStyle === 'textContent') { + target.textContent = content + // Otherwise, make the fragment and process it + } else { + let fragment = makeFragment(content) + + settleInfo.title = fragment.title + + // select-oob swaps + if (swapOptions.selectOOB) { + const oobSelectValues = swapOptions.selectOOB.split(',') + for (let i = 0; i < oobSelectValues.length; i++) { + const oobSelectValue = oobSelectValues[i].split(':', 2) + let id = oobSelectValue[0].trim() + if (id.indexOf('#') === 0) { + id = id.substring(1) + } + const oobValue = oobSelectValue[1] || 'true' + const oobElement = fragment.querySelector('#' + id) + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo) + } + } + } + // oob swaps + findAndSwapOobElements(fragment, settleInfo) + forEach(findAll(fragment, 'template'), /** @param {HTMLTemplateElement} template */function(template) { + findAndSwapOobElements(template.content, settleInfo) + if (template.content.childElementCount === 0) { + // Avoid polluting the DOM with empty templates that were only used to encapsulate oob swap + template.remove() + } + }) + + // normal swap + if (swapOptions.select) { + const newFragment = getDocument().createDocumentFragment() + forEach(fragment.querySelectorAll(swapOptions.select), function(node) { + newFragment.appendChild(node) + }) + fragment = newFragment + } + handlePreservedElements(fragment) + swapWithStyle(swapSpec.swapStyle, swapOptions.contextElement, target, fragment, settleInfo) + } - function splitOnWhitespace(trigger) { - return trigger.trim().split(/\s+/); - } + // apply saved focus and selection information to swapped content + if (selectionInfo.elt && + !bodyContains(selectionInfo.elt) && + getRawAttribute(selectionInfo.elt, 'id')) { + const newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, 'id')) + const focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll } + if (newActiveElt) { + // @ts-ignore + if (selectionInfo.start && newActiveElt.setSelectionRange) { + try { + // @ts-ignore + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end) + } catch (e) { + // the setSelectionRange method is present on fields that don't support it, so just let this fail + } + } + newActiveElt.focus(focusOptions) + } + } - /** - * mergeObjects takes all of the keys from - * obj2 and duplicates them into obj1 - * @param {Object} obj1 - * @param {Object} obj2 - * @returns {Object} - */ - function mergeObjects(obj1, obj2) { - for (var key in obj2) { - if (obj2.hasOwnProperty(key)) { - obj1[key] = obj2[key]; - } - } - return obj1; - } + target.classList.remove(htmx.config.swappingClass) + forEach(settleInfo.elts, function(elt) { + if (elt.classList) { + elt.classList.add(htmx.config.settlingClass) + } + triggerEvent(elt, 'htmx:afterSwap', swapOptions.eventInfo) + }) + if (swapOptions.afterSwapCallback) { + swapOptions.afterSwapCallback() + } - function parseJSON(jString) { - try { - return JSON.parse(jString); - } catch(error) { - logError(error); - return null; - } - } + // merge in new title after swap but before settle + if (!swapSpec.ignoreTitle) { + handleTitle(settleInfo.title) + } - function canAccessLocalStorage() { - var test = 'htmx:localStorageTest'; - try { - localStorage.setItem(test, test); - localStorage.removeItem(test); - return true; - } catch(e) { - return false; - } - } + // settle + const doSettle = function() { + forEach(settleInfo.tasks, function(task) { + task.call() + }) + forEach(settleInfo.elts, function(elt) { + if (elt.classList) { + elt.classList.remove(htmx.config.settlingClass) + } + triggerEvent(elt, 'htmx:afterSettle', swapOptions.eventInfo) + }) + + if (swapOptions.anchor) { + const anchorTarget = asElement(resolveTarget('#' + swapOptions.anchor)) + if (anchorTarget) { + anchorTarget.scrollIntoView({ block: 'start', behavior: 'auto' }) + } + } + + updateScrollState(settleInfo.elts, swapSpec) + if (swapOptions.afterSettleCallback) { + swapOptions.afterSettleCallback() + } + } - function normalizePath(path) { + if (swapSpec.settleDelay > 0) { + getWindow().setTimeout(doSettle, swapSpec.settleDelay) + } else { + doSettle() + } + } + + /** + * @param {XMLHttpRequest} xhr + * @param {string} header + * @param {EventTarget} elt + */ + function handleTriggerHeader(xhr, header, elt) { + const triggerBody = xhr.getResponseHeader(header) + if (triggerBody.indexOf('{') === 0) { + const triggers = parseJSON(triggerBody) + for (const eventName in triggers) { + if (triggers.hasOwnProperty(eventName)) { + let detail = triggers[eventName] + if (!isRawObject(detail)) { + detail = { value: detail } + } + triggerEvent(elt, eventName, detail) + } + } + } else { + const eventNames = triggerBody.split(',') + for (let i = 0; i < eventNames.length; i++) { + triggerEvent(elt, eventNames[i].trim(), []) + } + } + } + + const WHITESPACE = /\s/ + const WHITESPACE_OR_COMMA = /[\s,]/ + const SYMBOL_START = /[_$a-zA-Z]/ + const SYMBOL_CONT = /[_$a-zA-Z0-9]/ + const STRINGISH_START = ['"', "'", '/'] + const NOT_WHITESPACE = /[^\s]/ + const COMBINED_SELECTOR_START = /[{(]/ + const COMBINED_SELECTOR_END = /[})]/ + + /** + * @param {string} str + * @returns {string[]} + */ + function tokenizeString(str) { + /** @type string[] */ + const tokens = [] + let position = 0 + while (position < str.length) { + if (SYMBOL_START.exec(str.charAt(position))) { + var startPosition = position + while (SYMBOL_CONT.exec(str.charAt(position + 1))) { + position++ + } + tokens.push(str.substr(startPosition, position - startPosition + 1)) + } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) { + const startChar = str.charAt(position) + var startPosition = position + position++ + while (position < str.length && str.charAt(position) !== startChar) { + if (str.charAt(position) === '\\') { + position++ + } + position++ + } + tokens.push(str.substr(startPosition, position - startPosition + 1)) + } else { + const symbol = str.charAt(position) + tokens.push(symbol) + } + position++ + } + return tokens + } + + /** + * @param {string} token + * @param {string|null} last + * @param {string} paramName + * @returns {boolean} + */ + function isPossibleRelativeReference(token, last, paramName) { + return SYMBOL_START.exec(token.charAt(0)) && + token !== 'true' && + token !== 'false' && + token !== 'this' && + token !== paramName && + last !== '.' + } + + /** + * @param {EventTarget|string} elt + * @param {string[]} tokens + * @param {string} paramName + * @returns {ConditionalFunction|null} + */ + function maybeGenerateConditional(elt, tokens, paramName) { + if (tokens[0] === '[') { + tokens.shift() + let bracketCount = 1 + let conditionalSource = ' return (function(' + paramName + '){ return (' + let last = null + while (tokens.length > 0) { + const token = tokens[0] + // @ts-ignore For some reason tsc doesn't understand the shift call, and thinks we're comparing the same value here, i.e. '[' vs ']' + if (token === ']') { + bracketCount-- + if (bracketCount === 0) { + if (last === null) { + conditionalSource = conditionalSource + 'true' + } + tokens.shift() + conditionalSource += ')})' try { - var url = new URL(path); - if (url) { - path = url.pathname + url.search; - } - // remove trailing slash, unless index page - if (!(/^\/$/.test(path))) { - path = path.replace(/\/+$/, ''); - } - return path; + const conditionFunction = maybeEval(elt, function() { + return Function(conditionalSource)() + }, + function() { return true }) + conditionFunction.source = conditionalSource + return conditionFunction } catch (e) { - // be kind to IE11, which doesn't support URL() - return path; - } - } - - //========================================================================================== - // public API - //========================================================================================== - - function internalEval(str){ - return maybeEval(getDocument().body, function () { - return eval(str); - }); - } - - function onLoadHelper(callback) { - var value = htmx.on("htmx:load", function(evt) { - callback(evt.detail.elt); - }); - return value; - } - - function logAll(){ - htmx.logger = function(elt, event, data) { - if(console) { - console.log(event, elt, data); - } - } - } - - function logNone() { - htmx.logger = null - } - - function find(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelector(selector); - } else { - return find(getDocument(), eltOrSelector); - } - } - - function findAll(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelectorAll(selector); - } else { - return findAll(getDocument(), eltOrSelector); - } - } - - function removeElement(elt, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - removeElement(elt); - elt = null; - }, delay); - } else { - elt.parentElement.removeChild(elt); - } - } - - function addClassToElement(elt, clazz, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - addClassToElement(elt, clazz); - elt = null; - }, delay); - } else { - elt.classList && elt.classList.add(clazz); - } - } - - function removeClassFromElement(elt, clazz, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - removeClassFromElement(elt, clazz); - elt = null; - }, delay); - } else { - if (elt.classList) { - elt.classList.remove(clazz); - // if there are no classes left, remove the class attribute - if (elt.classList.length === 0) { - elt.removeAttribute("class"); - } - } - } - } - - function toggleClassOnElement(elt, clazz) { - elt = resolveTarget(elt); - elt.classList.toggle(clazz); - } - - function takeClassForElement(elt, clazz) { - elt = resolveTarget(elt); - forEach(elt.parentElement.children, function(child){ - removeClassFromElement(child, clazz); - }) - addClassToElement(elt, clazz); - } - - function closest(elt, selector) { - elt = resolveTarget(elt); - if (elt.closest) { - return elt.closest(selector); - } else { - // TODO remove when IE goes away - do{ - if (elt == null || matches(elt, selector)){ - return elt; - } - } - while (elt = elt && parentElt(elt)); - return null; - } - } - - function startsWith(str, prefix) { - return str.substring(0, prefix.length) === prefix - } - - function endsWith(str, suffix) { - return str.substring(str.length - suffix.length) === suffix - } - - function normalizeSelector(selector) { - var trimmedSelector = selector.trim(); - if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) { - return trimmedSelector.substring(1, trimmedSelector.length - 2); - } else { - return trimmedSelector; - } - } - - function querySelectorAllExt(elt, selector) { - if (selector.indexOf("closest ") === 0) { - return [closest(elt, normalizeSelector(selector.substr(8)))]; - } else if (selector.indexOf("find ") === 0) { - return [find(elt, normalizeSelector(selector.substr(5)))]; - } else if (selector === "next") { - return [elt.nextElementSibling] - } else if (selector.indexOf("next ") === 0) { - return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; - } else if (selector === "previous") { - return [elt.previousElementSibling] - } else if (selector.indexOf("previous ") === 0) { - return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; - } else if (selector === 'document') { - return [document]; - } else if (selector === 'window') { - return [window]; - } else if (selector === 'body') { - return [document.body]; - } else { - return getDocument().querySelectorAll(normalizeSelector(selector)); - } - } - - var scanForwardQuery = function(start, match) { - var results = getDocument().querySelectorAll(match); - for (var i = 0; i < results.length; i++) { - var elt = results[i]; - if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { - return elt; - } - } - } - - var scanBackwardsQuery = function(start, match) { - var results = getDocument().querySelectorAll(match); - for (var i = results.length - 1; i >= 0; i--) { - var elt = results[i]; - if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { - return elt; - } - } - } - - function querySelectorExt(eltOrSelector, selector) { - if (selector) { - return querySelectorAllExt(eltOrSelector, selector)[0]; - } else { - return querySelectorAllExt(getDocument().body, eltOrSelector)[0]; - } - } - - function resolveTarget(arg2) { - if (isType(arg2, 'String')) { - return find(arg2); - } else { - return arg2; - } - } - - function processEventArgs(arg1, arg2, arg3) { - if (isFunction(arg2)) { - return { - target: getDocument().body, - event: arg1, - listener: arg2 - } - } else { - return { - target: resolveTarget(arg1), - event: arg2, - listener: arg3 - } - } - - } - - function addEventListenerImpl(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 removeEventListenerImpl(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 - //==================================================================== - - var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors - function findAttributeTargets(elt, attrName) { - var attrTarget = getClosestAttributeValue(elt, attrName); - if (attrTarget) { - if (attrTarget === "this") { - return [findThisElement(elt, attrName)]; - } else { - var result = querySelectorAllExt(elt, attrTarget); - if (result.length === 0) { - logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!"); - return [DUMMY_ELT] - } else { - return result; - } - } - } - } - - function findThisElement(elt, attribute){ - return getClosestMatch(elt, function (elt) { - return getAttributeValue(elt, attribute) != null; - }) - } - - function getTarget(elt) { - var targetStr = getClosestAttributeValue(elt, "hx-target"); - if (targetStr) { - if (targetStr === "this") { - return findThisElement(elt,'hx-target'); - } else { - return querySelectorExt(elt, targetStr) - } - } else { - var data = getInternalData(elt); - if (data.boosted) { - return getDocument().body; - } else { - return elt; - } - } - } - - function shouldSettleAttribute(name) { - var attributesToSettle = htmx.config.attributesToSettle; - for (var i = 0; i < attributesToSettle.length; i++) { - if (name === attributesToSettle[i]) { - return true; - } - } - return false; - } - - function cloneAttributes(mergeTo, mergeFrom) { - forEach(mergeTo.attributes, function (attr) { - if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) { - mergeTo.removeAttribute(attr.name) - } - }); - forEach(mergeFrom.attributes, function (attr) { - if (shouldSettleAttribute(attr.name)) { - mergeTo.setAttribute(attr.name, attr.value); - } - }); - } - - function isInlineSwap(swapStyle, target) { - var extensions = getExtensions(target); - for (var i = 0; i < extensions.length; i++) { - var extension = extensions[i]; - try { - if (extension.isInlineSwap(swapStyle)) { - return true; - } - } catch(e) { - logError(e); - } - } - return swapStyle === "outerHTML"; - } - - /** - * - * @param {string} oobValue - * @param {HTMLElement} oobElement - * @param {*} settleInfo - * @returns - */ - function oobSwap(oobValue, oobElement, settleInfo) { - var selector = "#" + getRawAttribute(oobElement, "id"); - var swapStyle = "outerHTML"; - if (oobValue === "true") { - // do nothing - } else if (oobValue.indexOf(":") > 0) { - swapStyle = oobValue.substr(0, oobValue.indexOf(":")); - selector = oobValue.substr(oobValue.indexOf(":") + 1, oobValue.length); - } else { - swapStyle = oobValue; - } - - var targets = getDocument().querySelectorAll(selector); - if (targets) { - forEach( - targets, - function (target) { - var fragment; - var oobElementClone = oobElement.cloneNode(true); - fragment = getDocument().createDocumentFragment(); - fragment.appendChild(oobElementClone); - if (!isInlineSwap(swapStyle, target)) { - fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself - } - - var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment }; - if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return; - - target = beforeSwapDetails.target; // allow re-targeting - if (beforeSwapDetails['shouldSwap']){ - swap(swapStyle, target, target, fragment, settleInfo); - } - forEach(settleInfo.elts, function (elt) { - triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails); - }); - } - ); - oobElement.parentNode.removeChild(oobElement); - } else { - oobElement.parentNode.removeChild(oobElement); - triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}); - } - return oobValue; - } - - function handleOutOfBandSwaps(elt, fragment, settleInfo) { - var oobSelects = getClosestAttributeValue(elt, "hx-select-oob"); - if (oobSelects) { - var oobSelectValues = oobSelects.split(","); - for (var i = 0; i < oobSelectValues.length; i++) { - var oobSelectValue = oobSelectValues[i].split(":", 2); - var id = oobSelectValue[0].trim(); - if (id.indexOf("#") === 0) { - id = id.substring(1); - } - var oobValue = oobSelectValue[1] || "true"; - var oobElement = fragment.querySelector("#" + id); - if (oobElement) { - oobSwap(oobValue, oobElement, settleInfo); - } - } - } - forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) { - var oobValue = getAttributeValue(oobElement, "hx-swap-oob"); - if (oobValue != null) { - oobSwap(oobValue, oobElement, settleInfo); - } - }); - } - - function handlePreservedElements(fragment) { - forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function (preservedElt) { - var id = getAttributeValue(preservedElt, "id"); - var oldElt = getDocument().getElementById(id); - if (oldElt != null) { - preservedElt.parentNode.replaceChild(oldElt, preservedElt); - } - }); - } - - function handleAttributes(parentNode, fragment, settleInfo) { - forEach(fragment.querySelectorAll("[id]"), function (newNode) { - var id = getRawAttribute(newNode, "id") - if (id && id.length > 0) { - var normalizedId = id.replace("'", "\\'"); - var normalizedTag = newNode.tagName.replace(':', '\\:'); - var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']"); - if (oldNode && oldNode !== parentNode) { - var newAttributes = newNode.cloneNode(); - cloneAttributes(newNode, oldNode); - settleInfo.tasks.push(function () { - cloneAttributes(newNode, newAttributes); - }); - } - } - }); - } - - function makeAjaxLoadTask(child) { - return function () { - removeClassFromElement(child, htmx.config.addedClass); - processNode(child); - processScripts(child); - processFocus(child) - triggerEvent(child, 'htmx:load'); - }; - } - - function processFocus(child) { - var autofocus = "[autofocus]"; - var autoFocusedElt = matches(child, autofocus) ? child : child.querySelector(autofocus) - if (autoFocusedElt != null) { - autoFocusedElt.focus(); - } - } - - function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) { - handleAttributes(parentNode, fragment, settleInfo); - while(fragment.childNodes.length > 0){ - var child = fragment.firstChild; - addClassToElement(child, htmx.config.addedClass); - parentNode.insertBefore(child, insertBefore); - if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { - settleInfo.tasks.push(makeAjaxLoadTask(child)); - } - } - } - - // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, - // derived from Java's string hashcode implementation - function stringHash(string, hash) { - var char = 0; - while (char < string.length){ - hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int - } - return hash; - } - - function attributeHash(elt) { - var hash = 0; - // IE fix - if (elt.attributes) { - for (var i = 0; i < elt.attributes.length; i++) { - var attribute = elt.attributes[i]; - if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent) - hash = stringHash(attribute.name, hash); - hash = stringHash(attribute.value, hash); - } - } - } - return hash; - } - - function deInitOnHandlers(elt) { - var internalData = getInternalData(elt); - if (internalData.onHandlers) { - for (var i = 0; i < internalData.onHandlers.length; i++) { - const handlerInfo = internalData.onHandlers[i]; - elt.removeEventListener(handlerInfo.event, handlerInfo.listener); - } - delete internalData.onHandlers - } - } - - function deInitNode(element) { - var internalData = getInternalData(element); - if (internalData.timeout) { - clearTimeout(internalData.timeout); - } - if (internalData.webSocket) { - internalData.webSocket.close(); - } - if (internalData.sseEventSource) { - internalData.sseEventSource.close(); - } - if (internalData.listenerInfos) { - forEach(internalData.listenerInfos, function (info) { - if (info.on) { - info.on.removeEventListener(info.trigger, info.listener); - } - }); - } - deInitOnHandlers(element); - forEach(Object.keys(internalData), function(key) { delete internalData[key] }); - } - - function cleanUpElement(element) { - triggerEvent(element, "htmx:beforeCleanupElement") - deInitNode(element); - if (element.children) { // IE - forEach(element.children, function(child) { cleanUpElement(child) }); - } - } - - function swapOuterHTML(target, fragment, settleInfo) { - if (target.tagName === "BODY") { - return swapInnerHTML(target, fragment, settleInfo); - } else { - // @type {HTMLElement} - var newElt - var eltBeforeNewContent = target.previousSibling; - insertNodesBefore(parentElt(target), target, fragment, settleInfo); - if (eltBeforeNewContent == null) { - newElt = parentElt(target).firstChild; - } else { - newElt = eltBeforeNewContent.nextSibling; - } - settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target }); - while(newElt && newElt !== target) { - if (newElt.nodeType === Node.ELEMENT_NODE) { - settleInfo.elts.push(newElt); - } - newElt = newElt.nextElementSibling; - } - cleanUpElement(target); - parentElt(target).removeChild(target); - } - } - - function swapAfterBegin(target, fragment, settleInfo) { - return insertNodesBefore(target, target.firstChild, fragment, settleInfo); - } - - function swapBeforeBegin(target, fragment, settleInfo) { - return insertNodesBefore(parentElt(target), target, fragment, settleInfo); - } - - function swapBeforeEnd(target, fragment, settleInfo) { - return insertNodesBefore(target, null, fragment, settleInfo); - } - - function swapAfterEnd(target, fragment, settleInfo) { - return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo); - } - function swapDelete(target, fragment, settleInfo) { - cleanUpElement(target); - return parentElt(target).removeChild(target); - } - - function swapInnerHTML(target, fragment, settleInfo) { - var firstChild = target.firstChild; - insertNodesBefore(target, firstChild, fragment, settleInfo); - if (firstChild) { - while (firstChild.nextSibling) { - cleanUpElement(firstChild.nextSibling) - target.removeChild(firstChild.nextSibling); - } - cleanUpElement(firstChild) - target.removeChild(firstChild); - } - } - - function maybeSelectFromResponse(elt, fragment, selectOverride) { - var selector = selectOverride || getClosestAttributeValue(elt, "hx-select"); - if (selector) { - var newFragment = getDocument().createDocumentFragment(); - forEach(fragment.querySelectorAll(selector), function (node) { - newFragment.appendChild(node); - }); - fragment = newFragment; - } - return fragment; - } - - function swap(swapStyle, elt, target, fragment, settleInfo) { - switch (swapStyle) { - case "none": - return; - case "outerHTML": - swapOuterHTML(target, fragment, settleInfo); - return; - case "afterbegin": - swapAfterBegin(target, fragment, settleInfo); - return; - case "beforebegin": - swapBeforeBegin(target, fragment, settleInfo); - return; - case "beforeend": - swapBeforeEnd(target, fragment, settleInfo); - return; - case "afterend": - swapAfterEnd(target, fragment, settleInfo); - return; - case "delete": - swapDelete(target, fragment, settleInfo); - return; - default: - var extensions = getExtensions(elt); - for (var i = 0; i < extensions.length; i++) { - var ext = extensions[i]; - try { - var newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo); - if (newElements) { - if (typeof newElements.length !== 'undefined') { - // if handleSwap returns an array (like) of elements, we handle them - for (var j = 0; j < newElements.length; j++) { - var child = newElements[j]; - if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { - settleInfo.tasks.push(makeAjaxLoadTask(child)); - } - } - } - return; - } - } catch (e) { - logError(e); - } - } - if (swapStyle === "innerHTML") { - swapInnerHTML(target, fragment, settleInfo); - } else { - swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo); - } - } - } - - function findTitle(content) { - if (content.indexOf('<title') > -1) { - var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, ''); - var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX); - if (result) { - return result[2]; - } - } - } - - function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) { - settleInfo.title = findTitle(responseText); - var fragment = makeFragment(responseText); - if (fragment) { - handleOutOfBandSwaps(elt, fragment, settleInfo); - fragment = maybeSelectFromResponse(elt, fragment, selectOverride); - handlePreservedElements(fragment); - return swap(swapStyle, elt, target, fragment, settleInfo); - } - } - - function handleTrigger(xhr, header, elt) { - var triggerBody = xhr.getResponseHeader(header); - if (triggerBody.indexOf("{") === 0) { - var triggers = parseJSON(triggerBody); - for (var eventName in triggers) { - if (triggers.hasOwnProperty(eventName)) { - var detail = triggers[eventName]; - if (!isRawObject(detail)) { - detail = {"value": detail} - } - triggerEvent(elt, eventName, detail); - } - } - } else { - var eventNames = triggerBody.split(",") - for (var i = 0; i < eventNames.length; i++) { - triggerEvent(elt, eventNames[i].trim(), []); - } - } - } - - var WHITESPACE = /\s/; - var WHITESPACE_OR_COMMA = /[\s,]/; - var SYMBOL_START = /[_$a-zA-Z]/; - var SYMBOL_CONT = /[_$a-zA-Z0-9]/; - var STRINGISH_START = ['"', "'", "/"]; - var NOT_WHITESPACE = /[^\s]/; - var COMBINED_SELECTOR_START = /[{(]/; - var COMBINED_SELECTOR_END = /[})]/; - function tokenizeString(str) { - var tokens = []; - var position = 0; - while (position < str.length) { - if(SYMBOL_START.exec(str.charAt(position))) { - var startPosition = position; - while (SYMBOL_CONT.exec(str.charAt(position + 1))) { - position++; - } - tokens.push(str.substr(startPosition, position - startPosition + 1)); - } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) { - var startChar = str.charAt(position); - var startPosition = position; - position++; - while (position < str.length && str.charAt(position) !== startChar ) { - if (str.charAt(position) === "\\") { - position++; - } - position++; - } - tokens.push(str.substr(startPosition, position - startPosition + 1)); - } else { - var symbol = str.charAt(position); - tokens.push(symbol); - } - position++; - } - return tokens; - } - - function isPossibleRelativeReference(token, last, paramName) { - return SYMBOL_START.exec(token.charAt(0)) && - token !== "true" && - token !== "false" && - token !== "this" && - token !== paramName && - last !== "."; - } - - function maybeGenerateConditional(elt, tokens, paramName) { - if (tokens[0] === '[') { - tokens.shift(); - var bracketCount = 1; - var conditionalSource = " return (function(" + paramName + "){ return ("; - var last = null; - while (tokens.length > 0) { - var token = tokens[0]; - if (token === "]") { - bracketCount--; - if (bracketCount === 0) { - if (last === null) { - conditionalSource = conditionalSource + "true"; - } - tokens.shift(); - conditionalSource += ")})"; - try { - var conditionFunction = maybeEval(elt,function () { - return Function(conditionalSource)(); - }, - function(){return true}) - conditionFunction.source = conditionalSource; - return conditionFunction; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:syntax:error", {error:e, source:conditionalSource}) - return null; - } - } - } else if (token === "[") { - bracketCount++; - } - if (isPossibleRelativeReference(token, last, paramName)) { - conditionalSource += "((" + paramName + "." + token + ") ? (" + paramName + "." + token + ") : (window." + token + "))"; - } else { - conditionalSource = conditionalSource + token; - } - last = tokens.shift(); - } - } - } - - function consumeUntil(tokens, match) { - var result = ""; - while (tokens.length > 0 && !match.test(tokens[0])) { - result += tokens.shift(); - } - return result; - } - - function consumeCSSSelector(tokens) { - var result; - if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { - tokens.shift(); - result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim(); - tokens.shift(); - } else { - result = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } - return result; - } - - var INPUT_SELECTOR = 'input, textarea, select'; - - /** - * @param {HTMLElement} elt - * @param {string} explicitTrigger - * @param {cache} cache for trigger specs - * @returns {import("./htmx").HtmxTriggerSpecification[]} - */ - function parseAndCacheTrigger(elt, explicitTrigger, cache) { - var triggerSpecs = []; - var tokens = tokenizeString(explicitTrigger); - do { - consumeUntil(tokens, NOT_WHITESPACE); - var initialLength = tokens.length; - var trigger = consumeUntil(tokens, /[,\[\s]/); - if (trigger !== "") { - if (trigger === "every") { - var every = {trigger: 'every'}; - consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); - consumeUntil(tokens, NOT_WHITESPACE); - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - every.eventFilter = eventFilter; - } - triggerSpecs.push(every); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); - } else { - var triggerSpec = {trigger: trigger}; - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - triggerSpec.eventFilter = eventFilter; - } - while (tokens.length > 0 && tokens[0] !== ",") { - consumeUntil(tokens, NOT_WHITESPACE) - var token = tokens.shift(); - if (token === "changed") { - triggerSpec.changed = true; - } else if (token === "once") { - triggerSpec.once = true; - } else if (token === "consume") { - triggerSpec.consume = true; - } else if (token === "delay" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "from" && tokens[0] === ":") { - tokens.shift(); - if (COMBINED_SELECTOR_START.test(tokens[0])) { - var from_arg = consumeCSSSelector(tokens); - } else { - var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); - if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") { - tokens.shift(); - var selector = consumeCSSSelector(tokens); - // `next` and `previous` allow a selector-less syntax - if (selector.length > 0) { - from_arg += " " + selector; - } - } - } - triggerSpec.from = from_arg; - } else if (token === "target" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.target = consumeCSSSelector(tokens); - } else if (token === "throttle" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "queue" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if (token === "root" && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeCSSSelector(tokens); - } else if (token === "threshold" && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - } - triggerSpecs.push(triggerSpec); - } - } - if (tokens.length === initialLength) { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - consumeUntil(tokens, NOT_WHITESPACE); - } while (tokens[0] === "," && tokens.shift()) - if (cache) { - cache[explicitTrigger] = triggerSpecs - } - return triggerSpecs - } - - /** - * @param {HTMLElement} elt - * @returns {import("./htmx").HtmxTriggerSpecification[]} - */ - function getTriggerSpecs(elt) { - var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); - var triggerSpecs = []; - if (explicitTrigger) { - var cache = htmx.config.triggerSpecsCache - triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) - } - - if (triggerSpecs.length > 0) { - return triggerSpecs; - } else if (matches(elt, 'form')) { - return [{trigger: 'submit'}]; - } else if (matches(elt, 'input[type="button"], input[type="submit"]')){ - return [{trigger: 'click'}]; - } else if (matches(elt, INPUT_SELECTOR)) { - return [{trigger: 'change'}]; - } else { - return [{trigger: 'click'}]; - } - } - - function cancelPolling(elt) { - getInternalData(elt).cancelled = true; - } - - function processPolling(elt, handler, spec) { - var nodeData = getInternalData(elt); - nodeData.timeout = setTimeout(function () { - if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { - triggerSpec: spec, - target: elt - }))) { - handler(elt); - } - processPolling(elt, handler, spec); - } - }, spec.pollInterval); - } - - function isLocalLink(elt) { - return location.hostname === elt.hostname && - getRawAttribute(elt,'href') && - getRawAttribute(elt,'href').indexOf("#") !== 0; - } - - function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || 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"; - if (verb === "get") { - } - path = getRawAttribute(elt, 'action'); - } - triggerSpecs.forEach(function(triggerSpec) { - addEventListener(elt, function(elt, evt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return - } - issueAjaxRequest(verb, path, elt, evt) - }, nodeData, triggerSpec, true); - }); - } - } - - /** - * - * @param {Event} evt - * @param {HTMLElement} elt - * @returns - */ - function shouldCancel(evt, elt) { - if (evt.type === "submit" || evt.type === "click") { - if (elt.tagName === "FORM") { - return true; - } - if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { - return true; - } - if (elt.tagName === "A" && elt.href && - (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) { - return true; - } - } - return false; - } - - function ignoreBoostedAnchorCtrlClick(elt, evt) { - return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); - } - - function maybeFilterEvent(triggerSpec, elt, evt) { - var eventFilter = triggerSpec.eventFilter; - if(eventFilter){ - try { - return eventFilter.call(elt, evt) !== true; - } catch(e) { - triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); - return true; - } - } - return false; - } - - function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { - var elementData = getInternalData(elt); - var eltsToListenOn; - if (triggerSpec.from) { - eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); - } else { - eltsToListenOn = [elt]; - } - // store the initial values of the elements, so we can tell if they change - if (triggerSpec.changed) { - eltsToListenOn.forEach(function (eltToListenOn) { - var eltToListenOnData = getInternalData(eltToListenOn); - eltToListenOnData.lastValue = eltToListenOn.value; - }) - } - forEach(eltsToListenOn, function (eltToListenOn) { - var eventListener = function (evt) { - if (!bodyContains(elt)) { - eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); - return; - } - if (ignoreBoostedAnchorCtrlClick(elt, evt)) { - return; - } - if (explicitCancel || shouldCancel(evt, elt)) { - evt.preventDefault(); - } - if (maybeFilterEvent(triggerSpec, elt, evt)) { - return; - } - var eventData = getInternalData(evt); - eventData.triggerSpec = triggerSpec; - if (eventData.handledFor == null) { - eventData.handledFor = []; - } - if (eventData.handledFor.indexOf(elt) < 0) { - eventData.handledFor.push(elt); - if (triggerSpec.consume) { - evt.stopPropagation(); - } - if (triggerSpec.target && evt.target) { - if (!matches(evt.target, triggerSpec.target)) { - return; - } - } - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } - } - if (triggerSpec.changed) { - var eltToListenOnData = getInternalData(eltToListenOn) - if (eltToListenOnData.lastValue === eltToListenOn.value) { - return; - } - eltToListenOnData.lastValue = eltToListenOn.value - } - if (elementData.delayed) { - clearTimeout(elementData.delayed); - } - if (elementData.throttle) { - return; - } - - if (triggerSpec.throttle > 0) { - if (!elementData.throttle) { - handler(elt, evt); - elementData.throttle = setTimeout(function () { - elementData.throttle = null; - }, triggerSpec.throttle); - } - } else if (triggerSpec.delay > 0) { - elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); - } else { - triggerEvent(elt, 'htmx:trigger') - handler(elt, evt); - } - } - }; - if (nodeData.listenerInfos == null) { - nodeData.listenerInfos = []; - } - nodeData.listenerInfos.push({ - trigger: triggerSpec.trigger, - listener: eventListener, - on: eltToListenOn - }) - eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); - }); - } - - var windowIsScrolling = false // used by initScrollHandler - var scrollHandler = null; - function initScrollHandler() { - if (!scrollHandler) { - scrollHandler = function() { - windowIsScrolling = true - }; - window.addEventListener("scroll", scrollHandler) - setInterval(function() { - if (windowIsScrolling) { - windowIsScrolling = false; - forEach(getDocument().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"), function (elt) { - maybeReveal(elt); - }) - } - }, 200); - } - } - - function maybeReveal(elt) { - if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { - elt.setAttribute('data-hx-revealed', 'true'); - var nodeData = getInternalData(elt); - if (nodeData.initHash) { - triggerEvent(elt, 'revealed'); - } else { - // if the node isn't initialized, wait for it before triggering the request - elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true}); - } - } - } - - //==================================================================== - // Web Sockets - //==================================================================== - - function processWebSocketInfo(elt, nodeData, info) { - var values = splitOnWhitespace(info); - for (var i = 0; i < values.length; i++) { - var value = values[i].split(/:(.+)/); - if (value[0] === "connect") { - ensureWebSocket(elt, value[1], 0); - } - if (value[0] === "send") { - processWebSocketSend(elt); - } - } - } - - function ensureWebSocket(elt, wssSource, retryCount) { - if (!bodyContains(elt)) { - return; // stop ensuring websocket connection when socket bearing element ceases to exist - } - - if (wssSource.indexOf("/") == 0) { // complete absolute paths only - var base_part = location.hostname + (location.port ? ':'+location.port: ''); - if (location.protocol == 'https:') { - wssSource = "wss://" + base_part + wssSource; - } else if (location.protocol == 'http:') { - wssSource = "ws://" + base_part + wssSource; - } - } - var socket = htmx.createWebSocket(wssSource); - socket.onerror = function (e) { - triggerErrorEvent(elt, "htmx:wsError", {error:e, socket:socket}); - maybeCloseWebSocketSource(elt); - }; - - socket.onclose = function (e) { - if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later - var delay = getWebSocketReconnectDelay(retryCount); - setTimeout(function() { - ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout - }, delay); - } - }; - socket.onopen = function (e) { - retryCount = 0; - } - - getInternalData(elt).webSocket = socket; - socket.addEventListener('message', function (event) { - if (maybeCloseWebSocketSource(elt)) { - return; - } - - var response = event.data; - withExtensions(elt, function(extension){ - response = extension.transformResponse(response, null, elt); - }); - - var settleInfo = makeSettleInfo(elt); - var fragment = makeFragment(response); - var children = toArray(fragment.children); - for (var i = 0; i < children.length; i++) { - var child = children[i]; - oobSwap(getAttributeValue(child, "hx-swap-oob") || "true", child, settleInfo); - } - - settleImmediately(settleInfo.tasks); - }); - } - - function maybeCloseWebSocketSource(elt) { - if (!bodyContains(elt)) { - getInternalData(elt).webSocket.close(); - return true; - } - } - - function processWebSocketSend(elt) { - var webSocketSourceElt = getClosestMatch(elt, function (parent) { - return getInternalData(parent).webSocket != null; - }); - if (webSocketSourceElt) { - elt.addEventListener(getTriggerSpecs(elt)[0].trigger, function (evt) { - var webSocket = getInternalData(webSocketSourceElt).webSocket; - var headers = getHeaders(elt, webSocketSourceElt); - var results = getInputValues(elt, 'post'); - var errors = results.errors; - var rawParameters = results.values; - var expressionVars = getExpressionVars(elt); - var allParameters = mergeObjects(rawParameters, expressionVars); - var filteredParameters = filterValues(allParameters, elt); - filteredParameters['HEADERS'] = headers; - if (errors && errors.length > 0) { - triggerEvent(elt, 'htmx:validation:halted', errors); - return; - } - webSocket.send(JSON.stringify(filteredParameters)); - if(shouldCancel(evt, elt)){ - evt.preventDefault(); - } - }); - } else { - triggerErrorEvent(elt, "htmx:noWebSocketSourceError"); - } - } - - function getWebSocketReconnectDelay(retryCount) { - var delay = htmx.config.wsReconnectDelay; - if (typeof delay === 'function') { - // @ts-ignore - return delay(retryCount); - } - if (delay === 'full-jitter') { - var exp = Math.min(retryCount, 6); - var maxDelay = 1000 * Math.pow(2, exp); - return maxDelay * Math.random(); - } - logError('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"'); - } - - //==================================================================== - // Server Sent Events - //==================================================================== - - function processSSEInfo(elt, nodeData, info) { - var values = splitOnWhitespace(info); - for (var i = 0; i < values.length; i++) { - var value = values[i].split(/:(.+)/); - if (value[0] === "connect") { - processSSESource(elt, value[1]); - } - - if ((value[0] === "swap")) { - processSSESwap(elt, value[1]) - } - } - } - - function processSSESource(elt, sseSrc) { - var source = htmx.createEventSource(sseSrc); - source.onerror = function (e) { - triggerErrorEvent(elt, "htmx:sseError", {error:e, source:source}); - maybeCloseSSESource(elt); - }; - getInternalData(elt).sseEventSource = source; - } - - function processSSESwap(elt, sseEventName) { - var sseSourceElt = getClosestMatch(elt, hasEventSource); - if (sseSourceElt) { - var sseEventSource = getInternalData(sseSourceElt).sseEventSource; - var sseListener = function (event) { - if (maybeCloseSSESource(sseSourceElt)) { - return; - } - if (!bodyContains(elt)) { - sseEventSource.removeEventListener(sseEventName, sseListener); - return; - } - - /////////////////////////// - // TODO: merge this code with AJAX and WebSockets code in the future. - - var response = event.data; - withExtensions(elt, function(extension){ - response = extension.transformResponse(response, null, elt); - }); - - var swapSpec = getSwapSpecification(elt) - var target = getTarget(elt) - var settleInfo = makeSettleInfo(elt); - - selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) - settleImmediately(settleInfo.tasks) - triggerEvent(elt, "htmx:sseMessage", event) - }; - - getInternalData(elt).sseListener = sseListener; - sseEventSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "htmx:noSSESourceError"); - } - } - - function processSSETrigger(elt, handler, sseEventName) { - var sseSourceElt = getClosestMatch(elt, hasEventSource); - if (sseSourceElt) { - var sseEventSource = getInternalData(sseSourceElt).sseEventSource; - var sseListener = function () { - if (!maybeCloseSSESource(sseSourceElt)) { - if (bodyContains(elt)) { - handler(elt); - } else { - sseEventSource.removeEventListener(sseEventName, sseListener); - } - } - }; - getInternalData(elt).sseListener = sseListener; - sseEventSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "htmx:noSSESourceError"); - } - } - - function maybeCloseSSESource(elt) { - if (!bodyContains(elt)) { - getInternalData(elt).sseEventSource.close(); - return true; - } - } - - function hasEventSource(node) { - return getInternalData(node).sseEventSource != null; - } - - //==================================================================== - - function loadImmediately(elt, handler, nodeData, delay) { - var load = function(){ - if (!nodeData.loaded) { - nodeData.loaded = true; - handler(elt); - } - } - if (delay > 0) { - setTimeout(load, delay); - } else { - load(); - } - } - - function processVerbs(elt, nodeData, triggerSpecs) { - var explicitAction = false; - forEach(VERBS, function (verb) { - if (hasAttribute(elt,'hx-' + verb)) { - var path = getAttributeValue(elt, 'hx-' + verb); - explicitAction = true; - nodeData.path = path; - nodeData.verb = verb; - triggerSpecs.forEach(function(triggerSpec) { - addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return - } - issueAjaxRequest(verb, path, elt, evt) - }) - }); - } - }); - return explicitAction; - } - - function addTriggerHandler(elt, triggerSpec, nodeData, handler) { - if (triggerSpec.sseEvent) { - processSSETrigger(elt, handler, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - addEventListener(elt, handler, nodeData, triggerSpec); - maybeReveal(elt); - } else if (triggerSpec.trigger === "intersect") { - var observerOptions = {}; - if (triggerSpec.root) { - observerOptions.root = querySelectorExt(elt, triggerSpec.root) - } - if (triggerSpec.threshold) { - observerOptions.threshold = parseFloat(triggerSpec.threshold); - } - var observer = new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - if (entry.isIntersecting) { - triggerEvent(elt, "intersect"); - break; - } - } - }, observerOptions); - observer.observe(elt); - addEventListener(elt, handler, nodeData, triggerSpec); - } else if (triggerSpec.trigger === "load") { - if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { - loadImmediately(elt, handler, nodeData, triggerSpec.delay); - } - } else if (triggerSpec.pollInterval > 0) { - nodeData.polling = true; - processPolling(elt, handler, triggerSpec); - } else { - addEventListener(elt, handler, nodeData, triggerSpec); - } - } - - function evalScript(script) { - if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) { - var newScript = getDocument().createElement("script"); - forEach(script.attributes, function (attr) { - newScript.setAttribute(attr.name, attr.value); - }); - newScript.textContent = script.textContent; - newScript.async = false; - if (htmx.config.inlineScriptNonce) { - newScript.nonce = htmx.config.inlineScriptNonce; - } - var parent = script.parentElement; - - try { - parent.insertBefore(newScript, script); - } catch (e) { - logError(e); - } finally { - // remove old script element, but only if it is still in DOM - if (script.parentElement) { - script.parentElement.removeChild(script); - } - } - } - } - - function processScripts(elt) { - if (matches(elt, "script")) { - evalScript(elt); - } - forEach(findAll(elt, "script"), function (script) { - evalScript(script); - }); - } - - function shouldProcessHxOn(elt) { - var attributes = elt.attributes - for (var j = 0; j < attributes.length; j++) { - var attrName = attributes[j].name - if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") || - startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) { - return true - } - } - return false - } - - function findHxOnWildcardElements(elt) { - var node = null - var elements = [] - - if (shouldProcessHxOn(elt)) { - elements.push(elt) - } - - if (document.evaluate) { - var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + - ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt) - while (node = iter.iterateNext()) elements.push(node) - } else { - var allElements = elt.getElementsByTagName("*") - for (var i = 0; i < allElements.length; i++) { - if (shouldProcessHxOn(allElements[i])) { - elements.push(allElements[i]) - } - } - } - - return elements - } - - function findElementsToProcess(elt) { - if (elt.querySelectorAll) { - var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; - var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]"); - return results; - } else { - return []; - } - } - - // Handle submit buttons/inputs that have the form attribute set - // see https://developer.mozilla.org/docs/Web/HTML/Element/button - function maybeSetLastButtonClicked(evt) { - var elt = closest(evt.target, "button, input[type='submit']"); - var internalData = getRelatedFormData(evt) - if (internalData) { - internalData.lastButtonClicked = elt; - } - }; - function maybeUnsetLastButtonClicked(evt){ - var internalData = getRelatedFormData(evt) - if (internalData) { - internalData.lastButtonClicked = null; - } - } - function getRelatedFormData(evt) { - var elt = closest(evt.target, "button, input[type='submit']"); - if (!elt) { - return; - } - var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form'); - if (!form) { - return; - } - return getInternalData(form); - } - function initButtonTracking(elt) { - // need to handle both click and focus in: - // focusin - in case someone tabs in to a button and hits the space bar - // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 - elt.addEventListener('click', maybeSetLastButtonClicked) - elt.addEventListener('focusin', maybeSetLastButtonClicked) - elt.addEventListener('focusout', maybeUnsetLastButtonClicked) - } - - function countCurlies(line) { - var tokens = tokenizeString(line); - var netCurlies = 0; - for (var i = 0; i < tokens.length; i++) { - const token = tokens[i]; - if (token === "{") { - netCurlies++; - } else if (token === "}") { - netCurlies--; - } - } - return netCurlies; - } - - function addHxOnEventHandler(elt, eventName, code) { - var nodeData = getInternalData(elt); - if (!Array.isArray(nodeData.onHandlers)) { - nodeData.onHandlers = []; - } - var func; - var listener = function (e) { - return maybeEval(elt, function() { - if (!func) { - func = new Function("event", code); - } - func.call(elt, e); - }); - }; - elt.addEventListener(eventName, listener); - nodeData.onHandlers.push({event:eventName, listener:listener}); - } - - function processHxOn(elt) { - var hxOnValue = getAttributeValue(elt, 'hx-on'); - if (hxOnValue) { - var handlers = {} - var lines = hxOnValue.split("\n"); - var currentEvent = null; - var curlyCount = 0; - while (lines.length > 0) { - var line = lines.shift(); - var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/); - if (curlyCount === 0 && match) { - line.split(":") - currentEvent = match[1].slice(0, -1); // strip last colon - handlers[currentEvent] = match[2]; - } else { - handlers[currentEvent] += line; - } - curlyCount += countCurlies(line); - } - - for (var eventName in handlers) { - addHxOnEventHandler(elt, eventName, handlers[eventName]); - } - } - } - - function processHxOnWildcard(elt) { - // wipe any previous on handlers so that this function takes precedence - deInitOnHandlers(elt) - - for (var i = 0; i < elt.attributes.length; i++) { - var name = elt.attributes[i].name - var value = elt.attributes[i].value - if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) { - var afterOnPosition = name.indexOf("-on") + 3; - var nextChar = name.slice(afterOnPosition, afterOnPosition + 1); - if (nextChar === "-" || nextChar === ":") { - var eventName = name.slice(afterOnPosition + 1); - // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support - if (startsWith(eventName, ":")) { - eventName = "htmx" + eventName - } else if (startsWith(eventName, "-")) { - eventName = "htmx:" + eventName.slice(1); - } else if (startsWith(eventName, "htmx-")) { - eventName = "htmx:" + eventName.slice(5); - } - - addHxOnEventHandler(elt, eventName, value) - } - } - } - } - - function initNode(elt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return; - } - var nodeData = getInternalData(elt); - if (nodeData.initHash !== attributeHash(elt)) { - // clean up any previously processed info - deInitNode(elt); - - nodeData.initHash = attributeHash(elt); - - processHxOn(elt); - - triggerEvent(elt, "htmx:beforeProcessNode") - - if (elt.value) { - nodeData.lastValue = elt.value; - } - - var triggerSpecs = getTriggerSpecs(elt); - var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs); - - if (!hasExplicitHttpAction) { - if (getClosestAttributeValue(elt, "hx-boost") === "true") { - boostElement(elt, nodeData, triggerSpecs); - } else if (hasAttribute(elt, 'hx-trigger')) { - triggerSpecs.forEach(function (triggerSpec) { - // For "naked" triggers, don't do anything at all - addTriggerHandler(elt, triggerSpec, nodeData, function () { - }) - }) - } - } - - // Handle submit buttons/inputs that have the form attribute set - // see https://developer.mozilla.org/docs/Web/HTML/Element/button - if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) { - initButtonTracking(elt) - } - - var sseInfo = getAttributeValue(elt, 'hx-sse'); - if (sseInfo) { - processSSEInfo(elt, nodeData, sseInfo); - } - - var wsInfo = getAttributeValue(elt, 'hx-ws'); - if (wsInfo) { - processWebSocketInfo(elt, nodeData, wsInfo); - } - triggerEvent(elt, "htmx:afterProcessNode"); - } - } - - function processNode(elt) { - elt = resolveTarget(elt); - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return; - } - initNode(elt); - forEach(findElementsToProcess(elt), function(child) { initNode(child) }); - // Because it happens second, the new way of adding onHandlers superseeds the old one - // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored - forEach(findHxOnWildcardElements(elt), processHxOnWildcard); - } - - //==================================================================== - // Event/Log Support - //==================================================================== - - function kebabEventName(str) { - return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase(); - } - - 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({error:eventName}, detail)); - } - - function ignoreEventForLogging(eventName) { - return eventName === "htmx:afterProcessNode" - } - - /** - * `withExtensions` locates all active extensions for a provided element, then - * executes the provided function using each of the active extensions. It should - * be called internally at every extendable execution point in htmx. - * - * @param {HTMLElement} elt - * @param {(extension:import("./htmx").HtmxExtension) => void} toDo - * @returns void - */ - function withExtensions(elt, toDo) { - forEach(getExtensions(elt), function(extension){ - try { - toDo(extension); - } catch (e) { - logError(e); - } - }); - } - - function logError(msg) { - if(console.error) { - console.error(msg); - } else if (console.log) { - console.log("ERROR: ", msg); - } - } - - function triggerEvent(elt, eventName, detail) { - elt = resolveTarget(elt); - if (detail == null) { - detail = {}; - } - detail["elt"] = elt; - var event = makeEvent(eventName, detail); - if (htmx.logger && !ignoreEventForLogging(eventName)) { - htmx.logger(elt, eventName, detail); - } - if (detail.error) { - logError(detail.error); - triggerEvent(elt, "htmx:error", {errorInfo:detail}) - } - var eventResult = elt.dispatchEvent(event); - var kebabName = kebabEventName(eventName); - if (eventResult && kebabName !== eventName) { - var kebabedEvent = makeEvent(kebabName, event.detail); - eventResult = eventResult && elt.dispatchEvent(kebabedEvent) - } - withExtensions(elt, function (extension) { - eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) - }); - return eventResult; - } - - //==================================================================== - // History Support - //==================================================================== - var currentPathForHistory = location.pathname+location.search; - - function getHistoryElement() { - var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]'); - return historyElt || getDocument().body; - } - - function saveToHistoryCache(url, content, title, scroll) { - if (!canAccessLocalStorage()) { - return; - } - - if (htmx.config.historyCacheSize <= 0) { - // make sure that an eventually already existing cache is purged - localStorage.removeItem("htmx-history-cache"); - return; - } - - url = normalizePath(url); - - var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - historyCache.splice(i, 1); - break; - } - } - var newHistoryItem = {url:url, content: content, title:title, scroll:scroll}; - triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache}) - historyCache.push(newHistoryItem) - while (historyCache.length > htmx.config.historyCacheSize) { - historyCache.shift(); - } - while(historyCache.length > 0){ - try { - localStorage.setItem("htmx-history-cache", JSON.stringify(historyCache)); - break; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:historyCacheError", {cause:e, cache: historyCache}) - historyCache.shift(); // shrink the cache and retry - } - } - } - - function getCachedHistory(url) { - if (!canAccessLocalStorage()) { - return null; - } - - url = normalizePath(url); - - var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - return historyCache[i]; - } - } - return null; - } - - function cleanInnerHtmlForHistory(elt) { - var className = htmx.config.requestClass; - var clone = elt.cloneNode(true); - forEach(findAll(clone, "." + className), function(child){ - removeClassFromElement(child, className); - }); - return clone.innerHTML; - } - - function saveCurrentPageToHistory() { - var elt = getHistoryElement(); - var path = currentPathForHistory || location.pathname+location.search; - - // Allow history snapshot feature to be disabled where hx-history="false" - // is present *anywhere* in the current document we're about to save, - // so we can prevent privileged data entering the cache. - // The page will still be reachable as a history entry, but htmx will fetch it - // live from the server onpopstate rather than look in the localStorage cache - var disableHistoryCache - try { - disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') - } catch (e) { - // IE11: insensitive modifier not supported so fallback to case sensitive selector - disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') - } - if (!disableHistoryCache) { - triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt}); - saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); - } - - if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href); - } - - function pushUrlIntoHistory(path) { - // remove the cache buster parameter, if any - if (htmx.config.getCacheBusterParam) { - path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') - if (endsWith(path, '&') || endsWith(path, "?")) { - path = path.slice(0, -1); - } - } - if(htmx.config.historyEnabled) { - history.pushState({htmx:true}, "", path); - } - currentPathForHistory = path; - } - - function replaceUrlInHistory(path) { - if(htmx.config.historyEnabled) history.replaceState({htmx:true}, "", path); - currentPathForHistory = path; - } - - function settleImmediately(tasks) { - forEach(tasks, function (task) { - task.call(); - }); - } - - function loadHistoryFromServer(path) { - var request = new XMLHttpRequest(); - var details = {path: path, xhr:request}; - triggerEvent(getDocument().body, "htmx:historyCacheMiss", details); - request.open('GET', path, true); - request.setRequestHeader("HX-Request", "true"); - request.setRequestHeader("HX-History-Restore-Request", "true"); - request.setRequestHeader("HX-Current-URL", getDocument().location.href); - request.onload = function () { - if (this.status >= 200 && this.status < 400) { - triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); - var fragment = makeFragment(this.response); - // @ts-ignore - fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; - var historyElement = getHistoryElement(); - var settleInfo = makeSettleInfo(historyElement); - var title = findTitle(this.response); - if (title) { - var titleElt = find("title"); - if (titleElt) { - titleElt.innerHTML = title; - } else { - window.document.title = title; - } - } - // @ts-ignore - swapInnerHTML(historyElement, fragment, settleInfo) - settleImmediately(settleInfo.tasks); - currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response}); - } else { - triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details); - } - }; - request.send(); - } - - function restoreHistory(path) { - saveCurrentPageToHistory(); - path = path || location.pathname+location.search; - var cached = getCachedHistory(path); - if (cached) { - var fragment = makeFragment(cached.content); - var historyElement = getHistoryElement(); - var settleInfo = makeSettleInfo(historyElement); - swapInnerHTML(historyElement, fragment, settleInfo) - settleImmediately(settleInfo.tasks); - document.title = cached.title; - setTimeout(function () { - window.scrollTo(0, cached.scroll); - }, 0); // next 'tick', so browser has time to render layout - currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); - } else { - if (htmx.config.refreshOnHistoryMiss) { - - // @ts-ignore: optional parameter in reload() function throws error - window.location.reload(true); - } else { - loadHistoryFromServer(path); - } - } - } - - function addRequestIndicatorClasses(elt) { - var indicators = findAttributeTargets(elt, 'hx-indicator'); - if (indicators == null) { - indicators = [elt]; - } - forEach(indicators, function (ic) { - var internalData = getInternalData(ic); - internalData.requestCount = (internalData.requestCount || 0) + 1; - ic.classList["add"].call(ic.classList, htmx.config.requestClass); - }); - return indicators; - } - - function disableElements(elt) { - var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt'); - if (disabledElts == null) { - disabledElts = []; - } - forEach(disabledElts, function (disabledElement) { - var internalData = getInternalData(disabledElement); - internalData.requestCount = (internalData.requestCount || 0) + 1; - disabledElement.setAttribute("disabled", ""); - }); - return disabledElts; - } - - function removeRequestIndicators(indicators, disabled) { - forEach(indicators, function (ic) { - var internalData = getInternalData(ic); - internalData.requestCount = (internalData.requestCount || 0) - 1; - if (internalData.requestCount === 0) { - ic.classList["remove"].call(ic.classList, htmx.config.requestClass); - } - }); - forEach(disabled, function (disabledElement) { - var internalData = getInternalData(disabledElement); - internalData.requestCount = (internalData.requestCount || 0) - 1; - if (internalData.requestCount === 0) { - disabledElement.removeAttribute('disabled'); - } - }); - } - - //==================================================================== - // 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 || closest(elt, "fieldset[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 addValueToValues(name, value, values) { - // This is a little ugly because both the current value of the named value in the form - // and the new value could be arrays, so we have to handle all four cases :/ - if (name != null && value != null) { - var current = values[name]; - if (current === undefined) { - values[name] = value; - } else if (Array.isArray(current)) { - if (Array.isArray(value)) { - values[name] = current.concat(value); - } else { - current.push(value); - } - } else { - if (Array.isArray(value)) { - values[name] = [current].concat(value); - } else { - values[name] = [current, value]; - } - } - } - } - - function processInputValue(processed, values, errors, elt, validate) { - if (elt == null || haveSeenNode(processed, elt)) { - return; - } else { - processed.push(elt); - } - if (shouldInclude(elt)) { - var name = getRawAttribute(elt,"name"); - var value = elt.value; - if (elt.multiple && elt.tagName === "SELECT") { - value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value }); - } - // include file inputs - if (elt.files) { - value = toArray(elt.files); - } - addValueToValues(name, value, values); - if (validate) { - validateElement(elt, errors); - } - } - if (matches(elt, 'form')) { - var inputs = elt.elements; - forEach(inputs, function(input) { - processInputValue(processed, values, errors, input, validate); - }); - } - } - - function validateElement(element, errors) { - if (element.willValidate) { - triggerEvent(element, "htmx:validation:validate") - if (!element.checkValidity()) { - errors.push({elt: element, message:element.validationMessage, validity:element.validity}); - triggerEvent(element, "htmx:validation:failed", {message:element.validationMessage, validity:element.validity}) - } - } - } - - /** - * @param {HTMLElement} elt - * @param {string} verb - */ - function getInputValues(elt, verb) { - var processed = []; - var values = {}; - var formValues = {}; - var errors = []; - var internalData = getInternalData(elt); - if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { - internalData.lastButtonClicked = null - } - - // only validate when form is directly submitted and novalidate or formnovalidate are not set - // or if the element has an explicit hx-validate="true" on it - var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true"; - if (internalData.lastButtonClicked) { - validate = validate && internalData.lastButtonClicked.formNoValidate !== true; - } - - // for a non-GET include the closest form - if (verb !== 'get') { - processInputValue(processed, formValues, errors, closest(elt, 'form'), validate); - } - - // include the element itself - processInputValue(processed, values, errors, elt, validate); - - // if a button or submit was clicked last, include its value - if (internalData.lastButtonClicked || elt.tagName === "BUTTON" || - (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) { - var button = internalData.lastButtonClicked || elt - var name = getRawAttribute(button, "name") - addValueToValues(name, button.value, formValues) - } - - // include any explicit includes - var includes = findAttributeTargets(elt, "hx-include"); - forEach(includes, function(node) { - processInputValue(processed, values, errors, node, validate); - // if a non-form is included, include any input values within it - if (!matches(node, 'form')) { - forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { - processInputValue(processed, values, errors, descendant, validate); - }) - } - }); - - // form values take precedence, overriding the regular values - values = mergeObjects(values, formValues); - - return {errors:errors, values:values}; - } - - function appendParam(returnStr, name, realValue) { - if (returnStr !== "") { - returnStr += "&"; - } - if (String(realValue) === "[object Object]") { - realValue = JSON.stringify(realValue); - } - var s = encodeURIComponent(realValue); - returnStr += encodeURIComponent(name) + "=" + s; - 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; - } - - function makeFormData(values) { - var formData = new FormData(); - for (var name in values) { - if (values.hasOwnProperty(name)) { - var value = values[name]; - if (Array.isArray(value)) { - forEach(value, function(v) { - formData.append(name, v); - }); - } else { - formData.append(name, value); - } - } - } - return formData; - } - - //==================================================================== - // Ajax - //==================================================================== - - /** - * @param {HTMLElement} elt - * @param {HTMLElement} target - * @param {string} prompt - * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification - */ - function getHeaders(elt, target, prompt) { - var headers = { - "HX-Request" : "true", - "HX-Trigger" : getRawAttribute(elt, "id"), - "HX-Trigger-Name" : getRawAttribute(elt, "name"), - "HX-Target" : getAttributeValue(target, "id"), - "HX-Current-URL" : getDocument().location.href, - } - getValuesForElement(elt, "hx-headers", false, headers) - if (prompt !== undefined) { - headers["HX-Prompt"] = prompt; - } - if (getInternalData(elt).boosted) { - headers["HX-Boosted"] = "true"; - } - return headers; - } - - /** - * filterValues takes an object containing form input values - * and returns a new object that only contains keys that are - * specified by the closest "hx-params" attribute - * @param {Object} inputValues - * @param {HTMLElement} elt - * @returns {Object} - */ - function filterValues(inputValues, elt) { - var paramsValue = getClosestAttributeValue(elt, "hx-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 isAnchorLink(elt) { - return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0 - } - - /** - * - * @param {HTMLElement} elt - * @param {string} swapInfoOverride - * @returns {import("./htmx").HtmxSwapSpecification} - */ - function getSwapSpecification(elt, swapInfoOverride) { - var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap"); - var swapSpec = { - "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, - "swapDelay" : htmx.config.defaultSwapDelay, - "settleDelay" : htmx.config.defaultSettleDelay - } - if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { - swapSpec["show"] = "top" - } - if (swapInfo) { - var split = splitOnWhitespace(swapInfo); - if (split.length > 0) { - for (var i = 0; i < split.length; i++) { - var value = split[i]; - if (value.indexOf("swap:") === 0) { - swapSpec["swapDelay"] = parseInterval(value.substr(5)); - } else if (value.indexOf("settle:") === 0) { - swapSpec["settleDelay"] = parseInterval(value.substr(7)); - } else if (value.indexOf("transition:") === 0) { - swapSpec["transition"] = value.substr(11) === "true"; - } else if (value.indexOf("ignoreTitle:") === 0) { - swapSpec["ignoreTitle"] = value.substr(12) === "true"; - } else if (value.indexOf("scroll:") === 0) { - var scrollSpec = value.substr(7); - var splitSpec = scrollSpec.split(":"); - var scrollVal = splitSpec.pop(); - var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; - swapSpec["scroll"] = scrollVal; - swapSpec["scrollTarget"] = selectorVal; - } else if (value.indexOf("show:") === 0) { - var showSpec = value.substr(5); - var splitSpec = showSpec.split(":"); - var showVal = splitSpec.pop(); - var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; - swapSpec["show"] = showVal; - swapSpec["showTarget"] = selectorVal; - } else if (value.indexOf("focus-scroll:") === 0) { - var focusScrollVal = value.substr("focus-scroll:".length); - swapSpec["focusScroll"] = focusScrollVal == "true"; - } else if (i == 0) { - swapSpec["swapStyle"] = value; - } else { - logError('Unknown modifier in hx-swap: ' + value); - } - } - } - } - return swapSpec; - } - - function usesFormData(elt) { - return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || - (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data"); - } - - function encodeParamsForBody(xhr, elt, filteredParameters) { - var encodedParameters = null; - withExtensions(elt, function (extension) { - if (encodedParameters == null) { - encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt); - } - }); - if (encodedParameters != null) { - return encodedParameters; - } else { - if (usesFormData(elt)) { - return makeFormData(filteredParameters); - } else { - return urlEncode(filteredParameters); - } - } - } - - /** - * - * @param {Element} target - * @returns {import("./htmx").HtmxSettleInfo} - */ - function makeSettleInfo(target) { - return {tasks: [], elts: [target]}; - } - - function updateScrollState(content, swapSpec) { - var first = content[0]; - var last = content[content.length - 1]; - if (swapSpec.scroll) { - var target = null; - if (swapSpec.scrollTarget) { - target = querySelectorExt(first, swapSpec.scrollTarget); - } - if (swapSpec.scroll === "top" && (first || target)) { - target = target || first; - target.scrollTop = 0; - } - if (swapSpec.scroll === "bottom" && (last || target)) { - target = target || last; - target.scrollTop = target.scrollHeight; - } - } - if (swapSpec.show) { - var target = null; - if (swapSpec.showTarget) { - var targetStr = swapSpec.showTarget; - if (swapSpec.showTarget === "window") { - targetStr = "body"; - } - target = querySelectorExt(first, targetStr); - } - if (swapSpec.show === "top" && (first || target)) { - target = target || first; - target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior}); - } - if (swapSpec.show === "bottom" && (last || target)) { - target = target || last; - target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior}); - } - } - } - - /** - * @param {HTMLElement} elt - * @param {string} attr - * @param {boolean=} evalAsDefault - * @param {Object=} values - * @returns {Object} - */ - function getValuesForElement(elt, attr, evalAsDefault, values) { - if (values == null) { - values = {}; - } - if (elt == null) { - return values; - } - var attributeValue = getAttributeValue(elt, attr); - if (attributeValue) { - var str = attributeValue.trim(); - var evaluateValue = evalAsDefault; - if (str === "unset") { - return null; - } - if (str.indexOf("javascript:") === 0) { - str = str.substr(11); - evaluateValue = true; - } else if (str.indexOf("js:") === 0) { - str = str.substr(3); - evaluateValue = true; - } - if (str.indexOf('{') !== 0) { - str = "{" + str + "}"; - } - var varsValues; - if (evaluateValue) { - varsValues = maybeEval(elt,function () {return Function("return (" + str + ")")();}, {}); - } else { - varsValues = parseJSON(str); - } - for (var key in varsValues) { - if (varsValues.hasOwnProperty(key)) { - if (values[key] == null) { - values[key] = varsValues[key]; - } - } - } - } - return getValuesForElement(parentElt(elt), attr, evalAsDefault, values); - } - - function maybeEval(elt, toEval, defaultVal) { - if (htmx.config.allowEval) { - return toEval(); - } else { - triggerErrorEvent(elt, 'htmx:evalDisallowedError'); - return defaultVal; - } - } - - /** - * @param {HTMLElement} elt - * @param {*} expressionVars - * @returns - */ - function getHXVarsForElement(elt, expressionVars) { - return getValuesForElement(elt, "hx-vars", true, expressionVars); - } - - /** - * @param {HTMLElement} elt - * @param {*} expressionVars - * @returns - */ - function getHXValsForElement(elt, expressionVars) { - return getValuesForElement(elt, "hx-vals", false, expressionVars); - } - - /** - * @param {HTMLElement} elt - * @returns {Object} - */ - function getExpressionVars(elt) { - return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)); - } - - function safelySetHeaderValue(xhr, header, headerValue) { - if (headerValue !== null) { - try { - xhr.setRequestHeader(header, headerValue); - } catch (e) { - // On an exception, try to set the header URI encoded instead - xhr.setRequestHeader(header, encodeURIComponent(headerValue)); - xhr.setRequestHeader(header + "-URI-AutoEncoded", "true"); - } - } - } - - function getPathFromResponse(xhr) { - // NB: IE11 does not support this stuff - if (xhr.responseURL && typeof(URL) !== "undefined") { - try { - var url = new URL(xhr.responseURL); - return url.pathname + url.search; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:badResponseUrl", {url: xhr.responseURL}); - } - } - } - - function hasHeader(xhr, regexp) { - return regexp.test(xhr.getAllResponseHeaders()) - } - - function ajaxHelper(verb, path, context) { - verb = verb.toLowerCase(); - if (context) { - if (context instanceof Element || isType(context, 'String')) { - return issueAjaxRequest(verb, path, null, null, { - targetOverride: resolveTarget(context), - returnPromise: true - }); - } else { - return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, - { - handler : context.handler, - headers : context.headers, - values : context.values, - targetOverride: resolveTarget(context.target), - swapOverride: context.swap, - select: context.select, - returnPromise: true - }); - } - } else { - return issueAjaxRequest(verb, path, null, null, { - returnPromise: true - }); - } - } - - function hierarchyForElt(elt) { - var arr = []; - while (elt) { - arr.push(elt); - elt = elt.parentElement; - } - return arr; - } - - function verifyPath(elt, path, requestConfig) { - var sameHost - var url - if (typeof URL === "function") { - url = new URL(path, document.location.href); - var origin = document.location.origin; - sameHost = origin === url.origin; - } else { - // IE11 doesn't support URL - url = path - sameHost = startsWith(path, document.location.origin) - } - - if (htmx.config.selfRequestsOnly) { - if (!sameHost) { - return false; - } - } - return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig)); - } - - function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { - var resolve = null; - var reject = null; - etc = etc != null ? etc : {}; - if(etc.returnPromise && typeof Promise !== "undefined"){ - var promise = new Promise(function (_resolve, _reject) { - resolve = _resolve; - reject = _reject; - }); - } - if(elt == null) { - elt = getDocument().body; - } - var responseHandler = etc.handler || handleAjaxResponse; - var select = etc.select || null; - - if (!bodyContains(elt)) { - // do not issue requests for elements removed from the DOM - maybeCall(resolve); - return promise; - } - var target = etc.targetOverride || getTarget(elt); - if (target == null || target == DUMMY_ELT) { - triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); - maybeCall(reject); - return promise; - } - - var eltData = getInternalData(elt); - var submitter = eltData.lastButtonClicked; - - if (submitter) { - var buttonPath = getRawAttribute(submitter, "formaction"); - if (buttonPath != null) { - path = buttonPath; - } - - var buttonVerb = getRawAttribute(submitter, "formmethod") - if (buttonVerb != null) { - // ignore buttons with formmethod="dialog" - if (buttonVerb.toLowerCase() !== "dialog") { - verb = buttonVerb; - } - } - } - - var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); - // allow event-based confirmation w/ a callback - if (confirmed === undefined) { - var issueRequest = function(skipConfirmation) { - return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation); - } - var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion}; - if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { - maybeCall(resolve); - return promise; - } - } - - var syncElt = elt; - var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); - var queueStrategy = null; - var abortable = false; - if (syncStrategy) { - var syncStrings = syncStrategy.split(":"); - var selector = syncStrings[0].trim(); - if (selector === "this") { - syncElt = findThisElement(elt, 'hx-sync'); - } else { - syncElt = querySelectorExt(elt, selector); - } - // default to the drop strategy - syncStrategy = (syncStrings[1] || 'drop').trim(); - eltData = getInternalData(syncElt); - if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { - maybeCall(resolve); - return promise; - } else if (syncStrategy === "abort") { - if (eltData.xhr) { - maybeCall(resolve); - return promise; - } else { - abortable = true; - } - } else if (syncStrategy === "replace") { - triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue - } else if (syncStrategy.indexOf("queue") === 0) { - var queueStrArray = syncStrategy.split(" "); - queueStrategy = (queueStrArray[1] || "last").trim(); - } - } - - if (eltData.xhr) { - if (eltData.abortable) { - triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue - } else { - if(queueStrategy == null){ - if (event) { - var eventData = getInternalData(event); - if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { - queueStrategy = eventData.triggerSpec.queue; - } - } - if (queueStrategy == null) { - queueStrategy = "last"; - } - } - if (eltData.queuedRequests == null) { - eltData.queuedRequests = []; - } - if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } else if (queueStrategy === "all") { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } else if (queueStrategy === "last") { - eltData.queuedRequests = []; // dump existing queue - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } - maybeCall(resolve); - return promise; - } - } - - var xhr = new XMLHttpRequest(); - eltData.xhr = xhr; - eltData.abortable = abortable; - var endRequestLock = function(){ - eltData.xhr = null; - eltData.abortable = false; - if (eltData.queuedRequests != null && - eltData.queuedRequests.length > 0) { - var queuedRequest = eltData.queuedRequests.shift(); - queuedRequest(); - } - } - var promptQuestion = getClosestAttributeValue(elt, "hx-prompt"); - if (promptQuestion) { - var promptResponse = prompt(promptQuestion); - // prompt returns null if cancelled and empty string if accepted with no entry - if (promptResponse === null || - !triggerEvent(elt, 'htmx:prompt', {prompt: promptResponse, target:target})) { - maybeCall(resolve); - endRequestLock(); - return promise; - } + triggerErrorEvent(getDocument().body, 'htmx:syntax:error', { error: e, source: conditionalSource }) + return null } + } + } else if (token === '[') { + bracketCount++ + } + if (isPossibleRelativeReference(token, last, paramName)) { + conditionalSource += '((' + paramName + '.' + token + ') ? (' + paramName + '.' + token + ') : (window.' + token + '))' + } else { + conditionalSource = conditionalSource + token + } + last = tokens.shift() + } + } + } + + /** + * @param {string[]} tokens + * @param {RegExp} match + * @returns {string} + */ + function consumeUntil(tokens, match) { + let result = '' + while (tokens.length > 0 && !match.test(tokens[0])) { + result += tokens.shift() + } + return result + } + + /** + * @param {string[]} tokens + * @returns {string} + */ + function consumeCSSSelector(tokens) { + let result + if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { + tokens.shift() + result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim() + tokens.shift() + } else { + result = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } + return result + } + + const INPUT_SELECTOR = 'input, textarea, select' + + /** + * @param {Element} elt + * @param {string} explicitTrigger + * @param {Object} cache for trigger specs + * @returns {HtmxTriggerSpecification[]} + */ + function parseAndCacheTrigger(elt, explicitTrigger, cache) { + /** @type HtmxTriggerSpecification[] */ + const triggerSpecs = [] + const tokens = tokenizeString(explicitTrigger) + do { + consumeUntil(tokens, NOT_WHITESPACE) + const initialLength = tokens.length + const trigger = consumeUntil(tokens, /[,\[\s]/) + if (trigger !== '') { + if (trigger === 'every') { + /** @type HtmxTriggerSpecification */ + const every = { trigger: 'every' } + consumeUntil(tokens, NOT_WHITESPACE) + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)) + consumeUntil(tokens, NOT_WHITESPACE) + var eventFilter = maybeGenerateConditional(elt, tokens, 'event') + if (eventFilter) { + every.eventFilter = eventFilter + } + triggerSpecs.push(every) + } else { + /** @type HtmxTriggerSpecification */ + const triggerSpec = { trigger } + var eventFilter = maybeGenerateConditional(elt, tokens, 'event') + if (eventFilter) { + triggerSpec.eventFilter = eventFilter + } + while (tokens.length > 0 && tokens[0] !== ',') { + consumeUntil(tokens, NOT_WHITESPACE) + const token = tokens.shift() + if (token === 'changed') { + triggerSpec.changed = true + } else if (token === 'once') { + triggerSpec.once = true + } else if (token === 'consume') { + triggerSpec.consume = true + } else if (token === 'delay' && tokens[0] === ':') { + tokens.shift() + triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)) + } else if (token === 'from' && tokens[0] === ':') { + tokens.shift() + if (COMBINED_SELECTOR_START.test(tokens[0])) { + var from_arg = consumeCSSSelector(tokens) + } else { + var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA) + if (from_arg === 'closest' || from_arg === 'find' || from_arg === 'next' || from_arg === 'previous') { + tokens.shift() + const selector = consumeCSSSelector(tokens) + // `next` and `previous` allow a selector-less syntax + if (selector.length > 0) { + from_arg += ' ' + selector + } + } + } + triggerSpec.from = from_arg + } else if (token === 'target' && tokens[0] === ':') { + tokens.shift() + triggerSpec.target = consumeCSSSelector(tokens) + } else if (token === 'throttle' && tokens[0] === ':') { + tokens.shift() + triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)) + } else if (token === 'queue' && tokens[0] === ':') { + tokens.shift() + triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } else if (token === 'root' && tokens[0] === ':') { + tokens.shift() + triggerSpec[token] = consumeCSSSelector(tokens) + } else if (token === 'threshold' && tokens[0] === ':') { + tokens.shift() + triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } else { + triggerErrorEvent(elt, 'htmx:syntax:error', { token: tokens.shift() }) + } + } + triggerSpecs.push(triggerSpec) + } + } + if (tokens.length === initialLength) { + triggerErrorEvent(elt, 'htmx:syntax:error', { token: tokens.shift() }) + } + consumeUntil(tokens, NOT_WHITESPACE) + } while (tokens[0] === ',' && tokens.shift()) + if (cache) { + cache[explicitTrigger] = triggerSpecs + } + return triggerSpecs + } + + /** + * @param {Element} elt + * @returns {HtmxTriggerSpecification[]} + */ + function getTriggerSpecs(elt) { + const explicitTrigger = getAttributeValue(elt, 'hx-trigger') + let triggerSpecs = [] + if (explicitTrigger) { + const cache = htmx.config.triggerSpecsCache + triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) + } - if (confirmQuestion && !confirmed) { - if(!confirm(confirmQuestion)) { - maybeCall(resolve); - endRequestLock() - return promise; - } + if (triggerSpecs.length > 0) { + return triggerSpecs + } else if (matches(elt, 'form')) { + return [{ trigger: 'submit' }] + } else if (matches(elt, 'input[type="button"], input[type="submit"]')) { + return [{ trigger: 'click' }] + } else if (matches(elt, INPUT_SELECTOR)) { + return [{ trigger: 'change' }] + } else { + return [{ trigger: 'click' }] + } + } + + /** + * @param {Element} elt + */ + function cancelPolling(elt) { + getInternalData(elt).cancelled = true + } + + /** + * @param {Element} elt + * @param {TriggerHandler} handler + * @param {HtmxTriggerSpecification} spec + */ + function processPolling(elt, handler, spec) { + const nodeData = getInternalData(elt) + nodeData.timeout = getWindow().setTimeout(function() { + if (bodyContains(elt) && nodeData.cancelled !== true) { + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { + handler(elt) + } + processPolling(elt, handler, spec) + } + }, spec.pollInterval) + } + + /** + * @param {HTMLAnchorElement} elt + * @returns {boolean} + */ + function isLocalLink(elt) { + return location.hostname === elt.hostname && + getRawAttribute(elt, 'href') && + getRawAttribute(elt, 'href').indexOf('#') !== 0 + } + + /** + * @param {Element} elt + */ + function eltIsDisabled(elt) { + return closest(elt, htmx.config.disableSelector) + } + + /** + * @param {Element} elt + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification[]} triggerSpecs + */ + function boostElement(elt, nodeData, triggerSpecs) { + if ((elt instanceof HTMLAnchorElement && isLocalLink(elt) && (elt.target === '' || elt.target === '_self')) || elt.tagName === 'FORM') { + nodeData.boosted = true + let verb, path + if (elt.tagName === 'A') { + verb = 'get' + path = getRawAttribute(elt, 'href') + } else { + const rawAttribute = getRawAttribute(elt, 'method') + verb = rawAttribute ? rawAttribute.toLowerCase() : 'get' + if (verb === 'get') { + } + path = getRawAttribute(elt, 'action') + } + triggerSpecs.forEach(function(triggerSpec) { + addEventListener(elt, function(node, evt) { + const elt = asElement(node) + if (eltIsDisabled(elt)) { + cleanUpElement(elt) + return + } + issueAjaxRequest(verb, path, elt, evt) + }, nodeData, triggerSpec, true) + }) + } + } + + /** + * @param {Event} evt + * @param {Node} node + * @returns {boolean} + */ + function shouldCancel(evt, node) { + const elt = asElement(node) + if (!elt) { + return false + } + if (evt.type === 'submit' || evt.type === 'click') { + if (elt.tagName === 'FORM') { + return true + } + if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { + return true + } + if (elt instanceof HTMLAnchorElement && elt.href && + (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf('#') !== 0)) { + return true + } + } + return false + } + + /** + * @param {Node} elt + * @param {Event|MouseEvent|KeyboardEvent|TouchEvent} evt + * @returns {boolean} + */ + function ignoreBoostedAnchorCtrlClick(elt, evt) { + return getInternalData(elt).boosted && elt instanceof HTMLAnchorElement && evt.type === 'click' && + // @ts-ignore this will resolve to undefined for events that don't define those properties, which is fine + (evt.ctrlKey || evt.metaKey) + } + + /** + * @param {HtmxTriggerSpecification} triggerSpec + * @param {Node} elt + * @param {Event} evt + * @returns {boolean} + */ + function maybeFilterEvent(triggerSpec, elt, evt) { + const eventFilter = triggerSpec.eventFilter + if (eventFilter) { + try { + return eventFilter.call(elt, evt) !== true + } catch (e) { + const source = eventFilter.source + triggerErrorEvent(getDocument().body, 'htmx:eventFilter:error', { error: e, source }) + return true + } + } + return false + } + + /** + * @param {Node} elt + * @param {TriggerHandler} handler + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification} triggerSpec + * @param {boolean} [explicitCancel] + */ + function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { + const elementData = getInternalData(elt) + /** @type {(Node|Window)[]} */ + let eltsToListenOn + if (triggerSpec.from) { + eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from) + } else { + eltsToListenOn = [elt] + } + // store the initial values of the elements, so we can tell if they change + if (triggerSpec.changed) { + eltsToListenOn.forEach(function(eltToListenOn) { + const eltToListenOnData = getInternalData(eltToListenOn) + // @ts-ignore value will be undefined for non-input elements, which is fine + eltToListenOnData.lastValue = eltToListenOn.value + }) + } + forEach(eltsToListenOn, function(eltToListenOn) { + /** @type EventListener */ + const eventListener = function(evt) { + if (!bodyContains(elt)) { + eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener) + return + } + if (ignoreBoostedAnchorCtrlClick(elt, evt)) { + return + } + if (explicitCancel || shouldCancel(evt, elt)) { + evt.preventDefault() + } + if (maybeFilterEvent(triggerSpec, elt, evt)) { + return + } + const eventData = getInternalData(evt) + eventData.triggerSpec = triggerSpec + if (eventData.handledFor == null) { + eventData.handledFor = [] + } + if (eventData.handledFor.indexOf(elt) < 0) { + eventData.handledFor.push(elt) + if (triggerSpec.consume) { + evt.stopPropagation() + } + if (triggerSpec.target && evt.target) { + if (!matches(asElement(evt.target), triggerSpec.target)) { + return + } + } + if (triggerSpec.once) { + if (elementData.triggeredOnce) { + return + } else { + elementData.triggeredOnce = true + } + } + if (triggerSpec.changed) { + const eltToListenOnData = getInternalData(eltToListenOn) + // @ts-ignore value will be undefined for non-input elements, which is fine + const value = eltToListenOn.value + if (eltToListenOnData.lastValue === value) { + return + } + eltToListenOnData.lastValue = value + } + if (elementData.delayed) { + clearTimeout(elementData.delayed) + } + if (elementData.throttle) { + return + } + + if (triggerSpec.throttle > 0) { + if (!elementData.throttle) { + handler(elt, evt) + elementData.throttle = getWindow().setTimeout(function() { + elementData.throttle = null + }, triggerSpec.throttle) + } + } else if (triggerSpec.delay > 0) { + elementData.delayed = getWindow().setTimeout(function() { handler(elt, evt) }, triggerSpec.delay) + } else { + triggerEvent(elt, 'htmx:trigger') + handler(elt, evt) + } + } + } + if (nodeData.listenerInfos == null) { + nodeData.listenerInfos = [] + } + nodeData.listenerInfos.push({ + trigger: triggerSpec.trigger, + listener: eventListener, + on: eltToListenOn + }) + eltToListenOn.addEventListener(triggerSpec.trigger, eventListener) + }) + } + + let windowIsScrolling = false // used by initScrollHandler + let scrollHandler = null + function initScrollHandler() { + if (!scrollHandler) { + scrollHandler = function() { + windowIsScrolling = true + } + window.addEventListener('scroll', scrollHandler) + setInterval(function() { + if (windowIsScrolling) { + windowIsScrolling = false + forEach(getDocument().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"), function(elt) { + maybeReveal(elt) + }) + } + }, 200) + } + } + + /** + * @param {Element} elt + */ + function maybeReveal(elt) { + if (!hasAttribute(elt, 'data-hx-revealed') && isScrolledIntoView(elt)) { + elt.setAttribute('data-hx-revealed', 'true') + const nodeData = getInternalData(elt) + if (nodeData.initHash) { + triggerEvent(elt, 'revealed') + } else { + // if the node isn't initialized, wait for it before triggering the request + elt.addEventListener('htmx:afterProcessNode', function() { triggerEvent(elt, 'revealed') }, { once: true }) + } + } + } + + //= =================================================================== + + /** + * @param {Element} elt + * @param {TriggerHandler} handler + * @param {HtmxNodeInternalData} nodeData + * @param {number} delay + */ + function loadImmediately(elt, handler, nodeData, delay) { + const load = function() { + if (!nodeData.loaded) { + nodeData.loaded = true + handler(elt) + } + } + if (delay > 0) { + getWindow().setTimeout(load, delay) + } else { + load() + } + } + + /** + * @param {Element} elt + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification[]} triggerSpecs + * @returns {boolean} + */ + function processVerbs(elt, nodeData, triggerSpecs) { + let explicitAction = false + forEach(VERBS, function(verb) { + if (hasAttribute(elt, 'hx-' + verb)) { + const path = getAttributeValue(elt, 'hx-' + verb) + explicitAction = true + nodeData.path = path + nodeData.verb = verb + triggerSpecs.forEach(function(triggerSpec) { + addTriggerHandler(elt, triggerSpec, nodeData, function(node, evt) { + const elt = asElement(node) + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return } + issueAjaxRequest(verb, path, elt, evt) + }) + }) + } + }) + return explicitAction + } + + /** + * @callback TriggerHandler + * @param {Node} elt + * @param {Event} [evt] + */ + + /** + * @param {Node} elt + * @param {HtmxTriggerSpecification} triggerSpec + * @param {HtmxNodeInternalData} nodeData + * @param {TriggerHandler} handler + */ + function addTriggerHandler(elt, triggerSpec, nodeData, handler) { + if (triggerSpec.trigger === 'revealed') { + initScrollHandler() + addEventListener(elt, handler, nodeData, triggerSpec) + maybeReveal(asElement(elt)) + } else if (triggerSpec.trigger === 'intersect') { + const observerOptions = {} + if (triggerSpec.root) { + observerOptions.root = querySelectorExt(elt, triggerSpec.root) + } + if (triggerSpec.threshold) { + observerOptions.threshold = parseFloat(triggerSpec.threshold) + } + const observer = new IntersectionObserver(function(entries) { + for (let i = 0; i < entries.length; i++) { + const entry = entries[i] + if (entry.isIntersecting) { + triggerEvent(elt, 'intersect') + break + } + } + }, observerOptions) + observer.observe(asElement(elt)) + addEventListener(asElement(elt), handler, nodeData, triggerSpec) + } else if (triggerSpec.trigger === 'load') { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent('load', { elt }))) { + loadImmediately(asElement(elt), handler, nodeData, triggerSpec.delay) + } + } else if (triggerSpec.pollInterval > 0) { + nodeData.polling = true + processPolling(asElement(elt), handler, triggerSpec) + } else { + addEventListener(elt, handler, nodeData, triggerSpec) + } + } + + /** + * @param {Node} node + * @returns {boolean} + */ + function shouldProcessHxOn(node) { + const elt = asElement(node) + if (!elt) { + return false + } + const attributes = elt.attributes + for (let j = 0; j < attributes.length; j++) { + const attrName = attributes[j].name + if (startsWith(attrName, 'hx-on:') || startsWith(attrName, 'data-hx-on:') || + startsWith(attrName, 'hx-on-') || startsWith(attrName, 'data-hx-on-')) { + return true + } + } + return false + } + + /** + * @param {Node} elt + * @returns {Element[]} + */ + const HX_ON_QUERY = new XPathEvaluator() + .createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + + ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]') + + function processHXOnRoot(elt, elements) { + if (shouldProcessHxOn(elt)) { + elements.push(asElement(elt)) + } + const iter = HX_ON_QUERY.evaluate(elt) + let node = null + while (node = iter.iterateNext()) elements.push(asElement(node)) + } + + function findHxOnWildcardElements(elt) { + /** @type {Element[]} */ + const elements = [] + if (elt instanceof DocumentFragment) { + for (const child of elt.childNodes) { + processHXOnRoot(child, elements) + } + } else { + processHXOnRoot(elt, elements) + } + return elements + } + + /** + * @param {Element} elt + * @returns {NodeListOf<Element>|[]} + */ + function findElementsToProcess(elt) { + if (elt.querySelectorAll) { + const boostedSelector = ', [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]' + + const extensionSelectors = [] + for (const e in extensions) { + const extension = extensions[e] + if (extension.getSelectors) { + var selectors = extension.getSelectors() + if (selectors) { + extensionSelectors.push(selectors) + } + } + } + + const results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit']," + + ' [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]' + extensionSelectors.flat().map(s => ', ' + s).join('')) + + return results + } else { + return [] + } + } + + /** + * Handle submit buttons/inputs that have the form attribute set + * see https://developer.mozilla.org/docs/Web/HTML/Element/button + * @param {Event} evt + */ + function maybeSetLastButtonClicked(evt) { + const elt = /** @type {HTMLButtonElement|HTMLInputElement} */ (closest(asElement(evt.target), "button, input[type='submit']")) + const internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = elt + } + } + + /** + * @param {Event} evt + */ + function maybeUnsetLastButtonClicked(evt) { + const internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = null + } + } + + /** + * @param {Event} evt + * @returns {HtmxNodeInternalData|undefined} + */ + function getRelatedFormData(evt) { + const elt = closest(asElement(evt.target), "button, input[type='submit']") + if (!elt) { + return + } + const form = resolveTarget('#' + getRawAttribute(elt, 'form'), elt.getRootNode()) || closest(elt, 'form') + if (!form) { + return + } + return getInternalData(form) + } + + /** + * @param {EventTarget} elt + */ + function initButtonTracking(elt) { + // need to handle both click and focus in: + // focusin - in case someone tabs in to a button and hits the space bar + // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + elt.addEventListener('click', maybeSetLastButtonClicked) + elt.addEventListener('focusin', maybeSetLastButtonClicked) + elt.addEventListener('focusout', maybeUnsetLastButtonClicked) + } + + /** + * @param {Element} elt + * @param {string} eventName + * @param {string} code + */ + function addHxOnEventHandler(elt, eventName, code) { + const nodeData = getInternalData(elt) + if (!Array.isArray(nodeData.onHandlers)) { + nodeData.onHandlers = [] + } + let func + /** @type EventListener */ + const listener = function(e) { + maybeEval(elt, function() { + if (eltIsDisabled(elt)) { + return + } + if (!func) { + func = new Function('event', code) + } + func.call(elt, e) + }) + } + elt.addEventListener(eventName, listener) + nodeData.onHandlers.push({ event: eventName, listener }) + } + + /** + * @param {Element} elt + */ + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (let i = 0; i < elt.attributes.length; i++) { + const name = elt.attributes[i].name + const value = elt.attributes[i].value + if (startsWith(name, 'hx-on') || startsWith(name, 'data-hx-on')) { + const afterOnPosition = name.indexOf('-on') + 3 + const nextChar = name.slice(afterOnPosition, afterOnPosition + 1) + if (nextChar === '-' || nextChar === ':') { + let eventName = name.slice(afterOnPosition + 1) + // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support + if (startsWith(eventName, ':')) { + eventName = 'htmx' + eventName + } else if (startsWith(eventName, '-')) { + eventName = 'htmx:' + eventName.slice(1) + } else if (startsWith(eventName, 'htmx-')) { + eventName = 'htmx:' + eventName.slice(5) + } + + addHxOnEventHandler(elt, eventName, value) + } + } + } + } + + /** + * @param {Element|HTMLInputElement} elt + */ + function initNode(elt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + const nodeData = getInternalData(elt) + if (nodeData.initHash !== attributeHash(elt)) { + // clean up any previously processed info + deInitNode(elt) + + nodeData.initHash = attributeHash(elt) + + triggerEvent(elt, 'htmx:beforeProcessNode') + + // @ts-ignore value will be undefined for non-input elements, which is fine + if (elt.value) { + // @ts-ignore + nodeData.lastValue = elt.value + } + + const triggerSpecs = getTriggerSpecs(elt) + const hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs) + + if (!hasExplicitHttpAction) { + if (getClosestAttributeValue(elt, 'hx-boost') === 'true') { + boostElement(elt, nodeData, triggerSpecs) + } else if (hasAttribute(elt, 'hx-trigger')) { + triggerSpecs.forEach(function(triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function() { + }) + }) + } + } + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + if (elt.tagName === 'FORM' || (getRawAttribute(elt, 'type') === 'submit' && hasAttribute(elt, 'form'))) { + initButtonTracking(elt) + } - var headers = getHeaders(elt, target, promptResponse); - - if (verb !== 'get' && !usesFormData(elt)) { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; - } + triggerEvent(elt, 'htmx:afterProcessNode') + } + } + + /** + * Processes new content, enabling htmx behavior. This can be useful if you have content that is added to the DOM outside of the normal htmx request cycle but still want htmx attributes to work. + * + * @see https://htmx.org/api/#process + * + * @param {Element|string} elt element to process + */ + function processNode(elt) { + elt = resolveTarget(elt) + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + initNode(elt) + forEach(findElementsToProcess(elt), function(child) { initNode(child) }) + forEach(findHxOnWildcardElements(elt), processHxOnWildcard) + } + + //= =================================================================== + // Event/Log Support + //= =================================================================== + + /** + * @param {string} str + * @returns {string} + */ + function kebabEventName(str) { + return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase() + } + + /** + * @param {string} eventName + * @param {any} detail + * @returns {CustomEvent} + */ + function makeEvent(eventName, detail) { + let evt + if (window.CustomEvent && typeof window.CustomEvent === 'function') { + // TODO: `composed: true` here is a hack to make global event handlers work with events in shadow DOM + // This breaks expected encapsulation but needs to be here until decided otherwise by core devs + evt = new CustomEvent(eventName, { bubbles: true, cancelable: true, composed: true, detail }) + } else { + evt = getDocument().createEvent('CustomEvent') + evt.initCustomEvent(eventName, true, true, detail) + } + return evt + } + + /** + * @param {EventTarget|string} elt + * @param {string} eventName + * @param {any=} detail + */ + function triggerErrorEvent(elt, eventName, detail) { + triggerEvent(elt, eventName, mergeObjects({ error: eventName }, detail)) + } + + /** + * @param {string} eventName + * @returns {boolean} + */ + function ignoreEventForLogging(eventName) { + return eventName === 'htmx:afterProcessNode' + } + + /** + * `withExtensions` locates all active extensions for a provided element, then + * executes the provided function using each of the active extensions. It should + * be called internally at every extendable execution point in htmx. + * + * @param {Element} elt + * @param {(extension:HtmxExtension) => void} toDo + * @returns void + */ + function withExtensions(elt, toDo) { + forEach(getExtensions(elt), function(extension) { + try { + toDo(extension) + } catch (e) { + logError(e) + } + }) + } + + function logError(msg) { + if (console.error) { + console.error(msg) + } else if (console.log) { + console.log('ERROR: ', msg) + } + } + + /** + * Triggers a given event on an element + * + * @see https://htmx.org/api/#trigger + * + * @param {EventTarget|string} elt the element to trigger the event on + * @param {string} eventName the name of the event to trigger + * @param {any=} detail details for the event + * @returns {boolean} + */ + function triggerEvent(elt, eventName, detail) { + elt = resolveTarget(elt) + if (detail == null) { + detail = {} + } + detail.elt = elt + const event = makeEvent(eventName, detail) + if (htmx.logger && !ignoreEventForLogging(eventName)) { + htmx.logger(elt, eventName, detail) + } + if (detail.error) { + logError(detail.error) + triggerEvent(elt, 'htmx:error', { errorInfo: detail }) + } + let eventResult = elt.dispatchEvent(event) + const kebabName = kebabEventName(eventName) + if (eventResult && kebabName !== eventName) { + const kebabedEvent = makeEvent(kebabName, event.detail) + eventResult = eventResult && elt.dispatchEvent(kebabedEvent) + } + withExtensions(asElement(elt), function(extension) { + eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) + }) + return eventResult + } + + //= =================================================================== + // History Support + //= =================================================================== + let currentPathForHistory = location.pathname + location.search + + /** + * @returns {Element} + */ + function getHistoryElement() { + const historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]') + return historyElt || getDocument().body + } + + /** + * @param {string} url + * @param {Element} rootElt + */ + function saveToHistoryCache(url, rootElt) { + if (!canAccessLocalStorage()) { + return + } - if (etc.headers) { - headers = mergeObjects(headers, etc.headers); - } - var results = getInputValues(elt, verb); - var errors = results.errors; - var rawParameters = results.values; - if (etc.values) { - rawParameters = mergeObjects(rawParameters, etc.values); - } - var expressionVars = getExpressionVars(elt); - var allParameters = mergeObjects(rawParameters, expressionVars); - var filteredParameters = filterValues(allParameters, elt); + // get state to save + const innerHTML = cleanInnerHtmlForHistory(rootElt) + const title = getDocument().title + const scroll = window.scrollY - if (htmx.config.getCacheBusterParam && verb === 'get') { - filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true"; - } + if (htmx.config.historyCacheSize <= 0) { + // make sure that an eventually already existing cache is purged + localStorage.removeItem('htmx-history-cache') + return + } - // behavior of anchors w/ empty href is to use the current URL - if (path == null || path === "") { - path = getDocument().location.href; - } + url = normalizePath(url) + const historyCache = parseJSON(localStorage.getItem('htmx-history-cache')) || [] + for (let i = 0; i < historyCache.length; i++) { + if (historyCache[i].url === url) { + historyCache.splice(i, 1) + break + } + } - var requestAttrValues = getValuesForElement(elt, 'hx-request'); + /** @type HtmxHistoryItem */ + const newHistoryItem = { url, content: innerHTML, title, scroll } - var eltIsBoosted = getInternalData(elt).boosted; + triggerEvent(getDocument().body, 'htmx:historyItemCreated', { item: newHistoryItem, cache: historyCache }) - var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + historyCache.push(newHistoryItem) + while (historyCache.length > htmx.config.historyCacheSize) { + historyCache.shift() + } - var requestConfig = { - boosted: eltIsBoosted, - useUrlParams: useUrlParams, - parameters: filteredParameters, - unfilteredParameters: allParameters, - headers:headers, - target:target, - verb:verb, - errors:errors, - withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, - timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, - path:path, - triggeringEvent:event - }; + // keep trying to save the cache until it succeeds or is empty + while (historyCache.length > 0) { + try { + localStorage.setItem('htmx-history-cache', JSON.stringify(historyCache)) + break + } catch (e) { + triggerErrorEvent(getDocument().body, 'htmx:historyCacheError', { cause: e, cache: historyCache }) + historyCache.shift() // shrink the cache and retry + } + } + } + + /** + * @typedef {Object} HtmxHistoryItem + * @property {string} url + * @property {string} content + * @property {string} title + * @property {number} scroll + */ + + /** + * @param {string} url + * @returns {HtmxHistoryItem|null} + */ + function getCachedHistory(url) { + if (!canAccessLocalStorage()) { + return null + } - if(!triggerEvent(elt, 'htmx:configRequest', requestConfig)){ - maybeCall(resolve); - endRequestLock(); - return promise; - } + url = normalizePath(url) - // copy out in case the object was overwritten - path = requestConfig.path; - verb = requestConfig.verb; - headers = requestConfig.headers; - filteredParameters = requestConfig.parameters; - errors = requestConfig.errors; - useUrlParams = requestConfig.useUrlParams; - - if(errors && errors.length > 0){ - triggerEvent(elt, 'htmx:validation:halted', requestConfig) - maybeCall(resolve); - endRequestLock(); - return promise; - } + const historyCache = parseJSON(localStorage.getItem('htmx-history-cache')) || [] + for (let i = 0; i < historyCache.length; i++) { + if (historyCache[i].url === url) { + return historyCache[i] + } + } + return null + } + + /** + * @param {Element} elt + * @returns {string} + */ + function cleanInnerHtmlForHistory(elt) { + const className = htmx.config.requestClass + const clone = /** @type Element */ (elt.cloneNode(true)) + forEach(findAll(clone, '.' + className), function(child) { + removeClassFromElement(child, className) + }) + return clone.innerHTML + } + + function saveCurrentPageToHistory() { + const elt = getHistoryElement() + const path = currentPathForHistory || location.pathname + location.search + + // Allow history snapshot feature to be disabled where hx-history="false" + // is present *anywhere* in the current document we're about to save, + // so we can prevent privileged data entering the cache. + // The page will still be reachable as a history entry, but htmx will fetch it + // live from the server onpopstate rather than look in the localStorage cache + let disableHistoryCache + try { + disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') + } catch (e) { + // IE11: insensitive modifier not supported so fallback to case sensitive selector + disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') + } + if (!disableHistoryCache) { + triggerEvent(getDocument().body, 'htmx:beforeHistorySave', { path, historyElt: elt }) + saveToHistoryCache(path, elt) + } - var splitPath = path.split("#"); - var pathNoAnchor = splitPath[0]; - var anchor = splitPath[1]; - - var finalPath = path - if (useUrlParams) { - finalPath = pathNoAnchor; - var values = Object.keys(filteredParameters).length !== 0; - if (values) { - if (finalPath.indexOf("?") < 0) { - finalPath += "?"; - } else { - finalPath += "&"; - } - finalPath += urlEncode(filteredParameters); - if (anchor) { - finalPath += "#" + anchor; - } - } - } + if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, getDocument().title, window.location.href) + } + + /** + * @param {string} path + */ + function pushUrlIntoHistory(path) { + // remove the cache buster parameter, if any + if (htmx.config.getCacheBusterParam) { + path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') + if (endsWith(path, '&') || endsWith(path, '?')) { + path = path.slice(0, -1) + } + } + if (htmx.config.historyEnabled) { + history.pushState({ htmx: true }, '', path) + } + currentPathForHistory = path + } + + /** + * @param {string} path + */ + function replaceUrlInHistory(path) { + if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, '', path) + currentPathForHistory = path + } + + /** + * @param {HtmxSettleTask[]} tasks + */ + function settleImmediately(tasks) { + forEach(tasks, function(task) { + task.call(undefined) + }) + } + + /** + * @param {string} path + */ + function loadHistoryFromServer(path) { + const request = new XMLHttpRequest() + const details = { path, xhr: request } + triggerEvent(getDocument().body, 'htmx:historyCacheMiss', details) + request.open('GET', path, true) + request.setRequestHeader('HX-Request', 'true') + request.setRequestHeader('HX-History-Restore-Request', 'true') + request.setRequestHeader('HX-Current-URL', getDocument().location.href) + request.onload = function() { + if (this.status >= 200 && this.status < 400) { + triggerEvent(getDocument().body, 'htmx:historyCacheMissLoad', details) + const fragment = makeFragment(this.response) + /** @type ParentNode */ + const content = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment + const historyElement = getHistoryElement() + const settleInfo = makeSettleInfo(historyElement) + handleTitle(fragment.title) + + swapInnerHTML(historyElement, content, settleInfo) + settleImmediately(settleInfo.tasks) + currentPathForHistory = path + triggerEvent(getDocument().body, 'htmx:historyRestore', { path, cacheMiss: true, serverResponse: this.response }) + } else { + triggerErrorEvent(getDocument().body, 'htmx:historyCacheMissLoadError', details) + } + } + request.send() + } + + /** + * @param {string} [path] + */ + function restoreHistory(path) { + saveCurrentPageToHistory() + path = path || location.pathname + location.search + const cached = getCachedHistory(path) + if (cached) { + const fragment = makeFragment(cached.content) + const historyElement = getHistoryElement() + const settleInfo = makeSettleInfo(historyElement) + handleTitle(fragment.title) + swapInnerHTML(historyElement, fragment, settleInfo) + settleImmediately(settleInfo.tasks) + getWindow().setTimeout(function() { + window.scrollTo(0, cached.scroll) + }, 0) // next 'tick', so browser has time to render layout + currentPathForHistory = path + triggerEvent(getDocument().body, 'htmx:historyRestore', { path, item: cached }) + } else { + if (htmx.config.refreshOnHistoryMiss) { + // @ts-ignore: optional parameter in reload() function throws error + // noinspection JSUnresolvedReference + window.location.reload(true) + } else { + loadHistoryFromServer(path) + } + } + } + + /** + * @param {Element} elt + * @returns {Element[]} + */ + function addRequestIndicatorClasses(elt) { + let indicators = /** @type Element[] */ (findAttributeTargets(elt, 'hx-indicator')) + if (indicators == null) { + indicators = [elt] + } + forEach(indicators, function(ic) { + const internalData = getInternalData(ic) + internalData.requestCount = (internalData.requestCount || 0) + 1 + ic.classList.add.call(ic.classList, htmx.config.requestClass) + }) + return indicators + } + + /** + * @param {Element} elt + * @returns {Element[]} + */ + function disableElements(elt) { + let disabledElts = /** @type Element[] */ (findAttributeTargets(elt, 'hx-disabled-elt')) + if (disabledElts == null) { + disabledElts = [] + } + forEach(disabledElts, function(disabledElement) { + const internalData = getInternalData(disabledElement) + internalData.requestCount = (internalData.requestCount || 0) + 1 + disabledElement.setAttribute('disabled', '') + }) + return disabledElts + } + + /** + * @param {Element[]} indicators + * @param {Element[]} disabled + */ + function removeRequestIndicators(indicators, disabled) { + forEach(indicators, function(ic) { + const internalData = getInternalData(ic) + internalData.requestCount = (internalData.requestCount || 0) - 1 + if (internalData.requestCount === 0) { + ic.classList.remove.call(ic.classList, htmx.config.requestClass) + } + }) + forEach(disabled, function(disabledElement) { + const internalData = getInternalData(disabledElement) + internalData.requestCount = (internalData.requestCount || 0) - 1 + if (internalData.requestCount === 0) { + disabledElement.removeAttribute('disabled') + } + }) + } + + //= =================================================================== + // Input Value Processing + //= =================================================================== + + /** + * @param {Element[]} processed + * @param {Element} elt + * @returns {boolean} + */ + function haveSeenNode(processed, elt) { + for (let i = 0; i < processed.length; i++) { + const node = processed[i] + if (node.isSameNode(elt)) { + return true + } + } + return false + } + + /** + * @param {Element} element + * @return {boolean} + */ + function shouldInclude(element) { + // Cast to trick tsc, undefined values will work fine here + const elt = /** @type {HTMLInputElement} */ (element) + if (elt.name === '' || elt.name == null || elt.disabled || closest(elt, 'fieldset[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 + } + + /** @param {string} name + * @param {string|Array|FormDataEntryValue} value + * @param {FormData} formData */ + function addValueToFormData(name, value, formData) { + if (name != null && value != null) { + if (Array.isArray(value)) { + value.forEach(function(v) { formData.append(name, v) }) + } else { + formData.append(name, value) + } + } + } + + /** @param {string} name + * @param {string|Array} value + * @param {FormData} formData */ + function removeValueFromFormData(name, value, formData) { + if (name != null && value != null) { + let values = formData.getAll(name) + if (Array.isArray(value)) { + values = values.filter(v => value.indexOf(v) < 0) + } else { + values = values.filter(v => v !== value) + } + formData.delete(name) + forEach(values, v => formData.append(name, v)) + } + } + + /** + * @param {Element[]} processed + * @param {FormData} formData + * @param {HtmxElementValidationError[]} errors + * @param {Element|HTMLInputElement|HTMLSelectElement|HTMLFormElement} elt + * @param {boolean} validate + */ + function processInputValue(processed, formData, errors, elt, validate) { + if (elt == null || haveSeenNode(processed, elt)) { + return + } else { + processed.push(elt) + } + if (shouldInclude(elt)) { + const name = getRawAttribute(elt, 'name') + // @ts-ignore value will be undefined for non-input elements, which is fine + let value = elt.value + if (elt instanceof HTMLSelectElement && elt.multiple) { + value = toArray(elt.querySelectorAll('option:checked')).map(function(e) { return (/** @type HTMLOptionElement */(e)).value }) + } + // include file inputs + if (elt instanceof HTMLInputElement && elt.files) { + value = toArray(elt.files) + } + addValueToFormData(name, value, formData) + if (validate) { + validateElement(elt, errors) + } + } + if (elt instanceof HTMLFormElement) { + forEach(elt.elements, function(input) { + if (processed.indexOf(input) >= 0) { + // The input has already been processed and added to the values, but the FormData that will be + // constructed right after on the form, will include it once again. So remove that input's value + // now to avoid duplicates + removeValueFromFormData(input.name, input.value, formData) + } else { + processed.push(input) + } + if (validate) { + validateElement(input, errors) + } + }) + new FormData(elt).forEach(function(value, name) { + if (value instanceof File && value.name === '') { + return // ignore no-name files + } + addValueToFormData(name, value, formData) + }) + } + } + + /** + * + * @param {Element} elt + * @param {HtmxElementValidationError[]} errors + */ + function validateElement(elt, errors) { + const element = /** @type {HTMLElement & ElementInternals} */ (elt) + if (element.willValidate) { + triggerEvent(element, 'htmx:validation:validate') + if (!element.checkValidity()) { + errors.push({ elt: element, message: element.validationMessage, validity: element.validity }) + triggerEvent(element, 'htmx:validation:failed', { message: element.validationMessage, validity: element.validity }) + } + } + } + + /** + * Override values in the one FormData with those from another. + * @param {FormData} receiver the formdata that will be mutated + * @param {FormData} donor the formdata that will provide the overriding values + * @returns {FormData} the {@linkcode receiver} + */ + function overrideFormData(receiver, donor) { + for (const key of donor.keys()) { + receiver.delete(key) + donor.getAll(key).forEach(function(value) { + receiver.append(key, value) + }) + } + return receiver + } + + /** + * @param {Element|HTMLFormElement} elt + * @param {HttpVerb} verb + * @returns {{errors: HtmxElementValidationError[], formData: FormData, values: Object}} + */ + function getInputValues(elt, verb) { + /** @type Element[] */ + const processed = [] + const formData = new FormData() + const priorityFormData = new FormData() + /** @type HtmxElementValidationError[] */ + const errors = [] + const internalData = getInternalData(elt) + if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { + internalData.lastButtonClicked = null + } - if (!verifyPath(elt, finalPath, requestConfig)) { - triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) - maybeCall(reject); - return promise; - }; + // only validate when form is directly submitted and novalidate or formnovalidate are not set + // or if the element has an explicit hx-validate="true" on it + let validate = (elt instanceof HTMLFormElement && elt.noValidate !== true) || getAttributeValue(elt, 'hx-validate') === 'true' + if (internalData.lastButtonClicked) { + validate = validate && internalData.lastButtonClicked.formNoValidate !== true + } - xhr.open(verb.toUpperCase(), finalPath, true); - xhr.overrideMimeType("text/html"); - xhr.withCredentials = requestConfig.withCredentials; - xhr.timeout = requestConfig.timeout; + // for a non-GET include the closest form + if (verb !== 'get') { + processInputValue(processed, priorityFormData, errors, closest(elt, 'form'), validate) + } - // request headers - if (requestAttrValues.noHeaders) { - // ignore all headers - } else { - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - var headerValue = headers[header]; - safelySetHeaderValue(xhr, header, headerValue); - } - } - } + // include the element itself + processInputValue(processed, formData, errors, elt, validate) - var responseInfo = { - xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select, - pathInfo: { - requestPath: path, - finalRequestPath: finalPath, - anchor: anchor - } - }; - - xhr.onload = function () { - try { - var hierarchy = hierarchyForElt(elt); - responseInfo.pathInfo.responsePath = getPathFromResponse(xhr); - responseHandler(elt, responseInfo); - removeRequestIndicators(indicators, disableElts); - triggerEvent(elt, 'htmx:afterRequest', responseInfo); - triggerEvent(elt, 'htmx:afterOnLoad', responseInfo); - // if the body no longer contains the element, trigger the event on the closest parent - // remaining in the DOM - if (!bodyContains(elt)) { - var secondaryTriggerElt = null; - while (hierarchy.length > 0 && secondaryTriggerElt == null) { - var parentEltInHierarchy = hierarchy.shift(); - if (bodyContains(parentEltInHierarchy)) { - secondaryTriggerElt = parentEltInHierarchy; - } - } - if (secondaryTriggerElt) { - triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo); - triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo); - } - } - maybeCall(resolve); - endRequestLock(); - } catch (e) { - triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({error:e}, responseInfo)); - throw e; - } - } - xhr.onerror = function () { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:sendError', responseInfo); - maybeCall(reject); - endRequestLock(); - } - xhr.onabort = function() { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo); - maybeCall(reject); - endRequestLock(); - } - xhr.ontimeout = function() { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:timeout', responseInfo); - maybeCall(reject); - endRequestLock(); - } - if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){ - maybeCall(resolve); - endRequestLock() - return promise - } - var indicators = addRequestIndicatorClasses(elt); - var disableElts = disableElements(elt); - - forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { - forEach([xhr, xhr.upload], function (target) { - target.addEventListener(eventName, function(event){ - triggerEvent(elt, "htmx:xhr:" + eventName, { - lengthComputable:event.lengthComputable, - loaded:event.loaded, - total:event.total - }); - }) - }); - }); - triggerEvent(elt, 'htmx:beforeSend', responseInfo); - var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) - xhr.send(params); - return promise; - } - - function determineHistoryUpdates(elt, responseInfo) { - - var xhr = responseInfo.xhr; - - //=========================================== - // First consult response headers - //=========================================== - var pathFromHeaders = null; - var typeFromHeaders = null; - if (hasHeader(xhr,/HX-Push:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Push"); - typeFromHeaders = "push"; - } else if (hasHeader(xhr,/HX-Push-Url:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Push-Url"); - typeFromHeaders = "push"; - } else if (hasHeader(xhr,/HX-Replace-Url:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url"); - typeFromHeaders = "replace"; - } + // if a button or submit was clicked last, include its value + if (internalData.lastButtonClicked || elt.tagName === 'BUTTON' || + (elt.tagName === 'INPUT' && getRawAttribute(elt, 'type') === 'submit')) { + const button = internalData.lastButtonClicked || (/** @type HTMLInputElement|HTMLButtonElement */(elt)) + const name = getRawAttribute(button, 'name') + addValueToFormData(name, button.value, priorityFormData) + } - // if there was a response header, that has priority - if (pathFromHeaders) { - if (pathFromHeaders === "false") { - return {} - } else { - return { - type: typeFromHeaders, - path : pathFromHeaders - } - } - } + // include any explicit includes + const includes = findAttributeTargets(elt, 'hx-include') + forEach(includes, function(node) { + processInputValue(processed, formData, errors, asElement(node), validate) + // if a non-form is included, include any input values within it + if (!matches(node, 'form')) { + forEach(asParentNode(node).querySelectorAll(INPUT_SELECTOR), function(descendant) { + processInputValue(processed, formData, errors, descendant, validate) + }) + } + }) + + // values from a <form> take precedence, overriding the regular values + overrideFormData(formData, priorityFormData) + + return { errors, formData, values: formDataProxy(formData) } + } + + /** + * @param {string} returnStr + * @param {string} name + * @param {any} realValue + * @returns {string} + */ + function appendParam(returnStr, name, realValue) { + if (returnStr !== '') { + returnStr += '&' + } + if (String(realValue) === '[object Object]') { + realValue = JSON.stringify(realValue) + } + const s = encodeURIComponent(realValue) + returnStr += encodeURIComponent(name) + '=' + s + return returnStr + } + + /** + * @param {FormData|Object} values + * @returns string + */ + function urlEncode(values) { + values = formDataFromObject(values) + let returnStr = '' + values.forEach(function(value, key) { + returnStr = appendParam(returnStr, key, value) + }) + return returnStr + } + + //= =================================================================== + // Ajax + //= =================================================================== + + /** + * @param {Element} elt + * @param {Element} target + * @param {string} prompt + * @returns {HtmxHeaderSpecification} + */ + function getHeaders(elt, target, prompt) { + /** @type HtmxHeaderSpecification */ + const headers = { + 'HX-Request': 'true', + 'HX-Trigger': getRawAttribute(elt, 'id'), + 'HX-Trigger-Name': getRawAttribute(elt, 'name'), + 'HX-Target': getAttributeValue(target, 'id'), + 'HX-Current-URL': getDocument().location.href + } + getValuesForElement(elt, 'hx-headers', false, headers) + if (prompt !== undefined) { + headers['HX-Prompt'] = prompt + } + if (getInternalData(elt).boosted) { + headers['HX-Boosted'] = 'true' + } + return headers + } + + /** + * filterValues takes an object containing form input values + * and returns a new object that only contains keys that are + * specified by the closest "hx-params" attribute + * @param {FormData} inputValues + * @param {Element} elt + * @returns {FormData} + */ + function filterValues(inputValues, elt) { + const paramsValue = getClosestAttributeValue(elt, 'hx-params') + if (paramsValue) { + if (paramsValue === 'none') { + return new FormData() + } else if (paramsValue === '*') { + return inputValues + } else if (paramsValue.indexOf('not ') === 0) { + forEach(paramsValue.substr(4).split(','), function(name) { + name = name.trim() + inputValues.delete(name) + }) + return inputValues + } else { + const newValues = new FormData() + forEach(paramsValue.split(','), function(name) { + name = name.trim() + if (inputValues.has(name)) { + inputValues.getAll(name).forEach(function(value) { newValues.append(name, value) }) + } + }) + return newValues + } + } else { + return inputValues + } + } + + /** + * @param {Element} elt + * @return {boolean} + */ + function isAnchorLink(elt) { + return !!getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf('#') >= 0 + } + + /** + * @param {Element} elt + * @param {HtmxSwapStyle} [swapInfoOverride] + * @returns {HtmxSwapSpecification} + */ + function getSwapSpecification(elt, swapInfoOverride) { + const swapInfo = swapInfoOverride || getClosestAttributeValue(elt, 'hx-swap') + /** @type HtmxSwapSpecification */ + const swapSpec = { + swapStyle: getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, + swapDelay: htmx.config.defaultSwapDelay, + settleDelay: htmx.config.defaultSettleDelay + } + if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { + swapSpec.show = 'top' + } + if (swapInfo) { + const split = splitOnWhitespace(swapInfo) + if (split.length > 0) { + for (let i = 0; i < split.length; i++) { + const value = split[i] + if (value.indexOf('swap:') === 0) { + swapSpec.swapDelay = parseInterval(value.substr(5)) + } else if (value.indexOf('settle:') === 0) { + swapSpec.settleDelay = parseInterval(value.substr(7)) + } else if (value.indexOf('transition:') === 0) { + swapSpec.transition = value.substr(11) === 'true' + } else if (value.indexOf('ignoreTitle:') === 0) { + swapSpec.ignoreTitle = value.substr(12) === 'true' + } else if (value.indexOf('scroll:') === 0) { + const scrollSpec = value.substr(7) + var splitSpec = scrollSpec.split(':') + const scrollVal = splitSpec.pop() + var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null + // @ts-ignore + swapSpec.scroll = scrollVal + swapSpec.scrollTarget = selectorVal + } else if (value.indexOf('show:') === 0) { + const showSpec = value.substr(5) + var splitSpec = showSpec.split(':') + const showVal = splitSpec.pop() + var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null + swapSpec.show = showVal + swapSpec.showTarget = selectorVal + } else if (value.indexOf('focus-scroll:') === 0) { + const focusScrollVal = value.substr('focus-scroll:'.length) + swapSpec.focusScroll = focusScrollVal == 'true' + } else if (i == 0) { + swapSpec.swapStyle = value + } else { + logError('Unknown modifier in hx-swap: ' + value) + } + } + } + } + return swapSpec + } + + /** + * @param {Element} elt + * @return {boolean} + */ + function usesFormData(elt) { + return getClosestAttributeValue(elt, 'hx-encoding') === 'multipart/form-data' || + (matches(elt, 'form') && getRawAttribute(elt, 'enctype') === 'multipart/form-data') + } + + /** + * @param {XMLHttpRequest} xhr + * @param {Element} elt + * @param {FormData} filteredParameters + * @returns {*|string|null} + */ + function encodeParamsForBody(xhr, elt, filteredParameters) { + let encodedParameters = null + withExtensions(elt, function(extension) { + if (encodedParameters == null) { + encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt) + } + }) + if (encodedParameters != null) { + return encodedParameters + } else { + if (usesFormData(elt)) { + // Force conversion to an actual FormData object in case filteredParameters is a formDataProxy + // See https://github.com/bigskysoftware/htmx/issues/2317 + return overrideFormData(new FormData(), formDataFromObject(filteredParameters)) + } else { + return urlEncode(filteredParameters) + } + } + } + + /** + * + * @param {Element} target + * @returns {HtmxSettleInfo} + */ + function makeSettleInfo(target) { + return { tasks: [], elts: [target] } + } + + /** + * @param {Element[]} content + * @param {HtmxSwapSpecification} swapSpec + */ + function updateScrollState(content, swapSpec) { + const first = content[0] + const last = content[content.length - 1] + if (swapSpec.scroll) { + var target = null + if (swapSpec.scrollTarget) { + target = asElement(querySelectorExt(first, swapSpec.scrollTarget)) + } + if (swapSpec.scroll === 'top' && (first || target)) { + target = target || first + target.scrollTop = 0 + } + if (swapSpec.scroll === 'bottom' && (last || target)) { + target = target || last + target.scrollTop = target.scrollHeight + } + } + if (swapSpec.show) { + var target = null + if (swapSpec.showTarget) { + let targetStr = swapSpec.showTarget + if (swapSpec.showTarget === 'window') { + targetStr = 'body' + } + target = asElement(querySelectorExt(first, targetStr)) + } + if (swapSpec.show === 'top' && (first || target)) { + target = target || first + // @ts-ignore For some reason tsc doesn't recognize "instant" as a valid option for now + target.scrollIntoView({ block: 'start', behavior: htmx.config.scrollBehavior }) + } + if (swapSpec.show === 'bottom' && (last || target)) { + target = target || last + // @ts-ignore For some reason tsc doesn't recognize "instant" as a valid option for now + target.scrollIntoView({ block: 'end', behavior: htmx.config.scrollBehavior }) + } + } + } + + /** + * @param {Element} elt + * @param {string} attr + * @param {boolean=} evalAsDefault + * @param {Object=} values + * @returns {Object} + */ + function getValuesForElement(elt, attr, evalAsDefault, values) { + if (values == null) { + values = {} + } + if (elt == null) { + return values + } + const attributeValue = getAttributeValue(elt, attr) + if (attributeValue) { + let str = attributeValue.trim() + let evaluateValue = evalAsDefault + if (str === 'unset') { + return null + } + if (str.indexOf('javascript:') === 0) { + str = str.substr(11) + evaluateValue = true + } else if (str.indexOf('js:') === 0) { + str = str.substr(3) + evaluateValue = true + } + if (str.indexOf('{') !== 0) { + str = '{' + str + '}' + } + let varsValues + if (evaluateValue) { + varsValues = maybeEval(elt, function() { return Function('return (' + str + ')')() }, {}) + } else { + varsValues = parseJSON(str) + } + for (const key in varsValues) { + if (varsValues.hasOwnProperty(key)) { + if (values[key] == null) { + values[key] = varsValues[key] + } + } + } + } + return getValuesForElement(asElement(parentElt(elt)), attr, evalAsDefault, values) + } + + /** + * @param {EventTarget|string} elt + * @param {() => any} toEval + * @param {any=} defaultVal + * @returns {any} + */ + function maybeEval(elt, toEval, defaultVal) { + if (htmx.config.allowEval) { + return toEval() + } else { + triggerErrorEvent(elt, 'htmx:evalDisallowedError') + return defaultVal + } + } + + /** + * @param {Element} elt + * @param {*?} expressionVars + * @returns + */ + function getHXVarsForElement(elt, expressionVars) { + return getValuesForElement(elt, 'hx-vars', true, expressionVars) + } + + /** + * @param {Element} elt + * @param {*?} expressionVars + * @returns + */ + function getHXValsForElement(elt, expressionVars) { + return getValuesForElement(elt, 'hx-vals', false, expressionVars) + } + + /** + * @param {Element} elt + * @returns {FormData} + */ + function getExpressionVars(elt) { + return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)) + } + + /** + * @param {XMLHttpRequest} xhr + * @param {string} header + * @param {string|null} headerValue + */ + function safelySetHeaderValue(xhr, header, headerValue) { + if (headerValue !== null) { + try { + xhr.setRequestHeader(header, headerValue) + } catch (e) { + // On an exception, try to set the header URI encoded instead + xhr.setRequestHeader(header, encodeURIComponent(headerValue)) + xhr.setRequestHeader(header + '-URI-AutoEncoded', 'true') + } + } + } + + /** + * @param {XMLHttpRequest} xhr + * @return {string} + */ + function getPathFromResponse(xhr) { + // NB: IE11 does not support this stuff + if (xhr.responseURL && typeof (URL) !== 'undefined') { + try { + const url = new URL(xhr.responseURL) + return url.pathname + url.search + } catch (e) { + triggerErrorEvent(getDocument().body, 'htmx:badResponseUrl', { url: xhr.responseURL }) + } + } + } + + /** + * @param {XMLHttpRequest} xhr + * @param {RegExp} regexp + * @return {boolean} + */ + function hasHeader(xhr, regexp) { + return regexp.test(xhr.getAllResponseHeaders()) + } + + /** + * Issues an htmx-style AJAX request + * + * @see https://htmx.org/api/#ajax + * + * @param {HttpVerb} verb + * @param {string} path the URL path to make the AJAX + * @param {Element|string|HtmxAjaxHelperContext} context the element to target (defaults to the **body**) | a selector for the target | a context object that contains any of the following + * @return {Promise<void>} Promise that resolves immediately if no request is sent, or when the request is complete + */ + function ajaxHelper(verb, path, context) { + verb = (/** @type HttpVerb */(verb.toLowerCase())) + if (context) { + if (context instanceof Element || typeof context === 'string') { + return issueAjaxRequest(verb, path, null, null, { + targetOverride: resolveTarget(context), + returnPromise: true + }) + } else { + return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, + { + handler: context.handler, + headers: context.headers, + values: context.values, + targetOverride: resolveTarget(context.target), + swapOverride: context.swap, + select: context.select, + returnPromise: true + }) + } + } else { + return issueAjaxRequest(verb, path, null, null, { + returnPromise: true + }) + } + } + + /** + * @param {Element} elt + * @return {Element[]} + */ + function hierarchyForElt(elt) { + const arr = [] + while (elt) { + arr.push(elt) + elt = elt.parentElement + } + return arr + } + + /** + * @param {Element} elt + * @param {string} path + * @param {HtmxRequestConfig} requestConfig + * @return {boolean} + */ + function verifyPath(elt, path, requestConfig) { + let sameHost + let url + if (typeof URL === 'function') { + url = new URL(path, document.location.href) + const origin = document.location.origin + sameHost = origin === url.origin + } else { + // IE11 doesn't support URL + url = path + sameHost = startsWith(path, document.location.origin) + } - //=========================================== - // Next resolve via DOM values - //=========================================== - var requestPath = responseInfo.pathInfo.finalRequestPath; - var responsePath = responseInfo.pathInfo.responsePath; - - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url"); - var elementIsBoosted = getInternalData(elt).boosted; - - var saveType = null; - var path = null; - - if (pushUrl) { - saveType = "push"; - path = pushUrl; - } else if (replaceUrl) { - saveType = "replace"; - path = replaceUrl; - } else if (elementIsBoosted) { - saveType = "push"; - path = responsePath || requestPath; // if there is no response path, go with the original request path - } + if (htmx.config.selfRequestsOnly) { + if (!sameHost) { + return false + } + } + return triggerEvent(elt, 'htmx:validateUrl', mergeObjects({ url, sameHost }, requestConfig)) + } + + /** + * @param {Object|FormData} obj + * @return {FormData} + */ + function formDataFromObject(obj) { + if (obj instanceof FormData) return obj + const formData = new FormData() + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + if (typeof obj[key].forEach === 'function') { + obj[key].forEach(function(v) { formData.append(key, v) }) + } else if (typeof obj[key] === 'object') { + formData.append(key, JSON.stringify(obj[key])) + } else { + formData.append(key, obj[key]) + } + } + } + return formData + } + + /** + * @param {FormData} formData + * @param {string} name + * @param {Array} array + * @returns {Array} + */ + function formDataArrayProxy(formData, name, array) { + // mutating the array should mutate the underlying form data + return new Proxy(array, { + get: function(target, key) { + if (typeof key === 'number') return target[key] + if (key === 'length') return target.length + if (key === 'push') { + return function(value) { + target.push(value) + formData.append(name, value) + } + } + if (typeof target[key] === 'function') { + return function() { + target[key].apply(target, arguments) + formData.delete(name) + target.forEach(function(v) { formData.append(name, v) }) + } + } + + if (target[key] && target[key].length === 1) { + return target[key][0] + } else { + return target[key] + } + }, + set: function(target, index, value) { + target[index] = value + formData.delete(name) + target.forEach(function(v) { formData.append(name, v) }) + return true + } + }) + } + + /** + * @param {FormData} formData + * @returns {Object} + */ + function formDataProxy(formData) { + return new Proxy(formData, { + get: function(target, name) { + if (typeof name === 'symbol') { + // Forward symbol calls to the FormData itself directly + return Reflect.get(target, name) + } + if (name === 'toJSON') { + // Support JSON.stringify call on proxy + return () => Object.fromEntries(formData) + } + if (name in target) { + // Wrap in function with apply to correctly bind the FormData context, as a direct call would result in an illegal invocation error + if (typeof target[name] === 'function') { + return function() { + return formData[name].apply(formData, arguments) + } + } else { + return target[name] + } + } + const array = formData.getAll(name) + // Those 2 undefined & single value returns are for retro-compatibility as we weren't using FormData before + if (array.length === 0) { + return undefined + } else if (array.length === 1) { + return array[0] + } else { + return formDataArrayProxy(target, name, array) + } + }, + set: function(target, name, value) { + if (typeof name !== 'string') { + return false + } + target.delete(name) + if (typeof value.forEach === 'function') { + value.forEach(function(v) { target.append(name, v) }) + } else { + target.append(name, value) + } + return true + }, + deleteProperty: function(target, name) { + if (typeof name === 'string') { + target.delete(name) + } + return true + }, + // Support Object.assign call from proxy + ownKeys: function(target) { + return Reflect.ownKeys(Object.fromEntries(target)) + }, + getOwnPropertyDescriptor: function(target, prop) { + return Reflect.getOwnPropertyDescriptor(Object.fromEntries(target), prop) + } + }) + } + + /** + * @param {HttpVerb} verb + * @param {string} path + * @param {Element} elt + * @param {Event} event + * @param {HtmxAjaxEtc} [etc] + * @param {boolean} [confirmed] + * @return {Promise<void>} + */ + function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { + let resolve = null + let reject = null + etc = etc != null ? etc : {} + if (etc.returnPromise && typeof Promise !== 'undefined') { + var promise = new Promise(function(_resolve, _reject) { + resolve = _resolve + reject = _reject + }) + } + if (elt == null) { + elt = getDocument().body + } + const responseHandler = etc.handler || handleAjaxResponse + const select = etc.select || null - if (path) { - // false indicates no push, return empty object - if (path === "false") { - return {}; - } + if (!bodyContains(elt)) { + // do not issue requests for elements removed from the DOM + maybeCall(resolve) + return promise + } + const target = etc.targetOverride || asElement(getTarget(elt)) + if (target == null || target == DUMMY_ELT) { + triggerErrorEvent(elt, 'htmx:targetError', { target: getAttributeValue(elt, 'hx-target') }) + maybeCall(reject) + return promise + } - // true indicates we want to follow wherever the server ended up sending us - if (path === "true") { - path = responsePath || requestPath; // if there is no response path, go with the original request path - } + let eltData = getInternalData(elt) + const submitter = eltData.lastButtonClicked - // restore any anchor associated with the request - if (responseInfo.pathInfo.anchor && - path.indexOf("#") === -1) { - path = path + "#" + responseInfo.pathInfo.anchor; - } + if (submitter) { + const buttonPath = getRawAttribute(submitter, 'formaction') + if (buttonPath != null) { + path = buttonPath + } - return { - type:saveType, - path: path - } - } else { - return {}; - } + const buttonVerb = getRawAttribute(submitter, 'formmethod') + if (buttonVerb != null) { + // ignore buttons with formmethod="dialog" + if (buttonVerb.toLowerCase() !== 'dialog') { + verb = (/** @type HttpVerb */(buttonVerb)) } + } + } - function handleAjaxResponse(elt, responseInfo) { - var xhr = responseInfo.xhr; - var target = responseInfo.target; - var etc = responseInfo.etc; - var requestConfig = responseInfo.requestConfig; - var select = responseInfo.select; + const confirmQuestion = getClosestAttributeValue(elt, 'hx-confirm') + // allow event-based confirmation w/ a callback + if (confirmed === undefined) { + const issueRequest = function(skipConfirmation) { + return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation) + } + const confirmDetails = { target, elt, path, verb, triggeringEvent: event, etc, issueRequest, question: confirmQuestion } + if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { + maybeCall(resolve) + return promise + } + } - if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; + let syncElt = elt + let syncStrategy = getClosestAttributeValue(elt, 'hx-sync') + let queueStrategy = null + let abortable = false + if (syncStrategy) { + const syncStrings = syncStrategy.split(':') + const selector = syncStrings[0].trim() + if (selector === 'this') { + syncElt = findThisElement(elt, 'hx-sync') + } else { + syncElt = asElement(querySelectorExt(elt, selector)) + } + // default to the drop strategy + syncStrategy = (syncStrings[1] || 'drop').trim() + eltData = getInternalData(syncElt) + if (syncStrategy === 'drop' && eltData.xhr && eltData.abortable !== true) { + maybeCall(resolve) + return promise + } else if (syncStrategy === 'abort') { + if (eltData.xhr) { + maybeCall(resolve) + return promise + } else { + abortable = true + } + } else if (syncStrategy === 'replace') { + triggerEvent(syncElt, 'htmx:abort') // abort the current request and continue + } else if (syncStrategy.indexOf('queue') === 0) { + const queueStrArray = syncStrategy.split(' ') + queueStrategy = (queueStrArray[1] || 'last').trim() + } + } - if (hasHeader(xhr, /HX-Trigger:/i)) { - handleTrigger(xhr, "HX-Trigger", elt); - } + if (eltData.xhr) { + if (eltData.abortable) { + triggerEvent(syncElt, 'htmx:abort') // abort the current request and continue + } else { + if (queueStrategy == null) { + if (event) { + const eventData = getInternalData(event) + if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { + queueStrategy = eventData.triggerSpec.queue + } + } + if (queueStrategy == null) { + queueStrategy = 'last' + } + } + if (eltData.queuedRequests == null) { + eltData.queuedRequests = [] + } + if (queueStrategy === 'first' && eltData.queuedRequests.length === 0) { + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } else if (queueStrategy === 'all') { + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } else if (queueStrategy === 'last') { + eltData.queuedRequests = [] // dump existing queue + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } + maybeCall(resolve) + return promise + } + } - if (hasHeader(xhr, /HX-Location:/i)) { - saveCurrentPageToHistory(); - var redirectPath = xhr.getResponseHeader("HX-Location"); - var swapSpec; - if (redirectPath.indexOf("{") === 0) { - swapSpec = parseJSON(redirectPath); - // what's the best way to throw an error if the user didn't include this - redirectPath = swapSpec['path']; - delete swapSpec['path']; - } - ajaxHelper('GET', redirectPath, swapSpec).then(function(){ - pushUrlIntoHistory(redirectPath); - }); - return; - } + const xhr = new XMLHttpRequest() + eltData.xhr = xhr + eltData.abortable = abortable + const endRequestLock = function() { + eltData.xhr = null + eltData.abortable = false + if (eltData.queuedRequests != null && + eltData.queuedRequests.length > 0) { + const queuedRequest = eltData.queuedRequests.shift() + queuedRequest() + } + } + const promptQuestion = getClosestAttributeValue(elt, 'hx-prompt') + if (promptQuestion) { + var promptResponse = prompt(promptQuestion) + // prompt returns null if cancelled and empty string if accepted with no entry + if (promptResponse === null || + !triggerEvent(elt, 'htmx:prompt', { prompt: promptResponse, target })) { + maybeCall(resolve) + endRequestLock() + return promise + } + } - var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh"); + if (confirmQuestion && !confirmed) { + if (!confirm(confirmQuestion)) { + maybeCall(resolve) + endRequestLock() + return promise + } + } - if (hasHeader(xhr, /HX-Redirect:/i)) { - location.href = xhr.getResponseHeader("HX-Redirect"); - shouldRefresh && location.reload(); - return; - } + let headers = getHeaders(elt, target, promptResponse) - if (shouldRefresh) { - location.reload(); - return; - } + if (verb !== 'get' && !usesFormData(elt)) { + headers['Content-Type'] = 'application/x-www-form-urlencoded' + } - if (hasHeader(xhr,/HX-Retarget:/i)) { - if (xhr.getResponseHeader("HX-Retarget") === "this") { - responseInfo.target = elt; - } else { - responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget")); - } - } + if (etc.headers) { + headers = mergeObjects(headers, etc.headers) + } + const results = getInputValues(elt, verb) + let errors = results.errors + const rawFormData = results.formData + if (etc.values) { + overrideFormData(rawFormData, formDataFromObject(etc.values)) + } + const expressionVars = formDataFromObject(getExpressionVars(elt)) + const allFormData = overrideFormData(rawFormData, expressionVars) + let filteredFormData = filterValues(allFormData, elt) - var historyUpdate = determineHistoryUpdates(elt, responseInfo); - - // by default htmx only swaps on 200 return codes and does not swap - // on 204 'No Content' - // this can be ovverriden by responding to the htmx:beforeSwap event and - // overriding the detail.shouldSwap property - var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; - var serverResponse = xhr.response; - var isError = xhr.status >= 400; - var ignoreTitle = htmx.config.ignoreTitle - var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo); - if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; - - target = beforeSwapDetails.target; // allow re-targeting - serverResponse = beforeSwapDetails.serverResponse; // allow updating content - isError = beforeSwapDetails.isError; // allow updating error - ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title - - responseInfo.target = target; // Make updated target available to response events - responseInfo.failed = isError; // Make failed property available to response events - responseInfo.successful = !isError; // Make successful property available to response events - - if (beforeSwapDetails.shouldSwap) { - if (xhr.status === 286) { - cancelPolling(elt); - } + if (htmx.config.getCacheBusterParam && verb === 'get') { + filteredFormData.set('org.htmx.cache-buster', getRawAttribute(target, 'id') || 'true') + } - withExtensions(elt, function (extension) { - serverResponse = extension.transformResponse(serverResponse, xhr, elt); - }); + // behavior of anchors w/ empty href is to use the current URL + if (path == null || path === '') { + path = getDocument().location.href + } - // Save current page if there will be a history update - if (historyUpdate.type) { - saveCurrentPageToHistory(); - } + /** + * @type {Object} + * @property {boolean} [credentials] + * @property {number} [timeout] + * @property {boolean} [noHeaders] + */ + const requestAttrValues = getValuesForElement(elt, 'hx-request') + + const eltIsBoosted = getInternalData(elt).boosted + + let useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + + /** @type HtmxRequestConfig */ + const requestConfig = { + boosted: eltIsBoosted, + useUrlParams, + formData: filteredFormData, + parameters: formDataProxy(filteredFormData), + unfilteredFormData: allFormData, + unfilteredParameters: formDataProxy(allFormData), + headers, + target, + verb, + errors, + withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, + timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, + path, + triggeringEvent: event + } - var swapOverride = etc.swapOverride; - if (hasHeader(xhr,/HX-Reswap:/i)) { - swapOverride = xhr.getResponseHeader("HX-Reswap"); - } - var swapSpec = getSwapSpecification(elt, swapOverride); + if (!triggerEvent(elt, 'htmx:configRequest', requestConfig)) { + maybeCall(resolve) + endRequestLock() + return promise + } - if (swapSpec.hasOwnProperty('ignoreTitle')) { - ignoreTitle = swapSpec.ignoreTitle; - } + // copy out in case the object was overwritten + path = requestConfig.path + verb = requestConfig.verb + headers = requestConfig.headers + filteredFormData = formDataFromObject(requestConfig.parameters) + errors = requestConfig.errors + useUrlParams = requestConfig.useUrlParams + + if (errors && errors.length > 0) { + triggerEvent(elt, 'htmx:validation:halted', requestConfig) + maybeCall(resolve) + endRequestLock() + return promise + } - target.classList.add(htmx.config.swappingClass); - - // optional transition API promise callbacks - var settleResolve = null; - var settleReject = null; - - var doSwap = function () { - try { - var activeElt = document.activeElement; - var selectionInfo = {}; - try { - selectionInfo = { - elt: activeElt, - // @ts-ignore - start: activeElt ? activeElt.selectionStart : null, - // @ts-ignore - end: activeElt ? activeElt.selectionEnd : null - }; - } catch (e) { - // safari issue - see https://github.com/microsoft/playwright/issues/5894 - } - - var selectOverride; - if (select) { - selectOverride = select; - } - - if (hasHeader(xhr, /HX-Reselect:/i)) { - selectOverride = xhr.getResponseHeader("HX-Reselect"); - } - - // if we need to save history, do so, before swapping so that relative resources have the correct base URL - if (historyUpdate.type) { - triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)); - if (historyUpdate.type === "push") { - pushUrlIntoHistory(historyUpdate.path); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path}); - } else { - replaceUrlInHistory(historyUpdate.path); - triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path}); - } - } - - var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride); - - if (selectionInfo.elt && - !bodyContains(selectionInfo.elt) && - getRawAttribute(selectionInfo.elt, "id")) { - var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id")); - var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; - if (newActiveElt) { - // @ts-ignore - if (selectionInfo.start && newActiveElt.setSelectionRange) { - // @ts-ignore - try { - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); - } catch (e) { - // the setSelectionRange method is present on fields that don't support it, so just let this fail - } - } - newActiveElt.focus(focusOptions); - } - } - - target.classList.remove(htmx.config.swappingClass); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.add(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSwap', responseInfo); - }); - - if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); - } - - var doSettle = function () { - forEach(settleInfo.tasks, function (task) { - task.call(); - }); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.remove(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSettle', responseInfo); - }); - - if (responseInfo.pathInfo.anchor) { - var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor); - if(anchorTarget) { - anchorTarget.scrollIntoView({block:'start', behavior: "auto"}); - } - } - - if(settleInfo.title && !ignoreTitle) { - var titleElt = find("title"); - if(titleElt) { - titleElt.innerHTML = settleInfo.title; - } else { - window.document.title = settleInfo.title; - } - } - - updateScrollState(settleInfo.elts, swapSpec); - - if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); - } - maybeCall(settleResolve); - } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'htmx:swapError', responseInfo); - maybeCall(settleReject); - throw e; - } - }; - - var shouldTransition = htmx.config.globalViewTransitions - if(swapSpec.hasOwnProperty('transition')){ - shouldTransition = swapSpec.transition; - } + const splitPath = path.split('#') + const pathNoAnchor = splitPath[0] + const anchor = splitPath[1] + + let finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor + const hasValues = !filteredFormData.keys().next().done + if (hasValues) { + if (finalPath.indexOf('?') < 0) { + finalPath += '?' + } else { + finalPath += '&' + } + finalPath += urlEncode(filteredFormData) + if (anchor) { + finalPath += '#' + anchor + } + } + } - if(shouldTransition && - triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && - typeof Promise !== "undefined" && document.startViewTransition){ - var settlePromise = new Promise(function (_resolve, _reject) { - settleResolve = _resolve; - settleReject = _reject; - }); - // wrap the original doSwap() in a call to startViewTransition() - var innerDoSwap = doSwap; - doSwap = function() { - document.startViewTransition(function () { - innerDoSwap(); - return settlePromise; - }); - } - } + if (!verifyPath(elt, finalPath, requestConfig)) { + triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) + maybeCall(reject) + return promise + } + xhr.open(verb.toUpperCase(), finalPath, true) + xhr.overrideMimeType('text/html') + xhr.withCredentials = requestConfig.withCredentials + xhr.timeout = requestConfig.timeout - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); - } - } - if (isError) { - triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo)); - } + // request headers + if (requestAttrValues.noHeaders) { + // ignore all headers + } else { + for (const header in headers) { + if (headers.hasOwnProperty(header)) { + const headerValue = headers[header] + safelySetHeaderValue(xhr, header, headerValue) } + } + } - //==================================================================== - // Extensions API - //==================================================================== - - /** @type {Object<string, import("./htmx").HtmxExtension>} */ - var extensions = {}; - - /** - * extensionBase defines the default functions for all extensions. - * @returns {import("./htmx").HtmxExtension} - */ - function extensionBase() { - return { - init: function(api) {return null;}, - onEvent : function(name, evt) {return true;}, - transformResponse : function(text, xhr, elt) {return text;}, - isInlineSwap : function(swapStyle) {return false;}, - handleSwap : function(swapStyle, target, fragment, settleInfo) {return false;}, - encodeParameters : function(xhr, parameters, elt) {return null;} - } - } + /** @type {HtmxResponseInfo} */ + const responseInfo = { + xhr, + target, + requestConfig, + etc, + boosted: eltIsBoosted, + select, + pathInfo: { + requestPath: path, + finalRequestPath: finalPath, + responsePath: null, + anchor + } + } - /** - * defineExtension initializes the extension and adds it to the htmx registry - * - * @param {string} name - * @param {import("./htmx").HtmxExtension} extension - */ - function defineExtension(name, extension) { - if(extension.init) { - extension.init(internalAPI) - } - extensions[name] = mergeObjects(extensionBase(), extension); - } + xhr.onload = function() { + try { + const hierarchy = hierarchyForElt(elt) + responseInfo.pathInfo.responsePath = getPathFromResponse(xhr) + responseHandler(elt, responseInfo) + removeRequestIndicators(indicators, disableElts) + triggerEvent(elt, 'htmx:afterRequest', responseInfo) + triggerEvent(elt, 'htmx:afterOnLoad', responseInfo) + // if the body no longer contains the element, trigger the event on the closest parent + // remaining in the DOM + if (!bodyContains(elt)) { + let secondaryTriggerElt = null + while (hierarchy.length > 0 && secondaryTriggerElt == null) { + const parentEltInHierarchy = hierarchy.shift() + if (bodyContains(parentEltInHierarchy)) { + secondaryTriggerElt = parentEltInHierarchy + } + } + if (secondaryTriggerElt) { + triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo) + triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo) + } + } + maybeCall(resolve) + endRequestLock() + } catch (e) { + triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({ error: e }, responseInfo)) + throw e + } + } + xhr.onerror = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:sendError', responseInfo) + maybeCall(reject) + endRequestLock() + } + xhr.onabort = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo) + maybeCall(reject) + endRequestLock() + } + xhr.ontimeout = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:timeout', responseInfo) + maybeCall(reject) + endRequestLock() + } + if (!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)) { + maybeCall(resolve) + endRequestLock() + return promise + } + var indicators = addRequestIndicatorClasses(elt) + var disableElts = disableElements(elt) + + forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { + forEach([xhr, xhr.upload], function(target) { + target.addEventListener(eventName, function(event) { + triggerEvent(elt, 'htmx:xhr:' + eventName, { + lengthComputable: event.lengthComputable, + loaded: event.loaded, + total: event.total + }) + }) + }) + }) + triggerEvent(elt, 'htmx:beforeSend', responseInfo) + const params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredFormData) + xhr.send(params) + return promise + } + + /** + * @typedef {Object} HtmxHistoryUpdate + * @property {string|null} [type] + * @property {string|null} [path] + */ + + /** + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + * @return {HtmxHistoryUpdate} + */ + function determineHistoryUpdates(elt, responseInfo) { + const xhr = responseInfo.xhr + + //= ========================================== + // First consult response headers + //= ========================================== + let pathFromHeaders = null + let typeFromHeaders = null + if (hasHeader(xhr, /HX-Push:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Push') + typeFromHeaders = 'push' + } else if (hasHeader(xhr, /HX-Push-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Push-Url') + typeFromHeaders = 'push' + } else if (hasHeader(xhr, /HX-Replace-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Replace-Url') + typeFromHeaders = 'replace' + } - /** - * removeExtension removes an extension from the htmx registry - * - * @param {string} name - */ - function removeExtension(name) { - delete extensions[name]; + // if there was a response header, that has priority + if (pathFromHeaders) { + if (pathFromHeaders === 'false') { + return {} + } else { + return { + type: typeFromHeaders, + path: pathFromHeaders } + } + } - /** - * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element - * - * @param {HTMLElement} elt - * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn - * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore - */ - function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + //= ========================================== + // Next resolve via DOM values + //= ========================================== + const requestPath = responseInfo.pathInfo.finalRequestPath + const responsePath = responseInfo.pathInfo.responsePath + + const pushUrl = getClosestAttributeValue(elt, 'hx-push-url') + const replaceUrl = getClosestAttributeValue(elt, 'hx-replace-url') + const elementIsBoosted = getInternalData(elt).boosted + + let saveType = null + let path = null + + if (pushUrl) { + saveType = 'push' + path = pushUrl + } else if (replaceUrl) { + saveType = 'replace' + path = replaceUrl + } else if (elementIsBoosted) { + saveType = 'push' + path = responsePath || requestPath // if there is no response path, go with the original request path + } - if (elt == undefined) { - return extensionsToReturn; - } - if (extensionsToReturn == undefined) { - extensionsToReturn = []; - } - if (extensionsToIgnore == undefined) { - extensionsToIgnore = []; - } - var extensionsForElement = getAttributeValue(elt, "hx-ext"); - if (extensionsForElement) { - forEach(extensionsForElement.split(","), function(extensionName){ - extensionName = extensionName.replace(/ /g, ''); - if (extensionName.slice(0, 7) == "ignore:") { - extensionsToIgnore.push(extensionName.slice(7)); - return; - } - if (extensionsToIgnore.indexOf(extensionName) < 0) { - var extension = extensions[extensionName]; - if (extension && extensionsToReturn.indexOf(extension) < 0) { - extensionsToReturn.push(extension); - } - } - }); - } - return getExtensions(parentElt(elt), extensionsToReturn, extensionsToIgnore); - } + if (path) { + // false indicates no push, return empty object + if (path === 'false') { + return {} + } + + // true indicates we want to follow wherever the server ended up sending us + if (path === 'true') { + path = responsePath || requestPath // if there is no response path, go with the original request path + } + + // restore any anchor associated with the request + if (responseInfo.pathInfo.anchor && path.indexOf('#') === -1) { + path = path + '#' + responseInfo.pathInfo.anchor + } + + return { + type: saveType, + path + } + } else { + return {} + } + } + + /** + * @param {HtmxResponseHandlingConfig} responseHandlingConfig + * @param {number} status + * @return {boolean} + */ + function codeMatches(responseHandlingConfig, status) { + var regExp = new RegExp(responseHandlingConfig.code) + return regExp.test(status.toString(10)) + } + + /** + * @param {XMLHttpRequest} xhr + * @return {HtmxResponseHandlingConfig} + */ + function resolveResponseHandling(xhr) { + for (var i = 0; i < htmx.config.responseHandling.length; i++) { + /** @type HtmxResponseHandlingConfig */ + var responseHandlingElement = htmx.config.responseHandling[i] + if (codeMatches(responseHandlingElement, xhr.status)) { + return responseHandlingElement + } + } + // no matches, return no swap + return { + swap: false + } + } + + /** + * @param {string} title + */ + function handleTitle(title) { + if (title) { + const titleElt = find('title') + if (titleElt) { + titleElt.innerHTML = title + } else { + window.document.title = title + } + } + } + + /** + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + */ + function handleAjaxResponse(elt, responseInfo) { + const xhr = responseInfo.xhr + let target = responseInfo.target + const etc = responseInfo.etc + const responseInfoSelect = responseInfo.select + + if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return + + if (hasHeader(xhr, /HX-Trigger:/i)) { + handleTriggerHeader(xhr, 'HX-Trigger', elt) + } - //==================================================================== - // Initialization - //==================================================================== - var isReady = false - getDocument().addEventListener('DOMContentLoaded', function() { - isReady = true - }) + if (hasHeader(xhr, /HX-Location:/i)) { + saveCurrentPageToHistory() + let redirectPath = xhr.getResponseHeader('HX-Location') + /** @type {HtmxAjaxHelperContext&{path:string}} */ + var redirectSwapSpec + if (redirectPath.indexOf('{') === 0) { + redirectSwapSpec = parseJSON(redirectPath) + // what's the best way to throw an error if the user didn't include this + redirectPath = redirectSwapSpec.path + delete redirectSwapSpec.path + } + ajaxHelper('get', redirectPath, redirectSwapSpec).then(function() { + pushUrlIntoHistory(redirectPath) + }) + return + } - /** - * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. - * - * This function uses isReady because there is no realiable way to ask the browswer whether - * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded - * firing and readystate=complete. - */ - function ready(fn) { - // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by - // some means other than the initial page load. - if (isReady || getDocument().readyState === 'complete') { - fn(); - } else { - getDocument().addEventListener('DOMContentLoaded', fn); - } - } + const shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && xhr.getResponseHeader('HX-Refresh') === 'true' - function insertIndicatorStyles() { - if (htmx.config.includeIndicatorStyles !== false) { - getDocument().head.insertAdjacentHTML("beforeend", - "<style>\ - ." + htmx.config.indicatorClass + "{opacity:0}\ - ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ - ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ - </style>"); - } - } + if (hasHeader(xhr, /HX-Redirect:/i)) { + location.href = xhr.getResponseHeader('HX-Redirect') + shouldRefresh && location.reload() + return + } - function getMetaConfig() { - var element = getDocument().querySelector('meta[name="htmx-config"]'); - if (element) { - // @ts-ignore - return parseJSON(element.content); - } else { - return null; - } - } + if (shouldRefresh) { + location.reload() + return + } - function mergeMetaConfig() { - var metaConfig = getMetaConfig(); - if (metaConfig) { - htmx.config = mergeObjects(htmx.config , metaConfig) - } - } + if (hasHeader(xhr, /HX-Retarget:/i)) { + if (xhr.getResponseHeader('HX-Retarget') === 'this') { + responseInfo.target = elt + } else { + responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget'))) + } + } - // initialize the document - ready(function () { - mergeMetaConfig(); - insertIndicatorStyles(); - var body = getDocument().body; - processNode(body); - var restoredElts = getDocument().querySelectorAll( - "[hx-trigger='restored'],[data-hx-trigger='restored']" - ); - body.addEventListener("htmx:abort", function (evt) { - var target = evt.target; - var internalData = getInternalData(target); - if (internalData && internalData.xhr) { - internalData.xhr.abort(); - } - }); - /** @type {(ev: PopStateEvent) => any} */ - const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null; - /** @type {(ev: PopStateEvent) => any} */ - window.onpopstate = function (event) { - if (event.state && event.state.htmx) { - restoreHistory(); - forEach(restoredElts, function(elt){ - triggerEvent(elt, 'htmx:restored', { - 'document': getDocument(), - 'triggerEvent': triggerEvent - }); - }); - } else { - if (originalPopstate) { - originalPopstate(event); - } - } - }; - setTimeout(function () { - triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event - body = null; // kill reference for gc - }, 0); + const historyUpdate = determineHistoryUpdates(elt, responseInfo) + + const responseHandling = resolveResponseHandling(xhr) + const shouldSwap = responseHandling.swap + let isError = !!responseHandling.error + let ignoreTitle = htmx.config.ignoreTitle || responseHandling.ignoreTitle + let selectOverride = responseHandling.select + if (responseHandling.target) { + responseInfo.target = asElement(querySelectorExt(elt, responseHandling.target)) + } + var swapOverride = etc.swapOverride + if (swapOverride == null && responseHandling.swapOverride) { + swapOverride = responseHandling.swapOverride + } + + // response headers override response handling config + if (hasHeader(xhr, /HX-Retarget:/i)) { + if (xhr.getResponseHeader('HX-Retarget') === 'this') { + responseInfo.target = elt + } else { + responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget'))) + } + } + if (hasHeader(xhr, /HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader('HX-Reswap') + } + + var serverResponse = xhr.response + /** @type HtmxBeforeSwapDetails */ + var beforeSwapDetails = mergeObjects({ + shouldSwap, + serverResponse, + isError, + ignoreTitle, + selectOverride + }, responseInfo) + + if (responseHandling.event && !triggerEvent(target, responseHandling.event, beforeSwapDetails)) return + + if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return + + target = beforeSwapDetails.target // allow re-targeting + serverResponse = beforeSwapDetails.serverResponse // allow updating content + isError = beforeSwapDetails.isError // allow updating error + ignoreTitle = beforeSwapDetails.ignoreTitle // allow updating ignoring title + selectOverride = beforeSwapDetails.selectOverride // allow updating select override + + responseInfo.target = target // Make updated target available to response events + responseInfo.failed = isError // Make failed property available to response events + responseInfo.successful = !isError // Make successful property available to response events + + if (beforeSwapDetails.shouldSwap) { + if (xhr.status === 286) { + cancelPolling(elt) + } + + withExtensions(elt, function(extension) { + serverResponse = extension.transformResponse(serverResponse, xhr, elt) + }) + + // Save current page if there will be a history update + if (historyUpdate.type) { + saveCurrentPageToHistory() + } + + if (hasHeader(xhr, /HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader('HX-Reswap') + } + var swapSpec = getSwapSpecification(elt, swapOverride) + + if (!swapSpec.hasOwnProperty('ignoreTitle')) { + swapSpec.ignoreTitle = ignoreTitle + } + + target.classList.add(htmx.config.swappingClass) + + // optional transition API promise callbacks + let settleResolve = null + let settleReject = null + + if (responseInfoSelect) { + selectOverride = responseInfoSelect + } + + if (hasHeader(xhr, /HX-Reselect:/i)) { + selectOverride = xhr.getResponseHeader('HX-Reselect') + } + + const selectOOB = getClosestAttributeValue(elt, 'hx-select-oob') + const select = getClosestAttributeValue(elt, 'hx-select') + + let doSwap = function() { + try { + // if we need to save history, do so, before swapping so that relative resources have the correct base URL + if (historyUpdate.type) { + triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)) + if (historyUpdate.type === 'push') { + pushUrlIntoHistory(historyUpdate.path) + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', { path: historyUpdate.path }) + } else { + replaceUrlInHistory(historyUpdate.path) + triggerEvent(getDocument().body, 'htmx:replacedInHistory', { path: historyUpdate.path }) + } + } + + swap(target, serverResponse, swapSpec, { + select: selectOverride || select, + selectOOB, + eventInfo: responseInfo, + anchor: responseInfo.pathInfo.anchor, + contextElement: elt, + afterSwapCallback: function() { + if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { + let finalElt = elt + if (!bodyContains(elt)) { + finalElt = getDocument().body + } + handleTriggerHeader(xhr, 'HX-Trigger-After-Swap', finalElt) + } + }, + afterSettleCallback: function() { + if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { + let finalElt = elt + if (!bodyContains(elt)) { + finalElt = getDocument().body + } + handleTriggerHeader(xhr, 'HX-Trigger-After-Settle', finalElt) + } + maybeCall(settleResolve) + } + }) + } catch (e) { + triggerErrorEvent(elt, 'htmx:swapError', responseInfo) + maybeCall(settleReject) + throw e + } + } + + let shouldTransition = htmx.config.globalViewTransitions + if (swapSpec.hasOwnProperty('transition')) { + shouldTransition = swapSpec.transition + } + + if (shouldTransition && + triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && + typeof Promise !== 'undefined' && + // @ts-ignore experimental feature atm + document.startViewTransition) { + const settlePromise = new Promise(function(_resolve, _reject) { + settleResolve = _resolve + settleReject = _reject }) + // wrap the original doSwap() in a call to startViewTransition() + const innerDoSwap = doSwap + doSwap = function() { + // @ts-ignore experimental feature atm + document.startViewTransition(function() { + innerDoSwap() + return settlePromise + }) + } + } + + if (swapSpec.swapDelay > 0) { + getWindow().setTimeout(doSwap, swapSpec.swapDelay) + } else { + doSwap() + } + } + if (isError) { + triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({ error: 'Response Status Error Code ' + xhr.status + ' from ' + responseInfo.pathInfo.requestPath }, responseInfo)) + } + } + + //= =================================================================== + // Extensions API + //= =================================================================== + + /** @type {Object<string, HtmxExtension>} */ + const extensions = {} + + /** + * extensionBase defines the default functions for all extensions. + * @returns {HtmxExtension} + */ + function extensionBase() { + return { + init: function(api) { return null }, + getSelectors: function() { return null }, + onEvent: function(name, evt) { return true }, + transformResponse: function(text, xhr, elt) { return text }, + isInlineSwap: function(swapStyle) { return false }, + handleSwap: function(swapStyle, target, fragment, settleInfo) { return false }, + encodeParameters: function(xhr, parameters, elt) { return null } + } + } + + /** + * defineExtension initializes the extension and adds it to the htmx registry + * + * @see https://htmx.org/api/#defineExtension + * + * @param {string} name the extension name + * @param {HtmxExtension} extension the extension definition + */ + function defineExtension(name, extension) { + if (extension.init) { + extension.init(internalAPI) + } + extensions[name] = mergeObjects(extensionBase(), extension) + } + + /** + * removeExtension removes an extension from the htmx registry + * + * @see https://htmx.org/api/#removeExtension + * + * @param {string} name + */ + function removeExtension(name) { + delete extensions[name] + } + + /** + * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element + * + * @param {Element} elt + * @param {HtmxExtension[]=} extensionsToReturn + * @param {string[]=} extensionsToIgnore + * @returns {HtmxExtension[]} + */ + function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + if (extensionsToReturn == undefined) { + extensionsToReturn = [] + } + if (elt == undefined) { + return extensionsToReturn + } + if (extensionsToIgnore == undefined) { + extensionsToIgnore = [] + } + const extensionsForElement = getAttributeValue(elt, 'hx-ext') + if (extensionsForElement) { + forEach(extensionsForElement.split(','), function(extensionName) { + extensionName = extensionName.replace(/ /g, '') + if (extensionName.slice(0, 7) == 'ignore:') { + extensionsToIgnore.push(extensionName.slice(7)) + return + } + if (extensionsToIgnore.indexOf(extensionName) < 0) { + const extension = extensions[extensionName] + if (extension && extensionsToReturn.indexOf(extension) < 0) { + extensionsToReturn.push(extension) + } + } + }) + } + return getExtensions(asElement(parentElt(elt)), extensionsToReturn, extensionsToIgnore) + } + + //= =================================================================== + // Initialization + //= =================================================================== + var isReady = false + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true + }) + + /** + * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. + * + * This function uses isReady because there is no reliable way to ask the browser whether + * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded + * firing and readystate=complete. + */ + function ready(fn) { + // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by + // some means other than the initial page load. + if (isReady || getDocument().readyState === 'complete') { + fn() + } else { + getDocument().addEventListener('DOMContentLoaded', fn) + } + } + + function insertIndicatorStyles() { + if (htmx.config.includeIndicatorStyles !== false) { + const nonceAttribute = htmx.config.inlineStyleNonce ? ` nonce="${htmx.config.inlineStyleNonce}"` : '' + getDocument().head.insertAdjacentHTML('beforeend', + '<style' + nonceAttribute + '>\ + .' + htmx.config.indicatorClass + '{opacity:0}\ + .' + htmx.config.requestClass + ' .' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\ + .' + htmx.config.requestClass + '.' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\ + </style>') + } + } + + function getMetaConfig() { + /** @type HTMLMetaElement */ + const element = getDocument().querySelector('meta[name="htmx-config"]') + if (element) { + return parseJSON(element.content) + } else { + return null + } + } - return htmx; + function mergeMetaConfig() { + const metaConfig = getMetaConfig() + if (metaConfig) { + htmx.config = mergeObjects(htmx.config, metaConfig) + } + } + + // initialize the document + ready(function() { + mergeMetaConfig() + insertIndicatorStyles() + let body = getDocument().body + processNode(body) + const restoredElts = getDocument().querySelectorAll( + "[hx-trigger='restored'],[data-hx-trigger='restored']" + ) + body.addEventListener('htmx:abort', function(evt) { + const target = evt.target + const internalData = getInternalData(target) + if (internalData && internalData.xhr) { + internalData.xhr.abort() + } + }) + /** @type {(ev: PopStateEvent) => any} */ + const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null + /** @type {(ev: PopStateEvent) => any} */ + window.onpopstate = function(event) { + if (event.state && event.state.htmx) { + restoreHistory() + forEach(restoredElts, function(elt) { + triggerEvent(elt, 'htmx:restored', { + document: getDocument(), + triggerEvent + }) + }) + } else { + if (originalPopstate) { + originalPopstate(event) + } + } } -)() -})); + getWindow().setTimeout(function() { + triggerEvent(body, 'htmx:load', {}) // give ready handlers a chance to load up before firing this event + body = null // kill reference for gc + }, 0) + }) + + return htmx +})() + +/** @typedef {'get'|'head'|'post'|'put'|'delete'|'connect'|'options'|'trace'|'patch'} HttpVerb */ + +/** + * @typedef {Object} SwapOptions + * @property {string} [select] + * @property {string} [selectOOB] + * @property {*} [eventInfo] + * @property {string} [anchor] + * @property {Element} [contextElement] + * @property {swapCallback} [afterSwapCallback] + * @property {swapCallback} [afterSettleCallback] + */ + +/** + * @callback swapCallback + */ + +/** + * @typedef {'innerHTML' | 'outerHTML' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'delete' | 'none' | string} HtmxSwapStyle + */ + +/** + * @typedef HtmxSwapSpecification + * @property {HtmxSwapStyle} swapStyle + * @property {number} swapDelay + * @property {number} settleDelay + * @property {boolean} [transition] + * @property {boolean} [ignoreTitle] + * @property {string} [head] + * @property {'top' | 'bottom'} [scroll] + * @property {string} [scrollTarget] + * @property {string} [show] + * @property {string} [showTarget] + * @property {boolean} [focusScroll] + */ + +/** + * @typedef {((this:Node, evt:Event) => boolean) & {source: string}} ConditionalFunction + */ + +/** + * @typedef {Object} HtmxTriggerSpecification + * @property {string} trigger + * @property {number} [pollInterval] + * @property {ConditionalFunction} [eventFilter] + * @property {boolean} [changed] + * @property {boolean} [once] + * @property {boolean} [consume] + * @property {number} [delay] + * @property {string} [from] + * @property {string} [target] + * @property {number} [throttle] + * @property {string} [queue] + * @property {string} [root] + * @property {string} [threshold] + */ + +/** + * @typedef {{elt: Element, message: string, validity: ValidityState}} HtmxElementValidationError + */ + +/** + * @typedef {Record<string, string>} HtmxHeaderSpecification + * @property {'true'} HX-Request + * @property {string|null} HX-Trigger + * @property {string|null} HX-Trigger-Name + * @property {string|null} HX-Target + * @property {string} HX-Current-URL + * @property {string} [HX-Prompt] + * @property {'true'} [HX-Boosted] + * @property {string} [Content-Type] + * @property {'true'} [HX-History-Restore-Request] + */ + +/** @typedef HtmxAjaxHelperContext + * @property {Element|string} [source] + * @property {Event} [event] + * @property {HtmxAjaxHandler} [handler] + * @property {Element|string} target + * @property {HtmxSwapStyle} [swap] + * @property {Object|FormData} [values] + * @property {Record<string,string>} [headers] + * @property {string} [select] + */ + +/** + * @typedef {Object} HtmxRequestConfig + * @property {boolean} boosted + * @property {boolean} useUrlParams + * @property {FormData} formData + * @property {Object} parameters formData proxy + * @property {FormData} unfilteredFormData + * @property {Object} unfilteredParameters unfilteredFormData proxy + * @property {HtmxHeaderSpecification} headers + * @property {Element} target + * @property {HttpVerb} verb + * @property {HtmxElementValidationError[]} errors + * @property {boolean} withCredentials + * @property {number} timeout + * @property {string} path + * @property {Event} triggeringEvent + */ + +/** + * @typedef {Object} HtmxResponseInfo + * @property {XMLHttpRequest} xhr + * @property {Element} target + * @property {HtmxRequestConfig} requestConfig + * @property {HtmxAjaxEtc} etc + * @property {boolean} boosted + * @property {string} select + * @property {{requestPath: string, finalRequestPath: string, responsePath: string|null, anchor: string}} pathInfo + * @property {boolean} [failed] + * @property {boolean} [successful] + */ + +/** + * @typedef {Object} HtmxAjaxEtc + * @property {boolean} [returnPromise] + * @property {HtmxAjaxHandler} [handler] + * @property {string} [select] + * @property {Element} [targetOverride] + * @property {HtmxSwapStyle} [swapOverride] + * @property {Record<string,string>} [headers] + * @property {Object|FormData} [values] + * @property {boolean} [credentials] + * @property {number} [timeout] + */ + +/** + * @typedef {Object} HtmxResponseHandlingConfig + * @property {string} [code] + * @property {boolean} swap + * @property {boolean} [error] + * @property {boolean} [ignoreTitle] + * @property {string} [select] + * @property {string} [target] + * @property {string} [swapOverride] + * @property {string} [event] + */ + +/** + * @typedef {HtmxResponseInfo & {shouldSwap: boolean, serverResponse: any, isError: boolean, ignoreTitle: boolean, selectOverride:string}} HtmxBeforeSwapDetails + */ + +/** + * @callback HtmxAjaxHandler + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + */ + +/** + * @typedef {(() => void)} HtmxSettleTask + */ + +/** + * @typedef {Object} HtmxSettleInfo + * @property {HtmxSettleTask[]} tasks + * @property {Element[]} elts + * @property {string} [title] + */ + +/** + * @typedef {Object} HtmxExtension + * @see https://htmx.org/extensions/#defining + * @property {(api: any) => void} init + * @property {(name: string, event: Event|CustomEvent) => boolean} onEvent + * @property {(text: string, xhr: XMLHttpRequest, elt: Element) => string} transformResponse + * @property {(swapStyle: HtmxSwapStyle) => boolean} isInlineSwap + * @property {(swapStyle: HtmxSwapStyle, target: Element, fragment: Node, settleInfo: HtmxSettleInfo) => boolean} handleSwap + * @property {(xhr: XMLHttpRequest, parameters: FormData, elt: Element) => *|string|null} encodeParameters + */ diff --git a/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.min.js b/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.min.js index 53bbdf6..d66acce 100644 --- a/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.min.js +++ b/code/ch6_active_search/ch6_starter_video_collector/static/js/htmx.min.js @@ -1,4 +1,2 @@ -// /////////////////////////////////////////////////////////////////// -// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js -// -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(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 a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/<body/.test(e)}function l(e){var t=!N(e);var r=A(e);var n=e;if(r==="head"){n=n.replace(S,"")}if(Q.config.useTemplateFragments&&t){var i=a("<body><template>"+n+"</template></body>",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a("<table>"+n+"</table>",1);case"col":return a("<table><colgroup>"+n+"</colgroup></table>",2);case"tr":return a("<table><tbody>"+n+"</tbody></table>",2);case"td":case"th":return a("<table><tbody><tr>"+n+"</tr></tbody></table>",3);case"script":case"style":return a("<div>"+n+"</div>",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function oe(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function X(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var Y=function(e,t){var r=re().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function we(t,r){oe(t.attributes,function(e){if(!r.hasAttribute(e.name)&&be(e.name)){t.removeAttribute(e.name)}});oe(r.attributes,function(e){if(be(e.name)){t.setAttribute(e.name,e.value)}})}function Se(e,t){var r=Fr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){b(e)}}return e==="outerHTML"}function Ee(e,i,a){var t="#"+ee(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a<i.length;a++){var o=i[a].split(":",2);var s=o[0].trim();if(s.indexOf("#")===0){s=s.substring(1)}var l=o[1]||"true";var u=t.querySelector("#"+s);if(u){Ee(l,u,r)}}}oe(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=te(e,"hx-swap-oob");if(t!=null){Ee(t,e,r)}})}function Re(e){oe(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=te(e,"id");var r=re().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function Te(o,e,s){oe(e.querySelectorAll("[id]"),function(e){var t=ee(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Le(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=He(n.name,t);t=He(n.value,t)}}}return t}function Ae(e){var t=ae(e);if(t.onHandlers){for(var r=0;r<t.onHandlers.length;r++){const n=t.onHandlers[r];e.removeEventListener(n.event,n.listener)}delete t.onHandlers}}function Ne(e){var t=ae(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){oe(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}Ae(e);oe(Object.keys(t),function(e){delete t[e]})}function p(e){ce(e,"htmx:beforeCleanupElement");Ne(e);if(e.children){oe(e.children,function(e){p(e)})}}function Ie(t,e,r){if(t.tagName==="BODY"){return Ue(t,e,r)}else{var n;var i=t.previousSibling;m(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}p(t);u(t).removeChild(t)}}function ke(e,t,r){return m(e,e.firstChild,t,r)}function Pe(e,t,r){return m(u(e),e,t,r)}function Me(e,t,r){return m(e,null,t,r)}function Xe(e,t,r){return m(u(e),e.nextSibling,t,r)}function De(e,t,r){p(e);return u(e).removeChild(e)}function Ue(e,t,r){var n=e.firstChild;m(e,n,t,r);if(n){while(n.nextSibling){p(n.nextSibling);e.removeChild(n.nextSibling)}p(n);e.removeChild(n)}}function Be(e,t,r){var n=r||ne(e,"hx-select");if(n){var i=re().createDocumentFragment();oe(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function Fe(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Ie(r,n,i);return;case"afterbegin":ke(r,n,i);return;case"beforebegin":Pe(r,n,i);return;case"beforeend":Me(r,n,i);return;case"afterend":Xe(r,n,i);return;case"delete":De(r,n,i);return;default:var a=Fr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Oe(f))}}}return}}catch(e){b(e)}}if(e==="innerHTML"){Ue(r,n,i)}else{Fe(Q.config.defaultSwapStyle,t,r,n,i)}}}function Ve(e){if(e.indexOf("<title")>-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){ce(r,s[l].trim(),[])}}}var ze=/\s/;var x=/[\s,]/;var $e=/[_$a-zA-Z]/;var We=/[_$a-zA-Z0-9]/;var Ge=['"',"'","/"];var Je=/[^\s]/;var Ze=/[{(]/;var Ke=/[})]/;function Ye(e){var t=[];var r=0;while(r<e.length){if($e.exec(e.charAt(r))){var n=r;while(We.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ge.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function Qe(e,t,r){return $e.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function et(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){xt(e,a[1],0)}if(a[0]==="send"){bt(e)}}}function xt(s,r,n){if(!se(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=Q.createWebSocket(r);t.onerror=function(e){fe(s,"htmx:wsError",{error:e,socket:t});yt(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a<i.length;a++){var o=i[a];Ee(te(o,"hx-swap-oob")||"true",o,r)}nr(r.tasks)})}function yt(e){if(!se(e)){ae(e).webSocket.close();return true}}function bt(u){var f=c(u,function(e){return ae(e).webSocket!=null});if(f){u.addEventListener(it(u)[0].trigger,function(e){var t=ae(f).webSocket;var r=xr(u,f);var n=dr(u,"post");var i=n.errors;var a=n.values;var o=Hr(u);var s=le(a,o);var l=yr(s,u);l["HEADERS"]=r;if(i&&i.length>0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){Et(e,a[1])}if(a[0]==="swap"){Ct(e,a[1])}}}function Et(t,e){var r=Q.createEventSource(e);r.onerror=function(e){fe(t,"htmx:sseError",{error:e,source:r});Tt(t)};ae(t).sseEventSource=r}function Ct(a,o){var s=c(a,Ot);if(s){var l=ae(s).sseEventSource;var u=function(e){if(Tt(s)){return}if(!se(a)){l.removeEventListener(o,u);return}var t=e.data;R(a,function(e){t=e.transformResponse(t,null,a)});var r=wr(a);var n=ye(a);var i=T(a);je(r.swapStyle,n,a,t,i);nr(i.tasks);ce(a,"htmx:sseMessage",e)};ae(a).sseListener=u;l.addEventListener(o,u)}else{fe(a,"htmx:noSSESourceError")}}function Rt(e,t,r){var n=c(e,Ot);if(n){var i=ae(n).sseEventSource;var a=function(){if(!Tt(n)){if(se(e)){t(e)}else{i.removeEventListener(r,a)}}};ae(e).sseListener=a;i.addEventListener(r,a)}else{fe(e,"htmx:noSSESourceError")}}function Tt(e){if(!se(e)){ae(e).sseEventSource.close();return true}}function Ot(e){return ae(e).sseEventSource!=null}function qt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n>0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){ce(n,"intersect");break}}},i);a.observe(n);ht(n,r,t,e)}else if(e.trigger==="load"){if(!ct(e,n,Wt("load",{elt:n}))){qt(n,r,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r<t.length;r++){var n=t[r].name;if(s(n,"hx-on:")||s(n,"data-hx-on:")||s(n,"hx-on-")||s(n,"data-hx-on-")){return true}}return false}function kt(e){var t=null;var r=[];if(It(e)){r.push(e)}if(document.evaluate){var n=document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]',e);while(t=n.iterateNext())r.push(t)}else{var i=e.getElementsByTagName("*");for(var a=0;a<i.length;a++){if(It(i[a])){r.push(i[a])}}}return r}function Pt(e){if(e.querySelectorAll){var t=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";var r=e.querySelectorAll(i+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Mt(e){var t=v(e.target,"button, input[type='submit']");var r=Dt(e);if(r){r.lastButtonClicked=t}}function Xt(e){var t=Dt(e);if(t){t.lastButtonClicked=null}}function Dt(e){var t=v(e.target,"button, input[type='submit']");if(!t){return}var r=g("#"+ee(t,"form"))||v(t,"form");if(!r){return}return ae(r)}function Ut(e){e.addEventListener("click",Mt);e.addEventListener("focusin",Mt);e.addEventListener("focusout",Xt)}function Bt(e){var t=Ye(e);var r=0;for(var n=0;n<t.length;n++){const i=t[n];if(i==="{"){r++}else if(i==="}"){r--}}return r}function Ft(t,e,r){var n=ae(t);if(!Array.isArray(n.onHandlers)){n.onHandlers=[]}var i;var a=function(e){return Tr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Vt(e){var t=te(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;t<e.attributes.length;t++){var r=e.attributes[t].name;var n=e.attributes[t].value;if(s(r,"hx-on")||s(r,"data-hx-on")){var i=r.indexOf("-on")+3;var a=r.slice(i,i+1);if(a==="-"||a===":"){var o=r.slice(i+1);if(s(o,":")){o="htmx"+o}else if(s(o,"-")){o="htmx:"+o.slice(1)}else if(s(o,"htmx-")){o="htmx:"+o.slice(5)}Ft(e,o,n)}}}}function _t(t){if(v(t,Q.config.disableSelector)){p(t);return}var r=ae(t);if(r.initHash!==Le(t)){Ne(t);r.initHash=Le(t);Vt(t);ce(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=it(t);var n=Ht(t,r,e);if(!n){if(ne(t,"hx-boost")==="true"){lt(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){Lt(t,e,r,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&o(t,"form")){Ut(t)}var i=te(t,"hx-sse");if(i){St(t,r,i)}var a=te(t,"hx-ws");if(a){pt(t,r,a)}ce(t,"htmx:afterProcessNode")}}function zt(e){e=g(e);if(v(e,Q.config.disableSelector)){p(e);return}_t(e);oe(Pt(e),function(e){_t(e)});oe(kt(e),jt)}function $t(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=re().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function fe(e,t,r){ce(e,t,le({error:t},r))}function Gt(e){return e==="htmx:afterProcessNode"}function R(e,t){oe(Fr(e),function(e){try{t(e)}catch(e){b(e)}})}function b(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ce(e,t,r){e=g(e);if(r==null){r={}}r["elt"]=e;var n=Wt(t,r);if(Q.logger&&!Gt(t)){Q.logger(e,t,r)}if(r.error){b(r.error);ce(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=$t(t);if(i&&a!==t){var o=Wt(a,n.detail);i=i&&e.dispatchEvent(o)}R(e,function(e){i=i&&(e.onEvent(t,n)!==false&&!n.defaultPrevented)});return i}var Jt=location.pathname+location.search;function Zt(){var e=re().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||re().body}function Kt(e,t,r,n){if(!U()){return}if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}e=B(e);var i=E(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};ce(re().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Qt(e){var t=Q.config.requestClass;var r=e.cloneNode(true);oe(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function er(){var e=Zt();var t=Jt||location.pathname+location.search;var r;try{r=re().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){r=re().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!r){ce(re().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Kt(t,Qt(e),re().title,window.scrollY)}if(Q.config.historyEnabled)history.replaceState({htmx:true},re().title,window.location.href)}function tr(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(G(e,"&")||G(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Jt=e}function rr(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Jt=e}function nr(e){oe(e,function(e){e.call()})}function ir(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};ce(re().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",re().location.href);e.onload=function(){if(this.status>=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function fr(e){if(e.name===""||e.name==null||e.disabled||v(e,"fieldset[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 cr(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function hr(t,r,n,e,i){if(e==null||ur(t,e)){return}else{t.push(e)}if(fr(e)){var a=ee(e,"name");var o=e.value;if(e.multiple&&e.tagName==="SELECT"){o=M(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=M(e.files)}cr(a,o,r);if(i){vr(e,n)}}if(h(e,"form")){var s=e.elements;oe(s,function(e){hr(t,r,n,e,i)})}}function vr(e,t){if(e.willValidate){ce(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});ce(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function dr(e,t){var r=[];var n={};var i={};var a=[];var o=ae(e);if(o.lastButtonClicked&&!se(o.lastButtonClicked)){o.lastButtonClicked=null}var s=h(e,"form")&&e.noValidate!==true||te(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){hr(r,i,a,v(e,"form"),s)}hr(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=ee(l,"name");cr(u,l.value,i)}var f=pe(e,"hx-include");oe(f,function(e){hr(r,n,a,e,s);if(!h(e,"form")){oe(e.querySelectorAll(rt),function(e){hr(r,n,a,e,s)})}});n=le(n,i);return{errors:a,values:n}}function gr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function mr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t=gr(t,r,e)})}else{t=gr(t,r,n)}}}return t}function pr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function xr(e,t,r){var n={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":re().location.href};Rr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ae(e).boosted){n["HX-Boosted"]="true"}return n}function yr(t,e){var r=ne(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){oe(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};oe(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function br(e){return ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=d(o.substr(5))}else if(o.indexOf("settle:")===0){n["settleDelay"]=d(o.substr(7))}else if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}else if(o.indexOf("ignoreTitle:")===0){n["ignoreTitle"]=o.substr(12)==="true"}else if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","<style> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file +// v2.0.0 from https://github.com/bigskysoftware/htmx/releases +var htmx=function(){"use strict";const Q={onLoad:null,process:null,on:null,off:null,trigger:null,ajax:null,find:null,findAll:null,closest:null,values:function(e,t){const n=cn(e,t||"post");return n.values},remove:null,addClass:null,removeClass:null,toggleClass:null,takeClass:null,swap:null,defineExtension:null,removeExtension:null,logAll:null,logNone:null,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",inlineStyleNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",scrollBehavior:"instant",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get","delete"],selfRequestsOnly:true,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null,disableInheritance:false,responseHandling:[{code:"204",swap:false},{code:"[23]..",swap:true},{code:"[45]..",swap:false,error:true}],allowNestedOobSwaps:true},parseInterval:null,_:null,version:"2.0.0"};Q.onLoad=$;Q.process=Dt;Q.on=be;Q.off=we;Q.trigger=he;Q.ajax=Hn;Q.find=r;Q.findAll=p;Q.closest=g;Q.remove=K;Q.addClass=W;Q.removeClass=o;Q.toggleClass=Y;Q.takeClass=ge;Q.swap=ze;Q.defineExtension=Un;Q.removeExtension=Bn;Q.logAll=z;Q.logNone=J;Q.parseInterval=d;Q._=_;const n={addTriggerHandler:Et,bodyContains:le,canAccessLocalStorage:j,findThisElement:Ee,filterValues:dn,swap:ze,hasAttribute:s,getAttributeValue:te,getClosestAttributeValue:re,getClosestMatch:T,getExpressionVars:Cn,getHeaders:hn,getInputValues:cn,getInternalData:ie,getSwapSpecification:pn,getTriggerSpecs:lt,getTarget:Ce,makeFragment:D,mergeObjects:ue,makeSettleInfo:xn,oobSwap:Te,querySelectorExt:fe,settleImmediately:Gt,shouldCancel:dt,triggerEvent:he,triggerErrorEvent:ae,withExtensions:Ut};const v=["get","post","put","delete","patch"];const R=v.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");const O=e("head");function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e instanceof Element&&e.getAttribute(t)}function s(e,t){return!!e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){const t=e.parentElement;if(!t&&e.parentNode instanceof ShadowRoot)return e.parentNode;return t}function ne(){return document}function H(e,t){return e.getRootNode?e.getRootNode({composed:t}):ne()}function T(e,t){while(e&&!t(e)){e=u(e)}return e||null}function q(e,t,n){const r=te(t,n);const o=te(t,"hx-disinherit");var i=te(t,"hx-inherit");if(e!==t){if(Q.config.disableInheritance){if(i&&(i==="*"||i.split(" ").indexOf(n)>=0)){return r}else{return null}}if(o&&(o==="*"||o.split(" ").indexOf(n)>=0)){return"unset"}}return r}function re(t,n){let r=null;T(t,function(e){return!!(r=q(t,ce(e),n))});if(r!=="unset"){return r}}function a(e,t){const n=e instanceof Element&&(e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector);return!!n&&n.call(e,t)}function L(e){const t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;const n=t.exec(e);if(n){return n[1].toLowerCase()}else{return""}}function N(e){const t=new DOMParser;return t.parseFromString(e,"text/html")}function A(e,t){while(t.childNodes.length>0){e.append(t.childNodes[0])}}function I(e){const t=ne().createElement("script");se(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}return t}function P(e){return e.matches("script")&&(e.type==="text/javascript"||e.type==="module"||e.type==="")}function k(e){Array.from(e.querySelectorAll("script")).forEach(e=>{if(P(e)){const t=I(e);const n=e.parentNode;try{n.insertBefore(t,e)}catch(e){w(e)}finally{e.remove()}}})}function D(e){const t=e.replace(O,"");const n=L(t);let r;if(n==="html"){r=new DocumentFragment;const i=N(e);A(r,i.body);r.title=i.title}else if(n==="body"){r=new DocumentFragment;const i=N(t);A(r,i.body);r.title=i.title}else{const i=N('<body><template class="internal-htmx-wrapper">'+t+"</template></body>");r=i.querySelector("template").content;r.title=i.title;var o=r.querySelector("title");if(o&&o.parentNode===r){o.remove();r.title=o.innerText}}if(r){if(Q.config.allowScriptTags){k(r)}else{r.querySelectorAll("script").forEach(e=>e.remove())}}return r}function oe(e){if(e){e()}}function t(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function M(e){return typeof e==="function"}function X(e){return t(e,"Object")}function ie(e){const t="htmx-internal-data";let n=e[t];if(!n){n=e[t]={}}return n}function F(t){const n=[];if(t){for(let e=0;e<t.length;e++){n.push(t[e])}}return n}function se(t,n){if(t){for(let e=0;e<t.length;e++){n(t[e])}}}function U(e){const t=e.getBoundingClientRect();const n=t.top;const r=t.bottom;return n<window.innerHeight&&r>=0}function le(e){const t=e.getRootNode&&e.getRootNode();if(t&&t instanceof window.ShadowRoot){return ne().body.contains(t.host)}else{return ne().body.contains(e)}}function B(e){return e.trim().split(/\s+/)}function ue(e,t){for(const n in t){if(t.hasOwnProperty(n)){e[n]=t[n]}}return e}function S(e){try{return JSON.parse(e)}catch(e){w(e);return null}}function j(){const e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function V(t){try{const e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function _(e){return vn(ne().body,function(){return eval(e)})}function $(t){const e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function z(){Q.logger=function(e,t,n){if(console){console.log(t,e,n)}}}function J(){Q.logger=null}function r(e,t){if(typeof e!=="string"){return e.querySelector(t)}else{return r(ne(),e)}}function p(e,t){if(typeof e!=="string"){return e.querySelectorAll(t)}else{return p(ne(),e)}}function E(){return window}function K(e,t){e=y(e);if(t){E().setTimeout(function(){K(e);e=null},t)}else{u(e).removeChild(e)}}function ce(e){return e instanceof Element?e:null}function G(e){return e instanceof HTMLElement?e:null}function Z(e){return typeof e==="string"?e:null}function h(e){return e instanceof Element||e instanceof Document||e instanceof DocumentFragment?e:null}function W(e,t,n){e=ce(y(e));if(!e){return}if(n){E().setTimeout(function(){W(e,t);e=null},n)}else{e.classList&&e.classList.add(t)}}function o(e,t,n){let r=ce(y(e));if(!r){return}if(n){E().setTimeout(function(){o(r,t);r=null},n)}else{if(r.classList){r.classList.remove(t);if(r.classList.length===0){r.removeAttribute("class")}}}}function Y(e,t){e=y(e);e.classList.toggle(t)}function ge(e,t){e=y(e);se(e.parentElement.children,function(e){o(e,t)});W(ce(e),t)}function g(e,t){e=ce(y(e));if(e&&e.closest){return e.closest(t)}else{do{if(e==null||a(e,t)){return e}}while(e=e&&ce(u(e)));return null}}function l(e,t){return e.substring(0,t.length)===t}function pe(e,t){return e.substring(e.length-t.length)===t}function i(e){const t=e.trim();if(l(t,"<")&&pe(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function m(e,t,n){e=y(e);if(t.indexOf("closest ")===0){return[g(ce(e),i(t.substr(8)))]}else if(t.indexOf("find ")===0){return[r(h(e),i(t.substr(5)))]}else if(t==="next"){return[ce(e).nextElementSibling]}else if(t.indexOf("next ")===0){return[me(e,i(t.substr(5)),!!n)]}else if(t==="previous"){return[ce(e).previousElementSibling]}else if(t.indexOf("previous ")===0){return[ye(e,i(t.substr(9)),!!n)]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else if(t==="root"){return[H(e,!!n)]}else if(t.indexOf("global ")===0){return m(e,t.slice(7),true)}else{return F(h(H(e,!!n)).querySelectorAll(i(t)))}}var me=function(t,e,n){const r=h(H(t,n)).querySelectorAll(e);for(let e=0;e<r.length;e++){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_PRECEDING){return o}}};var ye=function(t,e,n){const r=h(H(t,n)).querySelectorAll(e);for(let e=r.length-1;e>=0;e--){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_FOLLOWING){return o}}};function fe(e,t){if(typeof e!=="string"){return m(e,t)[0]}else{return m(ne().body,e)[0]}}function y(e,t){if(typeof e==="string"){return r(h(t)||document,e)}else{return e}}function xe(e,t,n){if(M(t)){return{target:ne().body,event:Z(e),listener:t}}else{return{target:y(e),event:Z(t),listener:n}}}function be(t,n,r){_n(function(){const e=xe(t,n,r);e.target.addEventListener(e.event,e.listener)});const e=M(n);return e?n:r}function we(t,n,r){_n(function(){const e=xe(t,n,r);e.target.removeEventListener(e.event,e.listener)});return M(n)?n:r}const ve=ne().createElement("output");function Se(e,t){const n=re(e,t);if(n){if(n==="this"){return[Ee(e,t)]}else{const r=m(e,n);if(r.length===0){w('The selector "'+n+'" on '+t+" returned no matches!");return[ve]}else{return r}}}}function Ee(e,t){return ce(T(e,function(e){return te(ce(e),t)!=null}))}function Ce(e){const t=re(e,"hx-target");if(t){if(t==="this"){return Ee(e,"hx-target")}else{return fe(e,t)}}else{const n=ie(e);if(n.boosted){return ne().body}else{return e}}}function Re(t){const n=Q.config.attributesToSettle;for(let e=0;e<n.length;e++){if(t===n[e]){return true}}return false}function Oe(t,n){se(t.attributes,function(e){if(!n.hasAttribute(e.name)&&Re(e.name)){t.removeAttribute(e.name)}});se(n.attributes,function(e){if(Re(e.name)){t.setAttribute(e.name,e.value)}})}function He(t,e){const n=jn(e);for(let e=0;e<n.length;e++){const r=n[e];try{if(r.isInlineSwap(t)){return true}}catch(e){w(e)}}return t==="outerHTML"}function Te(e,o,i){let t="#"+ee(o,"id");let s="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){s=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{s=e}const n=ne().querySelectorAll(t);if(n){se(n,function(e){let t;const n=o.cloneNode(true);t=ne().createDocumentFragment();t.appendChild(n);if(!He(s,e)){t=h(n)}const r={shouldSwap:true,target:e,fragment:t};if(!he(e,"htmx:oobBeforeSwap",r))return;e=r.target;if(r.shouldSwap){_e(s,e,e,t,i)}se(i.elts,function(e){he(e,"htmx:oobAfterSwap",r)})});o.parentNode.removeChild(o)}else{o.parentNode.removeChild(o);ae(ne().body,"htmx:oobErrorNoTarget",{content:o})}return e}function qe(e){se(p(e,"[hx-preserve], [data-hx-preserve]"),function(e){const t=te(e,"id");const n=ne().getElementById(t);if(n!=null){e.parentNode.replaceChild(n,e)}})}function Le(l,e,u){se(e.querySelectorAll("[id]"),function(t){const n=ee(t,"id");if(n&&n.length>0){const r=n.replace("'","\\'");const o=t.tagName.replace(":","\\:");const e=h(l);const i=e&&e.querySelector(o+"[id='"+r+"']");if(i&&i!==e){const s=t.cloneNode();Oe(t,i);u.tasks.push(function(){Oe(t,s)})}}})}function Ne(e){return function(){o(e,Q.config.addedClass);Dt(ce(e));Ae(h(e));he(e,"htmx:load")}}function Ae(e){const t="[autofocus]";const n=G(a(e,t)?e:e.querySelector(t));if(n!=null){n.focus()}}function c(e,t,n,r){Le(e,n,r);while(n.childNodes.length>0){const o=n.firstChild;W(ce(o),Q.config.addedClass);e.insertBefore(o,t);if(o.nodeType!==Node.TEXT_NODE&&o.nodeType!==Node.COMMENT_NODE){r.tasks.push(Ne(o))}}}function Ie(e,t){let n=0;while(n<e.length){t=(t<<5)-t+e.charCodeAt(n++)|0}return t}function Pe(t){let n=0;if(t.attributes){for(let e=0;e<t.attributes.length;e++){const r=t.attributes[e];if(r.value){n=Ie(r.name,n);n=Ie(r.value,n)}}}return n}function ke(t){const n=ie(t);if(n.onHandlers){for(let e=0;e<n.onHandlers.length;e++){const r=n.onHandlers[e];we(t,r.event,r.listener)}delete n.onHandlers}}function De(e){const t=ie(e);if(t.timeout){clearTimeout(t.timeout)}if(t.listenerInfos){se(t.listenerInfos,function(e){if(e.on){we(e.on,e.trigger,e.listener)}})}ke(e);se(Object.keys(t),function(e){delete t[e]})}function f(e){he(e,"htmx:beforeCleanupElement");De(e);if(e.children){se(e.children,function(e){f(e)})}}function Me(t,e,n){let r;const o=t.previousSibling;c(u(t),t,e,n);if(o==null){r=u(t).firstChild}else{r=o.nextSibling}n.elts=n.elts.filter(function(e){return e!==t});while(r&&r!==t){if(r instanceof Element){n.elts.push(r);r=r.nextElementSibling}else{r=null}}f(t);if(t instanceof Element){t.remove()}else{t.parentNode.removeChild(t)}}function Xe(e,t,n){return c(e,e.firstChild,t,n)}function Fe(e,t,n){return c(u(e),e,t,n)}function Ue(e,t,n){return c(e,null,t,n)}function Be(e,t,n){return c(u(e),e.nextSibling,t,n)}function je(e){f(e);return u(e).removeChild(e)}function Ve(e,t,n){const r=e.firstChild;c(e,r,t,n);if(r){while(r.nextSibling){f(r.nextSibling);e.removeChild(r.nextSibling)}f(r);e.removeChild(r)}}function _e(t,e,n,r,o){switch(t){case"none":return;case"outerHTML":Me(n,r,o);return;case"afterbegin":Xe(n,r,o);return;case"beforebegin":Fe(n,r,o);return;case"beforeend":Ue(n,r,o);return;case"afterend":Be(n,r,o);return;case"delete":je(n);return;default:var i=jn(e);for(let e=0;e<i.length;e++){const s=i[e];try{const l=s.handleSwap(t,n,r,o);if(l){if(typeof l.length!=="undefined"){for(let e=0;e<l.length;e++){const u=l[e];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){o.tasks.push(Ne(u))}}}return}}catch(e){w(e)}}if(t==="innerHTML"){Ve(n,r,o)}else{_e(Q.config.defaultSwapStyle,e,n,r,o)}}}function $e(e,n){se(p(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){if(Q.config.allowNestedOobSwaps||e.parentElement===null){const t=te(e,"hx-swap-oob");if(t!=null){Te(t,e,n)}}else{e.removeAttribute("hx-swap-oob");e.removeAttribute("data-hx-swap-oob")}})}function ze(e,t,r,o){if(!o){o={}}e=y(e);const n=document.activeElement;let i={};try{i={elt:n,start:n?n.selectionStart:null,end:n?n.selectionEnd:null}}catch(e){}const s=xn(e);if(r.swapStyle==="textContent"){e.textContent=t}else{let n=D(t);s.title=n.title;if(o.selectOOB){const u=o.selectOOB.split(",");for(let t=0;t<u.length;t++){const c=u[t].split(":",2);let e=c[0].trim();if(e.indexOf("#")===0){e=e.substring(1)}const f=c[1]||"true";const a=n.querySelector("#"+e);if(a){Te(f,a,s)}}}$e(n,s);se(p(n,"template"),function(e){$e(e.content,s);if(e.content.childElementCount===0){e.remove()}});if(o.select){const h=ne().createDocumentFragment();se(n.querySelectorAll(o.select),function(e){h.appendChild(e)});n=h}qe(n);_e(r.swapStyle,o.contextElement,e,n,s)}if(i.elt&&!le(i.elt)&&ee(i.elt,"id")){const d=document.getElementById(ee(i.elt,"id"));const g={preventScroll:r.focusScroll!==undefined?!r.focusScroll:!Q.config.defaultFocusScroll};if(d){if(i.start&&d.setSelectionRange){try{d.setSelectionRange(i.start,i.end)}catch(e){}}d.focus(g)}}e.classList.remove(Q.config.swappingClass);se(s.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}he(e,"htmx:afterSwap",o.eventInfo)});if(o.afterSwapCallback){o.afterSwapCallback()}if(!r.ignoreTitle){Dn(s.title)}const l=function(){se(s.tasks,function(e){e.call()});se(s.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}he(e,"htmx:afterSettle",o.eventInfo)});if(o.anchor){const e=ce(y("#"+o.anchor));if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}bn(s.elts,r);if(o.afterSettleCallback){o.afterSettleCallback()}};if(r.settleDelay>0){E().setTimeout(l,r.settleDelay)}else{l()}}function Je(e,t,n){const r=e.getResponseHeader(t);if(r.indexOf("{")===0){const o=S(r);for(const i in o){if(o.hasOwnProperty(i)){let e=o[i];if(!X(e)){e={value:e}}he(n,i,e)}}}else{const s=r.split(",");for(let e=0;e<s.length;e++){he(n,s[e].trim(),[])}}}const Ke=/\s/;const x=/[\s,]/;const Ge=/[_$a-zA-Z]/;const Ze=/[_$a-zA-Z0-9]/;const We=['"',"'","/"];const Ye=/[^\s]/;const Qe=/[{(]/;const et=/[})]/;function tt(e){const t=[];let n=0;while(n<e.length){if(Ge.exec(e.charAt(n))){var r=n;while(Ze.exec(e.charAt(n+1))){n++}t.push(e.substr(r,n-r+1))}else if(We.indexOf(e.charAt(n))!==-1){const o=e.charAt(n);var r=n;n++;while(n<e.length&&e.charAt(n)!==o){if(e.charAt(n)==="\\"){n++}n++}t.push(e.substr(r,n-r+1))}else{const i=e.charAt(n);t.push(i)}n++}return t}function nt(e,t,n){return Ge.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==n&&t!=="."}function rt(r,o,i){if(o[0]==="["){o.shift();let e=1;let t=" return (function("+i+"){ return (";let n=null;while(o.length>0){const s=o[0];if(s==="]"){e--;if(e===0){if(n===null){t=t+"true"}o.shift();t+=")})";try{const l=vn(r,function(){return Function(t)()},function(){return true});l.source=t;return l}catch(e){ae(ne().body,"htmx:syntax:error",{error:e,source:t});return null}}}else if(s==="["){e++}if(nt(s,n,i)){t+="(("+i+"."+s+") ? ("+i+"."+s+") : (window."+s+"))"}else{t=t+s}n=o.shift()}}}function b(e,t){let n="";while(e.length>0&&!t.test(e[0])){n+=e.shift()}return n}function ot(e){let t;if(e.length>0&&Qe.test(e[0])){e.shift();t=b(e,et).trim();e.shift()}else{t=b(e,x)}return t}const it="input, textarea, select";function st(e,t,n){const r=[];const o=tt(t);do{b(o,Ye);const l=o.length;const u=b(o,/[,\[\s]/);if(u!==""){if(u==="every"){const c={trigger:"every"};b(o,Ye);c.pollInterval=d(b(o,/[,\[\s]/));b(o,Ye);var i=rt(e,o,"event");if(i){c.eventFilter=i}r.push(c)}else{const f={trigger:u};var i=rt(e,o,"event");if(i){f.eventFilter=i}while(o.length>0&&o[0]!==","){b(o,Ye);const a=o.shift();if(a==="changed"){f.changed=true}else if(a==="once"){f.once=true}else if(a==="consume"){f.consume=true}else if(a==="delay"&&o[0]===":"){o.shift();f.delay=d(b(o,x))}else if(a==="from"&&o[0]===":"){o.shift();if(Qe.test(o[0])){var s=ot(o)}else{var s=b(o,x);if(s==="closest"||s==="find"||s==="next"||s==="previous"){o.shift();const h=ot(o);if(h.length>0){s+=" "+h}}}f.from=s}else if(a==="target"&&o[0]===":"){o.shift();f.target=ot(o)}else if(a==="throttle"&&o[0]===":"){o.shift();f.throttle=d(b(o,x))}else if(a==="queue"&&o[0]===":"){o.shift();f.queue=b(o,x)}else if(a==="root"&&o[0]===":"){o.shift();f[a]=ot(o)}else if(a==="threshold"&&o[0]===":"){o.shift();f[a]=b(o,x)}else{ae(e,"htmx:syntax:error",{token:o.shift()})}}r.push(f)}}if(o.length===l){ae(e,"htmx:syntax:error",{token:o.shift()})}b(o,Ye)}while(o[0]===","&&o.shift());if(n){n[t]=r}return r}function lt(e){const t=te(e,"hx-trigger");let n=[];if(t){const r=Q.config.triggerSpecsCache;n=r&&r[t]||st(e,t,r)}if(n.length>0){return n}else if(a(e,"form")){return[{trigger:"submit"}]}else if(a(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(a(e,it)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function ut(e){ie(e).cancelled=true}function ct(e,t,n){const r=ie(e);r.timeout=E().setTimeout(function(){if(le(e)&&r.cancelled!==true){if(!pt(n,e,Xt("hx:poll:trigger",{triggerSpec:n,target:e}))){t(e)}ct(e,t,n)}},n.pollInterval)}function ft(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function at(e){return g(e,Q.config.disableSelector)}function ht(t,n,e){if(t instanceof HTMLAnchorElement&&ft(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){n.boosted=true;let r,o;if(t.tagName==="A"){r="get";o=ee(t,"href")}else{const i=ee(t,"method");r=i?i.toLowerCase():"get";if(r==="get"){}o=ee(t,"action")}e.forEach(function(e){mt(t,function(e,t){const n=ce(e);if(at(n)){f(n);return}de(r,o,n,t)},n,e,true)})}}function dt(e,t){const n=ce(t);if(!n){return false}if(e.type==="submit"||e.type==="click"){if(n.tagName==="FORM"){return true}if(a(n,'input[type="submit"], button')&&g(n,"form")!==null){return true}if(n instanceof HTMLAnchorElement&&n.href&&(n.getAttribute("href")==="#"||n.getAttribute("href").indexOf("#")!==0)){return true}}return false}function gt(e,t){return ie(e).boosted&&e instanceof HTMLAnchorElement&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function pt(e,t,n){const r=e.eventFilter;if(r){try{return r.call(t,n)!==true}catch(e){const o=r.source;ae(ne().body,"htmx:eventFilter:error",{error:e,source:o});return true}}return false}function mt(s,l,e,u,c){const f=ie(s);let t;if(u.from){t=m(s,u.from)}else{t=[s]}if(u.changed){t.forEach(function(e){const t=ie(e);t.lastValue=e.value})}se(t,function(o){const i=function(e){if(!le(s)){o.removeEventListener(u.trigger,i);return}if(gt(s,e)){return}if(c||dt(e,s)){e.preventDefault()}if(pt(u,s,e)){return}const t=ie(e);t.triggerSpec=u;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(s)<0){t.handledFor.push(s);if(u.consume){e.stopPropagation()}if(u.target&&e.target){if(!a(ce(e.target),u.target)){return}}if(u.once){if(f.triggeredOnce){return}else{f.triggeredOnce=true}}if(u.changed){const n=ie(o);const r=o.value;if(n.lastValue===r){return}n.lastValue=r}if(f.delayed){clearTimeout(f.delayed)}if(f.throttle){return}if(u.throttle>0){if(!f.throttle){l(s,e);f.throttle=E().setTimeout(function(){f.throttle=null},u.throttle)}}else if(u.delay>0){f.delayed=E().setTimeout(function(){l(s,e)},u.delay)}else{he(s,"htmx:trigger");l(s,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:u.trigger,listener:i,on:o});o.addEventListener(u.trigger,i)})}let yt=false;let xt=null;function bt(){if(!xt){xt=function(){yt=true};window.addEventListener("scroll",xt);setInterval(function(){if(yt){yt=false;se(ne().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"),function(e){wt(e)})}},200)}}function wt(e){if(!s(e,"data-hx-revealed")&&U(e)){e.setAttribute("data-hx-revealed","true");const t=ie(e);if(t.initHash){he(e,"revealed")}else{e.addEventListener("htmx:afterProcessNode",function(){he(e,"revealed")},{once:true})}}}function vt(e,t,n,r){const o=function(){if(!n.loaded){n.loaded=true;t(e)}};if(r>0){E().setTimeout(o,r)}else{o()}}function St(t,n,e){let i=false;se(v,function(r){if(s(t,"hx-"+r)){const o=te(t,"hx-"+r);i=true;n.path=o;n.verb=r;e.forEach(function(e){Et(t,e,n,function(e,t){const n=ce(e);if(g(n,Q.config.disableSelector)){f(n);return}de(r,o,n,t)})})}});return i}function Et(r,e,t,n){if(e.trigger==="revealed"){bt();mt(r,n,t,e);wt(ce(r))}else if(e.trigger==="intersect"){const o={};if(e.root){o.root=fe(r,e.root)}if(e.threshold){o.threshold=parseFloat(e.threshold)}const i=new IntersectionObserver(function(t){for(let e=0;e<t.length;e++){const n=t[e];if(n.isIntersecting){he(r,"intersect");break}}},o);i.observe(ce(r));mt(ce(r),n,t,e)}else if(e.trigger==="load"){if(!pt(e,r,Xt("load",{elt:r}))){vt(ce(r),n,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ct(ce(r),n,e)}else{mt(r,n,t,e)}}function Ct(e){const t=ce(e);if(!t){return false}const n=t.attributes;for(let e=0;e<n.length;e++){const r=n[e].name;if(l(r,"hx-on:")||l(r,"data-hx-on:")||l(r,"hx-on-")||l(r,"data-hx-on-")){return true}}return false}const Rt=(new XPathEvaluator).createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]');function Ot(e,t){if(Ct(e)){t.push(ce(e))}const n=Rt.evaluate(e);let r=null;while(r=n.iterateNext())t.push(ce(r))}function Ht(e){const t=[];if(e instanceof DocumentFragment){for(const n of e.childNodes){Ot(n,t)}}else{Ot(e,t)}return t}function Tt(e){if(e.querySelectorAll){const n=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";const r=[];for(const i in Xn){const s=Xn[i];if(s.getSelectors){var t=s.getSelectors();if(t){r.push(t)}}}const o=e.querySelectorAll(R+n+", form, [type='submit'],"+" [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]"+r.flat().map(e=>", "+e).join(""));return o}else{return[]}}function qt(e){const t=g(ce(e.target),"button, input[type='submit']");const n=Nt(e);if(n){n.lastButtonClicked=t}}function Lt(e){const t=Nt(e);if(t){t.lastButtonClicked=null}}function Nt(e){const t=g(ce(e.target),"button, input[type='submit']");if(!t){return}const n=y("#"+ee(t,"form"),t.getRootNode())||g(t,"form");if(!n){return}return ie(n)}function At(e){e.addEventListener("click",qt);e.addEventListener("focusin",qt);e.addEventListener("focusout",Lt)}function It(t,e,n){const r=ie(t);if(!Array.isArray(r.onHandlers)){r.onHandlers=[]}let o;const i=function(e){vn(t,function(){if(at(t)){return}if(!o){o=new Function("event",n)}o.call(t,e)})};t.addEventListener(e,i);r.onHandlers.push({event:e,listener:i})}function Pt(t){ke(t);for(let e=0;e<t.attributes.length;e++){const n=t.attributes[e].name;const r=t.attributes[e].value;if(l(n,"hx-on")||l(n,"data-hx-on")){const o=n.indexOf("-on")+3;const i=n.slice(o,o+1);if(i==="-"||i===":"){let e=n.slice(o+1);if(l(e,":")){e="htmx"+e}else if(l(e,"-")){e="htmx:"+e.slice(1)}else if(l(e,"htmx-")){e="htmx:"+e.slice(5)}It(t,e,r)}}}}function kt(t){if(g(t,Q.config.disableSelector)){f(t);return}const n=ie(t);if(n.initHash!==Pe(t)){De(t);n.initHash=Pe(t);he(t,"htmx:beforeProcessNode");if(t.value){n.lastValue=t.value}const e=lt(t);const r=St(t,n,e);if(!r){if(re(t,"hx-boost")==="true"){ht(t,n,e)}else if(s(t,"hx-trigger")){e.forEach(function(e){Et(t,e,n,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&s(t,"form")){At(t)}he(t,"htmx:afterProcessNode")}}function Dt(e){e=y(e);if(g(e,Q.config.disableSelector)){f(e);return}kt(e);se(Tt(e),function(e){kt(e)});se(Ht(e),Pt)}function Mt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Xt(e,t){let n;if(window.CustomEvent&&typeof window.CustomEvent==="function"){n=new CustomEvent(e,{bubbles:true,cancelable:true,composed:true,detail:t})}else{n=ne().createEvent("CustomEvent");n.initCustomEvent(e,true,true,t)}return n}function ae(e,t,n){he(e,t,ue({error:t},n))}function Ft(e){return e==="htmx:afterProcessNode"}function Ut(e,t){se(jn(e),function(e){try{t(e)}catch(e){w(e)}})}function w(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function he(e,t,n){e=y(e);if(n==null){n={}}n.elt=e;const r=Xt(t,n);if(Q.logger&&!Ft(t)){Q.logger(e,t,n)}if(n.error){w(n.error);he(e,"htmx:error",{errorInfo:n})}let o=e.dispatchEvent(r);const i=Mt(t);if(o&&i!==t){const s=Xt(i,r.detail);o=o&&e.dispatchEvent(s)}Ut(ce(e),function(e){o=o&&(e.onEvent(t,r)!==false&&!r.defaultPrevented)});return o}let Bt=location.pathname+location.search;function jt(){const e=ne().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||ne().body}function Vt(t,e){if(!j()){return}const n=$t(e);const r=ne().title;const o=window.scrollY;if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}t=V(t);const i=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e<i.length;e++){if(i[e].url===t){i.splice(e,1);break}}const s={url:t,content:n,title:r,scroll:o};he(ne().body,"htmx:historyItemCreated",{item:s,cache:i});i.push(s);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ae(ne().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function _t(t){if(!j()){return null}t=V(t);const n=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e<n.length;e++){if(n[e].url===t){return n[e]}}return null}function $t(e){const t=Q.config.requestClass;const n=e.cloneNode(true);se(p(n,"."+t),function(e){o(e,t)});return n.innerHTML}function zt(){const e=jt();const t=Bt||location.pathname+location.search;let n;try{n=ne().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){n=ne().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!n){he(ne().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Vt(t,e)}if(Q.config.historyEnabled)history.replaceState({htmx:true},ne().title,window.location.href)}function Jt(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(pe(e,"&")||pe(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Bt=e}function Kt(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Bt=e}function Gt(e){se(e,function(e){e.call(undefined)})}function Zt(o){const e=new XMLHttpRequest;const i={path:o,xhr:e};he(ne().body,"htmx:historyCacheMiss",i);e.open("GET",o,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",ne().location.href);e.onload=function(){if(this.status>=200&&this.status<400){he(ne().body,"htmx:historyCacheMissLoad",i);const e=D(this.response);const t=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;const n=jt();const r=xn(n);Dn(e.title);Ve(n,t,r);Gt(r.tasks);Bt=o;he(ne().body,"htmx:historyRestore",{path:o,cacheMiss:true,serverResponse:this.response})}else{ae(ne().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Wt(e){zt();e=e||location.pathname+location.search;const t=_t(e);if(t){const n=D(t.content);const r=jt();const o=xn(r);Dn(n.title);Ve(r,n,o);Gt(o.tasks);E().setTimeout(function(){window.scrollTo(0,t.scroll)},0);Bt=e;he(ne().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{Zt(e)}}}function Yt(e){let t=Se(e,"hx-indicator");if(t==null){t=[e]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.classList.add.call(e.classList,Q.config.requestClass)});return t}function Qt(e){let t=Se(e,"hx-disabled-elt");if(t==null){t=[]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function en(e,t){se(e,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList.remove.call(e.classList,Q.config.requestClass)}});se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function tn(t,n){for(let e=0;e<t.length;e++){const r=t[e];if(r.isSameNode(n)){return true}}return false}function nn(e){const t=e;if(t.name===""||t.name==null||t.disabled||g(t,"fieldset[disabled]")){return false}if(t.type==="button"||t.type==="submit"||t.tagName==="image"||t.tagName==="reset"||t.tagName==="file"){return false}if(t.type==="checkbox"||t.type==="radio"){return t.checked}return true}function rn(t,e,n){if(t!=null&&e!=null){if(Array.isArray(e)){e.forEach(function(e){n.append(t,e)})}else{n.append(t,e)}}}function on(t,n,r){if(t!=null&&n!=null){let e=r.getAll(t);if(Array.isArray(n)){e=e.filter(e=>n.indexOf(e)<0)}else{e=e.filter(e=>e!==n)}r.delete(t);se(e,e=>r.append(t,e))}}function sn(t,n,r,o,i){if(o==null||tn(t,o)){return}else{t.push(o)}if(nn(o)){const s=ee(o,"name");let e=o.value;if(o instanceof HTMLSelectElement&&o.multiple){e=F(o.querySelectorAll("option:checked")).map(function(e){return e.value})}if(o instanceof HTMLInputElement&&o.files){e=F(o.files)}rn(s,e,n);if(i){ln(o,r)}}if(o instanceof HTMLFormElement){se(o.elements,function(e){if(t.indexOf(e)>=0){on(e.name,e.value,n)}else{t.push(e)}if(i){ln(e,r)}});new FormData(o).forEach(function(e,t){if(e instanceof File&&e.name===""){return}rn(t,e,n)})}}function ln(e,t){const n=e;if(n.willValidate){he(n,"htmx:validation:validate");if(!n.checkValidity()){t.push({elt:n,message:n.validationMessage,validity:n.validity});he(n,"htmx:validation:failed",{message:n.validationMessage,validity:n.validity})}}}function un(t,e){for(const n of e.keys()){t.delete(n);e.getAll(n).forEach(function(e){t.append(n,e)})}return t}function cn(e,t){const n=[];const r=new FormData;const o=new FormData;const i=[];const s=ie(e);if(s.lastButtonClicked&&!le(s.lastButtonClicked)){s.lastButtonClicked=null}let l=e instanceof HTMLFormElement&&e.noValidate!==true||te(e,"hx-validate")==="true";if(s.lastButtonClicked){l=l&&s.lastButtonClicked.formNoValidate!==true}if(t!=="get"){sn(n,o,i,g(e,"form"),l)}sn(n,r,i,e,l);if(s.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){const c=s.lastButtonClicked||e;const f=ee(c,"name");rn(f,c.value,o)}const u=Se(e,"hx-include");se(u,function(e){sn(n,r,i,ce(e),l);if(!a(e,"form")){se(h(e).querySelectorAll(it),function(e){sn(n,r,i,e,l)})}});un(r,o);return{errors:i,formData:r,values:An(r)}}function fn(e,t,n){if(e!==""){e+="&"}if(String(n)==="[object Object]"){n=JSON.stringify(n)}const r=encodeURIComponent(n);e+=encodeURIComponent(t)+"="+r;return e}function an(e){e=Ln(e);let n="";e.forEach(function(e,t){n=fn(n,t,e)});return n}function hn(e,t,n){const r={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":ne().location.href};wn(e,"hx-headers",false,r);if(n!==undefined){r["HX-Prompt"]=n}if(ie(e).boosted){r["HX-Boosted"]="true"}return r}function dn(n,e){const t=re(e,"hx-params");if(t){if(t==="none"){return new FormData}else if(t==="*"){return n}else if(t.indexOf("not ")===0){se(t.substr(4).split(","),function(e){e=e.trim();n.delete(e)});return n}else{const r=new FormData;se(t.split(","),function(t){t=t.trim();if(n.has(t)){n.getAll(t).forEach(function(e){r.append(t,e)})}});return r}}else{return n}}function gn(e){return!!ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function pn(e,t){const n=t||re(e,"hx-swap");const r={swapStyle:ie(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ie(e).boosted&&!gn(e)){r.show="top"}if(n){const s=B(n);if(s.length>0){for(let e=0;e<s.length;e++){const l=s[e];if(l.indexOf("swap:")===0){r.swapDelay=d(l.substr(5))}else if(l.indexOf("settle:")===0){r.settleDelay=d(l.substr(7))}else if(l.indexOf("transition:")===0){r.transition=l.substr(11)==="true"}else if(l.indexOf("ignoreTitle:")===0){r.ignoreTitle=l.substr(12)==="true"}else if(l.indexOf("scroll:")===0){const u=l.substr(7);var o=u.split(":");const c=o.pop();var i=o.length>0?o.join(":"):null;r.scroll=c;r.scrollTarget=i}else if(l.indexOf("show:")===0){const f=l.substr(5);var o=f.split(":");const a=o.pop();var i=o.length>0?o.join(":"):null;r.show=a;r.showTarget=i}else if(l.indexOf("focus-scroll:")===0){const h=l.substr("focus-scroll:".length);r.focusScroll=h=="true"}else if(e==0){r.swapStyle=l}else{w("Unknown modifier in hx-swap: "+l)}}}}return r}function mn(e){return re(e,"hx-encoding")==="multipart/form-data"||a(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function yn(t,n,r){let o=null;Ut(n,function(e){if(o==null){o=e.encodeParameters(t,r,n)}});if(o!=null){return o}else{if(mn(n)){return un(new FormData,Ln(r))}else{return an(r)}}}function xn(e){return{tasks:[],elts:[e]}}function bn(e,t){const n=e[0];const r=e[e.length-1];if(t.scroll){var o=null;if(t.scrollTarget){o=ce(fe(n,t.scrollTarget))}if(t.scroll==="top"&&(n||o)){o=o||n;o.scrollTop=0}if(t.scroll==="bottom"&&(r||o)){o=o||r;o.scrollTop=o.scrollHeight}}if(t.show){var o=null;if(t.showTarget){let e=t.showTarget;if(t.showTarget==="window"){e="body"}o=ce(fe(n,e))}if(t.show==="top"&&(n||o)){o=o||n;o.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(r||o)){o=o||r;o.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function wn(r,e,o,i){if(i==null){i={}}if(r==null){return i}const s=te(r,e);if(s){let e=s.trim();let t=o;if(e==="unset"){return null}if(e.indexOf("javascript:")===0){e=e.substr(11);t=true}else if(e.indexOf("js:")===0){e=e.substr(3);t=true}if(e.indexOf("{")!==0){e="{"+e+"}"}let n;if(t){n=vn(r,function(){return Function("return ("+e+")")()},{})}else{n=S(e)}for(const l in n){if(n.hasOwnProperty(l)){if(i[l]==null){i[l]=n[l]}}}}return wn(ce(u(r)),e,o,i)}function vn(e,t,n){if(Q.config.allowEval){return t()}else{ae(e,"htmx:evalDisallowedError");return n}}function Sn(e,t){return wn(e,"hx-vars",true,t)}function En(e,t){return wn(e,"hx-vals",false,t)}function Cn(e){return ue(Sn(e),En(e))}function Rn(t,n,r){if(r!==null){try{t.setRequestHeader(n,r)}catch(e){t.setRequestHeader(n,encodeURIComponent(r));t.setRequestHeader(n+"-URI-AutoEncoded","true")}}}function On(t){if(t.responseURL&&typeof URL!=="undefined"){try{const e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ae(ne().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function C(e,t){return t.test(e.getAllResponseHeaders())}function Hn(e,t,n){e=e.toLowerCase();if(n){if(n instanceof Element||typeof n==="string"){return de(e,t,null,null,{targetOverride:y(n),returnPromise:true})}else{return de(e,t,y(n.source),n.event,{handler:n.handler,headers:n.headers,values:n.values,targetOverride:y(n.target),swapOverride:n.swap,select:n.select,returnPromise:true})}}else{return de(e,t,null,null,{returnPromise:true})}}function Tn(e){const t=[];while(e){t.push(e);e=e.parentElement}return t}function qn(e,t,n){let r;let o;if(typeof URL==="function"){o=new URL(t,document.location.href);const i=document.location.origin;r=i===o.origin}else{o=t;r=l(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!r){return false}}return he(e,"htmx:validateUrl",ue({url:o,sameHost:r},n))}function Ln(e){if(e instanceof FormData)return e;const t=new FormData;for(const n in e){if(e.hasOwnProperty(n)){if(typeof e[n].forEach==="function"){e[n].forEach(function(e){t.append(n,e)})}else if(typeof e[n]==="object"){t.append(n,JSON.stringify(e[n]))}else{t.append(n,e[n])}}}return t}function Nn(r,o,e){return new Proxy(e,{get:function(t,e){if(typeof e==="number")return t[e];if(e==="length")return t.length;if(e==="push"){return function(e){t.push(e);r.append(o,e)}}if(typeof t[e]==="function"){return function(){t[e].apply(t,arguments);r.delete(o);t.forEach(function(e){r.append(o,e)})}}if(t[e]&&t[e].length===1){return t[e][0]}else{return t[e]}},set:function(e,t,n){e[t]=n;r.delete(o);e.forEach(function(e){r.append(o,e)});return true}})}function An(r){return new Proxy(r,{get:function(e,t){if(typeof t==="symbol"){return Reflect.get(e,t)}if(t==="toJSON"){return()=>Object.fromEntries(r)}if(t in e){if(typeof e[t]==="function"){return function(){return r[t].apply(r,arguments)}}else{return e[t]}}const n=r.getAll(t);if(n.length===0){return undefined}else if(n.length===1){return n[0]}else{return Nn(e,t,n)}},set:function(t,n,e){if(typeof n!=="string"){return false}t.delete(n);if(typeof e.forEach==="function"){e.forEach(function(e){t.append(n,e)})}else{t.append(n,e)}return true},deleteProperty:function(e,t){if(typeof t==="string"){e.delete(t)}return true},ownKeys:function(e){return Reflect.ownKeys(Object.fromEntries(e))},getOwnPropertyDescriptor:function(e,t){return Reflect.getOwnPropertyDescriptor(Object.fromEntries(e),t)}})}function de(t,n,r,o,i,D){let s=null;let l=null;i=i!=null?i:{};if(i.returnPromise&&typeof Promise!=="undefined"){var e=new Promise(function(e,t){s=e;l=t})}if(r==null){r=ne().body}const M=i.handler||Mn;const X=i.select||null;if(!le(r)){oe(s);return e}const u=i.targetOverride||ce(Ce(r));if(u==null||u==ve){ae(r,"htmx:targetError",{target:te(r,"hx-target")});oe(l);return e}let c=ie(r);const f=c.lastButtonClicked;if(f){const L=ee(f,"formaction");if(L!=null){n=L}const N=ee(f,"formmethod");if(N!=null){if(N.toLowerCase()!=="dialog"){t=N}}}const a=re(r,"hx-confirm");if(D===undefined){const K=function(e){return de(t,n,r,o,i,!!e)};const G={target:u,elt:r,path:n,verb:t,triggeringEvent:o,etc:i,issueRequest:K,question:a};if(he(r,"htmx:confirm",G)===false){oe(s);return e}}let h=r;let d=re(r,"hx-sync");let g=null;let F=false;if(d){const A=d.split(":");const I=A[0].trim();if(I==="this"){h=Ee(r,"hx-sync")}else{h=ce(fe(r,I))}d=(A[1]||"drop").trim();c=ie(h);if(d==="drop"&&c.xhr&&c.abortable!==true){oe(s);return e}else if(d==="abort"){if(c.xhr){oe(s);return e}else{F=true}}else if(d==="replace"){he(h,"htmx:abort")}else if(d.indexOf("queue")===0){const Z=d.split(" ");g=(Z[1]||"last").trim()}}if(c.xhr){if(c.abortable){he(h,"htmx:abort")}else{if(g==null){if(o){const P=ie(o);if(P&&P.triggerSpec&&P.triggerSpec.queue){g=P.triggerSpec.queue}}if(g==null){g="last"}}if(c.queuedRequests==null){c.queuedRequests=[]}if(g==="first"&&c.queuedRequests.length===0){c.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="all"){c.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="last"){c.queuedRequests=[];c.queuedRequests.push(function(){de(t,n,r,o,i)})}oe(s);return e}}const p=new XMLHttpRequest;c.xhr=p;c.abortable=F;const m=function(){c.xhr=null;c.abortable=false;if(c.queuedRequests!=null&&c.queuedRequests.length>0){const e=c.queuedRequests.shift();e()}};const U=re(r,"hx-prompt");if(U){var y=prompt(U);if(y===null||!he(r,"htmx:prompt",{prompt:y,target:u})){oe(s);m();return e}}if(a&&!D){if(!confirm(a)){oe(s);m();return e}}let x=hn(r,u,y);if(t!=="get"&&!mn(r)){x["Content-Type"]="application/x-www-form-urlencoded"}if(i.headers){x=ue(x,i.headers)}const B=cn(r,t);let b=B.errors;const j=B.formData;if(i.values){un(j,Ln(i.values))}const V=Ln(Cn(r));const w=un(j,V);let v=dn(w,r);if(Q.config.getCacheBusterParam&&t==="get"){v.set("org.htmx.cache-buster",ee(u,"id")||"true")}if(n==null||n===""){n=ne().location.href}const S=wn(r,"hx-request");const _=ie(r).boosted;let E=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;const C={boosted:_,useUrlParams:E,formData:v,parameters:An(v),unfilteredFormData:w,unfilteredParameters:An(w),headers:x,target:u,verb:t,errors:b,withCredentials:i.credentials||S.credentials||Q.config.withCredentials,timeout:i.timeout||S.timeout||Q.config.timeout,path:n,triggeringEvent:o};if(!he(r,"htmx:configRequest",C)){oe(s);m();return e}n=C.path;t=C.verb;x=C.headers;v=Ln(C.parameters);b=C.errors;E=C.useUrlParams;if(b&&b.length>0){he(r,"htmx:validation:halted",C);oe(s);m();return e}const $=n.split("#");const z=$[0];const R=$[1];let O=n;if(E){O=z;const W=!v.keys().next().done;if(W){if(O.indexOf("?")<0){O+="?"}else{O+="&"}O+=an(v);if(R){O+="#"+R}}}if(!qn(r,O,C)){ae(r,"htmx:invalidPath",C);oe(l);return e}p.open(t.toUpperCase(),O,true);p.overrideMimeType("text/html");p.withCredentials=C.withCredentials;p.timeout=C.timeout;if(S.noHeaders){}else{for(const k in x){if(x.hasOwnProperty(k)){const Y=x[k];Rn(p,k,Y)}}}const H={xhr:p,target:u,requestConfig:C,etc:i,boosted:_,select:X,pathInfo:{requestPath:n,finalRequestPath:O,responsePath:null,anchor:R}};p.onload=function(){try{const t=Tn(r);H.pathInfo.responsePath=On(p);M(r,H);en(T,q);he(r,"htmx:afterRequest",H);he(r,"htmx:afterOnLoad",H);if(!le(r)){let e=null;while(t.length>0&&e==null){const n=t.shift();if(le(n)){e=n}}if(e){he(e,"htmx:afterRequest",H);he(e,"htmx:afterOnLoad",H)}}oe(s);m()}catch(e){ae(r,"htmx:onLoadError",ue({error:e},H));throw e}};p.onerror=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:sendError",H);oe(l);m()};p.onabort=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:sendAbort",H);oe(l);m()};p.ontimeout=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:timeout",H);oe(l);m()};if(!he(r,"htmx:beforeRequest",H)){oe(s);m();return e}var T=Yt(r);var q=Qt(r);se(["loadstart","loadend","progress","abort"],function(t){se([p,p.upload],function(e){e.addEventListener(t,function(e){he(r,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});he(r,"htmx:beforeSend",H);const J=E?null:yn(p,r,v);p.send(J);return e}function In(e,t){const n=t.xhr;let r=null;let o=null;if(C(n,/HX-Push:/i)){r=n.getResponseHeader("HX-Push");o="push"}else if(C(n,/HX-Push-Url:/i)){r=n.getResponseHeader("HX-Push-Url");o="push"}else if(C(n,/HX-Replace-Url:/i)){r=n.getResponseHeader("HX-Replace-Url");o="replace"}if(r){if(r==="false"){return{}}else{return{type:o,path:r}}}const i=t.pathInfo.finalRequestPath;const s=t.pathInfo.responsePath;const l=re(e,"hx-push-url");const u=re(e,"hx-replace-url");const c=ie(e).boosted;let f=null;let a=null;if(l){f="push";a=l}else if(u){f="replace";a=u}else if(c){f="push";a=s||i}if(a){if(a==="false"){return{}}if(a==="true"){a=s||i}if(t.pathInfo.anchor&&a.indexOf("#")===-1){a=a+"#"+t.pathInfo.anchor}return{type:f,path:a}}else{return{}}}function Pn(e,t){var n=new RegExp(e.code);return n.test(t.toString(10))}function kn(e){for(var t=0;t<Q.config.responseHandling.length;t++){var n=Q.config.responseHandling[t];if(Pn(n,e.status)){return n}}return{swap:false}}function Dn(e){if(e){const t=r("title");if(t){t.innerHTML=e}else{window.document.title=e}}}function Mn(o,i){const s=i.xhr;let l=i.target;const e=i.etc;const u=i.select;if(!he(o,"htmx:beforeOnLoad",i))return;if(C(s,/HX-Trigger:/i)){Je(s,"HX-Trigger",o)}if(C(s,/HX-Location:/i)){zt();let e=s.getResponseHeader("HX-Location");var t;if(e.indexOf("{")===0){t=S(e);e=t.path;delete t.path}Hn("get",e,t).then(function(){Jt(e)});return}const n=C(s,/HX-Refresh:/i)&&s.getResponseHeader("HX-Refresh")==="true";if(C(s,/HX-Redirect:/i)){location.href=s.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(C(s,/HX-Retarget:/i)){if(s.getResponseHeader("HX-Retarget")==="this"){i.target=o}else{i.target=ce(fe(o,s.getResponseHeader("HX-Retarget")))}}const c=In(o,i);const r=kn(s);const f=r.swap;let a=!!r.error;let h=Q.config.ignoreTitle||r.ignoreTitle;let d=r.select;if(r.target){i.target=ce(fe(o,r.target))}var g=e.swapOverride;if(g==null&&r.swapOverride){g=r.swapOverride}if(C(s,/HX-Retarget:/i)){if(s.getResponseHeader("HX-Retarget")==="this"){i.target=o}else{i.target=ce(fe(o,s.getResponseHeader("HX-Retarget")))}}if(C(s,/HX-Reswap:/i)){g=s.getResponseHeader("HX-Reswap")}var p=s.response;var m=ue({shouldSwap:f,serverResponse:p,isError:a,ignoreTitle:h,selectOverride:d},i);if(r.event&&!he(l,r.event,m))return;if(!he(l,"htmx:beforeSwap",m))return;l=m.target;p=m.serverResponse;a=m.isError;h=m.ignoreTitle;d=m.selectOverride;i.target=l;i.failed=a;i.successful=!a;if(m.shouldSwap){if(s.status===286){ut(o)}Ut(o,function(e){p=e.transformResponse(p,s,o)});if(c.type){zt()}if(C(s,/HX-Reswap:/i)){g=s.getResponseHeader("HX-Reswap")}var y=pn(o,g);if(!y.hasOwnProperty("ignoreTitle")){y.ignoreTitle=h}l.classList.add(Q.config.swappingClass);let n=null;let r=null;if(u){d=u}if(C(s,/HX-Reselect:/i)){d=s.getResponseHeader("HX-Reselect")}const x=re(o,"hx-select-oob");const b=re(o,"hx-select");let e=function(){try{if(c.type){he(ne().body,"htmx:beforeHistoryUpdate",ue({history:c},i));if(c.type==="push"){Jt(c.path);he(ne().body,"htmx:pushedIntoHistory",{path:c.path})}else{Kt(c.path);he(ne().body,"htmx:replacedInHistory",{path:c.path})}}ze(l,p,y,{select:d||b,selectOOB:x,eventInfo:i,anchor:i.pathInfo.anchor,contextElement:o,afterSwapCallback:function(){if(C(s,/HX-Trigger-After-Swap:/i)){let e=o;if(!le(o)){e=ne().body}Je(s,"HX-Trigger-After-Swap",e)}},afterSettleCallback:function(){if(C(s,/HX-Trigger-After-Settle:/i)){let e=o;if(!le(o)){e=ne().body}Je(s,"HX-Trigger-After-Settle",e)}oe(n)}})}catch(e){ae(o,"htmx:swapError",i);oe(r);throw e}};let t=Q.config.globalViewTransitions;if(y.hasOwnProperty("transition")){t=y.transition}if(t&&he(o,"htmx:beforeTransition",i)&&typeof Promise!=="undefined"&&document.startViewTransition){const w=new Promise(function(e,t){n=e;r=t});const v=e;e=function(){document.startViewTransition(function(){v();return w})}}if(y.swapDelay>0){E().setTimeout(e,y.swapDelay)}else{e()}}if(a){ae(o,"htmx:responseError",ue({error:"Response Status Error Code "+s.status+" from "+i.pathInfo.requestPath},i))}}const Xn={};function Fn(){return{init:function(e){return null},getSelectors:function(){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,n){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,n,r){return false},encodeParameters:function(e,t,n){return null}}}function Un(e,t){if(t.init){t.init(n)}Xn[e]=ue(Fn(),t)}function Bn(e){delete Xn[e]}function jn(e,n,r){if(n==undefined){n=[]}if(e==undefined){return n}if(r==undefined){r=[]}const t=te(e,"hx-ext");if(t){se(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){r.push(e.slice(7));return}if(r.indexOf(e)<0){const t=Xn[e];if(t&&n.indexOf(t)<0){n.push(t)}}})}return jn(ce(u(e)),n,r)}var Vn=false;ne().addEventListener("DOMContentLoaded",function(){Vn=true});function _n(e){if(Vn||ne().readyState==="complete"){e()}else{ne().addEventListener("DOMContentLoaded",e)}}function $n(){if(Q.config.includeIndicatorStyles!==false){const e=Q.config.inlineStyleNonce?` nonce="${Q.config.inlineStyleNonce}"`:"";ne().head.insertAdjacentHTML("beforeend","<style"+e+"> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zn(){const e=ne().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function Jn(){const e=zn();if(e){Q.config=ue(Q.config,e)}}_n(function(){Jn();$n();let e=ne().body;Dt(e);const t=ne().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){const t=e.target;const n=ie(t);if(n&&n.xhr){n.xhr.abort()}});const n=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){Wt();se(t,function(e){he(e,"htmx:restored",{document:ne(),triggerEvent:he})})}else{if(n){n(e)}}};E().setTimeout(function(){he(e,"htmx:load",{});e=null},0)});return Q}(); \ No newline at end of file diff --git a/code/ch6_active_search/ch6_starter_video_collector/templates/shared/_layout.html b/code/ch6_active_search/ch6_starter_video_collector/templates/shared/_layout.html index b4738bb..d8fe9b9 100644 --- a/code/ch6_active_search/ch6_starter_video_collector/templates/shared/_layout.html +++ b/code/ch6_active_search/ch6_starter_video_collector/templates/shared/_layout.html @@ -51,7 +51,7 @@ </footer> -<script src="/https/github.com/static/js/htmx.min.js?v=1.5.0"></script> +<script src="/https/github.com/static/js/htmx.min.js?v=2.0.0"></script> <script src="/https/github.com/static/js/jquery-3.5.1.slim.min.js"></script> <script src="/https/github.com/static/js/popper-1.16.1.min.js"></script> diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.d.ts b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.d.ts new file mode 100644 index 0000000..3775459 --- /dev/null +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.d.ts @@ -0,0 +1,195 @@ +declare namespace htmx { + const onLoad: (callback: (elt: Node) => void) => EventListener; + const process: (elt: string | Element) => void; + const on: (arg1: string | EventTarget, arg2: string | EventListener, arg3?: EventListener) => EventListener; + const off: (arg1: string | EventTarget, arg2: string | EventListener, arg3?: EventListener) => EventListener; + const trigger: (elt: string | EventTarget, eventName: string, detail?: any) => boolean; + const ajax: (verb: HttpVerb, path: string, context: string | Element | HtmxAjaxHelperContext) => Promise<void>; + const find: (eltOrSelector: string | ParentNode, selector?: string) => Element; + const findAll: (eltOrSelector: string | ParentNode, selector?: string) => NodeListOf<Element>; + const closest: (elt: string | Element, selector: string) => Element; + function values(elt: Element, type: HttpVerb): any; + const remove: (elt: Node, delay?: number) => void; + const addClass: (elt: string | Element, clazz: string, delay?: number) => void; + const removeClass: (node: string | Node, clazz: string, delay?: number) => void; + const toggleClass: (elt: string | Element, clazz: string) => void; + const takeClass: (elt: string | Node, clazz: string) => void; + const swap: (target: string | Element, content: string, swapSpec: HtmxSwapSpecification, swapOptions?: SwapOptions) => void; + const defineExtension: (name: string, extension: any) => void; + const removeExtension: (name: string) => void; + const logAll: () => void; + const logNone: () => void; + const logger: any; + namespace config { + const historyEnabled: boolean; + const historyCacheSize: number; + const refreshOnHistoryMiss: boolean; + const defaultSwapStyle: HtmxSwapStyle; + const defaultSwapDelay: number; + const defaultSettleDelay: number; + const includeIndicatorStyles: boolean; + const indicatorClass: string; + const requestClass: string; + const addedClass: string; + const settlingClass: string; + const swappingClass: string; + const allowEval: boolean; + const allowScriptTags: boolean; + const inlineScriptNonce: string; + const inlineStyleNonce: string; + const attributesToSettle: string[]; + const withCredentials: boolean; + const timeout: number; + const wsReconnectDelay: "full-jitter" | ((retryCount: number) => number); + const wsBinaryType: BinaryType; + const disableSelector: string; + const scrollBehavior: 'auto' | 'instant' | 'smooth'; + const defaultFocusScroll: boolean; + const getCacheBusterParam: boolean; + const globalViewTransitions: boolean; + const methodsThatUseUrlParams: (HttpVerb)[]; + const selfRequestsOnly: boolean; + const ignoreTitle: boolean; + const scrollIntoViewOnBoost: boolean; + const triggerSpecsCache: any | null; + const disableInheritance: boolean; + const responseHandling: HtmxResponseHandlingConfig[]; + const allowNestedOobSwaps: boolean; + } + const parseInterval: (str: string) => number; + const _: (str: string) => any; + const version: string; +} +type HttpVerb = 'get' | 'head' | 'post' | 'put' | 'delete' | 'connect' | 'options' | 'trace' | 'patch'; +type SwapOptions = { + select?: string; + selectOOB?: string; + eventInfo?: any; + anchor?: string; + contextElement?: Element; + afterSwapCallback?: swapCallback; + afterSettleCallback?: swapCallback; +}; +type swapCallback = () => any; +type HtmxSwapStyle = 'innerHTML' | 'outerHTML' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'delete' | 'none' | string; +type HtmxSwapSpecification = { + swapStyle: HtmxSwapStyle; + swapDelay: number; + settleDelay: number; + transition?: boolean; + ignoreTitle?: boolean; + head?: string; + scroll?: 'top' | 'bottom'; + scrollTarget?: string; + show?: string; + showTarget?: string; + focusScroll?: boolean; +}; +type ConditionalFunction = ((this: Node, evt: Event) => boolean) & { + source: string; +}; +type HtmxTriggerSpecification = { + trigger: string; + pollInterval?: number; + eventFilter?: ConditionalFunction; + changed?: boolean; + once?: boolean; + consume?: boolean; + delay?: number; + from?: string; + target?: string; + throttle?: number; + queue?: string; + root?: string; + threshold?: string; +}; +type HtmxElementValidationError = { + elt: Element; + message: string; + validity: ValidityState; +}; +type HtmxHeaderSpecification = Record<string, string>; +type HtmxAjaxHelperContext = { + source?: Element | string; + event?: Event; + handler?: HtmxAjaxHandler; + target: Element | string; + swap?: HtmxSwapStyle; + values?: any | FormData; + headers?: Record<string, string>; + select?: string; +}; +type HtmxRequestConfig = { + boosted: boolean; + useUrlParams: boolean; + formData: FormData; + /** + * formData proxy + */ + parameters: any; + unfilteredFormData: FormData; + /** + * unfilteredFormData proxy + */ + unfilteredParameters: any; + headers: HtmxHeaderSpecification; + target: Element; + verb: HttpVerb; + errors: HtmxElementValidationError[]; + withCredentials: boolean; + timeout: number; + path: string; + triggeringEvent: Event; +}; +type HtmxResponseInfo = { + xhr: XMLHttpRequest; + target: Element; + requestConfig: HtmxRequestConfig; + etc: HtmxAjaxEtc; + boosted: boolean; + select: string; + pathInfo: { + requestPath: string; + finalRequestPath: string; + responsePath: string | null; + anchor: string; + }; + failed?: boolean; + successful?: boolean; +}; +type HtmxAjaxEtc = { + returnPromise?: boolean; + handler?: HtmxAjaxHandler; + select?: string; + targetOverride?: Element; + swapOverride?: HtmxSwapStyle; + headers?: Record<string, string>; + values?: any | FormData; + credentials?: boolean; + timeout?: number; +}; +type HtmxResponseHandlingConfig = { + code?: string; + swap: boolean; + error?: boolean; + ignoreTitle?: boolean; + select?: string; + target?: string; + swapOverride?: string; + event?: string; +}; +type HtmxBeforeSwapDetails = HtmxResponseInfo & { + shouldSwap: boolean; + serverResponse: any; + isError: boolean; + ignoreTitle: boolean; + selectOverride: string; +}; +type HtmxAjaxHandler = (elt: Element, responseInfo: HtmxResponseInfo) => any; +type HtmxSettleTask = (() => void); +type HtmxSettleInfo = { + tasks: HtmxSettleTask[]; + elts: Element[]; + title?: string; +}; +type HtmxExtension = any; diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.js b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.js index 86e7668..c57bcd7 100644 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.js +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.js @@ -1,3909 +1,5131 @@ -// /////////////////////////////////////////////////////////////////// -// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.js -// - -// UMD insanity -// This code sets up support for (in order) AMD, ES6 modules, and globals. -(function (root, factory) { - //@ts-ignore - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - //@ts-ignore - define([], factory); - } else if (typeof module === 'object' && module.exports) { - // Node. Does not work with strict CommonJS, but - // only CommonJS-like environments that support module.exports, - // like Node. - module.exports = factory(); - } else { - // Browser globals - root.htmx = root.htmx || factory(); - } -}(typeof self !== 'undefined' ? self : this, function () { -return (function () { - 'use strict'; - - // Public API - //** @type {import("./htmx").HtmxApi} */ - // TODO: list all methods in public API - var htmx = { - onLoad: onLoadHelper, - process: processNode, - on: addEventListenerImpl, - off: removeEventListenerImpl, - trigger : triggerEvent, - ajax : ajaxHelper, - find : find, - findAll : findAll, - closest : closest, - values : function(elt, type){ - var inputValues = getInputValues(elt, type || "post"); - return inputValues.values; - }, - remove : removeElement, - addClass : addClassToElement, - removeClass : removeClassFromElement, - toggleClass : toggleClassOnElement, - takeClass : takeClassForElement, - defineExtension : defineExtension, - removeExtension : removeExtension, - logAll : logAll, - logNone : logNone, - logger : null, - config : { - historyEnabled:true, - historyCacheSize:10, - refreshOnHistoryMiss:false, - defaultSwapStyle:'innerHTML', - defaultSwapDelay:0, - defaultSettleDelay:20, - includeIndicatorStyles:true, - indicatorClass:'htmx-indicator', - requestClass:'htmx-request', - addedClass:'htmx-added', - settlingClass:'htmx-settling', - swappingClass:'htmx-swapping', - allowEval:true, - allowScriptTags:true, - inlineScriptNonce:'', - attributesToSettle:["class", "style", "width", "height"], - withCredentials:false, - timeout:0, - wsReconnectDelay: 'full-jitter', - wsBinaryType: 'blob', - disableSelector: "[hx-disable], [data-hx-disable]", - useTemplateFragments: false, - scrollBehavior: 'smooth', - defaultFocusScroll: false, - getCacheBusterParam: false, - globalViewTransitions: false, - methodsThatUseUrlParams: ["get"], - selfRequestsOnly: false, - ignoreTitle: false, - scrollIntoViewOnBoost: true, - triggerSpecsCache: null, - }, - parseInterval:parseInterval, - _:internalEval, - createEventSource: function(url){ - return new EventSource(url, {withCredentials:true}) - }, - createWebSocket: function(url){ - var sock = new WebSocket(url, []); - sock.binaryType = htmx.config.wsBinaryType; - return sock; - }, - version: "1.9.10" - }; - - /** @type {import("./htmx").HtmxInternalApi} */ - var internalAPI = { - addTriggerHandler: addTriggerHandler, - bodyContains: bodyContains, - canAccessLocalStorage: canAccessLocalStorage, - findThisElement: findThisElement, - filterValues: filterValues, - hasAttribute: hasAttribute, - getAttributeValue: getAttributeValue, - getClosestAttributeValue: getClosestAttributeValue, - getClosestMatch: getClosestMatch, - getExpressionVars: getExpressionVars, - getHeaders: getHeaders, - getInputValues: getInputValues, - getInternalData: getInternalData, - getSwapSpecification: getSwapSpecification, - getTriggerSpecs: getTriggerSpecs, - getTarget: getTarget, - makeFragment: makeFragment, - mergeObjects: mergeObjects, - makeSettleInfo: makeSettleInfo, - oobSwap: oobSwap, - querySelectorExt: querySelectorExt, - selectAndSwap: selectAndSwap, - settleImmediately: settleImmediately, - shouldCancel: shouldCancel, - triggerEvent: triggerEvent, - triggerErrorEvent: triggerErrorEvent, - withExtensions: withExtensions, - } - - var VERBS = ['get', 'post', 'put', 'delete', 'patch']; - var VERB_SELECTOR = VERBS.map(function(verb){ - return "[hx-" + verb + "], [data-hx-" + verb + "]" - }).join(", "); - - var HEAD_TAG_REGEX = makeTagRegEx('head'), - TITLE_TAG_REGEX = makeTagRegEx('title'), - SVG_TAGS_REGEX = makeTagRegEx('svg', true); - - //==================================================================== - // Utilities - //==================================================================== - - /** - * @param {string} tag - * @param {boolean} global - * @returns {RegExp} - */ - function makeTagRegEx(tag, global = false) { - return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, - global ? 'gim' : 'im'); - } - - function parseInterval(str) { - if (str == undefined) { - return undefined; - } - - let interval = NaN; - if (str.slice(-2) == "ms") { - interval = parseFloat(str.slice(0, -2)); - } else if (str.slice(-1) == "s") { - interval = parseFloat(str.slice(0, -1)) * 1000; - } else if (str.slice(-1) == "m") { - interval = parseFloat(str.slice(0, -1)) * 1000 * 60; - } else { - interval = parseFloat(str); - } - return isNaN(interval) ? undefined : interval; - } - - /** - * @param {HTMLElement} elt - * @param {string} name - * @returns {(string | null)} - */ - function getRawAttribute(elt, name) { - return elt.getAttribute && elt.getAttribute(name); - } - - // resolve with both hx and data-hx prefixes - function hasAttribute(elt, qualifiedName) { - return elt.hasAttribute && (elt.hasAttribute(qualifiedName) || - elt.hasAttribute("data-" + qualifiedName)); - } - - /** - * - * @param {HTMLElement} elt - * @param {string} qualifiedName - * @returns {(string | null)} - */ - function getAttributeValue(elt, qualifiedName) { - return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); - } - - /** - * @param {HTMLElement} elt - * @returns {HTMLElement | null} - */ - function parentElt(elt) { - return elt.parentElement; - } - - /** - * @returns {Document} - */ - function getDocument() { - return document; - } - - /** - * @param {HTMLElement} elt - * @param {(e:HTMLElement) => boolean} condition - * @returns {HTMLElement | null} - */ - function getClosestMatch(elt, condition) { - while (elt && !condition(elt)) { - elt = parentElt(elt); - } - - return elt ? elt : null; - } - - function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ - var attributeValue = getAttributeValue(ancestor, attributeName); - var disinherit = getAttributeValue(ancestor, "hx-disinherit"); - if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) { - return "unset"; - } else { - return attributeValue - } - } - - /** - * @param {HTMLElement} elt - * @param {string} attributeName - * @returns {string | null} - */ - function getClosestAttributeValue(elt, attributeName) { - var closestAttr = null; - getClosestMatch(elt, function (e) { - return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName); - }); - if (closestAttr !== "unset") { - return closestAttr; - } - } - - /** - * @param {HTMLElement} elt - * @param {string} selector - * @returns {boolean} - */ - function matches(elt, selector) { - // @ts-ignore: non-standard properties for browser compatibility - // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; - return matchesFunction && matchesFunction.call(elt, selector); - } - - /** - * @param {string} str - * @returns {string} - */ - 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 ""; - } - } - - /** - * - * @param {string} resp - * @param {number} depth - * @returns {Element} - */ - function parseHTML(resp, depth) { - var parser = new DOMParser(); - var responseDoc = parser.parseFromString(resp, "text/html"); - - /** @type {Element} */ - var responseNode = responseDoc.body; - while (depth > 0) { - depth--; - // @ts-ignore - responseNode = responseNode.firstChild; - } - if (responseNode == null) { - // @ts-ignore - responseNode = getDocument().createDocumentFragment(); - } - return responseNode; - } - - function aFullPageResponse(resp) { - return /<body/.test(resp) - } +// v2.0.0 from https://github.com/bigskysoftware/htmx/releases + +var htmx = (function() { + 'use strict' + + // Public API + const htmx = { + // Tsc madness here, assigning the functions directly results in an invalid TypeScript output, but reassigning is fine + /* Event processing */ + /** @type {typeof onLoadHelper} */ + onLoad: null, + /** @type {typeof processNode} */ + process: null, + /** @type {typeof addEventListenerImpl} */ + on: null, + /** @type {typeof removeEventListenerImpl} */ + off: null, + /** @type {typeof triggerEvent} */ + trigger: null, + /** @type {typeof ajaxHelper} */ + ajax: null, + /* DOM querying helpers */ + /** @type {typeof find} */ + find: null, + /** @type {typeof findAll} */ + findAll: null, + /** @type {typeof closest} */ + closest: null, + /** + * Returns the input values that would resolve for a given element via the htmx value resolution mechanism + * + * @see https://htmx.org/api/#values + * + * @param {Element} elt the element to resolve values on + * @param {HttpVerb} type the request type (e.g. **get** or **post**) non-GET's will include the enclosing form of the element. Defaults to **post** + * @returns {Object} + */ + values: function(elt, type) { + const inputValues = getInputValues(elt, type || 'post') + return inputValues.values + }, + /* DOM manipulation helpers */ + /** @type {typeof removeElement} */ + remove: null, + /** @type {typeof addClassToElement} */ + addClass: null, + /** @type {typeof removeClassFromElement} */ + removeClass: null, + /** @type {typeof toggleClassOnElement} */ + toggleClass: null, + /** @type {typeof takeClassForElement} */ + takeClass: null, + /** @type {typeof swap} */ + swap: null, + /* Extension entrypoints */ + /** @type {typeof defineExtension} */ + defineExtension: null, + /** @type {typeof removeExtension} */ + removeExtension: null, + /* Debugging */ + /** @type {typeof logAll} */ + logAll: null, + /** @type {typeof logNone} */ + logNone: null, + /* Debugging */ + /** + * The logger htmx uses to log with + * + * @see https://htmx.org/api/#logger + */ + logger: null, + /** + * A property holding the configuration htmx uses at runtime. + * + * Note that using a [meta tag](https://htmx.org/docs/#config) is the preferred mechanism for setting these properties. + * + * @see https://htmx.org/api/#config + */ + config: { + /** + * Whether to use history. + * @type boolean + * @default true + */ + historyEnabled: true, + /** + * The number of pages to keep in **localStorage** for history support. + * @type number + * @default 10 + */ + historyCacheSize: 10, + /** + * @type boolean + * @default false + */ + refreshOnHistoryMiss: false, + /** + * The default swap style to use if **[hx-swap](https://htmx.org/attributes/hx-swap)** is omitted. + * @type HtmxSwapStyle + * @default 'innerHTML' + */ + defaultSwapStyle: 'innerHTML', + /** + * The default delay between receiving a response from the server and doing the swap. + * @type number + * @default 0 + */ + defaultSwapDelay: 0, + /** + * The default delay between completing the content swap and settling attributes. + * @type number + * @default 20 + */ + defaultSettleDelay: 20, + /** + * If true, htmx will inject a small amount of CSS into the page to make indicators invisible unless the **htmx-indicator** class is present. + * @type boolean + * @default true + */ + includeIndicatorStyles: true, + /** + * The class to place on indicators when a request is in flight. + * @type string + * @default 'htmx-indicator' + */ + indicatorClass: 'htmx-indicator', + /** + * The class to place on triggering elements when a request is in flight. + * @type string + * @default 'htmx-request' + */ + requestClass: 'htmx-request', + /** + * The class to temporarily place on elements that htmx has added to the DOM. + * @type string + * @default 'htmx-added' + */ + addedClass: 'htmx-added', + /** + * The class to place on target elements when htmx is in the settling phase. + * @type string + * @default 'htmx-settling' + */ + settlingClass: 'htmx-settling', + /** + * The class to place on target elements when htmx is in the swapping phase. + * @type string + * @default 'htmx-swapping' + */ + swappingClass: 'htmx-swapping', + /** + * Allows the use of eval-like functionality in htmx, to enable **hx-vars**, trigger conditions & script tag evaluation. Can be set to **false** for CSP compatibility. + * @type boolean + * @default true + */ + allowEval: true, + /** + * If set to false, disables the interpretation of script tags. + * @type boolean + * @default true + */ + allowScriptTags: true, + /** + * If set, the nonce will be added to inline scripts. + * @type string + * @default '' + */ + inlineScriptNonce: '', + /** + * If set, the nonce will be added to inline styles. + * @type string + * @default '' + */ + inlineStyleNonce: '', + /** + * The attributes to settle during the settling phase. + * @type string[] + * @default ['class', 'style', 'width', 'height'] + */ + attributesToSettle: ['class', 'style', 'width', 'height'], + /** + * Allow cross-site Access-Control requests using credentials such as cookies, authorization headers or TLS client certificates. + * @type boolean + * @default false + */ + withCredentials: false, + /** + * @type number + * @default 0 + */ + timeout: 0, + /** + * The default implementation of **getWebSocketReconnectDelay** for reconnecting after unexpected connection loss by the event code **Abnormal Closure**, **Service Restart** or **Try Again Later**. + * @type {'full-jitter' | ((retryCount:number) => number)} + * @default "full-jitter" + */ + wsReconnectDelay: 'full-jitter', + /** + * The type of binary data being received over the WebSocket connection + * @type BinaryType + * @default 'blob' + */ + wsBinaryType: 'blob', + /** + * @type string + * @default '[hx-disable], [data-hx-disable]' + */ + disableSelector: '[hx-disable], [data-hx-disable]', + /** + * @type {'auto' | 'instant' | 'smooth'} + * @default 'smooth' + */ + scrollBehavior: 'instant', + /** + * If the focused element should be scrolled into view. + * @type boolean + * @default false + */ + defaultFocusScroll: false, + /** + * If set to true htmx will include a cache-busting parameter in GET requests to avoid caching partial responses by the browser + * @type boolean + * @default false + */ + getCacheBusterParam: false, + /** + * If set to true, htmx will use the View Transition API when swapping in new content. + * @type boolean + * @default false + */ + globalViewTransitions: false, + /** + * htmx will format requests with these methods by encoding their parameters in the URL, not the request body + * @type {(HttpVerb)[]} + * @default ['get', 'delete'] + */ + methodsThatUseUrlParams: ['get', 'delete'], + /** + * If set to true, disables htmx-based requests to non-origin hosts. + * @type boolean + * @default false + */ + selfRequestsOnly: true, + /** + * If set to true htmx will not update the title of the document when a title tag is found in new content + * @type boolean + * @default false + */ + ignoreTitle: false, + /** + * Whether the target of a boosted element is scrolled into the viewport. + * @type boolean + * @default true + */ + scrollIntoViewOnBoost: true, + /** + * The cache to store evaluated trigger specifications into. + * You may define a simple object to use a never-clearing cache, or implement your own system using a [proxy object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Proxy) + * @type {Object|null} + * @default null + */ + triggerSpecsCache: null, + /** @type boolean */ + disableInheritance: false, + /** @type HtmxResponseHandlingConfig[] */ + responseHandling: [ + { code: '204', swap: false }, + { code: '[23]..', swap: true }, + { code: '[45]..', swap: false, error: true } + ], + /** + * Whether to process OOB swaps on elements that are nested within the main response element. + * @type boolean + * @default true + */ + allowNestedOobSwaps: true + }, + /** @type {typeof parseInterval} */ + parseInterval: null, + /** @type {typeof internalEval} */ + _: null, + version: '2.0.0' + } + // Tsc madness part 2 + htmx.onLoad = onLoadHelper + htmx.process = processNode + htmx.on = addEventListenerImpl + htmx.off = removeEventListenerImpl + htmx.trigger = triggerEvent + htmx.ajax = ajaxHelper + htmx.find = find + htmx.findAll = findAll + htmx.closest = closest + htmx.remove = removeElement + htmx.addClass = addClassToElement + htmx.removeClass = removeClassFromElement + htmx.toggleClass = toggleClassOnElement + htmx.takeClass = takeClassForElement + htmx.swap = swap + htmx.defineExtension = defineExtension + htmx.removeExtension = removeExtension + htmx.logAll = logAll + htmx.logNone = logNone + htmx.parseInterval = parseInterval + htmx._ = internalEval + + const internalAPI = { + addTriggerHandler, + bodyContains, + canAccessLocalStorage, + findThisElement, + filterValues, + swap, + hasAttribute, + getAttributeValue, + getClosestAttributeValue, + getClosestMatch, + getExpressionVars, + getHeaders, + getInputValues, + getInternalData, + getSwapSpecification, + getTriggerSpecs, + getTarget, + makeFragment, + mergeObjects, + makeSettleInfo, + oobSwap, + querySelectorExt, + settleImmediately, + shouldCancel, + triggerEvent, + triggerErrorEvent, + withExtensions + } + + const VERBS = ['get', 'post', 'put', 'delete', 'patch'] + const VERB_SELECTOR = VERBS.map(function(verb) { + return '[hx-' + verb + '], [data-hx-' + verb + ']' + }).join(', ') + + const HEAD_TAG_REGEX = makeTagRegEx('head') + + //= =================================================================== + // Utilities + //= =================================================================== + + /** + * @param {string} tag + * @param {boolean} global + * @returns {RegExp} + */ + function makeTagRegEx(tag, global = false) { + return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, + global ? 'gim' : 'im') + } + + /** + * Parses an interval string consistent with the way htmx does. Useful for plugins that have timing-related attributes. + * + * Caution: Accepts an int followed by either **s** or **ms**. All other values use **parseFloat** + * + * @see https://htmx.org/api/#parseInterval + * + * @param {string} str timing string + * @returns {number|undefined} + */ + function parseInterval(str) { + if (str == undefined) { + return undefined + } - /** - * - * @param {string} response - * @returns {Element} - */ - function makeFragment(response) { - var partialResponse = !aFullPageResponse(response); - var startTag = getStartTag(response); - var content = response; - if (startTag === 'head') { - content = content.replace(HEAD_TAG_REGEX, ''); - } - if (htmx.config.useTemplateFragments && partialResponse) { - var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0); - // @ts-ignore type mismatch between DocumentFragment and Element. - // TODO: Are these close enough for htmx to use interchangeably? - return documentFragment.querySelector('template').content; - } - switch (startTag) { - case "thead": - case "tbody": - case "tfoot": - case "colgroup": - case "caption": - return parseHTML("<table>" + content + "</table>", 1); - case "col": - return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2); - case "tr": - return parseHTML("<table><tbody>" + content + "</tbody></table>", 2); - case "td": - case "th": - return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3); - case "script": - case "style": - return parseHTML("<div>" + content + "</div>", 1); - default: - return parseHTML(content, 0); - } - } + let interval = NaN + if (str.slice(-2) == 'ms') { + interval = parseFloat(str.slice(0, -2)) + } else if (str.slice(-1) == 's') { + interval = parseFloat(str.slice(0, -1)) * 1000 + } else if (str.slice(-1) == 'm') { + interval = parseFloat(str.slice(0, -1)) * 1000 * 60 + } else { + interval = parseFloat(str) + } + return isNaN(interval) ? undefined : interval + } + + /** + * @param {Node} elt + * @param {string} name + * @returns {(string | null)} + */ + function getRawAttribute(elt, name) { + return elt instanceof Element && elt.getAttribute(name) + } + + /** + * @param {Element} elt + * @param {string} qualifiedName + * @returns {boolean} + */ + // resolve with both hx and data-hx prefixes + function hasAttribute(elt, qualifiedName) { + return !!elt.hasAttribute && (elt.hasAttribute(qualifiedName) || + elt.hasAttribute('data-' + qualifiedName)) + } + + /** + * + * @param {Node} elt + * @param {string} qualifiedName + * @returns {(string | null)} + */ + function getAttributeValue(elt, qualifiedName) { + return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, 'data-' + qualifiedName) + } + + /** + * @param {Node} elt + * @returns {Node | null} + */ + function parentElt(elt) { + const parent = elt.parentElement + if (!parent && elt.parentNode instanceof ShadowRoot) return elt.parentNode + return parent + } + + /** + * @returns {Document} + */ + function getDocument() { + return document + } + + /** + * @param {Node} elt + * @param {boolean} global + * @returns {Node|Document} + */ + function getRootNode(elt, global) { + return elt.getRootNode ? elt.getRootNode({ composed: global }) : getDocument() + } + + /** + * @param {Node} elt + * @param {(e:Node) => boolean} condition + * @returns {Node | null} + */ + function getClosestMatch(elt, condition) { + while (elt && !condition(elt)) { + elt = parentElt(elt) + } - /** - * @param {Function} func - */ - function maybeCall(func){ - if(func) { - func(); - } + return elt || null + } + + /** + * @param {Element} initialElement + * @param {Element} ancestor + * @param {string} attributeName + * @returns {string|null} + */ + function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName) { + const attributeValue = getAttributeValue(ancestor, attributeName) + const disinherit = getAttributeValue(ancestor, 'hx-disinherit') + var inherit = getAttributeValue(ancestor, 'hx-inherit') + if (initialElement !== ancestor) { + if (htmx.config.disableInheritance) { + if (inherit && (inherit === '*' || inherit.split(' ').indexOf(attributeName) >= 0)) { + return attributeValue + } else { + return null + } + } + if (disinherit && (disinherit === '*' || disinherit.split(' ').indexOf(attributeName) >= 0)) { + return 'unset' + } + } + return attributeValue + } + + /** + * @param {Element} elt + * @param {string} attributeName + * @returns {string | null} + */ + function getClosestAttributeValue(elt, attributeName) { + let closestAttr = null + getClosestMatch(elt, function(e) { + return !!(closestAttr = getAttributeValueWithDisinheritance(elt, asElement(e), attributeName)) + }) + if (closestAttr !== 'unset') { + return closestAttr + } + } + + /** + * @param {Node} elt + * @param {string} selector + * @returns {boolean} + */ + function matches(elt, selector) { + // @ts-ignore: non-standard properties for browser compatibility + // noinspection JSUnresolvedVariable + const matchesFunction = elt instanceof Element && (elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector) + return !!matchesFunction && matchesFunction.call(elt, selector) + } + + /** + * @param {string} str + * @returns {string} + */ + function getStartTag(str) { + const tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i + const match = tagMatcher.exec(str) + if (match) { + return match[1].toLowerCase() + } else { + return '' + } + } + + /** + * @param {string} resp + * @returns {Document} + */ + function parseHTML(resp) { + const parser = new DOMParser() + return parser.parseFromString(resp, 'text/html') + } + + /** + * @param {DocumentFragment} fragment + * @param {Node} elt + */ + function takeChildrenFor(fragment, elt) { + while (elt.childNodes.length > 0) { + fragment.append(elt.childNodes[0]) + } + } + + /** + * @param {HTMLScriptElement} script + * @returns {HTMLScriptElement} + */ + function duplicateScript(script) { + const newScript = getDocument().createElement('script') + forEach(script.attributes, function(attr) { + newScript.setAttribute(attr.name, attr.value) + }) + newScript.textContent = script.textContent + newScript.async = false + if (htmx.config.inlineScriptNonce) { + newScript.nonce = htmx.config.inlineScriptNonce + } + return newScript + } + + /** + * @param {HTMLScriptElement} script + * @returns {boolean} + */ + function isJavaScriptScriptNode(script) { + return script.matches('script') && (script.type === 'text/javascript' || script.type === 'module' || script.type === '') + } + + /** + * we have to make new copies of script tags that we are going to insert because + * SOME browsers (not saying who, but it involves an element and an animal) don't + * execute scripts created in <template> tags when they are inserted into the DOM + * and all the others do lmao + * @param {DocumentFragment} fragment + */ + function normalizeScriptTags(fragment) { + Array.from(fragment.querySelectorAll('script')).forEach(/** @param {HTMLScriptElement} script */ (script) => { + if (isJavaScriptScriptNode(script)) { + const newScript = duplicateScript(script) + const parent = script.parentNode + try { + parent.insertBefore(newScript, script) + } catch (e) { + logError(e) + } finally { + script.remove() + } + } + }) + } + + /** + * @typedef {DocumentFragment & {title?: string}} DocumentFragmentWithTitle + * @description a document fragment representing the response HTML, including + * a `title` property for any title information found + */ + + /** + * @param {string} response HTML + * @returns {DocumentFragmentWithTitle} + */ + function makeFragment(response) { + // strip head tag to determine shape of response we are dealing with + const responseWithNoHead = response.replace(HEAD_TAG_REGEX, '') + const startTag = getStartTag(responseWithNoHead) + /** @type DocumentFragmentWithTitle */ + let fragment + if (startTag === 'html') { + // if it is a full document, parse it and return the body + fragment = /** @type DocumentFragmentWithTitle */ (new DocumentFragment()) + const doc = parseHTML(response) + takeChildrenFor(fragment, doc.body) + fragment.title = doc.title + } else if (startTag === 'body') { + // parse body w/o wrapping in template + fragment = /** @type DocumentFragmentWithTitle */ (new DocumentFragment()) + const doc = parseHTML(responseWithNoHead) + takeChildrenFor(fragment, doc.body) + fragment.title = doc.title + } else { + // otherwise we have non-body partial HTML content, so wrap it in a template to maximize parsing flexibility + const doc = parseHTML('<body><template class="internal-htmx-wrapper">' + responseWithNoHead + '</template></body>') + fragment = /** @type DocumentFragmentWithTitle */ (doc.querySelector('template').content) + // extract title into fragment for later processing + fragment.title = doc.title + + // for legacy reasons we support a title tag at the root level of non-body responses, so we need to handle it + var titleElement = fragment.querySelector('title') + if (titleElement && titleElement.parentNode === fragment) { + titleElement.remove() + fragment.title = titleElement.innerText + } + } + if (fragment) { + if (htmx.config.allowScriptTags) { + normalizeScriptTags(fragment) + } else { + // remove all script tags if scripts are disabled + fragment.querySelectorAll('script').forEach((script) => script.remove()) + } + } + return fragment + } + + /** + * @param {Function} func + */ + function maybeCall(func) { + if (func) { + func() + } + } + + /** + * @param {any} o + * @param {string} type + * @returns + */ + function isType(o, type) { + return Object.prototype.toString.call(o) === '[object ' + type + ']' + } + + /** + * @param {*} o + * @returns {o is Function} + */ + function isFunction(o) { + return typeof o === 'function' + } + + /** + * @param {*} o + * @returns {o is Object} + */ + function isRawObject(o) { + return isType(o, 'Object') + } + + /** + * @typedef {Object} OnHandler + * @property {(keyof HTMLElementEventMap)|string} event + * @property {EventListener} listener + */ + + /** + * @typedef {Object} ListenerInfo + * @property {string} trigger + * @property {EventListener} listener + * @property {EventTarget} on + */ + + /** + * @typedef {Object} HtmxNodeInternalData + * Element data + * @property {number} [initHash] + * @property {boolean} [boosted] + * @property {OnHandler[]} [onHandlers] + * @property {number} [timeout] + * @property {ListenerInfo[]} [listenerInfos] + * @property {boolean} [cancelled] + * @property {boolean} [triggeredOnce] + * @property {number} [delayed] + * @property {number|null} [throttle] + * @property {string} [lastValue] + * @property {boolean} [loaded] + * @property {string} [path] + * @property {string} [verb] + * @property {boolean} [polling] + * @property {HTMLButtonElement|HTMLInputElement|null} [lastButtonClicked] + * @property {number} [requestCount] + * @property {XMLHttpRequest} [xhr] + * @property {(() => void)[]} [queuedRequests] + * @property {boolean} [abortable] + * + * Event data + * @property {HtmxTriggerSpecification} [triggerSpec] + * @property {EventTarget[]} [handledFor] + */ + + /** + * getInternalData retrieves "private" data stored by htmx within an element + * @param {EventTarget|Event} elt + * @returns {HtmxNodeInternalData} + */ + function getInternalData(elt) { + const dataProp = 'htmx-internal-data' + let data = elt[dataProp] + if (!data) { + data = elt[dataProp] = {} + } + return data + } + + /** + * toArray converts an ArrayLike object into a real array. + * @template T + * @param {ArrayLike<T>} arr + * @returns {T[]} + */ + function toArray(arr) { + const returnArr = [] + if (arr) { + for (let i = 0; i < arr.length; i++) { + returnArr.push(arr[i]) + } + } + return returnArr + } + + /** + * @template T + * @param {T[]|NamedNodeMap|HTMLCollection|HTMLFormControlsCollection|ArrayLike<T>} arr + * @param {(T) => void} func + */ + function forEach(arr, func) { + if (arr) { + for (let i = 0; i < arr.length; i++) { + func(arr[i]) + } + } + } + + /** + * @param {Element} el + * @returns {boolean} + */ + function isScrolledIntoView(el) { + const rect = el.getBoundingClientRect() + const elemTop = rect.top + const elemBottom = rect.bottom + return elemTop < window.innerHeight && elemBottom >= 0 + } + + /** + * @param {Node} elt + * @returns {boolean} + */ + function bodyContains(elt) { + // IE Fix + const rootNode = elt.getRootNode && elt.getRootNode() + if (rootNode && rootNode instanceof window.ShadowRoot) { + return getDocument().body.contains(rootNode.host) + } else { + return getDocument().body.contains(elt) + } + } + + /** + * @param {string} trigger + * @returns {string[]} + */ + function splitOnWhitespace(trigger) { + return trigger.trim().split(/\s+/) + } + + /** + * mergeObjects takes all the keys from + * obj2 and duplicates them into obj1 + * @template T1 + * @template T2 + * @param {T1} obj1 + * @param {T2} obj2 + * @returns {T1 & T2} + */ + function mergeObjects(obj1, obj2) { + for (const key in obj2) { + if (obj2.hasOwnProperty(key)) { + // @ts-ignore tsc doesn't seem to properly handle types merging + obj1[key] = obj2[key] + } + } + // @ts-ignore tsc doesn't seem to properly handle types merging + return obj1 + } + + /** + * @param {string} jString + * @returns {any|null} + */ + function parseJSON(jString) { + try { + return JSON.parse(jString) + } catch (error) { + logError(error) + return null + } + } + + /** + * @returns {boolean} + */ + function canAccessLocalStorage() { + const test = 'htmx:localStorageTest' + try { + localStorage.setItem(test, test) + localStorage.removeItem(test) + return true + } catch (e) { + return false + } + } + + /** + * @param {string} path + * @returns {string} + */ + function normalizePath(path) { + try { + const url = new URL(path) + if (url) { + path = url.pathname + url.search + } + // remove trailing slash, unless index page + if (!(/^\/$/.test(path))) { + path = path.replace(/\/+$/, '') + } + return path + } catch (e) { + // be kind to IE11, which doesn't support URL() + return path + } + } + + //= ========================================================================================= + // public API + //= ========================================================================================= + + /** + * @param {string} str + * @returns {any} + */ + function internalEval(str) { + return maybeEval(getDocument().body, function() { + return eval(str) + }) + } + + /** + * Adds a callback for the **htmx:load** event. This can be used to process new content, for example initializing the content with a javascript library + * + * @see https://htmx.org/api/#onLoad + * + * @param {(elt: Node) => void} callback the callback to call on newly loaded content + * @returns {EventListener} + */ + function onLoadHelper(callback) { + const value = htmx.on('htmx:load', /** @param {CustomEvent} evt */ function(evt) { + callback(evt.detail.elt) + }) + return value + } + + /** + * Log all htmx events, useful for debugging. + * + * @see https://htmx.org/api/#logAll + */ + function logAll() { + htmx.logger = function(elt, event, data) { + if (console) { + console.log(event, elt, data) + } + } + } + + function logNone() { + htmx.logger = null + } + + /** + * Finds an element matching the selector + * + * @see https://htmx.org/api/#find + * + * @param {ParentNode|string} eltOrSelector the root element to find the matching element in, inclusive | the selector to match + * @param {string} [selector] the selector to match + * @returns {Element|null} + */ + function find(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return eltOrSelector.querySelector(selector) + } else { + return find(getDocument(), eltOrSelector) + } + } + + /** + * Finds all elements matching the selector + * + * @see https://htmx.org/api/#findAll + * + * @param {ParentNode|string} eltOrSelector the root element to find the matching elements in, inclusive | the selector to match + * @param {string} [selector] the selector to match + * @returns {NodeListOf<Element>} + */ + function findAll(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return eltOrSelector.querySelectorAll(selector) + } else { + return findAll(getDocument(), eltOrSelector) + } + } + + /** + * @returns Window + */ + function getWindow() { + return window + } + + /** + * Removes an element from the DOM + * + * @see https://htmx.org/api/#remove + * + * @param {Node} elt + * @param {number} [delay] + */ + function removeElement(elt, delay) { + elt = resolveTarget(elt) + if (delay) { + getWindow().setTimeout(function() { + removeElement(elt) + elt = null + }, delay) + } else { + parentElt(elt).removeChild(elt) + } + } + + /** + * @param {any} elt + * @return {Element|null} + */ + function asElement(elt) { + return elt instanceof Element ? elt : null + } + + /** + * @param {any} elt + * @return {HTMLElement|null} + */ + function asHtmlElement(elt) { + return elt instanceof HTMLElement ? elt : null + } + + /** + * @param {any} value + * @return {string|null} + */ + function asString(value) { + return typeof value === 'string' ? value : null + } + + /** + * @param {EventTarget} elt + * @return {ParentNode|null} + */ + function asParentNode(elt) { + return elt instanceof Element || elt instanceof Document || elt instanceof DocumentFragment ? elt : null + } + + /** + * This method adds a class to the given element. + * + * @see https://htmx.org/api/#addClass + * + * @param {Element|string} elt the element to add the class to + * @param {string} clazz the class to add + * @param {number} [delay] the delay (in milliseconds) before class is added + */ + function addClassToElement(elt, clazz, delay) { + elt = asElement(resolveTarget(elt)) + if (!elt) { + return + } + if (delay) { + getWindow().setTimeout(function() { + addClassToElement(elt, clazz) + elt = null + }, delay) + } else { + elt.classList && elt.classList.add(clazz) + } + } + + /** + * Removes a class from the given element + * + * @see https://htmx.org/api/#removeClass + * + * @param {Node|string} node element to remove the class from + * @param {string} clazz the class to remove + * @param {number} [delay] the delay (in milliseconds before class is removed) + */ + function removeClassFromElement(node, clazz, delay) { + let elt = asElement(resolveTarget(node)) + if (!elt) { + return + } + if (delay) { + getWindow().setTimeout(function() { + removeClassFromElement(elt, clazz) + elt = null + }, delay) + } else { + if (elt.classList) { + elt.classList.remove(clazz) + // if there are no classes left, remove the class attribute + if (elt.classList.length === 0) { + elt.removeAttribute('class') } + } + } + } + + /** + * Toggles the given class on an element + * + * @see https://htmx.org/api/#toggleClass + * + * @param {Element|string} elt the element to toggle the class on + * @param {string} clazz the class to toggle + */ + function toggleClassOnElement(elt, clazz) { + elt = resolveTarget(elt) + elt.classList.toggle(clazz) + } + + /** + * Takes the given class from its siblings, so that among its siblings, only the given element will have the class. + * + * @see https://htmx.org/api/#takeClass + * + * @param {Node|string} elt the element that will take the class + * @param {string} clazz the class to take + */ + function takeClassForElement(elt, clazz) { + elt = resolveTarget(elt) + forEach(elt.parentElement.children, function(child) { + removeClassFromElement(child, clazz) + }) + addClassToElement(asElement(elt), clazz) + } + + /** + * Finds the closest matching element in the given elements parentage, inclusive of the element + * + * @see https://htmx.org/api/#closest + * + * @param {Element|string} elt the element to find the selector from + * @param {string} selector the selector to find + * @returns {Element|null} + */ + function closest(elt, selector) { + elt = asElement(resolveTarget(elt)) + if (elt && elt.closest) { + return elt.closest(selector) + } else { + // TODO remove when IE goes away + do { + if (elt == null || matches(elt, selector)) { + return elt + } + } + while (elt = elt && asElement(parentElt(elt))) + return null + } + } + + /** + * @param {string} str + * @param {string} prefix + * @returns {boolean} + */ + function startsWith(str, prefix) { + return str.substring(0, prefix.length) === prefix + } + + /** + * @param {string} str + * @param {string} suffix + * @returns {boolean} + */ + function endsWith(str, suffix) { + return str.substring(str.length - suffix.length) === suffix + } + + /** + * @param {string} selector + * @returns {string} + */ + function normalizeSelector(selector) { + const trimmedSelector = selector.trim() + if (startsWith(trimmedSelector, '<') && endsWith(trimmedSelector, '/>')) { + return trimmedSelector.substring(1, trimmedSelector.length - 2) + } else { + return trimmedSelector + } + } + + /** + * @param {Node|Element|Document|string} elt + * @param {string} selector + * @param {boolean=} global + * @returns {(Node|Window)[]} + */ + function querySelectorAllExt(elt, selector, global) { + elt = resolveTarget(elt) + if (selector.indexOf('closest ') === 0) { + return [closest(asElement(elt), normalizeSelector(selector.substr(8)))] + } else if (selector.indexOf('find ') === 0) { + return [find(asParentNode(elt), normalizeSelector(selector.substr(5)))] + } else if (selector === 'next') { + return [asElement(elt).nextElementSibling] + } else if (selector.indexOf('next ') === 0) { + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)), !!global)] + } else if (selector === 'previous') { + return [asElement(elt).previousElementSibling] + } else if (selector.indexOf('previous ') === 0) { + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)), !!global)] + } else if (selector === 'document') { + return [document] + } else if (selector === 'window') { + return [window] + } else if (selector === 'body') { + return [document.body] + } else if (selector === 'root') { + return [getRootNode(elt, !!global)] + } else if (selector.indexOf('global ') === 0) { + return querySelectorAllExt(elt, selector.slice(7), true) + } else { + return toArray(asParentNode(getRootNode(elt, !!global)).querySelectorAll(normalizeSelector(selector))) + } + } + + /** + * @param {Node} start + * @param {string} match + * @param {boolean} global + * @returns {Element} + */ + var scanForwardQuery = function(start, match, global) { + const results = asParentNode(getRootNode(start, global)).querySelectorAll(match) + for (let i = 0; i < results.length; i++) { + const elt = results[i] + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { + return elt + } + } + } + + /** + * @param {Node} start + * @param {string} match + * @param {boolean} global + * @returns {Element} + */ + var scanBackwardsQuery = function(start, match, global) { + const results = asParentNode(getRootNode(start, global)).querySelectorAll(match) + for (let i = results.length - 1; i >= 0; i--) { + const elt = results[i] + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { + return elt + } + } + } + + /** + * @param {Node|string} eltOrSelector + * @param {string=} selector + * @returns {Node|Window} + */ + function querySelectorExt(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return querySelectorAllExt(eltOrSelector, selector)[0] + } else { + return querySelectorAllExt(getDocument().body, eltOrSelector)[0] + } + } + + /** + * @template {EventTarget} T + * @param {T|string} eltOrSelector + * @param {T} [context] + * @returns {Element|T|null} + */ + function resolveTarget(eltOrSelector, context) { + if (typeof eltOrSelector === 'string') { + return find(asParentNode(context) || document, eltOrSelector) + } else { + return eltOrSelector + } + } + + /** + * @typedef {keyof HTMLElementEventMap|string} AnyEventName + */ + + /** + * @typedef {Object} EventArgs + * @property {EventTarget} target + * @property {AnyEventName} event + * @property {EventListener} listener + */ + + /** + * @param {EventTarget|AnyEventName} arg1 + * @param {AnyEventName|EventListener} arg2 + * @param {EventListener} [arg3] + * @returns {EventArgs} + */ + function processEventArgs(arg1, arg2, arg3) { + if (isFunction(arg2)) { + return { + target: getDocument().body, + event: asString(arg1), + listener: arg2 + } + } else { + return { + target: resolveTarget(arg1), + event: asString(arg2), + listener: arg3 + } + } + } + + /** + * Adds an event listener to an element + * + * @see https://htmx.org/api/#on + * + * @param {EventTarget|string} arg1 the element to add the listener to | the event name to add the listener for + * @param {string|EventListener} arg2 the event name to add the listener for | the listener to add + * @param {EventListener} [arg3] the listener to add + * @returns {EventListener} + */ + function addEventListenerImpl(arg1, arg2, arg3) { + ready(function() { + const eventArgs = processEventArgs(arg1, arg2, arg3) + eventArgs.target.addEventListener(eventArgs.event, eventArgs.listener) + }) + const b = isFunction(arg2) + return b ? arg2 : arg3 + } + + /** + * Removes an event listener from an element + * + * @see https://htmx.org/api/#off + * + * @param {EventTarget|string} arg1 the element to remove the listener from | the event name to remove the listener from + * @param {string|EventListener} arg2 the event name to remove the listener from | the listener to remove + * @param {EventListener} [arg3] the listener to remove + * @returns {EventListener} + */ + function removeEventListenerImpl(arg1, arg2, arg3) { + ready(function() { + const eventArgs = processEventArgs(arg1, arg2, arg3) + eventArgs.target.removeEventListener(eventArgs.event, eventArgs.listener) + }) + return isFunction(arg2) ? arg2 : arg3 + } + + //= =================================================================== + // Node processing + //= =================================================================== + + const DUMMY_ELT = getDocument().createElement('output') // dummy element for bad selectors + /** + * @param {Element} elt + * @param {string} attrName + * @returns {(Node|Window)[]} + */ + function findAttributeTargets(elt, attrName) { + const attrTarget = getClosestAttributeValue(elt, attrName) + if (attrTarget) { + if (attrTarget === 'this') { + return [findThisElement(elt, attrName)] + } else { + const result = querySelectorAllExt(elt, attrTarget) + if (result.length === 0) { + logError('The selector "' + attrTarget + '" on ' + attrName + ' returned no matches!') + return [DUMMY_ELT] + } else { + return result + } + } + } + } + + /** + * @param {Element} elt + * @param {string} attribute + * @returns {Element|null} + */ + function findThisElement(elt, attribute) { + return asElement(getClosestMatch(elt, function(elt) { + return getAttributeValue(asElement(elt), attribute) != null + })) + } + + /** + * @param {Element} elt + * @returns {Node|Window|null} + */ + function getTarget(elt) { + const targetStr = getClosestAttributeValue(elt, 'hx-target') + if (targetStr) { + if (targetStr === 'this') { + return findThisElement(elt, 'hx-target') + } else { + return querySelectorExt(elt, targetStr) + } + } else { + const data = getInternalData(elt) + if (data.boosted) { + return getDocument().body + } else { + return elt + } + } + } + + /** + * @param {string} name + * @returns {boolean} + */ + function shouldSettleAttribute(name) { + const attributesToSettle = htmx.config.attributesToSettle + for (let i = 0; i < attributesToSettle.length; i++) { + if (name === attributesToSettle[i]) { + return true + } + } + return false + } + + /** + * @param {Element} mergeTo + * @param {Element} mergeFrom + */ + function cloneAttributes(mergeTo, mergeFrom) { + forEach(mergeTo.attributes, function(attr) { + if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) { + mergeTo.removeAttribute(attr.name) + } + }) + forEach(mergeFrom.attributes, function(attr) { + if (shouldSettleAttribute(attr.name)) { + mergeTo.setAttribute(attr.name, attr.value) + } + }) + } + + /** + * @param {HtmxSwapStyle} swapStyle + * @param {Element} target + * @returns {boolean} + */ + function isInlineSwap(swapStyle, target) { + const extensions = getExtensions(target) + for (let i = 0; i < extensions.length; i++) { + const extension = extensions[i] + try { + if (extension.isInlineSwap(swapStyle)) { + return true + } + } catch (e) { + logError(e) + } + } + return swapStyle === 'outerHTML' + } + + /** + * @param {string} oobValue + * @param {Element} oobElement + * @param {HtmxSettleInfo} settleInfo + * @returns + */ + function oobSwap(oobValue, oobElement, settleInfo) { + let selector = '#' + getRawAttribute(oobElement, 'id') + /** @type HtmxSwapStyle */ + let swapStyle = 'outerHTML' + if (oobValue === 'true') { + // do nothing + } else if (oobValue.indexOf(':') > 0) { + swapStyle = oobValue.substr(0, oobValue.indexOf(':')) + selector = oobValue.substr(oobValue.indexOf(':') + 1, oobValue.length) + } else { + swapStyle = oobValue + } - /** - * @param {any} o - * @param {string} type - * @returns - */ - function isType(o, type) { - return Object.prototype.toString.call(o) === "[object " + type + "]"; - } - - /** - * @param {*} o - * @returns {o is Function} - */ - function isFunction(o) { - return isType(o, "Function"); - } - - /** - * @param {*} o - * @returns {o is Object} - */ - function isRawObject(o) { - return isType(o, "Object"); - } - - /** - * getInternalData retrieves "private" data stored by htmx within an element - * @param {HTMLElement} elt - * @returns {*} - */ - function getInternalData(elt) { - var dataProp = 'htmx-internal-data'; - var data = elt[dataProp]; - if (!data) { - data = elt[dataProp] = {}; - } - return data; - } - - /** - * toArray converts an ArrayLike object into a real array. - * @param {ArrayLike} arr - * @returns {any[]} - */ - function toArray(arr) { - var returnArr = []; - if (arr) { - for (var i = 0; i < arr.length; i++) { - returnArr.push(arr[i]); - } - } - return returnArr + const targets = getDocument().querySelectorAll(selector) + if (targets) { + forEach( + targets, + function(target) { + let fragment + const oobElementClone = oobElement.cloneNode(true) + fragment = getDocument().createDocumentFragment() + fragment.appendChild(oobElementClone) + if (!isInlineSwap(swapStyle, target)) { + fragment = asParentNode(oobElementClone) // if this is not an inline swap, we use the content of the node, not the node itself + } + + const beforeSwapDetails = { shouldSwap: true, target, fragment } + if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return + + target = beforeSwapDetails.target // allow re-targeting + if (beforeSwapDetails.shouldSwap) { + swapWithStyle(swapStyle, target, target, fragment, settleInfo) + } + forEach(settleInfo.elts, function(elt) { + triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails) + }) + } + ) + oobElement.parentNode.removeChild(oobElement) + } else { + oobElement.parentNode.removeChild(oobElement) + triggerErrorEvent(getDocument().body, 'htmx:oobErrorNoTarget', { content: oobElement }) + } + return oobValue + } + + /** + * @param {DocumentFragment} fragment + */ + function handlePreservedElements(fragment) { + forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function(preservedElt) { + const id = getAttributeValue(preservedElt, 'id') + const oldElt = getDocument().getElementById(id) + if (oldElt != null) { + preservedElt.parentNode.replaceChild(oldElt, preservedElt) + } + }) + } + + /** + * @param {Node} parentNode + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function handleAttributes(parentNode, fragment, settleInfo) { + forEach(fragment.querySelectorAll('[id]'), function(newNode) { + const id = getRawAttribute(newNode, 'id') + if (id && id.length > 0) { + const normalizedId = id.replace("'", "\\'") + const normalizedTag = newNode.tagName.replace(':', '\\:') + const parentElt = asParentNode(parentNode) + const oldNode = parentElt && parentElt.querySelector(normalizedTag + "[id='" + normalizedId + "']") + if (oldNode && oldNode !== parentElt) { + const newAttributes = newNode.cloneNode() + cloneAttributes(newNode, oldNode) + settleInfo.tasks.push(function() { + cloneAttributes(newNode, newAttributes) + }) + } + } + }) + } + + /** + * @param {Node} child + * @returns {HtmxSettleTask} + */ + function makeAjaxLoadTask(child) { + return function() { + removeClassFromElement(child, htmx.config.addedClass) + processNode(asElement(child)) + processFocus(asParentNode(child)) + triggerEvent(child, 'htmx:load') + } + } + + /** + * @param {ParentNode} child + */ + function processFocus(child) { + const autofocus = '[autofocus]' + const autoFocusedElt = asHtmlElement(matches(child, autofocus) ? child : child.querySelector(autofocus)) + if (autoFocusedElt != null) { + autoFocusedElt.focus() + } + } + + /** + * @param {Node} parentNode + * @param {Node} insertBefore + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) { + handleAttributes(parentNode, fragment, settleInfo) + while (fragment.childNodes.length > 0) { + const child = fragment.firstChild + addClassToElement(asElement(child), htmx.config.addedClass) + parentNode.insertBefore(child, insertBefore) + if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { + settleInfo.tasks.push(makeAjaxLoadTask(child)) + } + } + } + + /** + * based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, + * derived from Java's string hashcode implementation + * @param {string} string + * @param {number} hash + * @returns {number} + */ + function stringHash(string, hash) { + let char = 0 + while (char < string.length) { + hash = (hash << 5) - hash + string.charCodeAt(char++) | 0 // bitwise or ensures we have a 32-bit int + } + return hash + } + + /** + * @param {Element} elt + * @returns {number} + */ + function attributeHash(elt) { + let hash = 0 + // IE fix + if (elt.attributes) { + for (let i = 0; i < elt.attributes.length; i++) { + const attribute = elt.attributes[i] + if (attribute.value) { // only include attributes w/ actual values (empty is same as non-existent) + hash = stringHash(attribute.name, hash) + hash = stringHash(attribute.value, hash) + } + } + } + return hash + } + + /** + * @param {EventTarget} elt + */ + function deInitOnHandlers(elt) { + const internalData = getInternalData(elt) + if (internalData.onHandlers) { + for (let i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i] + removeEventListenerImpl(elt, handlerInfo.event, handlerInfo.listener) + } + delete internalData.onHandlers + } + } + + /** + * @param {Node} element + */ + function deInitNode(element) { + const internalData = getInternalData(element) + if (internalData.timeout) { + clearTimeout(internalData.timeout) + } + if (internalData.listenerInfos) { + forEach(internalData.listenerInfos, function(info) { + if (info.on) { + removeEventListenerImpl(info.on, info.trigger, info.listener) } - - function forEach(arr, func) { - if (arr) { - for (var i = 0; i < arr.length; i++) { - func(arr[i]); - } - } + }) + } + deInitOnHandlers(element) + forEach(Object.keys(internalData), function(key) { delete internalData[key] }) + } + + /** + * @param {Node} element + */ + function cleanUpElement(element) { + triggerEvent(element, 'htmx:beforeCleanupElement') + deInitNode(element) + // @ts-ignore IE11 code + // noinspection JSUnresolvedReference + if (element.children) { // IE + // @ts-ignore + forEach(element.children, function(child) { cleanUpElement(child) }) + } + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapOuterHTML(target, fragment, settleInfo) { + /** @type {Node} */ + let newElt + const eltBeforeNewContent = target.previousSibling + insertNodesBefore(parentElt(target), target, fragment, settleInfo) + if (eltBeforeNewContent == null) { + newElt = parentElt(target).firstChild + } else { + newElt = eltBeforeNewContent.nextSibling + } + settleInfo.elts = settleInfo.elts.filter(function(e) { return e !== target }) + while (newElt && newElt !== target) { + if (newElt instanceof Element) { + settleInfo.elts.push(newElt) + newElt = newElt.nextElementSibling + } else { + newElt = null + } + } + cleanUpElement(target) + if (target instanceof Element) { + target.remove() + } else { + target.parentNode.removeChild(target) + } + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapAfterBegin(target, fragment, settleInfo) { + return insertNodesBefore(target, target.firstChild, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapBeforeBegin(target, fragment, settleInfo) { + return insertNodesBefore(parentElt(target), target, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapBeforeEnd(target, fragment, settleInfo) { + return insertNodesBefore(target, null, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapAfterEnd(target, fragment, settleInfo) { + return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo) + } + + /** + * @param {Node} target + */ + function swapDelete(target) { + cleanUpElement(target) + return parentElt(target).removeChild(target) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapInnerHTML(target, fragment, settleInfo) { + const firstChild = target.firstChild + insertNodesBefore(target, firstChild, fragment, settleInfo) + if (firstChild) { + while (firstChild.nextSibling) { + cleanUpElement(firstChild.nextSibling) + target.removeChild(firstChild.nextSibling) + } + cleanUpElement(firstChild) + target.removeChild(firstChild) + } + } + + /** + * @param {HtmxSwapStyle} swapStyle + * @param {Element} elt + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapWithStyle(swapStyle, elt, target, fragment, settleInfo) { + switch (swapStyle) { + case 'none': + return + case 'outerHTML': + swapOuterHTML(target, fragment, settleInfo) + return + case 'afterbegin': + swapAfterBegin(target, fragment, settleInfo) + return + case 'beforebegin': + swapBeforeBegin(target, fragment, settleInfo) + return + case 'beforeend': + swapBeforeEnd(target, fragment, settleInfo) + return + case 'afterend': + swapAfterEnd(target, fragment, settleInfo) + return + case 'delete': + swapDelete(target) + return + default: + var extensions = getExtensions(elt) + for (let i = 0; i < extensions.length; i++) { + const ext = extensions[i] + try { + const newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo) + if (newElements) { + if (typeof newElements.length !== 'undefined') { + // if handleSwap returns an array (like) of elements, we handle them + for (let j = 0; j < newElements.length; j++) { + const child = newElements[j] + if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { + settleInfo.tasks.push(makeAjaxLoadTask(child)) + } + } + } + return + } + } catch (e) { + logError(e) + } + } + if (swapStyle === 'innerHTML') { + swapInnerHTML(target, fragment, settleInfo) + } else { + swapWithStyle(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo) } + } + } + + /** + * @param {DocumentFragment} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function findAndSwapOobElements(fragment, settleInfo) { + forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function(oobElement) { + if (htmx.config.allowNestedOobSwaps || oobElement.parentElement === null) { + const oobValue = getAttributeValue(oobElement, 'hx-swap-oob') + if (oobValue != null) { + oobSwap(oobValue, oobElement, settleInfo) + } + } else { + oobElement.removeAttribute('hx-swap-oob') + oobElement.removeAttribute('data-hx-swap-oob') + } + }) + } + + /** + * Implements complete swapping pipeline, including: focus and selection preservation, + * title updates, scroll, OOB swapping, normal swapping and settling + * @param {string|Element} target + * @param {string} content + * @param {HtmxSwapSpecification} swapSpec + * @param {SwapOptions} [swapOptions] + */ + function swap(target, content, swapSpec, swapOptions) { + if (!swapOptions) { + swapOptions = {} + } - function isScrolledIntoView(el) { - var rect = el.getBoundingClientRect(); - var elemTop = rect.top; - var elemBottom = rect.bottom; - return elemTop < window.innerHeight && elemBottom >= 0; - } + target = resolveTarget(target) + + // preserve focus and selection + const activeElt = document.activeElement + let selectionInfo = {} + try { + selectionInfo = { + elt: activeElt, + // @ts-ignore + start: activeElt ? activeElt.selectionStart : null, + // @ts-ignore + end: activeElt ? activeElt.selectionEnd : null + } + } catch (e) { + // safari issue - see https://github.com/microsoft/playwright/issues/5894 + } + const settleInfo = makeSettleInfo(target) - function bodyContains(elt) { - // IE Fix - if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) { - return getDocument().body.contains(elt.getRootNode().host); - } else { - return getDocument().body.contains(elt); - } - } + // For text content swaps, don't parse the response as HTML, just insert it + if (swapSpec.swapStyle === 'textContent') { + target.textContent = content + // Otherwise, make the fragment and process it + } else { + let fragment = makeFragment(content) + + settleInfo.title = fragment.title + + // select-oob swaps + if (swapOptions.selectOOB) { + const oobSelectValues = swapOptions.selectOOB.split(',') + for (let i = 0; i < oobSelectValues.length; i++) { + const oobSelectValue = oobSelectValues[i].split(':', 2) + let id = oobSelectValue[0].trim() + if (id.indexOf('#') === 0) { + id = id.substring(1) + } + const oobValue = oobSelectValue[1] || 'true' + const oobElement = fragment.querySelector('#' + id) + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo) + } + } + } + // oob swaps + findAndSwapOobElements(fragment, settleInfo) + forEach(findAll(fragment, 'template'), /** @param {HTMLTemplateElement} template */function(template) { + findAndSwapOobElements(template.content, settleInfo) + if (template.content.childElementCount === 0) { + // Avoid polluting the DOM with empty templates that were only used to encapsulate oob swap + template.remove() + } + }) + + // normal swap + if (swapOptions.select) { + const newFragment = getDocument().createDocumentFragment() + forEach(fragment.querySelectorAll(swapOptions.select), function(node) { + newFragment.appendChild(node) + }) + fragment = newFragment + } + handlePreservedElements(fragment) + swapWithStyle(swapSpec.swapStyle, swapOptions.contextElement, target, fragment, settleInfo) + } - function splitOnWhitespace(trigger) { - return trigger.trim().split(/\s+/); - } + // apply saved focus and selection information to swapped content + if (selectionInfo.elt && + !bodyContains(selectionInfo.elt) && + getRawAttribute(selectionInfo.elt, 'id')) { + const newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, 'id')) + const focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll } + if (newActiveElt) { + // @ts-ignore + if (selectionInfo.start && newActiveElt.setSelectionRange) { + try { + // @ts-ignore + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end) + } catch (e) { + // the setSelectionRange method is present on fields that don't support it, so just let this fail + } + } + newActiveElt.focus(focusOptions) + } + } - /** - * mergeObjects takes all of the keys from - * obj2 and duplicates them into obj1 - * @param {Object} obj1 - * @param {Object} obj2 - * @returns {Object} - */ - function mergeObjects(obj1, obj2) { - for (var key in obj2) { - if (obj2.hasOwnProperty(key)) { - obj1[key] = obj2[key]; - } - } - return obj1; - } + target.classList.remove(htmx.config.swappingClass) + forEach(settleInfo.elts, function(elt) { + if (elt.classList) { + elt.classList.add(htmx.config.settlingClass) + } + triggerEvent(elt, 'htmx:afterSwap', swapOptions.eventInfo) + }) + if (swapOptions.afterSwapCallback) { + swapOptions.afterSwapCallback() + } - function parseJSON(jString) { - try { - return JSON.parse(jString); - } catch(error) { - logError(error); - return null; - } - } + // merge in new title after swap but before settle + if (!swapSpec.ignoreTitle) { + handleTitle(settleInfo.title) + } - function canAccessLocalStorage() { - var test = 'htmx:localStorageTest'; - try { - localStorage.setItem(test, test); - localStorage.removeItem(test); - return true; - } catch(e) { - return false; - } - } + // settle + const doSettle = function() { + forEach(settleInfo.tasks, function(task) { + task.call() + }) + forEach(settleInfo.elts, function(elt) { + if (elt.classList) { + elt.classList.remove(htmx.config.settlingClass) + } + triggerEvent(elt, 'htmx:afterSettle', swapOptions.eventInfo) + }) + + if (swapOptions.anchor) { + const anchorTarget = asElement(resolveTarget('#' + swapOptions.anchor)) + if (anchorTarget) { + anchorTarget.scrollIntoView({ block: 'start', behavior: 'auto' }) + } + } + + updateScrollState(settleInfo.elts, swapSpec) + if (swapOptions.afterSettleCallback) { + swapOptions.afterSettleCallback() + } + } - function normalizePath(path) { + if (swapSpec.settleDelay > 0) { + getWindow().setTimeout(doSettle, swapSpec.settleDelay) + } else { + doSettle() + } + } + + /** + * @param {XMLHttpRequest} xhr + * @param {string} header + * @param {EventTarget} elt + */ + function handleTriggerHeader(xhr, header, elt) { + const triggerBody = xhr.getResponseHeader(header) + if (triggerBody.indexOf('{') === 0) { + const triggers = parseJSON(triggerBody) + for (const eventName in triggers) { + if (triggers.hasOwnProperty(eventName)) { + let detail = triggers[eventName] + if (!isRawObject(detail)) { + detail = { value: detail } + } + triggerEvent(elt, eventName, detail) + } + } + } else { + const eventNames = triggerBody.split(',') + for (let i = 0; i < eventNames.length; i++) { + triggerEvent(elt, eventNames[i].trim(), []) + } + } + } + + const WHITESPACE = /\s/ + const WHITESPACE_OR_COMMA = /[\s,]/ + const SYMBOL_START = /[_$a-zA-Z]/ + const SYMBOL_CONT = /[_$a-zA-Z0-9]/ + const STRINGISH_START = ['"', "'", '/'] + const NOT_WHITESPACE = /[^\s]/ + const COMBINED_SELECTOR_START = /[{(]/ + const COMBINED_SELECTOR_END = /[})]/ + + /** + * @param {string} str + * @returns {string[]} + */ + function tokenizeString(str) { + /** @type string[] */ + const tokens = [] + let position = 0 + while (position < str.length) { + if (SYMBOL_START.exec(str.charAt(position))) { + var startPosition = position + while (SYMBOL_CONT.exec(str.charAt(position + 1))) { + position++ + } + tokens.push(str.substr(startPosition, position - startPosition + 1)) + } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) { + const startChar = str.charAt(position) + var startPosition = position + position++ + while (position < str.length && str.charAt(position) !== startChar) { + if (str.charAt(position) === '\\') { + position++ + } + position++ + } + tokens.push(str.substr(startPosition, position - startPosition + 1)) + } else { + const symbol = str.charAt(position) + tokens.push(symbol) + } + position++ + } + return tokens + } + + /** + * @param {string} token + * @param {string|null} last + * @param {string} paramName + * @returns {boolean} + */ + function isPossibleRelativeReference(token, last, paramName) { + return SYMBOL_START.exec(token.charAt(0)) && + token !== 'true' && + token !== 'false' && + token !== 'this' && + token !== paramName && + last !== '.' + } + + /** + * @param {EventTarget|string} elt + * @param {string[]} tokens + * @param {string} paramName + * @returns {ConditionalFunction|null} + */ + function maybeGenerateConditional(elt, tokens, paramName) { + if (tokens[0] === '[') { + tokens.shift() + let bracketCount = 1 + let conditionalSource = ' return (function(' + paramName + '){ return (' + let last = null + while (tokens.length > 0) { + const token = tokens[0] + // @ts-ignore For some reason tsc doesn't understand the shift call, and thinks we're comparing the same value here, i.e. '[' vs ']' + if (token === ']') { + bracketCount-- + if (bracketCount === 0) { + if (last === null) { + conditionalSource = conditionalSource + 'true' + } + tokens.shift() + conditionalSource += ')})' try { - var url = new URL(path); - if (url) { - path = url.pathname + url.search; - } - // remove trailing slash, unless index page - if (!(/^\/$/.test(path))) { - path = path.replace(/\/+$/, ''); - } - return path; + const conditionFunction = maybeEval(elt, function() { + return Function(conditionalSource)() + }, + function() { return true }) + conditionFunction.source = conditionalSource + return conditionFunction } catch (e) { - // be kind to IE11, which doesn't support URL() - return path; - } - } - - //========================================================================================== - // public API - //========================================================================================== - - function internalEval(str){ - return maybeEval(getDocument().body, function () { - return eval(str); - }); - } - - function onLoadHelper(callback) { - var value = htmx.on("htmx:load", function(evt) { - callback(evt.detail.elt); - }); - return value; - } - - function logAll(){ - htmx.logger = function(elt, event, data) { - if(console) { - console.log(event, elt, data); - } - } - } - - function logNone() { - htmx.logger = null - } - - function find(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelector(selector); - } else { - return find(getDocument(), eltOrSelector); - } - } - - function findAll(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelectorAll(selector); - } else { - return findAll(getDocument(), eltOrSelector); - } - } - - function removeElement(elt, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - removeElement(elt); - elt = null; - }, delay); - } else { - elt.parentElement.removeChild(elt); - } - } - - function addClassToElement(elt, clazz, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - addClassToElement(elt, clazz); - elt = null; - }, delay); - } else { - elt.classList && elt.classList.add(clazz); - } - } - - function removeClassFromElement(elt, clazz, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - removeClassFromElement(elt, clazz); - elt = null; - }, delay); - } else { - if (elt.classList) { - elt.classList.remove(clazz); - // if there are no classes left, remove the class attribute - if (elt.classList.length === 0) { - elt.removeAttribute("class"); - } - } - } - } - - function toggleClassOnElement(elt, clazz) { - elt = resolveTarget(elt); - elt.classList.toggle(clazz); - } - - function takeClassForElement(elt, clazz) { - elt = resolveTarget(elt); - forEach(elt.parentElement.children, function(child){ - removeClassFromElement(child, clazz); - }) - addClassToElement(elt, clazz); - } - - function closest(elt, selector) { - elt = resolveTarget(elt); - if (elt.closest) { - return elt.closest(selector); - } else { - // TODO remove when IE goes away - do{ - if (elt == null || matches(elt, selector)){ - return elt; - } - } - while (elt = elt && parentElt(elt)); - return null; - } - } - - function startsWith(str, prefix) { - return str.substring(0, prefix.length) === prefix - } - - function endsWith(str, suffix) { - return str.substring(str.length - suffix.length) === suffix - } - - function normalizeSelector(selector) { - var trimmedSelector = selector.trim(); - if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) { - return trimmedSelector.substring(1, trimmedSelector.length - 2); - } else { - return trimmedSelector; - } - } - - function querySelectorAllExt(elt, selector) { - if (selector.indexOf("closest ") === 0) { - return [closest(elt, normalizeSelector(selector.substr(8)))]; - } else if (selector.indexOf("find ") === 0) { - return [find(elt, normalizeSelector(selector.substr(5)))]; - } else if (selector === "next") { - return [elt.nextElementSibling] - } else if (selector.indexOf("next ") === 0) { - return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; - } else if (selector === "previous") { - return [elt.previousElementSibling] - } else if (selector.indexOf("previous ") === 0) { - return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; - } else if (selector === 'document') { - return [document]; - } else if (selector === 'window') { - return [window]; - } else if (selector === 'body') { - return [document.body]; - } else { - return getDocument().querySelectorAll(normalizeSelector(selector)); - } - } - - var scanForwardQuery = function(start, match) { - var results = getDocument().querySelectorAll(match); - for (var i = 0; i < results.length; i++) { - var elt = results[i]; - if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { - return elt; - } - } - } - - var scanBackwardsQuery = function(start, match) { - var results = getDocument().querySelectorAll(match); - for (var i = results.length - 1; i >= 0; i--) { - var elt = results[i]; - if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { - return elt; - } - } - } - - function querySelectorExt(eltOrSelector, selector) { - if (selector) { - return querySelectorAllExt(eltOrSelector, selector)[0]; - } else { - return querySelectorAllExt(getDocument().body, eltOrSelector)[0]; - } - } - - function resolveTarget(arg2) { - if (isType(arg2, 'String')) { - return find(arg2); - } else { - return arg2; - } - } - - function processEventArgs(arg1, arg2, arg3) { - if (isFunction(arg2)) { - return { - target: getDocument().body, - event: arg1, - listener: arg2 - } - } else { - return { - target: resolveTarget(arg1), - event: arg2, - listener: arg3 - } - } - - } - - function addEventListenerImpl(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 removeEventListenerImpl(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 - //==================================================================== - - var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors - function findAttributeTargets(elt, attrName) { - var attrTarget = getClosestAttributeValue(elt, attrName); - if (attrTarget) { - if (attrTarget === "this") { - return [findThisElement(elt, attrName)]; - } else { - var result = querySelectorAllExt(elt, attrTarget); - if (result.length === 0) { - logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!"); - return [DUMMY_ELT] - } else { - return result; - } - } - } - } - - function findThisElement(elt, attribute){ - return getClosestMatch(elt, function (elt) { - return getAttributeValue(elt, attribute) != null; - }) - } - - function getTarget(elt) { - var targetStr = getClosestAttributeValue(elt, "hx-target"); - if (targetStr) { - if (targetStr === "this") { - return findThisElement(elt,'hx-target'); - } else { - return querySelectorExt(elt, targetStr) - } - } else { - var data = getInternalData(elt); - if (data.boosted) { - return getDocument().body; - } else { - return elt; - } - } - } - - function shouldSettleAttribute(name) { - var attributesToSettle = htmx.config.attributesToSettle; - for (var i = 0; i < attributesToSettle.length; i++) { - if (name === attributesToSettle[i]) { - return true; - } - } - return false; - } - - function cloneAttributes(mergeTo, mergeFrom) { - forEach(mergeTo.attributes, function (attr) { - if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) { - mergeTo.removeAttribute(attr.name) - } - }); - forEach(mergeFrom.attributes, function (attr) { - if (shouldSettleAttribute(attr.name)) { - mergeTo.setAttribute(attr.name, attr.value); - } - }); - } - - function isInlineSwap(swapStyle, target) { - var extensions = getExtensions(target); - for (var i = 0; i < extensions.length; i++) { - var extension = extensions[i]; - try { - if (extension.isInlineSwap(swapStyle)) { - return true; - } - } catch(e) { - logError(e); - } - } - return swapStyle === "outerHTML"; - } - - /** - * - * @param {string} oobValue - * @param {HTMLElement} oobElement - * @param {*} settleInfo - * @returns - */ - function oobSwap(oobValue, oobElement, settleInfo) { - var selector = "#" + getRawAttribute(oobElement, "id"); - var swapStyle = "outerHTML"; - if (oobValue === "true") { - // do nothing - } else if (oobValue.indexOf(":") > 0) { - swapStyle = oobValue.substr(0, oobValue.indexOf(":")); - selector = oobValue.substr(oobValue.indexOf(":") + 1, oobValue.length); - } else { - swapStyle = oobValue; - } - - var targets = getDocument().querySelectorAll(selector); - if (targets) { - forEach( - targets, - function (target) { - var fragment; - var oobElementClone = oobElement.cloneNode(true); - fragment = getDocument().createDocumentFragment(); - fragment.appendChild(oobElementClone); - if (!isInlineSwap(swapStyle, target)) { - fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself - } - - var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment }; - if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return; - - target = beforeSwapDetails.target; // allow re-targeting - if (beforeSwapDetails['shouldSwap']){ - swap(swapStyle, target, target, fragment, settleInfo); - } - forEach(settleInfo.elts, function (elt) { - triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails); - }); - } - ); - oobElement.parentNode.removeChild(oobElement); - } else { - oobElement.parentNode.removeChild(oobElement); - triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}); - } - return oobValue; - } - - function handleOutOfBandSwaps(elt, fragment, settleInfo) { - var oobSelects = getClosestAttributeValue(elt, "hx-select-oob"); - if (oobSelects) { - var oobSelectValues = oobSelects.split(","); - for (var i = 0; i < oobSelectValues.length; i++) { - var oobSelectValue = oobSelectValues[i].split(":", 2); - var id = oobSelectValue[0].trim(); - if (id.indexOf("#") === 0) { - id = id.substring(1); - } - var oobValue = oobSelectValue[1] || "true"; - var oobElement = fragment.querySelector("#" + id); - if (oobElement) { - oobSwap(oobValue, oobElement, settleInfo); - } - } - } - forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) { - var oobValue = getAttributeValue(oobElement, "hx-swap-oob"); - if (oobValue != null) { - oobSwap(oobValue, oobElement, settleInfo); - } - }); - } - - function handlePreservedElements(fragment) { - forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function (preservedElt) { - var id = getAttributeValue(preservedElt, "id"); - var oldElt = getDocument().getElementById(id); - if (oldElt != null) { - preservedElt.parentNode.replaceChild(oldElt, preservedElt); - } - }); - } - - function handleAttributes(parentNode, fragment, settleInfo) { - forEach(fragment.querySelectorAll("[id]"), function (newNode) { - var id = getRawAttribute(newNode, "id") - if (id && id.length > 0) { - var normalizedId = id.replace("'", "\\'"); - var normalizedTag = newNode.tagName.replace(':', '\\:'); - var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']"); - if (oldNode && oldNode !== parentNode) { - var newAttributes = newNode.cloneNode(); - cloneAttributes(newNode, oldNode); - settleInfo.tasks.push(function () { - cloneAttributes(newNode, newAttributes); - }); - } - } - }); - } - - function makeAjaxLoadTask(child) { - return function () { - removeClassFromElement(child, htmx.config.addedClass); - processNode(child); - processScripts(child); - processFocus(child) - triggerEvent(child, 'htmx:load'); - }; - } - - function processFocus(child) { - var autofocus = "[autofocus]"; - var autoFocusedElt = matches(child, autofocus) ? child : child.querySelector(autofocus) - if (autoFocusedElt != null) { - autoFocusedElt.focus(); - } - } - - function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) { - handleAttributes(parentNode, fragment, settleInfo); - while(fragment.childNodes.length > 0){ - var child = fragment.firstChild; - addClassToElement(child, htmx.config.addedClass); - parentNode.insertBefore(child, insertBefore); - if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { - settleInfo.tasks.push(makeAjaxLoadTask(child)); - } - } - } - - // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, - // derived from Java's string hashcode implementation - function stringHash(string, hash) { - var char = 0; - while (char < string.length){ - hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int - } - return hash; - } - - function attributeHash(elt) { - var hash = 0; - // IE fix - if (elt.attributes) { - for (var i = 0; i < elt.attributes.length; i++) { - var attribute = elt.attributes[i]; - if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent) - hash = stringHash(attribute.name, hash); - hash = stringHash(attribute.value, hash); - } - } - } - return hash; - } - - function deInitOnHandlers(elt) { - var internalData = getInternalData(elt); - if (internalData.onHandlers) { - for (var i = 0; i < internalData.onHandlers.length; i++) { - const handlerInfo = internalData.onHandlers[i]; - elt.removeEventListener(handlerInfo.event, handlerInfo.listener); - } - delete internalData.onHandlers - } - } - - function deInitNode(element) { - var internalData = getInternalData(element); - if (internalData.timeout) { - clearTimeout(internalData.timeout); - } - if (internalData.webSocket) { - internalData.webSocket.close(); - } - if (internalData.sseEventSource) { - internalData.sseEventSource.close(); - } - if (internalData.listenerInfos) { - forEach(internalData.listenerInfos, function (info) { - if (info.on) { - info.on.removeEventListener(info.trigger, info.listener); - } - }); - } - deInitOnHandlers(element); - forEach(Object.keys(internalData), function(key) { delete internalData[key] }); - } - - function cleanUpElement(element) { - triggerEvent(element, "htmx:beforeCleanupElement") - deInitNode(element); - if (element.children) { // IE - forEach(element.children, function(child) { cleanUpElement(child) }); - } - } - - function swapOuterHTML(target, fragment, settleInfo) { - if (target.tagName === "BODY") { - return swapInnerHTML(target, fragment, settleInfo); - } else { - // @type {HTMLElement} - var newElt - var eltBeforeNewContent = target.previousSibling; - insertNodesBefore(parentElt(target), target, fragment, settleInfo); - if (eltBeforeNewContent == null) { - newElt = parentElt(target).firstChild; - } else { - newElt = eltBeforeNewContent.nextSibling; - } - settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target }); - while(newElt && newElt !== target) { - if (newElt.nodeType === Node.ELEMENT_NODE) { - settleInfo.elts.push(newElt); - } - newElt = newElt.nextElementSibling; - } - cleanUpElement(target); - parentElt(target).removeChild(target); - } - } - - function swapAfterBegin(target, fragment, settleInfo) { - return insertNodesBefore(target, target.firstChild, fragment, settleInfo); - } - - function swapBeforeBegin(target, fragment, settleInfo) { - return insertNodesBefore(parentElt(target), target, fragment, settleInfo); - } - - function swapBeforeEnd(target, fragment, settleInfo) { - return insertNodesBefore(target, null, fragment, settleInfo); - } - - function swapAfterEnd(target, fragment, settleInfo) { - return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo); - } - function swapDelete(target, fragment, settleInfo) { - cleanUpElement(target); - return parentElt(target).removeChild(target); - } - - function swapInnerHTML(target, fragment, settleInfo) { - var firstChild = target.firstChild; - insertNodesBefore(target, firstChild, fragment, settleInfo); - if (firstChild) { - while (firstChild.nextSibling) { - cleanUpElement(firstChild.nextSibling) - target.removeChild(firstChild.nextSibling); - } - cleanUpElement(firstChild) - target.removeChild(firstChild); - } - } - - function maybeSelectFromResponse(elt, fragment, selectOverride) { - var selector = selectOverride || getClosestAttributeValue(elt, "hx-select"); - if (selector) { - var newFragment = getDocument().createDocumentFragment(); - forEach(fragment.querySelectorAll(selector), function (node) { - newFragment.appendChild(node); - }); - fragment = newFragment; - } - return fragment; - } - - function swap(swapStyle, elt, target, fragment, settleInfo) { - switch (swapStyle) { - case "none": - return; - case "outerHTML": - swapOuterHTML(target, fragment, settleInfo); - return; - case "afterbegin": - swapAfterBegin(target, fragment, settleInfo); - return; - case "beforebegin": - swapBeforeBegin(target, fragment, settleInfo); - return; - case "beforeend": - swapBeforeEnd(target, fragment, settleInfo); - return; - case "afterend": - swapAfterEnd(target, fragment, settleInfo); - return; - case "delete": - swapDelete(target, fragment, settleInfo); - return; - default: - var extensions = getExtensions(elt); - for (var i = 0; i < extensions.length; i++) { - var ext = extensions[i]; - try { - var newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo); - if (newElements) { - if (typeof newElements.length !== 'undefined') { - // if handleSwap returns an array (like) of elements, we handle them - for (var j = 0; j < newElements.length; j++) { - var child = newElements[j]; - if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { - settleInfo.tasks.push(makeAjaxLoadTask(child)); - } - } - } - return; - } - } catch (e) { - logError(e); - } - } - if (swapStyle === "innerHTML") { - swapInnerHTML(target, fragment, settleInfo); - } else { - swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo); - } - } - } - - function findTitle(content) { - if (content.indexOf('<title') > -1) { - var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, ''); - var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX); - if (result) { - return result[2]; - } - } - } - - function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) { - settleInfo.title = findTitle(responseText); - var fragment = makeFragment(responseText); - if (fragment) { - handleOutOfBandSwaps(elt, fragment, settleInfo); - fragment = maybeSelectFromResponse(elt, fragment, selectOverride); - handlePreservedElements(fragment); - return swap(swapStyle, elt, target, fragment, settleInfo); - } - } - - function handleTrigger(xhr, header, elt) { - var triggerBody = xhr.getResponseHeader(header); - if (triggerBody.indexOf("{") === 0) { - var triggers = parseJSON(triggerBody); - for (var eventName in triggers) { - if (triggers.hasOwnProperty(eventName)) { - var detail = triggers[eventName]; - if (!isRawObject(detail)) { - detail = {"value": detail} - } - triggerEvent(elt, eventName, detail); - } - } - } else { - var eventNames = triggerBody.split(",") - for (var i = 0; i < eventNames.length; i++) { - triggerEvent(elt, eventNames[i].trim(), []); - } - } - } - - var WHITESPACE = /\s/; - var WHITESPACE_OR_COMMA = /[\s,]/; - var SYMBOL_START = /[_$a-zA-Z]/; - var SYMBOL_CONT = /[_$a-zA-Z0-9]/; - var STRINGISH_START = ['"', "'", "/"]; - var NOT_WHITESPACE = /[^\s]/; - var COMBINED_SELECTOR_START = /[{(]/; - var COMBINED_SELECTOR_END = /[})]/; - function tokenizeString(str) { - var tokens = []; - var position = 0; - while (position < str.length) { - if(SYMBOL_START.exec(str.charAt(position))) { - var startPosition = position; - while (SYMBOL_CONT.exec(str.charAt(position + 1))) { - position++; - } - tokens.push(str.substr(startPosition, position - startPosition + 1)); - } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) { - var startChar = str.charAt(position); - var startPosition = position; - position++; - while (position < str.length && str.charAt(position) !== startChar ) { - if (str.charAt(position) === "\\") { - position++; - } - position++; - } - tokens.push(str.substr(startPosition, position - startPosition + 1)); - } else { - var symbol = str.charAt(position); - tokens.push(symbol); - } - position++; - } - return tokens; - } - - function isPossibleRelativeReference(token, last, paramName) { - return SYMBOL_START.exec(token.charAt(0)) && - token !== "true" && - token !== "false" && - token !== "this" && - token !== paramName && - last !== "."; - } - - function maybeGenerateConditional(elt, tokens, paramName) { - if (tokens[0] === '[') { - tokens.shift(); - var bracketCount = 1; - var conditionalSource = " return (function(" + paramName + "){ return ("; - var last = null; - while (tokens.length > 0) { - var token = tokens[0]; - if (token === "]") { - bracketCount--; - if (bracketCount === 0) { - if (last === null) { - conditionalSource = conditionalSource + "true"; - } - tokens.shift(); - conditionalSource += ")})"; - try { - var conditionFunction = maybeEval(elt,function () { - return Function(conditionalSource)(); - }, - function(){return true}) - conditionFunction.source = conditionalSource; - return conditionFunction; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:syntax:error", {error:e, source:conditionalSource}) - return null; - } - } - } else if (token === "[") { - bracketCount++; - } - if (isPossibleRelativeReference(token, last, paramName)) { - conditionalSource += "((" + paramName + "." + token + ") ? (" + paramName + "." + token + ") : (window." + token + "))"; - } else { - conditionalSource = conditionalSource + token; - } - last = tokens.shift(); - } - } - } - - function consumeUntil(tokens, match) { - var result = ""; - while (tokens.length > 0 && !match.test(tokens[0])) { - result += tokens.shift(); - } - return result; - } - - function consumeCSSSelector(tokens) { - var result; - if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { - tokens.shift(); - result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim(); - tokens.shift(); - } else { - result = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } - return result; - } - - var INPUT_SELECTOR = 'input, textarea, select'; - - /** - * @param {HTMLElement} elt - * @param {string} explicitTrigger - * @param {cache} cache for trigger specs - * @returns {import("./htmx").HtmxTriggerSpecification[]} - */ - function parseAndCacheTrigger(elt, explicitTrigger, cache) { - var triggerSpecs = []; - var tokens = tokenizeString(explicitTrigger); - do { - consumeUntil(tokens, NOT_WHITESPACE); - var initialLength = tokens.length; - var trigger = consumeUntil(tokens, /[,\[\s]/); - if (trigger !== "") { - if (trigger === "every") { - var every = {trigger: 'every'}; - consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); - consumeUntil(tokens, NOT_WHITESPACE); - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - every.eventFilter = eventFilter; - } - triggerSpecs.push(every); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); - } else { - var triggerSpec = {trigger: trigger}; - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - triggerSpec.eventFilter = eventFilter; - } - while (tokens.length > 0 && tokens[0] !== ",") { - consumeUntil(tokens, NOT_WHITESPACE) - var token = tokens.shift(); - if (token === "changed") { - triggerSpec.changed = true; - } else if (token === "once") { - triggerSpec.once = true; - } else if (token === "consume") { - triggerSpec.consume = true; - } else if (token === "delay" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "from" && tokens[0] === ":") { - tokens.shift(); - if (COMBINED_SELECTOR_START.test(tokens[0])) { - var from_arg = consumeCSSSelector(tokens); - } else { - var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); - if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") { - tokens.shift(); - var selector = consumeCSSSelector(tokens); - // `next` and `previous` allow a selector-less syntax - if (selector.length > 0) { - from_arg += " " + selector; - } - } - } - triggerSpec.from = from_arg; - } else if (token === "target" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.target = consumeCSSSelector(tokens); - } else if (token === "throttle" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "queue" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if (token === "root" && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeCSSSelector(tokens); - } else if (token === "threshold" && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - } - triggerSpecs.push(triggerSpec); - } - } - if (tokens.length === initialLength) { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - consumeUntil(tokens, NOT_WHITESPACE); - } while (tokens[0] === "," && tokens.shift()) - if (cache) { - cache[explicitTrigger] = triggerSpecs - } - return triggerSpecs - } - - /** - * @param {HTMLElement} elt - * @returns {import("./htmx").HtmxTriggerSpecification[]} - */ - function getTriggerSpecs(elt) { - var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); - var triggerSpecs = []; - if (explicitTrigger) { - var cache = htmx.config.triggerSpecsCache - triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) - } - - if (triggerSpecs.length > 0) { - return triggerSpecs; - } else if (matches(elt, 'form')) { - return [{trigger: 'submit'}]; - } else if (matches(elt, 'input[type="button"], input[type="submit"]')){ - return [{trigger: 'click'}]; - } else if (matches(elt, INPUT_SELECTOR)) { - return [{trigger: 'change'}]; - } else { - return [{trigger: 'click'}]; - } - } - - function cancelPolling(elt) { - getInternalData(elt).cancelled = true; - } - - function processPolling(elt, handler, spec) { - var nodeData = getInternalData(elt); - nodeData.timeout = setTimeout(function () { - if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { - triggerSpec: spec, - target: elt - }))) { - handler(elt); - } - processPolling(elt, handler, spec); - } - }, spec.pollInterval); - } - - function isLocalLink(elt) { - return location.hostname === elt.hostname && - getRawAttribute(elt,'href') && - getRawAttribute(elt,'href').indexOf("#") !== 0; - } - - function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || 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"; - if (verb === "get") { - } - path = getRawAttribute(elt, 'action'); - } - triggerSpecs.forEach(function(triggerSpec) { - addEventListener(elt, function(elt, evt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return - } - issueAjaxRequest(verb, path, elt, evt) - }, nodeData, triggerSpec, true); - }); - } - } - - /** - * - * @param {Event} evt - * @param {HTMLElement} elt - * @returns - */ - function shouldCancel(evt, elt) { - if (evt.type === "submit" || evt.type === "click") { - if (elt.tagName === "FORM") { - return true; - } - if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { - return true; - } - if (elt.tagName === "A" && elt.href && - (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) { - return true; - } - } - return false; - } - - function ignoreBoostedAnchorCtrlClick(elt, evt) { - return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); - } - - function maybeFilterEvent(triggerSpec, elt, evt) { - var eventFilter = triggerSpec.eventFilter; - if(eventFilter){ - try { - return eventFilter.call(elt, evt) !== true; - } catch(e) { - triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); - return true; - } - } - return false; - } - - function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { - var elementData = getInternalData(elt); - var eltsToListenOn; - if (triggerSpec.from) { - eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); - } else { - eltsToListenOn = [elt]; - } - // store the initial values of the elements, so we can tell if they change - if (triggerSpec.changed) { - eltsToListenOn.forEach(function (eltToListenOn) { - var eltToListenOnData = getInternalData(eltToListenOn); - eltToListenOnData.lastValue = eltToListenOn.value; - }) - } - forEach(eltsToListenOn, function (eltToListenOn) { - var eventListener = function (evt) { - if (!bodyContains(elt)) { - eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); - return; - } - if (ignoreBoostedAnchorCtrlClick(elt, evt)) { - return; - } - if (explicitCancel || shouldCancel(evt, elt)) { - evt.preventDefault(); - } - if (maybeFilterEvent(triggerSpec, elt, evt)) { - return; - } - var eventData = getInternalData(evt); - eventData.triggerSpec = triggerSpec; - if (eventData.handledFor == null) { - eventData.handledFor = []; - } - if (eventData.handledFor.indexOf(elt) < 0) { - eventData.handledFor.push(elt); - if (triggerSpec.consume) { - evt.stopPropagation(); - } - if (triggerSpec.target && evt.target) { - if (!matches(evt.target, triggerSpec.target)) { - return; - } - } - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } - } - if (triggerSpec.changed) { - var eltToListenOnData = getInternalData(eltToListenOn) - if (eltToListenOnData.lastValue === eltToListenOn.value) { - return; - } - eltToListenOnData.lastValue = eltToListenOn.value - } - if (elementData.delayed) { - clearTimeout(elementData.delayed); - } - if (elementData.throttle) { - return; - } - - if (triggerSpec.throttle > 0) { - if (!elementData.throttle) { - handler(elt, evt); - elementData.throttle = setTimeout(function () { - elementData.throttle = null; - }, triggerSpec.throttle); - } - } else if (triggerSpec.delay > 0) { - elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); - } else { - triggerEvent(elt, 'htmx:trigger') - handler(elt, evt); - } - } - }; - if (nodeData.listenerInfos == null) { - nodeData.listenerInfos = []; - } - nodeData.listenerInfos.push({ - trigger: triggerSpec.trigger, - listener: eventListener, - on: eltToListenOn - }) - eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); - }); - } - - var windowIsScrolling = false // used by initScrollHandler - var scrollHandler = null; - function initScrollHandler() { - if (!scrollHandler) { - scrollHandler = function() { - windowIsScrolling = true - }; - window.addEventListener("scroll", scrollHandler) - setInterval(function() { - if (windowIsScrolling) { - windowIsScrolling = false; - forEach(getDocument().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"), function (elt) { - maybeReveal(elt); - }) - } - }, 200); - } - } - - function maybeReveal(elt) { - if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { - elt.setAttribute('data-hx-revealed', 'true'); - var nodeData = getInternalData(elt); - if (nodeData.initHash) { - triggerEvent(elt, 'revealed'); - } else { - // if the node isn't initialized, wait for it before triggering the request - elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true}); - } - } - } - - //==================================================================== - // Web Sockets - //==================================================================== - - function processWebSocketInfo(elt, nodeData, info) { - var values = splitOnWhitespace(info); - for (var i = 0; i < values.length; i++) { - var value = values[i].split(/:(.+)/); - if (value[0] === "connect") { - ensureWebSocket(elt, value[1], 0); - } - if (value[0] === "send") { - processWebSocketSend(elt); - } - } - } - - function ensureWebSocket(elt, wssSource, retryCount) { - if (!bodyContains(elt)) { - return; // stop ensuring websocket connection when socket bearing element ceases to exist - } - - if (wssSource.indexOf("/") == 0) { // complete absolute paths only - var base_part = location.hostname + (location.port ? ':'+location.port: ''); - if (location.protocol == 'https:') { - wssSource = "wss://" + base_part + wssSource; - } else if (location.protocol == 'http:') { - wssSource = "ws://" + base_part + wssSource; - } - } - var socket = htmx.createWebSocket(wssSource); - socket.onerror = function (e) { - triggerErrorEvent(elt, "htmx:wsError", {error:e, socket:socket}); - maybeCloseWebSocketSource(elt); - }; - - socket.onclose = function (e) { - if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later - var delay = getWebSocketReconnectDelay(retryCount); - setTimeout(function() { - ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout - }, delay); - } - }; - socket.onopen = function (e) { - retryCount = 0; - } - - getInternalData(elt).webSocket = socket; - socket.addEventListener('message', function (event) { - if (maybeCloseWebSocketSource(elt)) { - return; - } - - var response = event.data; - withExtensions(elt, function(extension){ - response = extension.transformResponse(response, null, elt); - }); - - var settleInfo = makeSettleInfo(elt); - var fragment = makeFragment(response); - var children = toArray(fragment.children); - for (var i = 0; i < children.length; i++) { - var child = children[i]; - oobSwap(getAttributeValue(child, "hx-swap-oob") || "true", child, settleInfo); - } - - settleImmediately(settleInfo.tasks); - }); - } - - function maybeCloseWebSocketSource(elt) { - if (!bodyContains(elt)) { - getInternalData(elt).webSocket.close(); - return true; - } - } - - function processWebSocketSend(elt) { - var webSocketSourceElt = getClosestMatch(elt, function (parent) { - return getInternalData(parent).webSocket != null; - }); - if (webSocketSourceElt) { - elt.addEventListener(getTriggerSpecs(elt)[0].trigger, function (evt) { - var webSocket = getInternalData(webSocketSourceElt).webSocket; - var headers = getHeaders(elt, webSocketSourceElt); - var results = getInputValues(elt, 'post'); - var errors = results.errors; - var rawParameters = results.values; - var expressionVars = getExpressionVars(elt); - var allParameters = mergeObjects(rawParameters, expressionVars); - var filteredParameters = filterValues(allParameters, elt); - filteredParameters['HEADERS'] = headers; - if (errors && errors.length > 0) { - triggerEvent(elt, 'htmx:validation:halted', errors); - return; - } - webSocket.send(JSON.stringify(filteredParameters)); - if(shouldCancel(evt, elt)){ - evt.preventDefault(); - } - }); - } else { - triggerErrorEvent(elt, "htmx:noWebSocketSourceError"); - } - } - - function getWebSocketReconnectDelay(retryCount) { - var delay = htmx.config.wsReconnectDelay; - if (typeof delay === 'function') { - // @ts-ignore - return delay(retryCount); - } - if (delay === 'full-jitter') { - var exp = Math.min(retryCount, 6); - var maxDelay = 1000 * Math.pow(2, exp); - return maxDelay * Math.random(); - } - logError('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"'); - } - - //==================================================================== - // Server Sent Events - //==================================================================== - - function processSSEInfo(elt, nodeData, info) { - var values = splitOnWhitespace(info); - for (var i = 0; i < values.length; i++) { - var value = values[i].split(/:(.+)/); - if (value[0] === "connect") { - processSSESource(elt, value[1]); - } - - if ((value[0] === "swap")) { - processSSESwap(elt, value[1]) - } - } - } - - function processSSESource(elt, sseSrc) { - var source = htmx.createEventSource(sseSrc); - source.onerror = function (e) { - triggerErrorEvent(elt, "htmx:sseError", {error:e, source:source}); - maybeCloseSSESource(elt); - }; - getInternalData(elt).sseEventSource = source; - } - - function processSSESwap(elt, sseEventName) { - var sseSourceElt = getClosestMatch(elt, hasEventSource); - if (sseSourceElt) { - var sseEventSource = getInternalData(sseSourceElt).sseEventSource; - var sseListener = function (event) { - if (maybeCloseSSESource(sseSourceElt)) { - return; - } - if (!bodyContains(elt)) { - sseEventSource.removeEventListener(sseEventName, sseListener); - return; - } - - /////////////////////////// - // TODO: merge this code with AJAX and WebSockets code in the future. - - var response = event.data; - withExtensions(elt, function(extension){ - response = extension.transformResponse(response, null, elt); - }); - - var swapSpec = getSwapSpecification(elt) - var target = getTarget(elt) - var settleInfo = makeSettleInfo(elt); - - selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) - settleImmediately(settleInfo.tasks) - triggerEvent(elt, "htmx:sseMessage", event) - }; - - getInternalData(elt).sseListener = sseListener; - sseEventSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "htmx:noSSESourceError"); - } - } - - function processSSETrigger(elt, handler, sseEventName) { - var sseSourceElt = getClosestMatch(elt, hasEventSource); - if (sseSourceElt) { - var sseEventSource = getInternalData(sseSourceElt).sseEventSource; - var sseListener = function () { - if (!maybeCloseSSESource(sseSourceElt)) { - if (bodyContains(elt)) { - handler(elt); - } else { - sseEventSource.removeEventListener(sseEventName, sseListener); - } - } - }; - getInternalData(elt).sseListener = sseListener; - sseEventSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "htmx:noSSESourceError"); - } - } - - function maybeCloseSSESource(elt) { - if (!bodyContains(elt)) { - getInternalData(elt).sseEventSource.close(); - return true; - } - } - - function hasEventSource(node) { - return getInternalData(node).sseEventSource != null; - } - - //==================================================================== - - function loadImmediately(elt, handler, nodeData, delay) { - var load = function(){ - if (!nodeData.loaded) { - nodeData.loaded = true; - handler(elt); - } - } - if (delay > 0) { - setTimeout(load, delay); - } else { - load(); - } - } - - function processVerbs(elt, nodeData, triggerSpecs) { - var explicitAction = false; - forEach(VERBS, function (verb) { - if (hasAttribute(elt,'hx-' + verb)) { - var path = getAttributeValue(elt, 'hx-' + verb); - explicitAction = true; - nodeData.path = path; - nodeData.verb = verb; - triggerSpecs.forEach(function(triggerSpec) { - addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return - } - issueAjaxRequest(verb, path, elt, evt) - }) - }); - } - }); - return explicitAction; - } - - function addTriggerHandler(elt, triggerSpec, nodeData, handler) { - if (triggerSpec.sseEvent) { - processSSETrigger(elt, handler, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - addEventListener(elt, handler, nodeData, triggerSpec); - maybeReveal(elt); - } else if (triggerSpec.trigger === "intersect") { - var observerOptions = {}; - if (triggerSpec.root) { - observerOptions.root = querySelectorExt(elt, triggerSpec.root) - } - if (triggerSpec.threshold) { - observerOptions.threshold = parseFloat(triggerSpec.threshold); - } - var observer = new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - if (entry.isIntersecting) { - triggerEvent(elt, "intersect"); - break; - } - } - }, observerOptions); - observer.observe(elt); - addEventListener(elt, handler, nodeData, triggerSpec); - } else if (triggerSpec.trigger === "load") { - if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { - loadImmediately(elt, handler, nodeData, triggerSpec.delay); - } - } else if (triggerSpec.pollInterval > 0) { - nodeData.polling = true; - processPolling(elt, handler, triggerSpec); - } else { - addEventListener(elt, handler, nodeData, triggerSpec); - } - } - - function evalScript(script) { - if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) { - var newScript = getDocument().createElement("script"); - forEach(script.attributes, function (attr) { - newScript.setAttribute(attr.name, attr.value); - }); - newScript.textContent = script.textContent; - newScript.async = false; - if (htmx.config.inlineScriptNonce) { - newScript.nonce = htmx.config.inlineScriptNonce; - } - var parent = script.parentElement; - - try { - parent.insertBefore(newScript, script); - } catch (e) { - logError(e); - } finally { - // remove old script element, but only if it is still in DOM - if (script.parentElement) { - script.parentElement.removeChild(script); - } - } - } - } - - function processScripts(elt) { - if (matches(elt, "script")) { - evalScript(elt); - } - forEach(findAll(elt, "script"), function (script) { - evalScript(script); - }); - } - - function shouldProcessHxOn(elt) { - var attributes = elt.attributes - for (var j = 0; j < attributes.length; j++) { - var attrName = attributes[j].name - if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") || - startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) { - return true - } - } - return false - } - - function findHxOnWildcardElements(elt) { - var node = null - var elements = [] - - if (shouldProcessHxOn(elt)) { - elements.push(elt) - } - - if (document.evaluate) { - var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + - ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt) - while (node = iter.iterateNext()) elements.push(node) - } else { - var allElements = elt.getElementsByTagName("*") - for (var i = 0; i < allElements.length; i++) { - if (shouldProcessHxOn(allElements[i])) { - elements.push(allElements[i]) - } - } - } - - return elements - } - - function findElementsToProcess(elt) { - if (elt.querySelectorAll) { - var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; - var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]"); - return results; - } else { - return []; - } - } - - // Handle submit buttons/inputs that have the form attribute set - // see https://developer.mozilla.org/docs/Web/HTML/Element/button - function maybeSetLastButtonClicked(evt) { - var elt = closest(evt.target, "button, input[type='submit']"); - var internalData = getRelatedFormData(evt) - if (internalData) { - internalData.lastButtonClicked = elt; - } - }; - function maybeUnsetLastButtonClicked(evt){ - var internalData = getRelatedFormData(evt) - if (internalData) { - internalData.lastButtonClicked = null; - } - } - function getRelatedFormData(evt) { - var elt = closest(evt.target, "button, input[type='submit']"); - if (!elt) { - return; - } - var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form'); - if (!form) { - return; - } - return getInternalData(form); - } - function initButtonTracking(elt) { - // need to handle both click and focus in: - // focusin - in case someone tabs in to a button and hits the space bar - // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 - elt.addEventListener('click', maybeSetLastButtonClicked) - elt.addEventListener('focusin', maybeSetLastButtonClicked) - elt.addEventListener('focusout', maybeUnsetLastButtonClicked) - } - - function countCurlies(line) { - var tokens = tokenizeString(line); - var netCurlies = 0; - for (var i = 0; i < tokens.length; i++) { - const token = tokens[i]; - if (token === "{") { - netCurlies++; - } else if (token === "}") { - netCurlies--; - } - } - return netCurlies; - } - - function addHxOnEventHandler(elt, eventName, code) { - var nodeData = getInternalData(elt); - if (!Array.isArray(nodeData.onHandlers)) { - nodeData.onHandlers = []; - } - var func; - var listener = function (e) { - return maybeEval(elt, function() { - if (!func) { - func = new Function("event", code); - } - func.call(elt, e); - }); - }; - elt.addEventListener(eventName, listener); - nodeData.onHandlers.push({event:eventName, listener:listener}); - } - - function processHxOn(elt) { - var hxOnValue = getAttributeValue(elt, 'hx-on'); - if (hxOnValue) { - var handlers = {} - var lines = hxOnValue.split("\n"); - var currentEvent = null; - var curlyCount = 0; - while (lines.length > 0) { - var line = lines.shift(); - var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/); - if (curlyCount === 0 && match) { - line.split(":") - currentEvent = match[1].slice(0, -1); // strip last colon - handlers[currentEvent] = match[2]; - } else { - handlers[currentEvent] += line; - } - curlyCount += countCurlies(line); - } - - for (var eventName in handlers) { - addHxOnEventHandler(elt, eventName, handlers[eventName]); - } - } - } - - function processHxOnWildcard(elt) { - // wipe any previous on handlers so that this function takes precedence - deInitOnHandlers(elt) - - for (var i = 0; i < elt.attributes.length; i++) { - var name = elt.attributes[i].name - var value = elt.attributes[i].value - if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) { - var afterOnPosition = name.indexOf("-on") + 3; - var nextChar = name.slice(afterOnPosition, afterOnPosition + 1); - if (nextChar === "-" || nextChar === ":") { - var eventName = name.slice(afterOnPosition + 1); - // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support - if (startsWith(eventName, ":")) { - eventName = "htmx" + eventName - } else if (startsWith(eventName, "-")) { - eventName = "htmx:" + eventName.slice(1); - } else if (startsWith(eventName, "htmx-")) { - eventName = "htmx:" + eventName.slice(5); - } - - addHxOnEventHandler(elt, eventName, value) - } - } - } - } - - function initNode(elt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return; - } - var nodeData = getInternalData(elt); - if (nodeData.initHash !== attributeHash(elt)) { - // clean up any previously processed info - deInitNode(elt); - - nodeData.initHash = attributeHash(elt); - - processHxOn(elt); - - triggerEvent(elt, "htmx:beforeProcessNode") - - if (elt.value) { - nodeData.lastValue = elt.value; - } - - var triggerSpecs = getTriggerSpecs(elt); - var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs); - - if (!hasExplicitHttpAction) { - if (getClosestAttributeValue(elt, "hx-boost") === "true") { - boostElement(elt, nodeData, triggerSpecs); - } else if (hasAttribute(elt, 'hx-trigger')) { - triggerSpecs.forEach(function (triggerSpec) { - // For "naked" triggers, don't do anything at all - addTriggerHandler(elt, triggerSpec, nodeData, function () { - }) - }) - } - } - - // Handle submit buttons/inputs that have the form attribute set - // see https://developer.mozilla.org/docs/Web/HTML/Element/button - if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) { - initButtonTracking(elt) - } - - var sseInfo = getAttributeValue(elt, 'hx-sse'); - if (sseInfo) { - processSSEInfo(elt, nodeData, sseInfo); - } - - var wsInfo = getAttributeValue(elt, 'hx-ws'); - if (wsInfo) { - processWebSocketInfo(elt, nodeData, wsInfo); - } - triggerEvent(elt, "htmx:afterProcessNode"); - } - } - - function processNode(elt) { - elt = resolveTarget(elt); - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return; - } - initNode(elt); - forEach(findElementsToProcess(elt), function(child) { initNode(child) }); - // Because it happens second, the new way of adding onHandlers superseeds the old one - // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored - forEach(findHxOnWildcardElements(elt), processHxOnWildcard); - } - - //==================================================================== - // Event/Log Support - //==================================================================== - - function kebabEventName(str) { - return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase(); - } - - 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({error:eventName}, detail)); - } - - function ignoreEventForLogging(eventName) { - return eventName === "htmx:afterProcessNode" - } - - /** - * `withExtensions` locates all active extensions for a provided element, then - * executes the provided function using each of the active extensions. It should - * be called internally at every extendable execution point in htmx. - * - * @param {HTMLElement} elt - * @param {(extension:import("./htmx").HtmxExtension) => void} toDo - * @returns void - */ - function withExtensions(elt, toDo) { - forEach(getExtensions(elt), function(extension){ - try { - toDo(extension); - } catch (e) { - logError(e); - } - }); - } - - function logError(msg) { - if(console.error) { - console.error(msg); - } else if (console.log) { - console.log("ERROR: ", msg); - } - } - - function triggerEvent(elt, eventName, detail) { - elt = resolveTarget(elt); - if (detail == null) { - detail = {}; - } - detail["elt"] = elt; - var event = makeEvent(eventName, detail); - if (htmx.logger && !ignoreEventForLogging(eventName)) { - htmx.logger(elt, eventName, detail); - } - if (detail.error) { - logError(detail.error); - triggerEvent(elt, "htmx:error", {errorInfo:detail}) - } - var eventResult = elt.dispatchEvent(event); - var kebabName = kebabEventName(eventName); - if (eventResult && kebabName !== eventName) { - var kebabedEvent = makeEvent(kebabName, event.detail); - eventResult = eventResult && elt.dispatchEvent(kebabedEvent) - } - withExtensions(elt, function (extension) { - eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) - }); - return eventResult; - } - - //==================================================================== - // History Support - //==================================================================== - var currentPathForHistory = location.pathname+location.search; - - function getHistoryElement() { - var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]'); - return historyElt || getDocument().body; - } - - function saveToHistoryCache(url, content, title, scroll) { - if (!canAccessLocalStorage()) { - return; - } - - if (htmx.config.historyCacheSize <= 0) { - // make sure that an eventually already existing cache is purged - localStorage.removeItem("htmx-history-cache"); - return; - } - - url = normalizePath(url); - - var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - historyCache.splice(i, 1); - break; - } - } - var newHistoryItem = {url:url, content: content, title:title, scroll:scroll}; - triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache}) - historyCache.push(newHistoryItem) - while (historyCache.length > htmx.config.historyCacheSize) { - historyCache.shift(); - } - while(historyCache.length > 0){ - try { - localStorage.setItem("htmx-history-cache", JSON.stringify(historyCache)); - break; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:historyCacheError", {cause:e, cache: historyCache}) - historyCache.shift(); // shrink the cache and retry - } - } - } - - function getCachedHistory(url) { - if (!canAccessLocalStorage()) { - return null; - } - - url = normalizePath(url); - - var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - return historyCache[i]; - } - } - return null; - } - - function cleanInnerHtmlForHistory(elt) { - var className = htmx.config.requestClass; - var clone = elt.cloneNode(true); - forEach(findAll(clone, "." + className), function(child){ - removeClassFromElement(child, className); - }); - return clone.innerHTML; - } - - function saveCurrentPageToHistory() { - var elt = getHistoryElement(); - var path = currentPathForHistory || location.pathname+location.search; - - // Allow history snapshot feature to be disabled where hx-history="false" - // is present *anywhere* in the current document we're about to save, - // so we can prevent privileged data entering the cache. - // The page will still be reachable as a history entry, but htmx will fetch it - // live from the server onpopstate rather than look in the localStorage cache - var disableHistoryCache - try { - disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') - } catch (e) { - // IE11: insensitive modifier not supported so fallback to case sensitive selector - disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') - } - if (!disableHistoryCache) { - triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt}); - saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); - } - - if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href); - } - - function pushUrlIntoHistory(path) { - // remove the cache buster parameter, if any - if (htmx.config.getCacheBusterParam) { - path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') - if (endsWith(path, '&') || endsWith(path, "?")) { - path = path.slice(0, -1); - } - } - if(htmx.config.historyEnabled) { - history.pushState({htmx:true}, "", path); - } - currentPathForHistory = path; - } - - function replaceUrlInHistory(path) { - if(htmx.config.historyEnabled) history.replaceState({htmx:true}, "", path); - currentPathForHistory = path; - } - - function settleImmediately(tasks) { - forEach(tasks, function (task) { - task.call(); - }); - } - - function loadHistoryFromServer(path) { - var request = new XMLHttpRequest(); - var details = {path: path, xhr:request}; - triggerEvent(getDocument().body, "htmx:historyCacheMiss", details); - request.open('GET', path, true); - request.setRequestHeader("HX-Request", "true"); - request.setRequestHeader("HX-History-Restore-Request", "true"); - request.setRequestHeader("HX-Current-URL", getDocument().location.href); - request.onload = function () { - if (this.status >= 200 && this.status < 400) { - triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); - var fragment = makeFragment(this.response); - // @ts-ignore - fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; - var historyElement = getHistoryElement(); - var settleInfo = makeSettleInfo(historyElement); - var title = findTitle(this.response); - if (title) { - var titleElt = find("title"); - if (titleElt) { - titleElt.innerHTML = title; - } else { - window.document.title = title; - } - } - // @ts-ignore - swapInnerHTML(historyElement, fragment, settleInfo) - settleImmediately(settleInfo.tasks); - currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response}); - } else { - triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details); - } - }; - request.send(); - } - - function restoreHistory(path) { - saveCurrentPageToHistory(); - path = path || location.pathname+location.search; - var cached = getCachedHistory(path); - if (cached) { - var fragment = makeFragment(cached.content); - var historyElement = getHistoryElement(); - var settleInfo = makeSettleInfo(historyElement); - swapInnerHTML(historyElement, fragment, settleInfo) - settleImmediately(settleInfo.tasks); - document.title = cached.title; - setTimeout(function () { - window.scrollTo(0, cached.scroll); - }, 0); // next 'tick', so browser has time to render layout - currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); - } else { - if (htmx.config.refreshOnHistoryMiss) { - - // @ts-ignore: optional parameter in reload() function throws error - window.location.reload(true); - } else { - loadHistoryFromServer(path); - } - } - } - - function addRequestIndicatorClasses(elt) { - var indicators = findAttributeTargets(elt, 'hx-indicator'); - if (indicators == null) { - indicators = [elt]; - } - forEach(indicators, function (ic) { - var internalData = getInternalData(ic); - internalData.requestCount = (internalData.requestCount || 0) + 1; - ic.classList["add"].call(ic.classList, htmx.config.requestClass); - }); - return indicators; - } - - function disableElements(elt) { - var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt'); - if (disabledElts == null) { - disabledElts = []; - } - forEach(disabledElts, function (disabledElement) { - var internalData = getInternalData(disabledElement); - internalData.requestCount = (internalData.requestCount || 0) + 1; - disabledElement.setAttribute("disabled", ""); - }); - return disabledElts; - } - - function removeRequestIndicators(indicators, disabled) { - forEach(indicators, function (ic) { - var internalData = getInternalData(ic); - internalData.requestCount = (internalData.requestCount || 0) - 1; - if (internalData.requestCount === 0) { - ic.classList["remove"].call(ic.classList, htmx.config.requestClass); - } - }); - forEach(disabled, function (disabledElement) { - var internalData = getInternalData(disabledElement); - internalData.requestCount = (internalData.requestCount || 0) - 1; - if (internalData.requestCount === 0) { - disabledElement.removeAttribute('disabled'); - } - }); - } - - //==================================================================== - // 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 || closest(elt, "fieldset[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 addValueToValues(name, value, values) { - // This is a little ugly because both the current value of the named value in the form - // and the new value could be arrays, so we have to handle all four cases :/ - if (name != null && value != null) { - var current = values[name]; - if (current === undefined) { - values[name] = value; - } else if (Array.isArray(current)) { - if (Array.isArray(value)) { - values[name] = current.concat(value); - } else { - current.push(value); - } - } else { - if (Array.isArray(value)) { - values[name] = [current].concat(value); - } else { - values[name] = [current, value]; - } - } - } - } - - function processInputValue(processed, values, errors, elt, validate) { - if (elt == null || haveSeenNode(processed, elt)) { - return; - } else { - processed.push(elt); - } - if (shouldInclude(elt)) { - var name = getRawAttribute(elt,"name"); - var value = elt.value; - if (elt.multiple && elt.tagName === "SELECT") { - value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value }); - } - // include file inputs - if (elt.files) { - value = toArray(elt.files); - } - addValueToValues(name, value, values); - if (validate) { - validateElement(elt, errors); - } - } - if (matches(elt, 'form')) { - var inputs = elt.elements; - forEach(inputs, function(input) { - processInputValue(processed, values, errors, input, validate); - }); - } - } - - function validateElement(element, errors) { - if (element.willValidate) { - triggerEvent(element, "htmx:validation:validate") - if (!element.checkValidity()) { - errors.push({elt: element, message:element.validationMessage, validity:element.validity}); - triggerEvent(element, "htmx:validation:failed", {message:element.validationMessage, validity:element.validity}) - } - } - } - - /** - * @param {HTMLElement} elt - * @param {string} verb - */ - function getInputValues(elt, verb) { - var processed = []; - var values = {}; - var formValues = {}; - var errors = []; - var internalData = getInternalData(elt); - if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { - internalData.lastButtonClicked = null - } - - // only validate when form is directly submitted and novalidate or formnovalidate are not set - // or if the element has an explicit hx-validate="true" on it - var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true"; - if (internalData.lastButtonClicked) { - validate = validate && internalData.lastButtonClicked.formNoValidate !== true; - } - - // for a non-GET include the closest form - if (verb !== 'get') { - processInputValue(processed, formValues, errors, closest(elt, 'form'), validate); - } - - // include the element itself - processInputValue(processed, values, errors, elt, validate); - - // if a button or submit was clicked last, include its value - if (internalData.lastButtonClicked || elt.tagName === "BUTTON" || - (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) { - var button = internalData.lastButtonClicked || elt - var name = getRawAttribute(button, "name") - addValueToValues(name, button.value, formValues) - } - - // include any explicit includes - var includes = findAttributeTargets(elt, "hx-include"); - forEach(includes, function(node) { - processInputValue(processed, values, errors, node, validate); - // if a non-form is included, include any input values within it - if (!matches(node, 'form')) { - forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { - processInputValue(processed, values, errors, descendant, validate); - }) - } - }); - - // form values take precedence, overriding the regular values - values = mergeObjects(values, formValues); - - return {errors:errors, values:values}; - } - - function appendParam(returnStr, name, realValue) { - if (returnStr !== "") { - returnStr += "&"; - } - if (String(realValue) === "[object Object]") { - realValue = JSON.stringify(realValue); - } - var s = encodeURIComponent(realValue); - returnStr += encodeURIComponent(name) + "=" + s; - 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; - } - - function makeFormData(values) { - var formData = new FormData(); - for (var name in values) { - if (values.hasOwnProperty(name)) { - var value = values[name]; - if (Array.isArray(value)) { - forEach(value, function(v) { - formData.append(name, v); - }); - } else { - formData.append(name, value); - } - } - } - return formData; - } - - //==================================================================== - // Ajax - //==================================================================== - - /** - * @param {HTMLElement} elt - * @param {HTMLElement} target - * @param {string} prompt - * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification - */ - function getHeaders(elt, target, prompt) { - var headers = { - "HX-Request" : "true", - "HX-Trigger" : getRawAttribute(elt, "id"), - "HX-Trigger-Name" : getRawAttribute(elt, "name"), - "HX-Target" : getAttributeValue(target, "id"), - "HX-Current-URL" : getDocument().location.href, - } - getValuesForElement(elt, "hx-headers", false, headers) - if (prompt !== undefined) { - headers["HX-Prompt"] = prompt; - } - if (getInternalData(elt).boosted) { - headers["HX-Boosted"] = "true"; - } - return headers; - } - - /** - * filterValues takes an object containing form input values - * and returns a new object that only contains keys that are - * specified by the closest "hx-params" attribute - * @param {Object} inputValues - * @param {HTMLElement} elt - * @returns {Object} - */ - function filterValues(inputValues, elt) { - var paramsValue = getClosestAttributeValue(elt, "hx-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 isAnchorLink(elt) { - return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0 - } - - /** - * - * @param {HTMLElement} elt - * @param {string} swapInfoOverride - * @returns {import("./htmx").HtmxSwapSpecification} - */ - function getSwapSpecification(elt, swapInfoOverride) { - var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap"); - var swapSpec = { - "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, - "swapDelay" : htmx.config.defaultSwapDelay, - "settleDelay" : htmx.config.defaultSettleDelay - } - if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { - swapSpec["show"] = "top" - } - if (swapInfo) { - var split = splitOnWhitespace(swapInfo); - if (split.length > 0) { - for (var i = 0; i < split.length; i++) { - var value = split[i]; - if (value.indexOf("swap:") === 0) { - swapSpec["swapDelay"] = parseInterval(value.substr(5)); - } else if (value.indexOf("settle:") === 0) { - swapSpec["settleDelay"] = parseInterval(value.substr(7)); - } else if (value.indexOf("transition:") === 0) { - swapSpec["transition"] = value.substr(11) === "true"; - } else if (value.indexOf("ignoreTitle:") === 0) { - swapSpec["ignoreTitle"] = value.substr(12) === "true"; - } else if (value.indexOf("scroll:") === 0) { - var scrollSpec = value.substr(7); - var splitSpec = scrollSpec.split(":"); - var scrollVal = splitSpec.pop(); - var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; - swapSpec["scroll"] = scrollVal; - swapSpec["scrollTarget"] = selectorVal; - } else if (value.indexOf("show:") === 0) { - var showSpec = value.substr(5); - var splitSpec = showSpec.split(":"); - var showVal = splitSpec.pop(); - var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; - swapSpec["show"] = showVal; - swapSpec["showTarget"] = selectorVal; - } else if (value.indexOf("focus-scroll:") === 0) { - var focusScrollVal = value.substr("focus-scroll:".length); - swapSpec["focusScroll"] = focusScrollVal == "true"; - } else if (i == 0) { - swapSpec["swapStyle"] = value; - } else { - logError('Unknown modifier in hx-swap: ' + value); - } - } - } - } - return swapSpec; - } - - function usesFormData(elt) { - return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || - (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data"); - } - - function encodeParamsForBody(xhr, elt, filteredParameters) { - var encodedParameters = null; - withExtensions(elt, function (extension) { - if (encodedParameters == null) { - encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt); - } - }); - if (encodedParameters != null) { - return encodedParameters; - } else { - if (usesFormData(elt)) { - return makeFormData(filteredParameters); - } else { - return urlEncode(filteredParameters); - } - } - } - - /** - * - * @param {Element} target - * @returns {import("./htmx").HtmxSettleInfo} - */ - function makeSettleInfo(target) { - return {tasks: [], elts: [target]}; - } - - function updateScrollState(content, swapSpec) { - var first = content[0]; - var last = content[content.length - 1]; - if (swapSpec.scroll) { - var target = null; - if (swapSpec.scrollTarget) { - target = querySelectorExt(first, swapSpec.scrollTarget); - } - if (swapSpec.scroll === "top" && (first || target)) { - target = target || first; - target.scrollTop = 0; - } - if (swapSpec.scroll === "bottom" && (last || target)) { - target = target || last; - target.scrollTop = target.scrollHeight; - } - } - if (swapSpec.show) { - var target = null; - if (swapSpec.showTarget) { - var targetStr = swapSpec.showTarget; - if (swapSpec.showTarget === "window") { - targetStr = "body"; - } - target = querySelectorExt(first, targetStr); - } - if (swapSpec.show === "top" && (first || target)) { - target = target || first; - target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior}); - } - if (swapSpec.show === "bottom" && (last || target)) { - target = target || last; - target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior}); - } - } - } - - /** - * @param {HTMLElement} elt - * @param {string} attr - * @param {boolean=} evalAsDefault - * @param {Object=} values - * @returns {Object} - */ - function getValuesForElement(elt, attr, evalAsDefault, values) { - if (values == null) { - values = {}; - } - if (elt == null) { - return values; - } - var attributeValue = getAttributeValue(elt, attr); - if (attributeValue) { - var str = attributeValue.trim(); - var evaluateValue = evalAsDefault; - if (str === "unset") { - return null; - } - if (str.indexOf("javascript:") === 0) { - str = str.substr(11); - evaluateValue = true; - } else if (str.indexOf("js:") === 0) { - str = str.substr(3); - evaluateValue = true; - } - if (str.indexOf('{') !== 0) { - str = "{" + str + "}"; - } - var varsValues; - if (evaluateValue) { - varsValues = maybeEval(elt,function () {return Function("return (" + str + ")")();}, {}); - } else { - varsValues = parseJSON(str); - } - for (var key in varsValues) { - if (varsValues.hasOwnProperty(key)) { - if (values[key] == null) { - values[key] = varsValues[key]; - } - } - } - } - return getValuesForElement(parentElt(elt), attr, evalAsDefault, values); - } - - function maybeEval(elt, toEval, defaultVal) { - if (htmx.config.allowEval) { - return toEval(); - } else { - triggerErrorEvent(elt, 'htmx:evalDisallowedError'); - return defaultVal; - } - } - - /** - * @param {HTMLElement} elt - * @param {*} expressionVars - * @returns - */ - function getHXVarsForElement(elt, expressionVars) { - return getValuesForElement(elt, "hx-vars", true, expressionVars); - } - - /** - * @param {HTMLElement} elt - * @param {*} expressionVars - * @returns - */ - function getHXValsForElement(elt, expressionVars) { - return getValuesForElement(elt, "hx-vals", false, expressionVars); - } - - /** - * @param {HTMLElement} elt - * @returns {Object} - */ - function getExpressionVars(elt) { - return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)); - } - - function safelySetHeaderValue(xhr, header, headerValue) { - if (headerValue !== null) { - try { - xhr.setRequestHeader(header, headerValue); - } catch (e) { - // On an exception, try to set the header URI encoded instead - xhr.setRequestHeader(header, encodeURIComponent(headerValue)); - xhr.setRequestHeader(header + "-URI-AutoEncoded", "true"); - } - } - } - - function getPathFromResponse(xhr) { - // NB: IE11 does not support this stuff - if (xhr.responseURL && typeof(URL) !== "undefined") { - try { - var url = new URL(xhr.responseURL); - return url.pathname + url.search; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:badResponseUrl", {url: xhr.responseURL}); - } - } - } - - function hasHeader(xhr, regexp) { - return regexp.test(xhr.getAllResponseHeaders()) - } - - function ajaxHelper(verb, path, context) { - verb = verb.toLowerCase(); - if (context) { - if (context instanceof Element || isType(context, 'String')) { - return issueAjaxRequest(verb, path, null, null, { - targetOverride: resolveTarget(context), - returnPromise: true - }); - } else { - return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, - { - handler : context.handler, - headers : context.headers, - values : context.values, - targetOverride: resolveTarget(context.target), - swapOverride: context.swap, - select: context.select, - returnPromise: true - }); - } - } else { - return issueAjaxRequest(verb, path, null, null, { - returnPromise: true - }); - } - } - - function hierarchyForElt(elt) { - var arr = []; - while (elt) { - arr.push(elt); - elt = elt.parentElement; - } - return arr; - } - - function verifyPath(elt, path, requestConfig) { - var sameHost - var url - if (typeof URL === "function") { - url = new URL(path, document.location.href); - var origin = document.location.origin; - sameHost = origin === url.origin; - } else { - // IE11 doesn't support URL - url = path - sameHost = startsWith(path, document.location.origin) - } - - if (htmx.config.selfRequestsOnly) { - if (!sameHost) { - return false; - } - } - return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig)); - } - - function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { - var resolve = null; - var reject = null; - etc = etc != null ? etc : {}; - if(etc.returnPromise && typeof Promise !== "undefined"){ - var promise = new Promise(function (_resolve, _reject) { - resolve = _resolve; - reject = _reject; - }); - } - if(elt == null) { - elt = getDocument().body; - } - var responseHandler = etc.handler || handleAjaxResponse; - var select = etc.select || null; - - if (!bodyContains(elt)) { - // do not issue requests for elements removed from the DOM - maybeCall(resolve); - return promise; - } - var target = etc.targetOverride || getTarget(elt); - if (target == null || target == DUMMY_ELT) { - triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); - maybeCall(reject); - return promise; - } - - var eltData = getInternalData(elt); - var submitter = eltData.lastButtonClicked; - - if (submitter) { - var buttonPath = getRawAttribute(submitter, "formaction"); - if (buttonPath != null) { - path = buttonPath; - } - - var buttonVerb = getRawAttribute(submitter, "formmethod") - if (buttonVerb != null) { - // ignore buttons with formmethod="dialog" - if (buttonVerb.toLowerCase() !== "dialog") { - verb = buttonVerb; - } - } - } - - var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); - // allow event-based confirmation w/ a callback - if (confirmed === undefined) { - var issueRequest = function(skipConfirmation) { - return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation); - } - var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion}; - if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { - maybeCall(resolve); - return promise; - } - } - - var syncElt = elt; - var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); - var queueStrategy = null; - var abortable = false; - if (syncStrategy) { - var syncStrings = syncStrategy.split(":"); - var selector = syncStrings[0].trim(); - if (selector === "this") { - syncElt = findThisElement(elt, 'hx-sync'); - } else { - syncElt = querySelectorExt(elt, selector); - } - // default to the drop strategy - syncStrategy = (syncStrings[1] || 'drop').trim(); - eltData = getInternalData(syncElt); - if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { - maybeCall(resolve); - return promise; - } else if (syncStrategy === "abort") { - if (eltData.xhr) { - maybeCall(resolve); - return promise; - } else { - abortable = true; - } - } else if (syncStrategy === "replace") { - triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue - } else if (syncStrategy.indexOf("queue") === 0) { - var queueStrArray = syncStrategy.split(" "); - queueStrategy = (queueStrArray[1] || "last").trim(); - } - } - - if (eltData.xhr) { - if (eltData.abortable) { - triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue - } else { - if(queueStrategy == null){ - if (event) { - var eventData = getInternalData(event); - if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { - queueStrategy = eventData.triggerSpec.queue; - } - } - if (queueStrategy == null) { - queueStrategy = "last"; - } - } - if (eltData.queuedRequests == null) { - eltData.queuedRequests = []; - } - if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } else if (queueStrategy === "all") { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } else if (queueStrategy === "last") { - eltData.queuedRequests = []; // dump existing queue - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } - maybeCall(resolve); - return promise; - } - } - - var xhr = new XMLHttpRequest(); - eltData.xhr = xhr; - eltData.abortable = abortable; - var endRequestLock = function(){ - eltData.xhr = null; - eltData.abortable = false; - if (eltData.queuedRequests != null && - eltData.queuedRequests.length > 0) { - var queuedRequest = eltData.queuedRequests.shift(); - queuedRequest(); - } - } - var promptQuestion = getClosestAttributeValue(elt, "hx-prompt"); - if (promptQuestion) { - var promptResponse = prompt(promptQuestion); - // prompt returns null if cancelled and empty string if accepted with no entry - if (promptResponse === null || - !triggerEvent(elt, 'htmx:prompt', {prompt: promptResponse, target:target})) { - maybeCall(resolve); - endRequestLock(); - return promise; - } + triggerErrorEvent(getDocument().body, 'htmx:syntax:error', { error: e, source: conditionalSource }) + return null } + } + } else if (token === '[') { + bracketCount++ + } + if (isPossibleRelativeReference(token, last, paramName)) { + conditionalSource += '((' + paramName + '.' + token + ') ? (' + paramName + '.' + token + ') : (window.' + token + '))' + } else { + conditionalSource = conditionalSource + token + } + last = tokens.shift() + } + } + } + + /** + * @param {string[]} tokens + * @param {RegExp} match + * @returns {string} + */ + function consumeUntil(tokens, match) { + let result = '' + while (tokens.length > 0 && !match.test(tokens[0])) { + result += tokens.shift() + } + return result + } + + /** + * @param {string[]} tokens + * @returns {string} + */ + function consumeCSSSelector(tokens) { + let result + if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { + tokens.shift() + result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim() + tokens.shift() + } else { + result = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } + return result + } + + const INPUT_SELECTOR = 'input, textarea, select' + + /** + * @param {Element} elt + * @param {string} explicitTrigger + * @param {Object} cache for trigger specs + * @returns {HtmxTriggerSpecification[]} + */ + function parseAndCacheTrigger(elt, explicitTrigger, cache) { + /** @type HtmxTriggerSpecification[] */ + const triggerSpecs = [] + const tokens = tokenizeString(explicitTrigger) + do { + consumeUntil(tokens, NOT_WHITESPACE) + const initialLength = tokens.length + const trigger = consumeUntil(tokens, /[,\[\s]/) + if (trigger !== '') { + if (trigger === 'every') { + /** @type HtmxTriggerSpecification */ + const every = { trigger: 'every' } + consumeUntil(tokens, NOT_WHITESPACE) + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)) + consumeUntil(tokens, NOT_WHITESPACE) + var eventFilter = maybeGenerateConditional(elt, tokens, 'event') + if (eventFilter) { + every.eventFilter = eventFilter + } + triggerSpecs.push(every) + } else { + /** @type HtmxTriggerSpecification */ + const triggerSpec = { trigger } + var eventFilter = maybeGenerateConditional(elt, tokens, 'event') + if (eventFilter) { + triggerSpec.eventFilter = eventFilter + } + while (tokens.length > 0 && tokens[0] !== ',') { + consumeUntil(tokens, NOT_WHITESPACE) + const token = tokens.shift() + if (token === 'changed') { + triggerSpec.changed = true + } else if (token === 'once') { + triggerSpec.once = true + } else if (token === 'consume') { + triggerSpec.consume = true + } else if (token === 'delay' && tokens[0] === ':') { + tokens.shift() + triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)) + } else if (token === 'from' && tokens[0] === ':') { + tokens.shift() + if (COMBINED_SELECTOR_START.test(tokens[0])) { + var from_arg = consumeCSSSelector(tokens) + } else { + var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA) + if (from_arg === 'closest' || from_arg === 'find' || from_arg === 'next' || from_arg === 'previous') { + tokens.shift() + const selector = consumeCSSSelector(tokens) + // `next` and `previous` allow a selector-less syntax + if (selector.length > 0) { + from_arg += ' ' + selector + } + } + } + triggerSpec.from = from_arg + } else if (token === 'target' && tokens[0] === ':') { + tokens.shift() + triggerSpec.target = consumeCSSSelector(tokens) + } else if (token === 'throttle' && tokens[0] === ':') { + tokens.shift() + triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)) + } else if (token === 'queue' && tokens[0] === ':') { + tokens.shift() + triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } else if (token === 'root' && tokens[0] === ':') { + tokens.shift() + triggerSpec[token] = consumeCSSSelector(tokens) + } else if (token === 'threshold' && tokens[0] === ':') { + tokens.shift() + triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } else { + triggerErrorEvent(elt, 'htmx:syntax:error', { token: tokens.shift() }) + } + } + triggerSpecs.push(triggerSpec) + } + } + if (tokens.length === initialLength) { + triggerErrorEvent(elt, 'htmx:syntax:error', { token: tokens.shift() }) + } + consumeUntil(tokens, NOT_WHITESPACE) + } while (tokens[0] === ',' && tokens.shift()) + if (cache) { + cache[explicitTrigger] = triggerSpecs + } + return triggerSpecs + } + + /** + * @param {Element} elt + * @returns {HtmxTriggerSpecification[]} + */ + function getTriggerSpecs(elt) { + const explicitTrigger = getAttributeValue(elt, 'hx-trigger') + let triggerSpecs = [] + if (explicitTrigger) { + const cache = htmx.config.triggerSpecsCache + triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) + } - if (confirmQuestion && !confirmed) { - if(!confirm(confirmQuestion)) { - maybeCall(resolve); - endRequestLock() - return promise; - } + if (triggerSpecs.length > 0) { + return triggerSpecs + } else if (matches(elt, 'form')) { + return [{ trigger: 'submit' }] + } else if (matches(elt, 'input[type="button"], input[type="submit"]')) { + return [{ trigger: 'click' }] + } else if (matches(elt, INPUT_SELECTOR)) { + return [{ trigger: 'change' }] + } else { + return [{ trigger: 'click' }] + } + } + + /** + * @param {Element} elt + */ + function cancelPolling(elt) { + getInternalData(elt).cancelled = true + } + + /** + * @param {Element} elt + * @param {TriggerHandler} handler + * @param {HtmxTriggerSpecification} spec + */ + function processPolling(elt, handler, spec) { + const nodeData = getInternalData(elt) + nodeData.timeout = getWindow().setTimeout(function() { + if (bodyContains(elt) && nodeData.cancelled !== true) { + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { + handler(elt) + } + processPolling(elt, handler, spec) + } + }, spec.pollInterval) + } + + /** + * @param {HTMLAnchorElement} elt + * @returns {boolean} + */ + function isLocalLink(elt) { + return location.hostname === elt.hostname && + getRawAttribute(elt, 'href') && + getRawAttribute(elt, 'href').indexOf('#') !== 0 + } + + /** + * @param {Element} elt + */ + function eltIsDisabled(elt) { + return closest(elt, htmx.config.disableSelector) + } + + /** + * @param {Element} elt + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification[]} triggerSpecs + */ + function boostElement(elt, nodeData, triggerSpecs) { + if ((elt instanceof HTMLAnchorElement && isLocalLink(elt) && (elt.target === '' || elt.target === '_self')) || elt.tagName === 'FORM') { + nodeData.boosted = true + let verb, path + if (elt.tagName === 'A') { + verb = 'get' + path = getRawAttribute(elt, 'href') + } else { + const rawAttribute = getRawAttribute(elt, 'method') + verb = rawAttribute ? rawAttribute.toLowerCase() : 'get' + if (verb === 'get') { + } + path = getRawAttribute(elt, 'action') + } + triggerSpecs.forEach(function(triggerSpec) { + addEventListener(elt, function(node, evt) { + const elt = asElement(node) + if (eltIsDisabled(elt)) { + cleanUpElement(elt) + return + } + issueAjaxRequest(verb, path, elt, evt) + }, nodeData, triggerSpec, true) + }) + } + } + + /** + * @param {Event} evt + * @param {Node} node + * @returns {boolean} + */ + function shouldCancel(evt, node) { + const elt = asElement(node) + if (!elt) { + return false + } + if (evt.type === 'submit' || evt.type === 'click') { + if (elt.tagName === 'FORM') { + return true + } + if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { + return true + } + if (elt instanceof HTMLAnchorElement && elt.href && + (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf('#') !== 0)) { + return true + } + } + return false + } + + /** + * @param {Node} elt + * @param {Event|MouseEvent|KeyboardEvent|TouchEvent} evt + * @returns {boolean} + */ + function ignoreBoostedAnchorCtrlClick(elt, evt) { + return getInternalData(elt).boosted && elt instanceof HTMLAnchorElement && evt.type === 'click' && + // @ts-ignore this will resolve to undefined for events that don't define those properties, which is fine + (evt.ctrlKey || evt.metaKey) + } + + /** + * @param {HtmxTriggerSpecification} triggerSpec + * @param {Node} elt + * @param {Event} evt + * @returns {boolean} + */ + function maybeFilterEvent(triggerSpec, elt, evt) { + const eventFilter = triggerSpec.eventFilter + if (eventFilter) { + try { + return eventFilter.call(elt, evt) !== true + } catch (e) { + const source = eventFilter.source + triggerErrorEvent(getDocument().body, 'htmx:eventFilter:error', { error: e, source }) + return true + } + } + return false + } + + /** + * @param {Node} elt + * @param {TriggerHandler} handler + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification} triggerSpec + * @param {boolean} [explicitCancel] + */ + function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { + const elementData = getInternalData(elt) + /** @type {(Node|Window)[]} */ + let eltsToListenOn + if (triggerSpec.from) { + eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from) + } else { + eltsToListenOn = [elt] + } + // store the initial values of the elements, so we can tell if they change + if (triggerSpec.changed) { + eltsToListenOn.forEach(function(eltToListenOn) { + const eltToListenOnData = getInternalData(eltToListenOn) + // @ts-ignore value will be undefined for non-input elements, which is fine + eltToListenOnData.lastValue = eltToListenOn.value + }) + } + forEach(eltsToListenOn, function(eltToListenOn) { + /** @type EventListener */ + const eventListener = function(evt) { + if (!bodyContains(elt)) { + eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener) + return + } + if (ignoreBoostedAnchorCtrlClick(elt, evt)) { + return + } + if (explicitCancel || shouldCancel(evt, elt)) { + evt.preventDefault() + } + if (maybeFilterEvent(triggerSpec, elt, evt)) { + return + } + const eventData = getInternalData(evt) + eventData.triggerSpec = triggerSpec + if (eventData.handledFor == null) { + eventData.handledFor = [] + } + if (eventData.handledFor.indexOf(elt) < 0) { + eventData.handledFor.push(elt) + if (triggerSpec.consume) { + evt.stopPropagation() + } + if (triggerSpec.target && evt.target) { + if (!matches(asElement(evt.target), triggerSpec.target)) { + return + } + } + if (triggerSpec.once) { + if (elementData.triggeredOnce) { + return + } else { + elementData.triggeredOnce = true + } + } + if (triggerSpec.changed) { + const eltToListenOnData = getInternalData(eltToListenOn) + // @ts-ignore value will be undefined for non-input elements, which is fine + const value = eltToListenOn.value + if (eltToListenOnData.lastValue === value) { + return + } + eltToListenOnData.lastValue = value + } + if (elementData.delayed) { + clearTimeout(elementData.delayed) + } + if (elementData.throttle) { + return + } + + if (triggerSpec.throttle > 0) { + if (!elementData.throttle) { + handler(elt, evt) + elementData.throttle = getWindow().setTimeout(function() { + elementData.throttle = null + }, triggerSpec.throttle) + } + } else if (triggerSpec.delay > 0) { + elementData.delayed = getWindow().setTimeout(function() { handler(elt, evt) }, triggerSpec.delay) + } else { + triggerEvent(elt, 'htmx:trigger') + handler(elt, evt) + } + } + } + if (nodeData.listenerInfos == null) { + nodeData.listenerInfos = [] + } + nodeData.listenerInfos.push({ + trigger: triggerSpec.trigger, + listener: eventListener, + on: eltToListenOn + }) + eltToListenOn.addEventListener(triggerSpec.trigger, eventListener) + }) + } + + let windowIsScrolling = false // used by initScrollHandler + let scrollHandler = null + function initScrollHandler() { + if (!scrollHandler) { + scrollHandler = function() { + windowIsScrolling = true + } + window.addEventListener('scroll', scrollHandler) + setInterval(function() { + if (windowIsScrolling) { + windowIsScrolling = false + forEach(getDocument().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"), function(elt) { + maybeReveal(elt) + }) + } + }, 200) + } + } + + /** + * @param {Element} elt + */ + function maybeReveal(elt) { + if (!hasAttribute(elt, 'data-hx-revealed') && isScrolledIntoView(elt)) { + elt.setAttribute('data-hx-revealed', 'true') + const nodeData = getInternalData(elt) + if (nodeData.initHash) { + triggerEvent(elt, 'revealed') + } else { + // if the node isn't initialized, wait for it before triggering the request + elt.addEventListener('htmx:afterProcessNode', function() { triggerEvent(elt, 'revealed') }, { once: true }) + } + } + } + + //= =================================================================== + + /** + * @param {Element} elt + * @param {TriggerHandler} handler + * @param {HtmxNodeInternalData} nodeData + * @param {number} delay + */ + function loadImmediately(elt, handler, nodeData, delay) { + const load = function() { + if (!nodeData.loaded) { + nodeData.loaded = true + handler(elt) + } + } + if (delay > 0) { + getWindow().setTimeout(load, delay) + } else { + load() + } + } + + /** + * @param {Element} elt + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification[]} triggerSpecs + * @returns {boolean} + */ + function processVerbs(elt, nodeData, triggerSpecs) { + let explicitAction = false + forEach(VERBS, function(verb) { + if (hasAttribute(elt, 'hx-' + verb)) { + const path = getAttributeValue(elt, 'hx-' + verb) + explicitAction = true + nodeData.path = path + nodeData.verb = verb + triggerSpecs.forEach(function(triggerSpec) { + addTriggerHandler(elt, triggerSpec, nodeData, function(node, evt) { + const elt = asElement(node) + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return } + issueAjaxRequest(verb, path, elt, evt) + }) + }) + } + }) + return explicitAction + } + + /** + * @callback TriggerHandler + * @param {Node} elt + * @param {Event} [evt] + */ + + /** + * @param {Node} elt + * @param {HtmxTriggerSpecification} triggerSpec + * @param {HtmxNodeInternalData} nodeData + * @param {TriggerHandler} handler + */ + function addTriggerHandler(elt, triggerSpec, nodeData, handler) { + if (triggerSpec.trigger === 'revealed') { + initScrollHandler() + addEventListener(elt, handler, nodeData, triggerSpec) + maybeReveal(asElement(elt)) + } else if (triggerSpec.trigger === 'intersect') { + const observerOptions = {} + if (triggerSpec.root) { + observerOptions.root = querySelectorExt(elt, triggerSpec.root) + } + if (triggerSpec.threshold) { + observerOptions.threshold = parseFloat(triggerSpec.threshold) + } + const observer = new IntersectionObserver(function(entries) { + for (let i = 0; i < entries.length; i++) { + const entry = entries[i] + if (entry.isIntersecting) { + triggerEvent(elt, 'intersect') + break + } + } + }, observerOptions) + observer.observe(asElement(elt)) + addEventListener(asElement(elt), handler, nodeData, triggerSpec) + } else if (triggerSpec.trigger === 'load') { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent('load', { elt }))) { + loadImmediately(asElement(elt), handler, nodeData, triggerSpec.delay) + } + } else if (triggerSpec.pollInterval > 0) { + nodeData.polling = true + processPolling(asElement(elt), handler, triggerSpec) + } else { + addEventListener(elt, handler, nodeData, triggerSpec) + } + } + + /** + * @param {Node} node + * @returns {boolean} + */ + function shouldProcessHxOn(node) { + const elt = asElement(node) + if (!elt) { + return false + } + const attributes = elt.attributes + for (let j = 0; j < attributes.length; j++) { + const attrName = attributes[j].name + if (startsWith(attrName, 'hx-on:') || startsWith(attrName, 'data-hx-on:') || + startsWith(attrName, 'hx-on-') || startsWith(attrName, 'data-hx-on-')) { + return true + } + } + return false + } + + /** + * @param {Node} elt + * @returns {Element[]} + */ + const HX_ON_QUERY = new XPathEvaluator() + .createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + + ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]') + + function processHXOnRoot(elt, elements) { + if (shouldProcessHxOn(elt)) { + elements.push(asElement(elt)) + } + const iter = HX_ON_QUERY.evaluate(elt) + let node = null + while (node = iter.iterateNext()) elements.push(asElement(node)) + } + + function findHxOnWildcardElements(elt) { + /** @type {Element[]} */ + const elements = [] + if (elt instanceof DocumentFragment) { + for (const child of elt.childNodes) { + processHXOnRoot(child, elements) + } + } else { + processHXOnRoot(elt, elements) + } + return elements + } + + /** + * @param {Element} elt + * @returns {NodeListOf<Element>|[]} + */ + function findElementsToProcess(elt) { + if (elt.querySelectorAll) { + const boostedSelector = ', [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]' + + const extensionSelectors = [] + for (const e in extensions) { + const extension = extensions[e] + if (extension.getSelectors) { + var selectors = extension.getSelectors() + if (selectors) { + extensionSelectors.push(selectors) + } + } + } + + const results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit']," + + ' [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]' + extensionSelectors.flat().map(s => ', ' + s).join('')) + + return results + } else { + return [] + } + } + + /** + * Handle submit buttons/inputs that have the form attribute set + * see https://developer.mozilla.org/docs/Web/HTML/Element/button + * @param {Event} evt + */ + function maybeSetLastButtonClicked(evt) { + const elt = /** @type {HTMLButtonElement|HTMLInputElement} */ (closest(asElement(evt.target), "button, input[type='submit']")) + const internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = elt + } + } + + /** + * @param {Event} evt + */ + function maybeUnsetLastButtonClicked(evt) { + const internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = null + } + } + + /** + * @param {Event} evt + * @returns {HtmxNodeInternalData|undefined} + */ + function getRelatedFormData(evt) { + const elt = closest(asElement(evt.target), "button, input[type='submit']") + if (!elt) { + return + } + const form = resolveTarget('#' + getRawAttribute(elt, 'form'), elt.getRootNode()) || closest(elt, 'form') + if (!form) { + return + } + return getInternalData(form) + } + + /** + * @param {EventTarget} elt + */ + function initButtonTracking(elt) { + // need to handle both click and focus in: + // focusin - in case someone tabs in to a button and hits the space bar + // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + elt.addEventListener('click', maybeSetLastButtonClicked) + elt.addEventListener('focusin', maybeSetLastButtonClicked) + elt.addEventListener('focusout', maybeUnsetLastButtonClicked) + } + + /** + * @param {Element} elt + * @param {string} eventName + * @param {string} code + */ + function addHxOnEventHandler(elt, eventName, code) { + const nodeData = getInternalData(elt) + if (!Array.isArray(nodeData.onHandlers)) { + nodeData.onHandlers = [] + } + let func + /** @type EventListener */ + const listener = function(e) { + maybeEval(elt, function() { + if (eltIsDisabled(elt)) { + return + } + if (!func) { + func = new Function('event', code) + } + func.call(elt, e) + }) + } + elt.addEventListener(eventName, listener) + nodeData.onHandlers.push({ event: eventName, listener }) + } + + /** + * @param {Element} elt + */ + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (let i = 0; i < elt.attributes.length; i++) { + const name = elt.attributes[i].name + const value = elt.attributes[i].value + if (startsWith(name, 'hx-on') || startsWith(name, 'data-hx-on')) { + const afterOnPosition = name.indexOf('-on') + 3 + const nextChar = name.slice(afterOnPosition, afterOnPosition + 1) + if (nextChar === '-' || nextChar === ':') { + let eventName = name.slice(afterOnPosition + 1) + // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support + if (startsWith(eventName, ':')) { + eventName = 'htmx' + eventName + } else if (startsWith(eventName, '-')) { + eventName = 'htmx:' + eventName.slice(1) + } else if (startsWith(eventName, 'htmx-')) { + eventName = 'htmx:' + eventName.slice(5) + } + + addHxOnEventHandler(elt, eventName, value) + } + } + } + } + + /** + * @param {Element|HTMLInputElement} elt + */ + function initNode(elt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + const nodeData = getInternalData(elt) + if (nodeData.initHash !== attributeHash(elt)) { + // clean up any previously processed info + deInitNode(elt) + + nodeData.initHash = attributeHash(elt) + + triggerEvent(elt, 'htmx:beforeProcessNode') + + // @ts-ignore value will be undefined for non-input elements, which is fine + if (elt.value) { + // @ts-ignore + nodeData.lastValue = elt.value + } + + const triggerSpecs = getTriggerSpecs(elt) + const hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs) + + if (!hasExplicitHttpAction) { + if (getClosestAttributeValue(elt, 'hx-boost') === 'true') { + boostElement(elt, nodeData, triggerSpecs) + } else if (hasAttribute(elt, 'hx-trigger')) { + triggerSpecs.forEach(function(triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function() { + }) + }) + } + } + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + if (elt.tagName === 'FORM' || (getRawAttribute(elt, 'type') === 'submit' && hasAttribute(elt, 'form'))) { + initButtonTracking(elt) + } - var headers = getHeaders(elt, target, promptResponse); - - if (verb !== 'get' && !usesFormData(elt)) { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; - } + triggerEvent(elt, 'htmx:afterProcessNode') + } + } + + /** + * Processes new content, enabling htmx behavior. This can be useful if you have content that is added to the DOM outside of the normal htmx request cycle but still want htmx attributes to work. + * + * @see https://htmx.org/api/#process + * + * @param {Element|string} elt element to process + */ + function processNode(elt) { + elt = resolveTarget(elt) + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + initNode(elt) + forEach(findElementsToProcess(elt), function(child) { initNode(child) }) + forEach(findHxOnWildcardElements(elt), processHxOnWildcard) + } + + //= =================================================================== + // Event/Log Support + //= =================================================================== + + /** + * @param {string} str + * @returns {string} + */ + function kebabEventName(str) { + return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase() + } + + /** + * @param {string} eventName + * @param {any} detail + * @returns {CustomEvent} + */ + function makeEvent(eventName, detail) { + let evt + if (window.CustomEvent && typeof window.CustomEvent === 'function') { + // TODO: `composed: true` here is a hack to make global event handlers work with events in shadow DOM + // This breaks expected encapsulation but needs to be here until decided otherwise by core devs + evt = new CustomEvent(eventName, { bubbles: true, cancelable: true, composed: true, detail }) + } else { + evt = getDocument().createEvent('CustomEvent') + evt.initCustomEvent(eventName, true, true, detail) + } + return evt + } + + /** + * @param {EventTarget|string} elt + * @param {string} eventName + * @param {any=} detail + */ + function triggerErrorEvent(elt, eventName, detail) { + triggerEvent(elt, eventName, mergeObjects({ error: eventName }, detail)) + } + + /** + * @param {string} eventName + * @returns {boolean} + */ + function ignoreEventForLogging(eventName) { + return eventName === 'htmx:afterProcessNode' + } + + /** + * `withExtensions` locates all active extensions for a provided element, then + * executes the provided function using each of the active extensions. It should + * be called internally at every extendable execution point in htmx. + * + * @param {Element} elt + * @param {(extension:HtmxExtension) => void} toDo + * @returns void + */ + function withExtensions(elt, toDo) { + forEach(getExtensions(elt), function(extension) { + try { + toDo(extension) + } catch (e) { + logError(e) + } + }) + } + + function logError(msg) { + if (console.error) { + console.error(msg) + } else if (console.log) { + console.log('ERROR: ', msg) + } + } + + /** + * Triggers a given event on an element + * + * @see https://htmx.org/api/#trigger + * + * @param {EventTarget|string} elt the element to trigger the event on + * @param {string} eventName the name of the event to trigger + * @param {any=} detail details for the event + * @returns {boolean} + */ + function triggerEvent(elt, eventName, detail) { + elt = resolveTarget(elt) + if (detail == null) { + detail = {} + } + detail.elt = elt + const event = makeEvent(eventName, detail) + if (htmx.logger && !ignoreEventForLogging(eventName)) { + htmx.logger(elt, eventName, detail) + } + if (detail.error) { + logError(detail.error) + triggerEvent(elt, 'htmx:error', { errorInfo: detail }) + } + let eventResult = elt.dispatchEvent(event) + const kebabName = kebabEventName(eventName) + if (eventResult && kebabName !== eventName) { + const kebabedEvent = makeEvent(kebabName, event.detail) + eventResult = eventResult && elt.dispatchEvent(kebabedEvent) + } + withExtensions(asElement(elt), function(extension) { + eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) + }) + return eventResult + } + + //= =================================================================== + // History Support + //= =================================================================== + let currentPathForHistory = location.pathname + location.search + + /** + * @returns {Element} + */ + function getHistoryElement() { + const historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]') + return historyElt || getDocument().body + } + + /** + * @param {string} url + * @param {Element} rootElt + */ + function saveToHistoryCache(url, rootElt) { + if (!canAccessLocalStorage()) { + return + } - if (etc.headers) { - headers = mergeObjects(headers, etc.headers); - } - var results = getInputValues(elt, verb); - var errors = results.errors; - var rawParameters = results.values; - if (etc.values) { - rawParameters = mergeObjects(rawParameters, etc.values); - } - var expressionVars = getExpressionVars(elt); - var allParameters = mergeObjects(rawParameters, expressionVars); - var filteredParameters = filterValues(allParameters, elt); + // get state to save + const innerHTML = cleanInnerHtmlForHistory(rootElt) + const title = getDocument().title + const scroll = window.scrollY - if (htmx.config.getCacheBusterParam && verb === 'get') { - filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true"; - } + if (htmx.config.historyCacheSize <= 0) { + // make sure that an eventually already existing cache is purged + localStorage.removeItem('htmx-history-cache') + return + } - // behavior of anchors w/ empty href is to use the current URL - if (path == null || path === "") { - path = getDocument().location.href; - } + url = normalizePath(url) + const historyCache = parseJSON(localStorage.getItem('htmx-history-cache')) || [] + for (let i = 0; i < historyCache.length; i++) { + if (historyCache[i].url === url) { + historyCache.splice(i, 1) + break + } + } - var requestAttrValues = getValuesForElement(elt, 'hx-request'); + /** @type HtmxHistoryItem */ + const newHistoryItem = { url, content: innerHTML, title, scroll } - var eltIsBoosted = getInternalData(elt).boosted; + triggerEvent(getDocument().body, 'htmx:historyItemCreated', { item: newHistoryItem, cache: historyCache }) - var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + historyCache.push(newHistoryItem) + while (historyCache.length > htmx.config.historyCacheSize) { + historyCache.shift() + } - var requestConfig = { - boosted: eltIsBoosted, - useUrlParams: useUrlParams, - parameters: filteredParameters, - unfilteredParameters: allParameters, - headers:headers, - target:target, - verb:verb, - errors:errors, - withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, - timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, - path:path, - triggeringEvent:event - }; + // keep trying to save the cache until it succeeds or is empty + while (historyCache.length > 0) { + try { + localStorage.setItem('htmx-history-cache', JSON.stringify(historyCache)) + break + } catch (e) { + triggerErrorEvent(getDocument().body, 'htmx:historyCacheError', { cause: e, cache: historyCache }) + historyCache.shift() // shrink the cache and retry + } + } + } + + /** + * @typedef {Object} HtmxHistoryItem + * @property {string} url + * @property {string} content + * @property {string} title + * @property {number} scroll + */ + + /** + * @param {string} url + * @returns {HtmxHistoryItem|null} + */ + function getCachedHistory(url) { + if (!canAccessLocalStorage()) { + return null + } - if(!triggerEvent(elt, 'htmx:configRequest', requestConfig)){ - maybeCall(resolve); - endRequestLock(); - return promise; - } + url = normalizePath(url) - // copy out in case the object was overwritten - path = requestConfig.path; - verb = requestConfig.verb; - headers = requestConfig.headers; - filteredParameters = requestConfig.parameters; - errors = requestConfig.errors; - useUrlParams = requestConfig.useUrlParams; - - if(errors && errors.length > 0){ - triggerEvent(elt, 'htmx:validation:halted', requestConfig) - maybeCall(resolve); - endRequestLock(); - return promise; - } + const historyCache = parseJSON(localStorage.getItem('htmx-history-cache')) || [] + for (let i = 0; i < historyCache.length; i++) { + if (historyCache[i].url === url) { + return historyCache[i] + } + } + return null + } + + /** + * @param {Element} elt + * @returns {string} + */ + function cleanInnerHtmlForHistory(elt) { + const className = htmx.config.requestClass + const clone = /** @type Element */ (elt.cloneNode(true)) + forEach(findAll(clone, '.' + className), function(child) { + removeClassFromElement(child, className) + }) + return clone.innerHTML + } + + function saveCurrentPageToHistory() { + const elt = getHistoryElement() + const path = currentPathForHistory || location.pathname + location.search + + // Allow history snapshot feature to be disabled where hx-history="false" + // is present *anywhere* in the current document we're about to save, + // so we can prevent privileged data entering the cache. + // The page will still be reachable as a history entry, but htmx will fetch it + // live from the server onpopstate rather than look in the localStorage cache + let disableHistoryCache + try { + disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') + } catch (e) { + // IE11: insensitive modifier not supported so fallback to case sensitive selector + disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') + } + if (!disableHistoryCache) { + triggerEvent(getDocument().body, 'htmx:beforeHistorySave', { path, historyElt: elt }) + saveToHistoryCache(path, elt) + } - var splitPath = path.split("#"); - var pathNoAnchor = splitPath[0]; - var anchor = splitPath[1]; - - var finalPath = path - if (useUrlParams) { - finalPath = pathNoAnchor; - var values = Object.keys(filteredParameters).length !== 0; - if (values) { - if (finalPath.indexOf("?") < 0) { - finalPath += "?"; - } else { - finalPath += "&"; - } - finalPath += urlEncode(filteredParameters); - if (anchor) { - finalPath += "#" + anchor; - } - } - } + if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, getDocument().title, window.location.href) + } + + /** + * @param {string} path + */ + function pushUrlIntoHistory(path) { + // remove the cache buster parameter, if any + if (htmx.config.getCacheBusterParam) { + path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') + if (endsWith(path, '&') || endsWith(path, '?')) { + path = path.slice(0, -1) + } + } + if (htmx.config.historyEnabled) { + history.pushState({ htmx: true }, '', path) + } + currentPathForHistory = path + } + + /** + * @param {string} path + */ + function replaceUrlInHistory(path) { + if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, '', path) + currentPathForHistory = path + } + + /** + * @param {HtmxSettleTask[]} tasks + */ + function settleImmediately(tasks) { + forEach(tasks, function(task) { + task.call(undefined) + }) + } + + /** + * @param {string} path + */ + function loadHistoryFromServer(path) { + const request = new XMLHttpRequest() + const details = { path, xhr: request } + triggerEvent(getDocument().body, 'htmx:historyCacheMiss', details) + request.open('GET', path, true) + request.setRequestHeader('HX-Request', 'true') + request.setRequestHeader('HX-History-Restore-Request', 'true') + request.setRequestHeader('HX-Current-URL', getDocument().location.href) + request.onload = function() { + if (this.status >= 200 && this.status < 400) { + triggerEvent(getDocument().body, 'htmx:historyCacheMissLoad', details) + const fragment = makeFragment(this.response) + /** @type ParentNode */ + const content = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment + const historyElement = getHistoryElement() + const settleInfo = makeSettleInfo(historyElement) + handleTitle(fragment.title) + + swapInnerHTML(historyElement, content, settleInfo) + settleImmediately(settleInfo.tasks) + currentPathForHistory = path + triggerEvent(getDocument().body, 'htmx:historyRestore', { path, cacheMiss: true, serverResponse: this.response }) + } else { + triggerErrorEvent(getDocument().body, 'htmx:historyCacheMissLoadError', details) + } + } + request.send() + } + + /** + * @param {string} [path] + */ + function restoreHistory(path) { + saveCurrentPageToHistory() + path = path || location.pathname + location.search + const cached = getCachedHistory(path) + if (cached) { + const fragment = makeFragment(cached.content) + const historyElement = getHistoryElement() + const settleInfo = makeSettleInfo(historyElement) + handleTitle(fragment.title) + swapInnerHTML(historyElement, fragment, settleInfo) + settleImmediately(settleInfo.tasks) + getWindow().setTimeout(function() { + window.scrollTo(0, cached.scroll) + }, 0) // next 'tick', so browser has time to render layout + currentPathForHistory = path + triggerEvent(getDocument().body, 'htmx:historyRestore', { path, item: cached }) + } else { + if (htmx.config.refreshOnHistoryMiss) { + // @ts-ignore: optional parameter in reload() function throws error + // noinspection JSUnresolvedReference + window.location.reload(true) + } else { + loadHistoryFromServer(path) + } + } + } + + /** + * @param {Element} elt + * @returns {Element[]} + */ + function addRequestIndicatorClasses(elt) { + let indicators = /** @type Element[] */ (findAttributeTargets(elt, 'hx-indicator')) + if (indicators == null) { + indicators = [elt] + } + forEach(indicators, function(ic) { + const internalData = getInternalData(ic) + internalData.requestCount = (internalData.requestCount || 0) + 1 + ic.classList.add.call(ic.classList, htmx.config.requestClass) + }) + return indicators + } + + /** + * @param {Element} elt + * @returns {Element[]} + */ + function disableElements(elt) { + let disabledElts = /** @type Element[] */ (findAttributeTargets(elt, 'hx-disabled-elt')) + if (disabledElts == null) { + disabledElts = [] + } + forEach(disabledElts, function(disabledElement) { + const internalData = getInternalData(disabledElement) + internalData.requestCount = (internalData.requestCount || 0) + 1 + disabledElement.setAttribute('disabled', '') + }) + return disabledElts + } + + /** + * @param {Element[]} indicators + * @param {Element[]} disabled + */ + function removeRequestIndicators(indicators, disabled) { + forEach(indicators, function(ic) { + const internalData = getInternalData(ic) + internalData.requestCount = (internalData.requestCount || 0) - 1 + if (internalData.requestCount === 0) { + ic.classList.remove.call(ic.classList, htmx.config.requestClass) + } + }) + forEach(disabled, function(disabledElement) { + const internalData = getInternalData(disabledElement) + internalData.requestCount = (internalData.requestCount || 0) - 1 + if (internalData.requestCount === 0) { + disabledElement.removeAttribute('disabled') + } + }) + } + + //= =================================================================== + // Input Value Processing + //= =================================================================== + + /** + * @param {Element[]} processed + * @param {Element} elt + * @returns {boolean} + */ + function haveSeenNode(processed, elt) { + for (let i = 0; i < processed.length; i++) { + const node = processed[i] + if (node.isSameNode(elt)) { + return true + } + } + return false + } + + /** + * @param {Element} element + * @return {boolean} + */ + function shouldInclude(element) { + // Cast to trick tsc, undefined values will work fine here + const elt = /** @type {HTMLInputElement} */ (element) + if (elt.name === '' || elt.name == null || elt.disabled || closest(elt, 'fieldset[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 + } + + /** @param {string} name + * @param {string|Array|FormDataEntryValue} value + * @param {FormData} formData */ + function addValueToFormData(name, value, formData) { + if (name != null && value != null) { + if (Array.isArray(value)) { + value.forEach(function(v) { formData.append(name, v) }) + } else { + formData.append(name, value) + } + } + } + + /** @param {string} name + * @param {string|Array} value + * @param {FormData} formData */ + function removeValueFromFormData(name, value, formData) { + if (name != null && value != null) { + let values = formData.getAll(name) + if (Array.isArray(value)) { + values = values.filter(v => value.indexOf(v) < 0) + } else { + values = values.filter(v => v !== value) + } + formData.delete(name) + forEach(values, v => formData.append(name, v)) + } + } + + /** + * @param {Element[]} processed + * @param {FormData} formData + * @param {HtmxElementValidationError[]} errors + * @param {Element|HTMLInputElement|HTMLSelectElement|HTMLFormElement} elt + * @param {boolean} validate + */ + function processInputValue(processed, formData, errors, elt, validate) { + if (elt == null || haveSeenNode(processed, elt)) { + return + } else { + processed.push(elt) + } + if (shouldInclude(elt)) { + const name = getRawAttribute(elt, 'name') + // @ts-ignore value will be undefined for non-input elements, which is fine + let value = elt.value + if (elt instanceof HTMLSelectElement && elt.multiple) { + value = toArray(elt.querySelectorAll('option:checked')).map(function(e) { return (/** @type HTMLOptionElement */(e)).value }) + } + // include file inputs + if (elt instanceof HTMLInputElement && elt.files) { + value = toArray(elt.files) + } + addValueToFormData(name, value, formData) + if (validate) { + validateElement(elt, errors) + } + } + if (elt instanceof HTMLFormElement) { + forEach(elt.elements, function(input) { + if (processed.indexOf(input) >= 0) { + // The input has already been processed and added to the values, but the FormData that will be + // constructed right after on the form, will include it once again. So remove that input's value + // now to avoid duplicates + removeValueFromFormData(input.name, input.value, formData) + } else { + processed.push(input) + } + if (validate) { + validateElement(input, errors) + } + }) + new FormData(elt).forEach(function(value, name) { + if (value instanceof File && value.name === '') { + return // ignore no-name files + } + addValueToFormData(name, value, formData) + }) + } + } + + /** + * + * @param {Element} elt + * @param {HtmxElementValidationError[]} errors + */ + function validateElement(elt, errors) { + const element = /** @type {HTMLElement & ElementInternals} */ (elt) + if (element.willValidate) { + triggerEvent(element, 'htmx:validation:validate') + if (!element.checkValidity()) { + errors.push({ elt: element, message: element.validationMessage, validity: element.validity }) + triggerEvent(element, 'htmx:validation:failed', { message: element.validationMessage, validity: element.validity }) + } + } + } + + /** + * Override values in the one FormData with those from another. + * @param {FormData} receiver the formdata that will be mutated + * @param {FormData} donor the formdata that will provide the overriding values + * @returns {FormData} the {@linkcode receiver} + */ + function overrideFormData(receiver, donor) { + for (const key of donor.keys()) { + receiver.delete(key) + donor.getAll(key).forEach(function(value) { + receiver.append(key, value) + }) + } + return receiver + } + + /** + * @param {Element|HTMLFormElement} elt + * @param {HttpVerb} verb + * @returns {{errors: HtmxElementValidationError[], formData: FormData, values: Object}} + */ + function getInputValues(elt, verb) { + /** @type Element[] */ + const processed = [] + const formData = new FormData() + const priorityFormData = new FormData() + /** @type HtmxElementValidationError[] */ + const errors = [] + const internalData = getInternalData(elt) + if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { + internalData.lastButtonClicked = null + } - if (!verifyPath(elt, finalPath, requestConfig)) { - triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) - maybeCall(reject); - return promise; - }; + // only validate when form is directly submitted and novalidate or formnovalidate are not set + // or if the element has an explicit hx-validate="true" on it + let validate = (elt instanceof HTMLFormElement && elt.noValidate !== true) || getAttributeValue(elt, 'hx-validate') === 'true' + if (internalData.lastButtonClicked) { + validate = validate && internalData.lastButtonClicked.formNoValidate !== true + } - xhr.open(verb.toUpperCase(), finalPath, true); - xhr.overrideMimeType("text/html"); - xhr.withCredentials = requestConfig.withCredentials; - xhr.timeout = requestConfig.timeout; + // for a non-GET include the closest form + if (verb !== 'get') { + processInputValue(processed, priorityFormData, errors, closest(elt, 'form'), validate) + } - // request headers - if (requestAttrValues.noHeaders) { - // ignore all headers - } else { - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - var headerValue = headers[header]; - safelySetHeaderValue(xhr, header, headerValue); - } - } - } + // include the element itself + processInputValue(processed, formData, errors, elt, validate) - var responseInfo = { - xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select, - pathInfo: { - requestPath: path, - finalRequestPath: finalPath, - anchor: anchor - } - }; - - xhr.onload = function () { - try { - var hierarchy = hierarchyForElt(elt); - responseInfo.pathInfo.responsePath = getPathFromResponse(xhr); - responseHandler(elt, responseInfo); - removeRequestIndicators(indicators, disableElts); - triggerEvent(elt, 'htmx:afterRequest', responseInfo); - triggerEvent(elt, 'htmx:afterOnLoad', responseInfo); - // if the body no longer contains the element, trigger the event on the closest parent - // remaining in the DOM - if (!bodyContains(elt)) { - var secondaryTriggerElt = null; - while (hierarchy.length > 0 && secondaryTriggerElt == null) { - var parentEltInHierarchy = hierarchy.shift(); - if (bodyContains(parentEltInHierarchy)) { - secondaryTriggerElt = parentEltInHierarchy; - } - } - if (secondaryTriggerElt) { - triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo); - triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo); - } - } - maybeCall(resolve); - endRequestLock(); - } catch (e) { - triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({error:e}, responseInfo)); - throw e; - } - } - xhr.onerror = function () { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:sendError', responseInfo); - maybeCall(reject); - endRequestLock(); - } - xhr.onabort = function() { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo); - maybeCall(reject); - endRequestLock(); - } - xhr.ontimeout = function() { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:timeout', responseInfo); - maybeCall(reject); - endRequestLock(); - } - if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){ - maybeCall(resolve); - endRequestLock() - return promise - } - var indicators = addRequestIndicatorClasses(elt); - var disableElts = disableElements(elt); - - forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { - forEach([xhr, xhr.upload], function (target) { - target.addEventListener(eventName, function(event){ - triggerEvent(elt, "htmx:xhr:" + eventName, { - lengthComputable:event.lengthComputable, - loaded:event.loaded, - total:event.total - }); - }) - }); - }); - triggerEvent(elt, 'htmx:beforeSend', responseInfo); - var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) - xhr.send(params); - return promise; - } - - function determineHistoryUpdates(elt, responseInfo) { - - var xhr = responseInfo.xhr; - - //=========================================== - // First consult response headers - //=========================================== - var pathFromHeaders = null; - var typeFromHeaders = null; - if (hasHeader(xhr,/HX-Push:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Push"); - typeFromHeaders = "push"; - } else if (hasHeader(xhr,/HX-Push-Url:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Push-Url"); - typeFromHeaders = "push"; - } else if (hasHeader(xhr,/HX-Replace-Url:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url"); - typeFromHeaders = "replace"; - } + // if a button or submit was clicked last, include its value + if (internalData.lastButtonClicked || elt.tagName === 'BUTTON' || + (elt.tagName === 'INPUT' && getRawAttribute(elt, 'type') === 'submit')) { + const button = internalData.lastButtonClicked || (/** @type HTMLInputElement|HTMLButtonElement */(elt)) + const name = getRawAttribute(button, 'name') + addValueToFormData(name, button.value, priorityFormData) + } - // if there was a response header, that has priority - if (pathFromHeaders) { - if (pathFromHeaders === "false") { - return {} - } else { - return { - type: typeFromHeaders, - path : pathFromHeaders - } - } - } + // include any explicit includes + const includes = findAttributeTargets(elt, 'hx-include') + forEach(includes, function(node) { + processInputValue(processed, formData, errors, asElement(node), validate) + // if a non-form is included, include any input values within it + if (!matches(node, 'form')) { + forEach(asParentNode(node).querySelectorAll(INPUT_SELECTOR), function(descendant) { + processInputValue(processed, formData, errors, descendant, validate) + }) + } + }) + + // values from a <form> take precedence, overriding the regular values + overrideFormData(formData, priorityFormData) + + return { errors, formData, values: formDataProxy(formData) } + } + + /** + * @param {string} returnStr + * @param {string} name + * @param {any} realValue + * @returns {string} + */ + function appendParam(returnStr, name, realValue) { + if (returnStr !== '') { + returnStr += '&' + } + if (String(realValue) === '[object Object]') { + realValue = JSON.stringify(realValue) + } + const s = encodeURIComponent(realValue) + returnStr += encodeURIComponent(name) + '=' + s + return returnStr + } + + /** + * @param {FormData|Object} values + * @returns string + */ + function urlEncode(values) { + values = formDataFromObject(values) + let returnStr = '' + values.forEach(function(value, key) { + returnStr = appendParam(returnStr, key, value) + }) + return returnStr + } + + //= =================================================================== + // Ajax + //= =================================================================== + + /** + * @param {Element} elt + * @param {Element} target + * @param {string} prompt + * @returns {HtmxHeaderSpecification} + */ + function getHeaders(elt, target, prompt) { + /** @type HtmxHeaderSpecification */ + const headers = { + 'HX-Request': 'true', + 'HX-Trigger': getRawAttribute(elt, 'id'), + 'HX-Trigger-Name': getRawAttribute(elt, 'name'), + 'HX-Target': getAttributeValue(target, 'id'), + 'HX-Current-URL': getDocument().location.href + } + getValuesForElement(elt, 'hx-headers', false, headers) + if (prompt !== undefined) { + headers['HX-Prompt'] = prompt + } + if (getInternalData(elt).boosted) { + headers['HX-Boosted'] = 'true' + } + return headers + } + + /** + * filterValues takes an object containing form input values + * and returns a new object that only contains keys that are + * specified by the closest "hx-params" attribute + * @param {FormData} inputValues + * @param {Element} elt + * @returns {FormData} + */ + function filterValues(inputValues, elt) { + const paramsValue = getClosestAttributeValue(elt, 'hx-params') + if (paramsValue) { + if (paramsValue === 'none') { + return new FormData() + } else if (paramsValue === '*') { + return inputValues + } else if (paramsValue.indexOf('not ') === 0) { + forEach(paramsValue.substr(4).split(','), function(name) { + name = name.trim() + inputValues.delete(name) + }) + return inputValues + } else { + const newValues = new FormData() + forEach(paramsValue.split(','), function(name) { + name = name.trim() + if (inputValues.has(name)) { + inputValues.getAll(name).forEach(function(value) { newValues.append(name, value) }) + } + }) + return newValues + } + } else { + return inputValues + } + } + + /** + * @param {Element} elt + * @return {boolean} + */ + function isAnchorLink(elt) { + return !!getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf('#') >= 0 + } + + /** + * @param {Element} elt + * @param {HtmxSwapStyle} [swapInfoOverride] + * @returns {HtmxSwapSpecification} + */ + function getSwapSpecification(elt, swapInfoOverride) { + const swapInfo = swapInfoOverride || getClosestAttributeValue(elt, 'hx-swap') + /** @type HtmxSwapSpecification */ + const swapSpec = { + swapStyle: getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, + swapDelay: htmx.config.defaultSwapDelay, + settleDelay: htmx.config.defaultSettleDelay + } + if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { + swapSpec.show = 'top' + } + if (swapInfo) { + const split = splitOnWhitespace(swapInfo) + if (split.length > 0) { + for (let i = 0; i < split.length; i++) { + const value = split[i] + if (value.indexOf('swap:') === 0) { + swapSpec.swapDelay = parseInterval(value.substr(5)) + } else if (value.indexOf('settle:') === 0) { + swapSpec.settleDelay = parseInterval(value.substr(7)) + } else if (value.indexOf('transition:') === 0) { + swapSpec.transition = value.substr(11) === 'true' + } else if (value.indexOf('ignoreTitle:') === 0) { + swapSpec.ignoreTitle = value.substr(12) === 'true' + } else if (value.indexOf('scroll:') === 0) { + const scrollSpec = value.substr(7) + var splitSpec = scrollSpec.split(':') + const scrollVal = splitSpec.pop() + var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null + // @ts-ignore + swapSpec.scroll = scrollVal + swapSpec.scrollTarget = selectorVal + } else if (value.indexOf('show:') === 0) { + const showSpec = value.substr(5) + var splitSpec = showSpec.split(':') + const showVal = splitSpec.pop() + var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null + swapSpec.show = showVal + swapSpec.showTarget = selectorVal + } else if (value.indexOf('focus-scroll:') === 0) { + const focusScrollVal = value.substr('focus-scroll:'.length) + swapSpec.focusScroll = focusScrollVal == 'true' + } else if (i == 0) { + swapSpec.swapStyle = value + } else { + logError('Unknown modifier in hx-swap: ' + value) + } + } + } + } + return swapSpec + } + + /** + * @param {Element} elt + * @return {boolean} + */ + function usesFormData(elt) { + return getClosestAttributeValue(elt, 'hx-encoding') === 'multipart/form-data' || + (matches(elt, 'form') && getRawAttribute(elt, 'enctype') === 'multipart/form-data') + } + + /** + * @param {XMLHttpRequest} xhr + * @param {Element} elt + * @param {FormData} filteredParameters + * @returns {*|string|null} + */ + function encodeParamsForBody(xhr, elt, filteredParameters) { + let encodedParameters = null + withExtensions(elt, function(extension) { + if (encodedParameters == null) { + encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt) + } + }) + if (encodedParameters != null) { + return encodedParameters + } else { + if (usesFormData(elt)) { + // Force conversion to an actual FormData object in case filteredParameters is a formDataProxy + // See https://github.com/bigskysoftware/htmx/issues/2317 + return overrideFormData(new FormData(), formDataFromObject(filteredParameters)) + } else { + return urlEncode(filteredParameters) + } + } + } + + /** + * + * @param {Element} target + * @returns {HtmxSettleInfo} + */ + function makeSettleInfo(target) { + return { tasks: [], elts: [target] } + } + + /** + * @param {Element[]} content + * @param {HtmxSwapSpecification} swapSpec + */ + function updateScrollState(content, swapSpec) { + const first = content[0] + const last = content[content.length - 1] + if (swapSpec.scroll) { + var target = null + if (swapSpec.scrollTarget) { + target = asElement(querySelectorExt(first, swapSpec.scrollTarget)) + } + if (swapSpec.scroll === 'top' && (first || target)) { + target = target || first + target.scrollTop = 0 + } + if (swapSpec.scroll === 'bottom' && (last || target)) { + target = target || last + target.scrollTop = target.scrollHeight + } + } + if (swapSpec.show) { + var target = null + if (swapSpec.showTarget) { + let targetStr = swapSpec.showTarget + if (swapSpec.showTarget === 'window') { + targetStr = 'body' + } + target = asElement(querySelectorExt(first, targetStr)) + } + if (swapSpec.show === 'top' && (first || target)) { + target = target || first + // @ts-ignore For some reason tsc doesn't recognize "instant" as a valid option for now + target.scrollIntoView({ block: 'start', behavior: htmx.config.scrollBehavior }) + } + if (swapSpec.show === 'bottom' && (last || target)) { + target = target || last + // @ts-ignore For some reason tsc doesn't recognize "instant" as a valid option for now + target.scrollIntoView({ block: 'end', behavior: htmx.config.scrollBehavior }) + } + } + } + + /** + * @param {Element} elt + * @param {string} attr + * @param {boolean=} evalAsDefault + * @param {Object=} values + * @returns {Object} + */ + function getValuesForElement(elt, attr, evalAsDefault, values) { + if (values == null) { + values = {} + } + if (elt == null) { + return values + } + const attributeValue = getAttributeValue(elt, attr) + if (attributeValue) { + let str = attributeValue.trim() + let evaluateValue = evalAsDefault + if (str === 'unset') { + return null + } + if (str.indexOf('javascript:') === 0) { + str = str.substr(11) + evaluateValue = true + } else if (str.indexOf('js:') === 0) { + str = str.substr(3) + evaluateValue = true + } + if (str.indexOf('{') !== 0) { + str = '{' + str + '}' + } + let varsValues + if (evaluateValue) { + varsValues = maybeEval(elt, function() { return Function('return (' + str + ')')() }, {}) + } else { + varsValues = parseJSON(str) + } + for (const key in varsValues) { + if (varsValues.hasOwnProperty(key)) { + if (values[key] == null) { + values[key] = varsValues[key] + } + } + } + } + return getValuesForElement(asElement(parentElt(elt)), attr, evalAsDefault, values) + } + + /** + * @param {EventTarget|string} elt + * @param {() => any} toEval + * @param {any=} defaultVal + * @returns {any} + */ + function maybeEval(elt, toEval, defaultVal) { + if (htmx.config.allowEval) { + return toEval() + } else { + triggerErrorEvent(elt, 'htmx:evalDisallowedError') + return defaultVal + } + } + + /** + * @param {Element} elt + * @param {*?} expressionVars + * @returns + */ + function getHXVarsForElement(elt, expressionVars) { + return getValuesForElement(elt, 'hx-vars', true, expressionVars) + } + + /** + * @param {Element} elt + * @param {*?} expressionVars + * @returns + */ + function getHXValsForElement(elt, expressionVars) { + return getValuesForElement(elt, 'hx-vals', false, expressionVars) + } + + /** + * @param {Element} elt + * @returns {FormData} + */ + function getExpressionVars(elt) { + return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)) + } + + /** + * @param {XMLHttpRequest} xhr + * @param {string} header + * @param {string|null} headerValue + */ + function safelySetHeaderValue(xhr, header, headerValue) { + if (headerValue !== null) { + try { + xhr.setRequestHeader(header, headerValue) + } catch (e) { + // On an exception, try to set the header URI encoded instead + xhr.setRequestHeader(header, encodeURIComponent(headerValue)) + xhr.setRequestHeader(header + '-URI-AutoEncoded', 'true') + } + } + } + + /** + * @param {XMLHttpRequest} xhr + * @return {string} + */ + function getPathFromResponse(xhr) { + // NB: IE11 does not support this stuff + if (xhr.responseURL && typeof (URL) !== 'undefined') { + try { + const url = new URL(xhr.responseURL) + return url.pathname + url.search + } catch (e) { + triggerErrorEvent(getDocument().body, 'htmx:badResponseUrl', { url: xhr.responseURL }) + } + } + } + + /** + * @param {XMLHttpRequest} xhr + * @param {RegExp} regexp + * @return {boolean} + */ + function hasHeader(xhr, regexp) { + return regexp.test(xhr.getAllResponseHeaders()) + } + + /** + * Issues an htmx-style AJAX request + * + * @see https://htmx.org/api/#ajax + * + * @param {HttpVerb} verb + * @param {string} path the URL path to make the AJAX + * @param {Element|string|HtmxAjaxHelperContext} context the element to target (defaults to the **body**) | a selector for the target | a context object that contains any of the following + * @return {Promise<void>} Promise that resolves immediately if no request is sent, or when the request is complete + */ + function ajaxHelper(verb, path, context) { + verb = (/** @type HttpVerb */(verb.toLowerCase())) + if (context) { + if (context instanceof Element || typeof context === 'string') { + return issueAjaxRequest(verb, path, null, null, { + targetOverride: resolveTarget(context), + returnPromise: true + }) + } else { + return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, + { + handler: context.handler, + headers: context.headers, + values: context.values, + targetOverride: resolveTarget(context.target), + swapOverride: context.swap, + select: context.select, + returnPromise: true + }) + } + } else { + return issueAjaxRequest(verb, path, null, null, { + returnPromise: true + }) + } + } + + /** + * @param {Element} elt + * @return {Element[]} + */ + function hierarchyForElt(elt) { + const arr = [] + while (elt) { + arr.push(elt) + elt = elt.parentElement + } + return arr + } + + /** + * @param {Element} elt + * @param {string} path + * @param {HtmxRequestConfig} requestConfig + * @return {boolean} + */ + function verifyPath(elt, path, requestConfig) { + let sameHost + let url + if (typeof URL === 'function') { + url = new URL(path, document.location.href) + const origin = document.location.origin + sameHost = origin === url.origin + } else { + // IE11 doesn't support URL + url = path + sameHost = startsWith(path, document.location.origin) + } - //=========================================== - // Next resolve via DOM values - //=========================================== - var requestPath = responseInfo.pathInfo.finalRequestPath; - var responsePath = responseInfo.pathInfo.responsePath; - - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url"); - var elementIsBoosted = getInternalData(elt).boosted; - - var saveType = null; - var path = null; - - if (pushUrl) { - saveType = "push"; - path = pushUrl; - } else if (replaceUrl) { - saveType = "replace"; - path = replaceUrl; - } else if (elementIsBoosted) { - saveType = "push"; - path = responsePath || requestPath; // if there is no response path, go with the original request path - } + if (htmx.config.selfRequestsOnly) { + if (!sameHost) { + return false + } + } + return triggerEvent(elt, 'htmx:validateUrl', mergeObjects({ url, sameHost }, requestConfig)) + } + + /** + * @param {Object|FormData} obj + * @return {FormData} + */ + function formDataFromObject(obj) { + if (obj instanceof FormData) return obj + const formData = new FormData() + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + if (typeof obj[key].forEach === 'function') { + obj[key].forEach(function(v) { formData.append(key, v) }) + } else if (typeof obj[key] === 'object') { + formData.append(key, JSON.stringify(obj[key])) + } else { + formData.append(key, obj[key]) + } + } + } + return formData + } + + /** + * @param {FormData} formData + * @param {string} name + * @param {Array} array + * @returns {Array} + */ + function formDataArrayProxy(formData, name, array) { + // mutating the array should mutate the underlying form data + return new Proxy(array, { + get: function(target, key) { + if (typeof key === 'number') return target[key] + if (key === 'length') return target.length + if (key === 'push') { + return function(value) { + target.push(value) + formData.append(name, value) + } + } + if (typeof target[key] === 'function') { + return function() { + target[key].apply(target, arguments) + formData.delete(name) + target.forEach(function(v) { formData.append(name, v) }) + } + } + + if (target[key] && target[key].length === 1) { + return target[key][0] + } else { + return target[key] + } + }, + set: function(target, index, value) { + target[index] = value + formData.delete(name) + target.forEach(function(v) { formData.append(name, v) }) + return true + } + }) + } + + /** + * @param {FormData} formData + * @returns {Object} + */ + function formDataProxy(formData) { + return new Proxy(formData, { + get: function(target, name) { + if (typeof name === 'symbol') { + // Forward symbol calls to the FormData itself directly + return Reflect.get(target, name) + } + if (name === 'toJSON') { + // Support JSON.stringify call on proxy + return () => Object.fromEntries(formData) + } + if (name in target) { + // Wrap in function with apply to correctly bind the FormData context, as a direct call would result in an illegal invocation error + if (typeof target[name] === 'function') { + return function() { + return formData[name].apply(formData, arguments) + } + } else { + return target[name] + } + } + const array = formData.getAll(name) + // Those 2 undefined & single value returns are for retro-compatibility as we weren't using FormData before + if (array.length === 0) { + return undefined + } else if (array.length === 1) { + return array[0] + } else { + return formDataArrayProxy(target, name, array) + } + }, + set: function(target, name, value) { + if (typeof name !== 'string') { + return false + } + target.delete(name) + if (typeof value.forEach === 'function') { + value.forEach(function(v) { target.append(name, v) }) + } else { + target.append(name, value) + } + return true + }, + deleteProperty: function(target, name) { + if (typeof name === 'string') { + target.delete(name) + } + return true + }, + // Support Object.assign call from proxy + ownKeys: function(target) { + return Reflect.ownKeys(Object.fromEntries(target)) + }, + getOwnPropertyDescriptor: function(target, prop) { + return Reflect.getOwnPropertyDescriptor(Object.fromEntries(target), prop) + } + }) + } + + /** + * @param {HttpVerb} verb + * @param {string} path + * @param {Element} elt + * @param {Event} event + * @param {HtmxAjaxEtc} [etc] + * @param {boolean} [confirmed] + * @return {Promise<void>} + */ + function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { + let resolve = null + let reject = null + etc = etc != null ? etc : {} + if (etc.returnPromise && typeof Promise !== 'undefined') { + var promise = new Promise(function(_resolve, _reject) { + resolve = _resolve + reject = _reject + }) + } + if (elt == null) { + elt = getDocument().body + } + const responseHandler = etc.handler || handleAjaxResponse + const select = etc.select || null - if (path) { - // false indicates no push, return empty object - if (path === "false") { - return {}; - } + if (!bodyContains(elt)) { + // do not issue requests for elements removed from the DOM + maybeCall(resolve) + return promise + } + const target = etc.targetOverride || asElement(getTarget(elt)) + if (target == null || target == DUMMY_ELT) { + triggerErrorEvent(elt, 'htmx:targetError', { target: getAttributeValue(elt, 'hx-target') }) + maybeCall(reject) + return promise + } - // true indicates we want to follow wherever the server ended up sending us - if (path === "true") { - path = responsePath || requestPath; // if there is no response path, go with the original request path - } + let eltData = getInternalData(elt) + const submitter = eltData.lastButtonClicked - // restore any anchor associated with the request - if (responseInfo.pathInfo.anchor && - path.indexOf("#") === -1) { - path = path + "#" + responseInfo.pathInfo.anchor; - } + if (submitter) { + const buttonPath = getRawAttribute(submitter, 'formaction') + if (buttonPath != null) { + path = buttonPath + } - return { - type:saveType, - path: path - } - } else { - return {}; - } + const buttonVerb = getRawAttribute(submitter, 'formmethod') + if (buttonVerb != null) { + // ignore buttons with formmethod="dialog" + if (buttonVerb.toLowerCase() !== 'dialog') { + verb = (/** @type HttpVerb */(buttonVerb)) } + } + } - function handleAjaxResponse(elt, responseInfo) { - var xhr = responseInfo.xhr; - var target = responseInfo.target; - var etc = responseInfo.etc; - var requestConfig = responseInfo.requestConfig; - var select = responseInfo.select; + const confirmQuestion = getClosestAttributeValue(elt, 'hx-confirm') + // allow event-based confirmation w/ a callback + if (confirmed === undefined) { + const issueRequest = function(skipConfirmation) { + return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation) + } + const confirmDetails = { target, elt, path, verb, triggeringEvent: event, etc, issueRequest, question: confirmQuestion } + if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { + maybeCall(resolve) + return promise + } + } - if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; + let syncElt = elt + let syncStrategy = getClosestAttributeValue(elt, 'hx-sync') + let queueStrategy = null + let abortable = false + if (syncStrategy) { + const syncStrings = syncStrategy.split(':') + const selector = syncStrings[0].trim() + if (selector === 'this') { + syncElt = findThisElement(elt, 'hx-sync') + } else { + syncElt = asElement(querySelectorExt(elt, selector)) + } + // default to the drop strategy + syncStrategy = (syncStrings[1] || 'drop').trim() + eltData = getInternalData(syncElt) + if (syncStrategy === 'drop' && eltData.xhr && eltData.abortable !== true) { + maybeCall(resolve) + return promise + } else if (syncStrategy === 'abort') { + if (eltData.xhr) { + maybeCall(resolve) + return promise + } else { + abortable = true + } + } else if (syncStrategy === 'replace') { + triggerEvent(syncElt, 'htmx:abort') // abort the current request and continue + } else if (syncStrategy.indexOf('queue') === 0) { + const queueStrArray = syncStrategy.split(' ') + queueStrategy = (queueStrArray[1] || 'last').trim() + } + } - if (hasHeader(xhr, /HX-Trigger:/i)) { - handleTrigger(xhr, "HX-Trigger", elt); - } + if (eltData.xhr) { + if (eltData.abortable) { + triggerEvent(syncElt, 'htmx:abort') // abort the current request and continue + } else { + if (queueStrategy == null) { + if (event) { + const eventData = getInternalData(event) + if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { + queueStrategy = eventData.triggerSpec.queue + } + } + if (queueStrategy == null) { + queueStrategy = 'last' + } + } + if (eltData.queuedRequests == null) { + eltData.queuedRequests = [] + } + if (queueStrategy === 'first' && eltData.queuedRequests.length === 0) { + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } else if (queueStrategy === 'all') { + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } else if (queueStrategy === 'last') { + eltData.queuedRequests = [] // dump existing queue + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } + maybeCall(resolve) + return promise + } + } - if (hasHeader(xhr, /HX-Location:/i)) { - saveCurrentPageToHistory(); - var redirectPath = xhr.getResponseHeader("HX-Location"); - var swapSpec; - if (redirectPath.indexOf("{") === 0) { - swapSpec = parseJSON(redirectPath); - // what's the best way to throw an error if the user didn't include this - redirectPath = swapSpec['path']; - delete swapSpec['path']; - } - ajaxHelper('GET', redirectPath, swapSpec).then(function(){ - pushUrlIntoHistory(redirectPath); - }); - return; - } + const xhr = new XMLHttpRequest() + eltData.xhr = xhr + eltData.abortable = abortable + const endRequestLock = function() { + eltData.xhr = null + eltData.abortable = false + if (eltData.queuedRequests != null && + eltData.queuedRequests.length > 0) { + const queuedRequest = eltData.queuedRequests.shift() + queuedRequest() + } + } + const promptQuestion = getClosestAttributeValue(elt, 'hx-prompt') + if (promptQuestion) { + var promptResponse = prompt(promptQuestion) + // prompt returns null if cancelled and empty string if accepted with no entry + if (promptResponse === null || + !triggerEvent(elt, 'htmx:prompt', { prompt: promptResponse, target })) { + maybeCall(resolve) + endRequestLock() + return promise + } + } - var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh"); + if (confirmQuestion && !confirmed) { + if (!confirm(confirmQuestion)) { + maybeCall(resolve) + endRequestLock() + return promise + } + } - if (hasHeader(xhr, /HX-Redirect:/i)) { - location.href = xhr.getResponseHeader("HX-Redirect"); - shouldRefresh && location.reload(); - return; - } + let headers = getHeaders(elt, target, promptResponse) - if (shouldRefresh) { - location.reload(); - return; - } + if (verb !== 'get' && !usesFormData(elt)) { + headers['Content-Type'] = 'application/x-www-form-urlencoded' + } - if (hasHeader(xhr,/HX-Retarget:/i)) { - if (xhr.getResponseHeader("HX-Retarget") === "this") { - responseInfo.target = elt; - } else { - responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget")); - } - } + if (etc.headers) { + headers = mergeObjects(headers, etc.headers) + } + const results = getInputValues(elt, verb) + let errors = results.errors + const rawFormData = results.formData + if (etc.values) { + overrideFormData(rawFormData, formDataFromObject(etc.values)) + } + const expressionVars = formDataFromObject(getExpressionVars(elt)) + const allFormData = overrideFormData(rawFormData, expressionVars) + let filteredFormData = filterValues(allFormData, elt) - var historyUpdate = determineHistoryUpdates(elt, responseInfo); - - // by default htmx only swaps on 200 return codes and does not swap - // on 204 'No Content' - // this can be ovverriden by responding to the htmx:beforeSwap event and - // overriding the detail.shouldSwap property - var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; - var serverResponse = xhr.response; - var isError = xhr.status >= 400; - var ignoreTitle = htmx.config.ignoreTitle - var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo); - if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; - - target = beforeSwapDetails.target; // allow re-targeting - serverResponse = beforeSwapDetails.serverResponse; // allow updating content - isError = beforeSwapDetails.isError; // allow updating error - ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title - - responseInfo.target = target; // Make updated target available to response events - responseInfo.failed = isError; // Make failed property available to response events - responseInfo.successful = !isError; // Make successful property available to response events - - if (beforeSwapDetails.shouldSwap) { - if (xhr.status === 286) { - cancelPolling(elt); - } + if (htmx.config.getCacheBusterParam && verb === 'get') { + filteredFormData.set('org.htmx.cache-buster', getRawAttribute(target, 'id') || 'true') + } - withExtensions(elt, function (extension) { - serverResponse = extension.transformResponse(serverResponse, xhr, elt); - }); + // behavior of anchors w/ empty href is to use the current URL + if (path == null || path === '') { + path = getDocument().location.href + } - // Save current page if there will be a history update - if (historyUpdate.type) { - saveCurrentPageToHistory(); - } + /** + * @type {Object} + * @property {boolean} [credentials] + * @property {number} [timeout] + * @property {boolean} [noHeaders] + */ + const requestAttrValues = getValuesForElement(elt, 'hx-request') + + const eltIsBoosted = getInternalData(elt).boosted + + let useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + + /** @type HtmxRequestConfig */ + const requestConfig = { + boosted: eltIsBoosted, + useUrlParams, + formData: filteredFormData, + parameters: formDataProxy(filteredFormData), + unfilteredFormData: allFormData, + unfilteredParameters: formDataProxy(allFormData), + headers, + target, + verb, + errors, + withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, + timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, + path, + triggeringEvent: event + } - var swapOverride = etc.swapOverride; - if (hasHeader(xhr,/HX-Reswap:/i)) { - swapOverride = xhr.getResponseHeader("HX-Reswap"); - } - var swapSpec = getSwapSpecification(elt, swapOverride); + if (!triggerEvent(elt, 'htmx:configRequest', requestConfig)) { + maybeCall(resolve) + endRequestLock() + return promise + } - if (swapSpec.hasOwnProperty('ignoreTitle')) { - ignoreTitle = swapSpec.ignoreTitle; - } + // copy out in case the object was overwritten + path = requestConfig.path + verb = requestConfig.verb + headers = requestConfig.headers + filteredFormData = formDataFromObject(requestConfig.parameters) + errors = requestConfig.errors + useUrlParams = requestConfig.useUrlParams + + if (errors && errors.length > 0) { + triggerEvent(elt, 'htmx:validation:halted', requestConfig) + maybeCall(resolve) + endRequestLock() + return promise + } - target.classList.add(htmx.config.swappingClass); - - // optional transition API promise callbacks - var settleResolve = null; - var settleReject = null; - - var doSwap = function () { - try { - var activeElt = document.activeElement; - var selectionInfo = {}; - try { - selectionInfo = { - elt: activeElt, - // @ts-ignore - start: activeElt ? activeElt.selectionStart : null, - // @ts-ignore - end: activeElt ? activeElt.selectionEnd : null - }; - } catch (e) { - // safari issue - see https://github.com/microsoft/playwright/issues/5894 - } - - var selectOverride; - if (select) { - selectOverride = select; - } - - if (hasHeader(xhr, /HX-Reselect:/i)) { - selectOverride = xhr.getResponseHeader("HX-Reselect"); - } - - // if we need to save history, do so, before swapping so that relative resources have the correct base URL - if (historyUpdate.type) { - triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)); - if (historyUpdate.type === "push") { - pushUrlIntoHistory(historyUpdate.path); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path}); - } else { - replaceUrlInHistory(historyUpdate.path); - triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path}); - } - } - - var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride); - - if (selectionInfo.elt && - !bodyContains(selectionInfo.elt) && - getRawAttribute(selectionInfo.elt, "id")) { - var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id")); - var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; - if (newActiveElt) { - // @ts-ignore - if (selectionInfo.start && newActiveElt.setSelectionRange) { - // @ts-ignore - try { - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); - } catch (e) { - // the setSelectionRange method is present on fields that don't support it, so just let this fail - } - } - newActiveElt.focus(focusOptions); - } - } - - target.classList.remove(htmx.config.swappingClass); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.add(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSwap', responseInfo); - }); - - if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); - } - - var doSettle = function () { - forEach(settleInfo.tasks, function (task) { - task.call(); - }); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.remove(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSettle', responseInfo); - }); - - if (responseInfo.pathInfo.anchor) { - var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor); - if(anchorTarget) { - anchorTarget.scrollIntoView({block:'start', behavior: "auto"}); - } - } - - if(settleInfo.title && !ignoreTitle) { - var titleElt = find("title"); - if(titleElt) { - titleElt.innerHTML = settleInfo.title; - } else { - window.document.title = settleInfo.title; - } - } - - updateScrollState(settleInfo.elts, swapSpec); - - if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); - } - maybeCall(settleResolve); - } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'htmx:swapError', responseInfo); - maybeCall(settleReject); - throw e; - } - }; - - var shouldTransition = htmx.config.globalViewTransitions - if(swapSpec.hasOwnProperty('transition')){ - shouldTransition = swapSpec.transition; - } + const splitPath = path.split('#') + const pathNoAnchor = splitPath[0] + const anchor = splitPath[1] + + let finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor + const hasValues = !filteredFormData.keys().next().done + if (hasValues) { + if (finalPath.indexOf('?') < 0) { + finalPath += '?' + } else { + finalPath += '&' + } + finalPath += urlEncode(filteredFormData) + if (anchor) { + finalPath += '#' + anchor + } + } + } - if(shouldTransition && - triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && - typeof Promise !== "undefined" && document.startViewTransition){ - var settlePromise = new Promise(function (_resolve, _reject) { - settleResolve = _resolve; - settleReject = _reject; - }); - // wrap the original doSwap() in a call to startViewTransition() - var innerDoSwap = doSwap; - doSwap = function() { - document.startViewTransition(function () { - innerDoSwap(); - return settlePromise; - }); - } - } + if (!verifyPath(elt, finalPath, requestConfig)) { + triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) + maybeCall(reject) + return promise + } + xhr.open(verb.toUpperCase(), finalPath, true) + xhr.overrideMimeType('text/html') + xhr.withCredentials = requestConfig.withCredentials + xhr.timeout = requestConfig.timeout - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); - } - } - if (isError) { - triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo)); - } + // request headers + if (requestAttrValues.noHeaders) { + // ignore all headers + } else { + for (const header in headers) { + if (headers.hasOwnProperty(header)) { + const headerValue = headers[header] + safelySetHeaderValue(xhr, header, headerValue) } + } + } - //==================================================================== - // Extensions API - //==================================================================== - - /** @type {Object<string, import("./htmx").HtmxExtension>} */ - var extensions = {}; - - /** - * extensionBase defines the default functions for all extensions. - * @returns {import("./htmx").HtmxExtension} - */ - function extensionBase() { - return { - init: function(api) {return null;}, - onEvent : function(name, evt) {return true;}, - transformResponse : function(text, xhr, elt) {return text;}, - isInlineSwap : function(swapStyle) {return false;}, - handleSwap : function(swapStyle, target, fragment, settleInfo) {return false;}, - encodeParameters : function(xhr, parameters, elt) {return null;} - } - } + /** @type {HtmxResponseInfo} */ + const responseInfo = { + xhr, + target, + requestConfig, + etc, + boosted: eltIsBoosted, + select, + pathInfo: { + requestPath: path, + finalRequestPath: finalPath, + responsePath: null, + anchor + } + } - /** - * defineExtension initializes the extension and adds it to the htmx registry - * - * @param {string} name - * @param {import("./htmx").HtmxExtension} extension - */ - function defineExtension(name, extension) { - if(extension.init) { - extension.init(internalAPI) - } - extensions[name] = mergeObjects(extensionBase(), extension); - } + xhr.onload = function() { + try { + const hierarchy = hierarchyForElt(elt) + responseInfo.pathInfo.responsePath = getPathFromResponse(xhr) + responseHandler(elt, responseInfo) + removeRequestIndicators(indicators, disableElts) + triggerEvent(elt, 'htmx:afterRequest', responseInfo) + triggerEvent(elt, 'htmx:afterOnLoad', responseInfo) + // if the body no longer contains the element, trigger the event on the closest parent + // remaining in the DOM + if (!bodyContains(elt)) { + let secondaryTriggerElt = null + while (hierarchy.length > 0 && secondaryTriggerElt == null) { + const parentEltInHierarchy = hierarchy.shift() + if (bodyContains(parentEltInHierarchy)) { + secondaryTriggerElt = parentEltInHierarchy + } + } + if (secondaryTriggerElt) { + triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo) + triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo) + } + } + maybeCall(resolve) + endRequestLock() + } catch (e) { + triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({ error: e }, responseInfo)) + throw e + } + } + xhr.onerror = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:sendError', responseInfo) + maybeCall(reject) + endRequestLock() + } + xhr.onabort = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo) + maybeCall(reject) + endRequestLock() + } + xhr.ontimeout = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:timeout', responseInfo) + maybeCall(reject) + endRequestLock() + } + if (!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)) { + maybeCall(resolve) + endRequestLock() + return promise + } + var indicators = addRequestIndicatorClasses(elt) + var disableElts = disableElements(elt) + + forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { + forEach([xhr, xhr.upload], function(target) { + target.addEventListener(eventName, function(event) { + triggerEvent(elt, 'htmx:xhr:' + eventName, { + lengthComputable: event.lengthComputable, + loaded: event.loaded, + total: event.total + }) + }) + }) + }) + triggerEvent(elt, 'htmx:beforeSend', responseInfo) + const params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredFormData) + xhr.send(params) + return promise + } + + /** + * @typedef {Object} HtmxHistoryUpdate + * @property {string|null} [type] + * @property {string|null} [path] + */ + + /** + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + * @return {HtmxHistoryUpdate} + */ + function determineHistoryUpdates(elt, responseInfo) { + const xhr = responseInfo.xhr + + //= ========================================== + // First consult response headers + //= ========================================== + let pathFromHeaders = null + let typeFromHeaders = null + if (hasHeader(xhr, /HX-Push:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Push') + typeFromHeaders = 'push' + } else if (hasHeader(xhr, /HX-Push-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Push-Url') + typeFromHeaders = 'push' + } else if (hasHeader(xhr, /HX-Replace-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Replace-Url') + typeFromHeaders = 'replace' + } - /** - * removeExtension removes an extension from the htmx registry - * - * @param {string} name - */ - function removeExtension(name) { - delete extensions[name]; + // if there was a response header, that has priority + if (pathFromHeaders) { + if (pathFromHeaders === 'false') { + return {} + } else { + return { + type: typeFromHeaders, + path: pathFromHeaders } + } + } - /** - * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element - * - * @param {HTMLElement} elt - * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn - * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore - */ - function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + //= ========================================== + // Next resolve via DOM values + //= ========================================== + const requestPath = responseInfo.pathInfo.finalRequestPath + const responsePath = responseInfo.pathInfo.responsePath + + const pushUrl = getClosestAttributeValue(elt, 'hx-push-url') + const replaceUrl = getClosestAttributeValue(elt, 'hx-replace-url') + const elementIsBoosted = getInternalData(elt).boosted + + let saveType = null + let path = null + + if (pushUrl) { + saveType = 'push' + path = pushUrl + } else if (replaceUrl) { + saveType = 'replace' + path = replaceUrl + } else if (elementIsBoosted) { + saveType = 'push' + path = responsePath || requestPath // if there is no response path, go with the original request path + } - if (elt == undefined) { - return extensionsToReturn; - } - if (extensionsToReturn == undefined) { - extensionsToReturn = []; - } - if (extensionsToIgnore == undefined) { - extensionsToIgnore = []; - } - var extensionsForElement = getAttributeValue(elt, "hx-ext"); - if (extensionsForElement) { - forEach(extensionsForElement.split(","), function(extensionName){ - extensionName = extensionName.replace(/ /g, ''); - if (extensionName.slice(0, 7) == "ignore:") { - extensionsToIgnore.push(extensionName.slice(7)); - return; - } - if (extensionsToIgnore.indexOf(extensionName) < 0) { - var extension = extensions[extensionName]; - if (extension && extensionsToReturn.indexOf(extension) < 0) { - extensionsToReturn.push(extension); - } - } - }); - } - return getExtensions(parentElt(elt), extensionsToReturn, extensionsToIgnore); - } + if (path) { + // false indicates no push, return empty object + if (path === 'false') { + return {} + } + + // true indicates we want to follow wherever the server ended up sending us + if (path === 'true') { + path = responsePath || requestPath // if there is no response path, go with the original request path + } + + // restore any anchor associated with the request + if (responseInfo.pathInfo.anchor && path.indexOf('#') === -1) { + path = path + '#' + responseInfo.pathInfo.anchor + } + + return { + type: saveType, + path + } + } else { + return {} + } + } + + /** + * @param {HtmxResponseHandlingConfig} responseHandlingConfig + * @param {number} status + * @return {boolean} + */ + function codeMatches(responseHandlingConfig, status) { + var regExp = new RegExp(responseHandlingConfig.code) + return regExp.test(status.toString(10)) + } + + /** + * @param {XMLHttpRequest} xhr + * @return {HtmxResponseHandlingConfig} + */ + function resolveResponseHandling(xhr) { + for (var i = 0; i < htmx.config.responseHandling.length; i++) { + /** @type HtmxResponseHandlingConfig */ + var responseHandlingElement = htmx.config.responseHandling[i] + if (codeMatches(responseHandlingElement, xhr.status)) { + return responseHandlingElement + } + } + // no matches, return no swap + return { + swap: false + } + } + + /** + * @param {string} title + */ + function handleTitle(title) { + if (title) { + const titleElt = find('title') + if (titleElt) { + titleElt.innerHTML = title + } else { + window.document.title = title + } + } + } + + /** + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + */ + function handleAjaxResponse(elt, responseInfo) { + const xhr = responseInfo.xhr + let target = responseInfo.target + const etc = responseInfo.etc + const responseInfoSelect = responseInfo.select + + if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return + + if (hasHeader(xhr, /HX-Trigger:/i)) { + handleTriggerHeader(xhr, 'HX-Trigger', elt) + } - //==================================================================== - // Initialization - //==================================================================== - var isReady = false - getDocument().addEventListener('DOMContentLoaded', function() { - isReady = true - }) + if (hasHeader(xhr, /HX-Location:/i)) { + saveCurrentPageToHistory() + let redirectPath = xhr.getResponseHeader('HX-Location') + /** @type {HtmxAjaxHelperContext&{path:string}} */ + var redirectSwapSpec + if (redirectPath.indexOf('{') === 0) { + redirectSwapSpec = parseJSON(redirectPath) + // what's the best way to throw an error if the user didn't include this + redirectPath = redirectSwapSpec.path + delete redirectSwapSpec.path + } + ajaxHelper('get', redirectPath, redirectSwapSpec).then(function() { + pushUrlIntoHistory(redirectPath) + }) + return + } - /** - * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. - * - * This function uses isReady because there is no realiable way to ask the browswer whether - * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded - * firing and readystate=complete. - */ - function ready(fn) { - // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by - // some means other than the initial page load. - if (isReady || getDocument().readyState === 'complete') { - fn(); - } else { - getDocument().addEventListener('DOMContentLoaded', fn); - } - } + const shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && xhr.getResponseHeader('HX-Refresh') === 'true' - function insertIndicatorStyles() { - if (htmx.config.includeIndicatorStyles !== false) { - getDocument().head.insertAdjacentHTML("beforeend", - "<style>\ - ." + htmx.config.indicatorClass + "{opacity:0}\ - ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ - ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ - </style>"); - } - } + if (hasHeader(xhr, /HX-Redirect:/i)) { + location.href = xhr.getResponseHeader('HX-Redirect') + shouldRefresh && location.reload() + return + } - function getMetaConfig() { - var element = getDocument().querySelector('meta[name="htmx-config"]'); - if (element) { - // @ts-ignore - return parseJSON(element.content); - } else { - return null; - } - } + if (shouldRefresh) { + location.reload() + return + } - function mergeMetaConfig() { - var metaConfig = getMetaConfig(); - if (metaConfig) { - htmx.config = mergeObjects(htmx.config , metaConfig) - } - } + if (hasHeader(xhr, /HX-Retarget:/i)) { + if (xhr.getResponseHeader('HX-Retarget') === 'this') { + responseInfo.target = elt + } else { + responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget'))) + } + } - // initialize the document - ready(function () { - mergeMetaConfig(); - insertIndicatorStyles(); - var body = getDocument().body; - processNode(body); - var restoredElts = getDocument().querySelectorAll( - "[hx-trigger='restored'],[data-hx-trigger='restored']" - ); - body.addEventListener("htmx:abort", function (evt) { - var target = evt.target; - var internalData = getInternalData(target); - if (internalData && internalData.xhr) { - internalData.xhr.abort(); - } - }); - /** @type {(ev: PopStateEvent) => any} */ - const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null; - /** @type {(ev: PopStateEvent) => any} */ - window.onpopstate = function (event) { - if (event.state && event.state.htmx) { - restoreHistory(); - forEach(restoredElts, function(elt){ - triggerEvent(elt, 'htmx:restored', { - 'document': getDocument(), - 'triggerEvent': triggerEvent - }); - }); - } else { - if (originalPopstate) { - originalPopstate(event); - } - } - }; - setTimeout(function () { - triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event - body = null; // kill reference for gc - }, 0); + const historyUpdate = determineHistoryUpdates(elt, responseInfo) + + const responseHandling = resolveResponseHandling(xhr) + const shouldSwap = responseHandling.swap + let isError = !!responseHandling.error + let ignoreTitle = htmx.config.ignoreTitle || responseHandling.ignoreTitle + let selectOverride = responseHandling.select + if (responseHandling.target) { + responseInfo.target = asElement(querySelectorExt(elt, responseHandling.target)) + } + var swapOverride = etc.swapOverride + if (swapOverride == null && responseHandling.swapOverride) { + swapOverride = responseHandling.swapOverride + } + + // response headers override response handling config + if (hasHeader(xhr, /HX-Retarget:/i)) { + if (xhr.getResponseHeader('HX-Retarget') === 'this') { + responseInfo.target = elt + } else { + responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget'))) + } + } + if (hasHeader(xhr, /HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader('HX-Reswap') + } + + var serverResponse = xhr.response + /** @type HtmxBeforeSwapDetails */ + var beforeSwapDetails = mergeObjects({ + shouldSwap, + serverResponse, + isError, + ignoreTitle, + selectOverride + }, responseInfo) + + if (responseHandling.event && !triggerEvent(target, responseHandling.event, beforeSwapDetails)) return + + if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return + + target = beforeSwapDetails.target // allow re-targeting + serverResponse = beforeSwapDetails.serverResponse // allow updating content + isError = beforeSwapDetails.isError // allow updating error + ignoreTitle = beforeSwapDetails.ignoreTitle // allow updating ignoring title + selectOverride = beforeSwapDetails.selectOverride // allow updating select override + + responseInfo.target = target // Make updated target available to response events + responseInfo.failed = isError // Make failed property available to response events + responseInfo.successful = !isError // Make successful property available to response events + + if (beforeSwapDetails.shouldSwap) { + if (xhr.status === 286) { + cancelPolling(elt) + } + + withExtensions(elt, function(extension) { + serverResponse = extension.transformResponse(serverResponse, xhr, elt) + }) + + // Save current page if there will be a history update + if (historyUpdate.type) { + saveCurrentPageToHistory() + } + + if (hasHeader(xhr, /HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader('HX-Reswap') + } + var swapSpec = getSwapSpecification(elt, swapOverride) + + if (!swapSpec.hasOwnProperty('ignoreTitle')) { + swapSpec.ignoreTitle = ignoreTitle + } + + target.classList.add(htmx.config.swappingClass) + + // optional transition API promise callbacks + let settleResolve = null + let settleReject = null + + if (responseInfoSelect) { + selectOverride = responseInfoSelect + } + + if (hasHeader(xhr, /HX-Reselect:/i)) { + selectOverride = xhr.getResponseHeader('HX-Reselect') + } + + const selectOOB = getClosestAttributeValue(elt, 'hx-select-oob') + const select = getClosestAttributeValue(elt, 'hx-select') + + let doSwap = function() { + try { + // if we need to save history, do so, before swapping so that relative resources have the correct base URL + if (historyUpdate.type) { + triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)) + if (historyUpdate.type === 'push') { + pushUrlIntoHistory(historyUpdate.path) + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', { path: historyUpdate.path }) + } else { + replaceUrlInHistory(historyUpdate.path) + triggerEvent(getDocument().body, 'htmx:replacedInHistory', { path: historyUpdate.path }) + } + } + + swap(target, serverResponse, swapSpec, { + select: selectOverride || select, + selectOOB, + eventInfo: responseInfo, + anchor: responseInfo.pathInfo.anchor, + contextElement: elt, + afterSwapCallback: function() { + if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { + let finalElt = elt + if (!bodyContains(elt)) { + finalElt = getDocument().body + } + handleTriggerHeader(xhr, 'HX-Trigger-After-Swap', finalElt) + } + }, + afterSettleCallback: function() { + if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { + let finalElt = elt + if (!bodyContains(elt)) { + finalElt = getDocument().body + } + handleTriggerHeader(xhr, 'HX-Trigger-After-Settle', finalElt) + } + maybeCall(settleResolve) + } + }) + } catch (e) { + triggerErrorEvent(elt, 'htmx:swapError', responseInfo) + maybeCall(settleReject) + throw e + } + } + + let shouldTransition = htmx.config.globalViewTransitions + if (swapSpec.hasOwnProperty('transition')) { + shouldTransition = swapSpec.transition + } + + if (shouldTransition && + triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && + typeof Promise !== 'undefined' && + // @ts-ignore experimental feature atm + document.startViewTransition) { + const settlePromise = new Promise(function(_resolve, _reject) { + settleResolve = _resolve + settleReject = _reject }) + // wrap the original doSwap() in a call to startViewTransition() + const innerDoSwap = doSwap + doSwap = function() { + // @ts-ignore experimental feature atm + document.startViewTransition(function() { + innerDoSwap() + return settlePromise + }) + } + } + + if (swapSpec.swapDelay > 0) { + getWindow().setTimeout(doSwap, swapSpec.swapDelay) + } else { + doSwap() + } + } + if (isError) { + triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({ error: 'Response Status Error Code ' + xhr.status + ' from ' + responseInfo.pathInfo.requestPath }, responseInfo)) + } + } + + //= =================================================================== + // Extensions API + //= =================================================================== + + /** @type {Object<string, HtmxExtension>} */ + const extensions = {} + + /** + * extensionBase defines the default functions for all extensions. + * @returns {HtmxExtension} + */ + function extensionBase() { + return { + init: function(api) { return null }, + getSelectors: function() { return null }, + onEvent: function(name, evt) { return true }, + transformResponse: function(text, xhr, elt) { return text }, + isInlineSwap: function(swapStyle) { return false }, + handleSwap: function(swapStyle, target, fragment, settleInfo) { return false }, + encodeParameters: function(xhr, parameters, elt) { return null } + } + } + + /** + * defineExtension initializes the extension and adds it to the htmx registry + * + * @see https://htmx.org/api/#defineExtension + * + * @param {string} name the extension name + * @param {HtmxExtension} extension the extension definition + */ + function defineExtension(name, extension) { + if (extension.init) { + extension.init(internalAPI) + } + extensions[name] = mergeObjects(extensionBase(), extension) + } + + /** + * removeExtension removes an extension from the htmx registry + * + * @see https://htmx.org/api/#removeExtension + * + * @param {string} name + */ + function removeExtension(name) { + delete extensions[name] + } + + /** + * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element + * + * @param {Element} elt + * @param {HtmxExtension[]=} extensionsToReturn + * @param {string[]=} extensionsToIgnore + * @returns {HtmxExtension[]} + */ + function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + if (extensionsToReturn == undefined) { + extensionsToReturn = [] + } + if (elt == undefined) { + return extensionsToReturn + } + if (extensionsToIgnore == undefined) { + extensionsToIgnore = [] + } + const extensionsForElement = getAttributeValue(elt, 'hx-ext') + if (extensionsForElement) { + forEach(extensionsForElement.split(','), function(extensionName) { + extensionName = extensionName.replace(/ /g, '') + if (extensionName.slice(0, 7) == 'ignore:') { + extensionsToIgnore.push(extensionName.slice(7)) + return + } + if (extensionsToIgnore.indexOf(extensionName) < 0) { + const extension = extensions[extensionName] + if (extension && extensionsToReturn.indexOf(extension) < 0) { + extensionsToReturn.push(extension) + } + } + }) + } + return getExtensions(asElement(parentElt(elt)), extensionsToReturn, extensionsToIgnore) + } + + //= =================================================================== + // Initialization + //= =================================================================== + var isReady = false + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true + }) + + /** + * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. + * + * This function uses isReady because there is no reliable way to ask the browser whether + * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded + * firing and readystate=complete. + */ + function ready(fn) { + // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by + // some means other than the initial page load. + if (isReady || getDocument().readyState === 'complete') { + fn() + } else { + getDocument().addEventListener('DOMContentLoaded', fn) + } + } + + function insertIndicatorStyles() { + if (htmx.config.includeIndicatorStyles !== false) { + const nonceAttribute = htmx.config.inlineStyleNonce ? ` nonce="${htmx.config.inlineStyleNonce}"` : '' + getDocument().head.insertAdjacentHTML('beforeend', + '<style' + nonceAttribute + '>\ + .' + htmx.config.indicatorClass + '{opacity:0}\ + .' + htmx.config.requestClass + ' .' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\ + .' + htmx.config.requestClass + '.' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\ + </style>') + } + } + + function getMetaConfig() { + /** @type HTMLMetaElement */ + const element = getDocument().querySelector('meta[name="htmx-config"]') + if (element) { + return parseJSON(element.content) + } else { + return null + } + } - return htmx; + function mergeMetaConfig() { + const metaConfig = getMetaConfig() + if (metaConfig) { + htmx.config = mergeObjects(htmx.config, metaConfig) + } + } + + // initialize the document + ready(function() { + mergeMetaConfig() + insertIndicatorStyles() + let body = getDocument().body + processNode(body) + const restoredElts = getDocument().querySelectorAll( + "[hx-trigger='restored'],[data-hx-trigger='restored']" + ) + body.addEventListener('htmx:abort', function(evt) { + const target = evt.target + const internalData = getInternalData(target) + if (internalData && internalData.xhr) { + internalData.xhr.abort() + } + }) + /** @type {(ev: PopStateEvent) => any} */ + const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null + /** @type {(ev: PopStateEvent) => any} */ + window.onpopstate = function(event) { + if (event.state && event.state.htmx) { + restoreHistory() + forEach(restoredElts, function(elt) { + triggerEvent(elt, 'htmx:restored', { + document: getDocument(), + triggerEvent + }) + }) + } else { + if (originalPopstate) { + originalPopstate(event) + } + } } -)() -})); + getWindow().setTimeout(function() { + triggerEvent(body, 'htmx:load', {}) // give ready handlers a chance to load up before firing this event + body = null // kill reference for gc + }, 0) + }) + + return htmx +})() + +/** @typedef {'get'|'head'|'post'|'put'|'delete'|'connect'|'options'|'trace'|'patch'} HttpVerb */ + +/** + * @typedef {Object} SwapOptions + * @property {string} [select] + * @property {string} [selectOOB] + * @property {*} [eventInfo] + * @property {string} [anchor] + * @property {Element} [contextElement] + * @property {swapCallback} [afterSwapCallback] + * @property {swapCallback} [afterSettleCallback] + */ + +/** + * @callback swapCallback + */ + +/** + * @typedef {'innerHTML' | 'outerHTML' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'delete' | 'none' | string} HtmxSwapStyle + */ + +/** + * @typedef HtmxSwapSpecification + * @property {HtmxSwapStyle} swapStyle + * @property {number} swapDelay + * @property {number} settleDelay + * @property {boolean} [transition] + * @property {boolean} [ignoreTitle] + * @property {string} [head] + * @property {'top' | 'bottom'} [scroll] + * @property {string} [scrollTarget] + * @property {string} [show] + * @property {string} [showTarget] + * @property {boolean} [focusScroll] + */ + +/** + * @typedef {((this:Node, evt:Event) => boolean) & {source: string}} ConditionalFunction + */ + +/** + * @typedef {Object} HtmxTriggerSpecification + * @property {string} trigger + * @property {number} [pollInterval] + * @property {ConditionalFunction} [eventFilter] + * @property {boolean} [changed] + * @property {boolean} [once] + * @property {boolean} [consume] + * @property {number} [delay] + * @property {string} [from] + * @property {string} [target] + * @property {number} [throttle] + * @property {string} [queue] + * @property {string} [root] + * @property {string} [threshold] + */ + +/** + * @typedef {{elt: Element, message: string, validity: ValidityState}} HtmxElementValidationError + */ + +/** + * @typedef {Record<string, string>} HtmxHeaderSpecification + * @property {'true'} HX-Request + * @property {string|null} HX-Trigger + * @property {string|null} HX-Trigger-Name + * @property {string|null} HX-Target + * @property {string} HX-Current-URL + * @property {string} [HX-Prompt] + * @property {'true'} [HX-Boosted] + * @property {string} [Content-Type] + * @property {'true'} [HX-History-Restore-Request] + */ + +/** @typedef HtmxAjaxHelperContext + * @property {Element|string} [source] + * @property {Event} [event] + * @property {HtmxAjaxHandler} [handler] + * @property {Element|string} target + * @property {HtmxSwapStyle} [swap] + * @property {Object|FormData} [values] + * @property {Record<string,string>} [headers] + * @property {string} [select] + */ + +/** + * @typedef {Object} HtmxRequestConfig + * @property {boolean} boosted + * @property {boolean} useUrlParams + * @property {FormData} formData + * @property {Object} parameters formData proxy + * @property {FormData} unfilteredFormData + * @property {Object} unfilteredParameters unfilteredFormData proxy + * @property {HtmxHeaderSpecification} headers + * @property {Element} target + * @property {HttpVerb} verb + * @property {HtmxElementValidationError[]} errors + * @property {boolean} withCredentials + * @property {number} timeout + * @property {string} path + * @property {Event} triggeringEvent + */ + +/** + * @typedef {Object} HtmxResponseInfo + * @property {XMLHttpRequest} xhr + * @property {Element} target + * @property {HtmxRequestConfig} requestConfig + * @property {HtmxAjaxEtc} etc + * @property {boolean} boosted + * @property {string} select + * @property {{requestPath: string, finalRequestPath: string, responsePath: string|null, anchor: string}} pathInfo + * @property {boolean} [failed] + * @property {boolean} [successful] + */ + +/** + * @typedef {Object} HtmxAjaxEtc + * @property {boolean} [returnPromise] + * @property {HtmxAjaxHandler} [handler] + * @property {string} [select] + * @property {Element} [targetOverride] + * @property {HtmxSwapStyle} [swapOverride] + * @property {Record<string,string>} [headers] + * @property {Object|FormData} [values] + * @property {boolean} [credentials] + * @property {number} [timeout] + */ + +/** + * @typedef {Object} HtmxResponseHandlingConfig + * @property {string} [code] + * @property {boolean} swap + * @property {boolean} [error] + * @property {boolean} [ignoreTitle] + * @property {string} [select] + * @property {string} [target] + * @property {string} [swapOverride] + * @property {string} [event] + */ + +/** + * @typedef {HtmxResponseInfo & {shouldSwap: boolean, serverResponse: any, isError: boolean, ignoreTitle: boolean, selectOverride:string}} HtmxBeforeSwapDetails + */ + +/** + * @callback HtmxAjaxHandler + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + */ + +/** + * @typedef {(() => void)} HtmxSettleTask + */ + +/** + * @typedef {Object} HtmxSettleInfo + * @property {HtmxSettleTask[]} tasks + * @property {Element[]} elts + * @property {string} [title] + */ + +/** + * @typedef {Object} HtmxExtension + * @see https://htmx.org/extensions/#defining + * @property {(api: any) => void} init + * @property {(name: string, event: Event|CustomEvent) => boolean} onEvent + * @property {(text: string, xhr: XMLHttpRequest, elt: Element) => string} transformResponse + * @property {(swapStyle: HtmxSwapStyle) => boolean} isInlineSwap + * @property {(swapStyle: HtmxSwapStyle, target: Element, fragment: Node, settleInfo: HtmxSettleInfo) => boolean} handleSwap + * @property {(xhr: XMLHttpRequest, parameters: FormData, elt: Element) => *|string|null} encodeParameters + */ diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.min.js b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.min.js index 53bbdf6..d66acce 100644 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.min.js +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/static/js/htmx.min.js @@ -1,4 +1,2 @@ -// /////////////////////////////////////////////////////////////////// -// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js -// -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(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 a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/<body/.test(e)}function l(e){var t=!N(e);var r=A(e);var n=e;if(r==="head"){n=n.replace(S,"")}if(Q.config.useTemplateFragments&&t){var i=a("<body><template>"+n+"</template></body>",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a("<table>"+n+"</table>",1);case"col":return a("<table><colgroup>"+n+"</colgroup></table>",2);case"tr":return a("<table><tbody>"+n+"</tbody></table>",2);case"td":case"th":return a("<table><tbody><tr>"+n+"</tr></tbody></table>",3);case"script":case"style":return a("<div>"+n+"</div>",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function oe(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function X(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var Y=function(e,t){var r=re().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function we(t,r){oe(t.attributes,function(e){if(!r.hasAttribute(e.name)&&be(e.name)){t.removeAttribute(e.name)}});oe(r.attributes,function(e){if(be(e.name)){t.setAttribute(e.name,e.value)}})}function Se(e,t){var r=Fr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){b(e)}}return e==="outerHTML"}function Ee(e,i,a){var t="#"+ee(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a<i.length;a++){var o=i[a].split(":",2);var s=o[0].trim();if(s.indexOf("#")===0){s=s.substring(1)}var l=o[1]||"true";var u=t.querySelector("#"+s);if(u){Ee(l,u,r)}}}oe(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=te(e,"hx-swap-oob");if(t!=null){Ee(t,e,r)}})}function Re(e){oe(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=te(e,"id");var r=re().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function Te(o,e,s){oe(e.querySelectorAll("[id]"),function(e){var t=ee(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Le(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=He(n.name,t);t=He(n.value,t)}}}return t}function Ae(e){var t=ae(e);if(t.onHandlers){for(var r=0;r<t.onHandlers.length;r++){const n=t.onHandlers[r];e.removeEventListener(n.event,n.listener)}delete t.onHandlers}}function Ne(e){var t=ae(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){oe(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}Ae(e);oe(Object.keys(t),function(e){delete t[e]})}function p(e){ce(e,"htmx:beforeCleanupElement");Ne(e);if(e.children){oe(e.children,function(e){p(e)})}}function Ie(t,e,r){if(t.tagName==="BODY"){return Ue(t,e,r)}else{var n;var i=t.previousSibling;m(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}p(t);u(t).removeChild(t)}}function ke(e,t,r){return m(e,e.firstChild,t,r)}function Pe(e,t,r){return m(u(e),e,t,r)}function Me(e,t,r){return m(e,null,t,r)}function Xe(e,t,r){return m(u(e),e.nextSibling,t,r)}function De(e,t,r){p(e);return u(e).removeChild(e)}function Ue(e,t,r){var n=e.firstChild;m(e,n,t,r);if(n){while(n.nextSibling){p(n.nextSibling);e.removeChild(n.nextSibling)}p(n);e.removeChild(n)}}function Be(e,t,r){var n=r||ne(e,"hx-select");if(n){var i=re().createDocumentFragment();oe(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function Fe(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Ie(r,n,i);return;case"afterbegin":ke(r,n,i);return;case"beforebegin":Pe(r,n,i);return;case"beforeend":Me(r,n,i);return;case"afterend":Xe(r,n,i);return;case"delete":De(r,n,i);return;default:var a=Fr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Oe(f))}}}return}}catch(e){b(e)}}if(e==="innerHTML"){Ue(r,n,i)}else{Fe(Q.config.defaultSwapStyle,t,r,n,i)}}}function Ve(e){if(e.indexOf("<title")>-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){ce(r,s[l].trim(),[])}}}var ze=/\s/;var x=/[\s,]/;var $e=/[_$a-zA-Z]/;var We=/[_$a-zA-Z0-9]/;var Ge=['"',"'","/"];var Je=/[^\s]/;var Ze=/[{(]/;var Ke=/[})]/;function Ye(e){var t=[];var r=0;while(r<e.length){if($e.exec(e.charAt(r))){var n=r;while(We.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ge.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function Qe(e,t,r){return $e.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function et(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){xt(e,a[1],0)}if(a[0]==="send"){bt(e)}}}function xt(s,r,n){if(!se(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=Q.createWebSocket(r);t.onerror=function(e){fe(s,"htmx:wsError",{error:e,socket:t});yt(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a<i.length;a++){var o=i[a];Ee(te(o,"hx-swap-oob")||"true",o,r)}nr(r.tasks)})}function yt(e){if(!se(e)){ae(e).webSocket.close();return true}}function bt(u){var f=c(u,function(e){return ae(e).webSocket!=null});if(f){u.addEventListener(it(u)[0].trigger,function(e){var t=ae(f).webSocket;var r=xr(u,f);var n=dr(u,"post");var i=n.errors;var a=n.values;var o=Hr(u);var s=le(a,o);var l=yr(s,u);l["HEADERS"]=r;if(i&&i.length>0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){Et(e,a[1])}if(a[0]==="swap"){Ct(e,a[1])}}}function Et(t,e){var r=Q.createEventSource(e);r.onerror=function(e){fe(t,"htmx:sseError",{error:e,source:r});Tt(t)};ae(t).sseEventSource=r}function Ct(a,o){var s=c(a,Ot);if(s){var l=ae(s).sseEventSource;var u=function(e){if(Tt(s)){return}if(!se(a)){l.removeEventListener(o,u);return}var t=e.data;R(a,function(e){t=e.transformResponse(t,null,a)});var r=wr(a);var n=ye(a);var i=T(a);je(r.swapStyle,n,a,t,i);nr(i.tasks);ce(a,"htmx:sseMessage",e)};ae(a).sseListener=u;l.addEventListener(o,u)}else{fe(a,"htmx:noSSESourceError")}}function Rt(e,t,r){var n=c(e,Ot);if(n){var i=ae(n).sseEventSource;var a=function(){if(!Tt(n)){if(se(e)){t(e)}else{i.removeEventListener(r,a)}}};ae(e).sseListener=a;i.addEventListener(r,a)}else{fe(e,"htmx:noSSESourceError")}}function Tt(e){if(!se(e)){ae(e).sseEventSource.close();return true}}function Ot(e){return ae(e).sseEventSource!=null}function qt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n>0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){ce(n,"intersect");break}}},i);a.observe(n);ht(n,r,t,e)}else if(e.trigger==="load"){if(!ct(e,n,Wt("load",{elt:n}))){qt(n,r,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r<t.length;r++){var n=t[r].name;if(s(n,"hx-on:")||s(n,"data-hx-on:")||s(n,"hx-on-")||s(n,"data-hx-on-")){return true}}return false}function kt(e){var t=null;var r=[];if(It(e)){r.push(e)}if(document.evaluate){var n=document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]',e);while(t=n.iterateNext())r.push(t)}else{var i=e.getElementsByTagName("*");for(var a=0;a<i.length;a++){if(It(i[a])){r.push(i[a])}}}return r}function Pt(e){if(e.querySelectorAll){var t=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";var r=e.querySelectorAll(i+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Mt(e){var t=v(e.target,"button, input[type='submit']");var r=Dt(e);if(r){r.lastButtonClicked=t}}function Xt(e){var t=Dt(e);if(t){t.lastButtonClicked=null}}function Dt(e){var t=v(e.target,"button, input[type='submit']");if(!t){return}var r=g("#"+ee(t,"form"))||v(t,"form");if(!r){return}return ae(r)}function Ut(e){e.addEventListener("click",Mt);e.addEventListener("focusin",Mt);e.addEventListener("focusout",Xt)}function Bt(e){var t=Ye(e);var r=0;for(var n=0;n<t.length;n++){const i=t[n];if(i==="{"){r++}else if(i==="}"){r--}}return r}function Ft(t,e,r){var n=ae(t);if(!Array.isArray(n.onHandlers)){n.onHandlers=[]}var i;var a=function(e){return Tr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Vt(e){var t=te(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;t<e.attributes.length;t++){var r=e.attributes[t].name;var n=e.attributes[t].value;if(s(r,"hx-on")||s(r,"data-hx-on")){var i=r.indexOf("-on")+3;var a=r.slice(i,i+1);if(a==="-"||a===":"){var o=r.slice(i+1);if(s(o,":")){o="htmx"+o}else if(s(o,"-")){o="htmx:"+o.slice(1)}else if(s(o,"htmx-")){o="htmx:"+o.slice(5)}Ft(e,o,n)}}}}function _t(t){if(v(t,Q.config.disableSelector)){p(t);return}var r=ae(t);if(r.initHash!==Le(t)){Ne(t);r.initHash=Le(t);Vt(t);ce(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=it(t);var n=Ht(t,r,e);if(!n){if(ne(t,"hx-boost")==="true"){lt(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){Lt(t,e,r,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&o(t,"form")){Ut(t)}var i=te(t,"hx-sse");if(i){St(t,r,i)}var a=te(t,"hx-ws");if(a){pt(t,r,a)}ce(t,"htmx:afterProcessNode")}}function zt(e){e=g(e);if(v(e,Q.config.disableSelector)){p(e);return}_t(e);oe(Pt(e),function(e){_t(e)});oe(kt(e),jt)}function $t(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=re().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function fe(e,t,r){ce(e,t,le({error:t},r))}function Gt(e){return e==="htmx:afterProcessNode"}function R(e,t){oe(Fr(e),function(e){try{t(e)}catch(e){b(e)}})}function b(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ce(e,t,r){e=g(e);if(r==null){r={}}r["elt"]=e;var n=Wt(t,r);if(Q.logger&&!Gt(t)){Q.logger(e,t,r)}if(r.error){b(r.error);ce(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=$t(t);if(i&&a!==t){var o=Wt(a,n.detail);i=i&&e.dispatchEvent(o)}R(e,function(e){i=i&&(e.onEvent(t,n)!==false&&!n.defaultPrevented)});return i}var Jt=location.pathname+location.search;function Zt(){var e=re().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||re().body}function Kt(e,t,r,n){if(!U()){return}if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}e=B(e);var i=E(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};ce(re().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Qt(e){var t=Q.config.requestClass;var r=e.cloneNode(true);oe(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function er(){var e=Zt();var t=Jt||location.pathname+location.search;var r;try{r=re().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){r=re().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!r){ce(re().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Kt(t,Qt(e),re().title,window.scrollY)}if(Q.config.historyEnabled)history.replaceState({htmx:true},re().title,window.location.href)}function tr(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(G(e,"&")||G(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Jt=e}function rr(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Jt=e}function nr(e){oe(e,function(e){e.call()})}function ir(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};ce(re().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",re().location.href);e.onload=function(){if(this.status>=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function fr(e){if(e.name===""||e.name==null||e.disabled||v(e,"fieldset[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 cr(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function hr(t,r,n,e,i){if(e==null||ur(t,e)){return}else{t.push(e)}if(fr(e)){var a=ee(e,"name");var o=e.value;if(e.multiple&&e.tagName==="SELECT"){o=M(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=M(e.files)}cr(a,o,r);if(i){vr(e,n)}}if(h(e,"form")){var s=e.elements;oe(s,function(e){hr(t,r,n,e,i)})}}function vr(e,t){if(e.willValidate){ce(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});ce(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function dr(e,t){var r=[];var n={};var i={};var a=[];var o=ae(e);if(o.lastButtonClicked&&!se(o.lastButtonClicked)){o.lastButtonClicked=null}var s=h(e,"form")&&e.noValidate!==true||te(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){hr(r,i,a,v(e,"form"),s)}hr(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=ee(l,"name");cr(u,l.value,i)}var f=pe(e,"hx-include");oe(f,function(e){hr(r,n,a,e,s);if(!h(e,"form")){oe(e.querySelectorAll(rt),function(e){hr(r,n,a,e,s)})}});n=le(n,i);return{errors:a,values:n}}function gr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function mr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t=gr(t,r,e)})}else{t=gr(t,r,n)}}}return t}function pr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function xr(e,t,r){var n={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":re().location.href};Rr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ae(e).boosted){n["HX-Boosted"]="true"}return n}function yr(t,e){var r=ne(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){oe(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};oe(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function br(e){return ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=d(o.substr(5))}else if(o.indexOf("settle:")===0){n["settleDelay"]=d(o.substr(7))}else if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}else if(o.indexOf("ignoreTitle:")===0){n["ignoreTitle"]=o.substr(12)==="true"}else if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","<style> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file +// v2.0.0 from https://github.com/bigskysoftware/htmx/releases +var htmx=function(){"use strict";const Q={onLoad:null,process:null,on:null,off:null,trigger:null,ajax:null,find:null,findAll:null,closest:null,values:function(e,t){const n=cn(e,t||"post");return n.values},remove:null,addClass:null,removeClass:null,toggleClass:null,takeClass:null,swap:null,defineExtension:null,removeExtension:null,logAll:null,logNone:null,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",inlineStyleNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",scrollBehavior:"instant",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get","delete"],selfRequestsOnly:true,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null,disableInheritance:false,responseHandling:[{code:"204",swap:false},{code:"[23]..",swap:true},{code:"[45]..",swap:false,error:true}],allowNestedOobSwaps:true},parseInterval:null,_:null,version:"2.0.0"};Q.onLoad=$;Q.process=Dt;Q.on=be;Q.off=we;Q.trigger=he;Q.ajax=Hn;Q.find=r;Q.findAll=p;Q.closest=g;Q.remove=K;Q.addClass=W;Q.removeClass=o;Q.toggleClass=Y;Q.takeClass=ge;Q.swap=ze;Q.defineExtension=Un;Q.removeExtension=Bn;Q.logAll=z;Q.logNone=J;Q.parseInterval=d;Q._=_;const n={addTriggerHandler:Et,bodyContains:le,canAccessLocalStorage:j,findThisElement:Ee,filterValues:dn,swap:ze,hasAttribute:s,getAttributeValue:te,getClosestAttributeValue:re,getClosestMatch:T,getExpressionVars:Cn,getHeaders:hn,getInputValues:cn,getInternalData:ie,getSwapSpecification:pn,getTriggerSpecs:lt,getTarget:Ce,makeFragment:D,mergeObjects:ue,makeSettleInfo:xn,oobSwap:Te,querySelectorExt:fe,settleImmediately:Gt,shouldCancel:dt,triggerEvent:he,triggerErrorEvent:ae,withExtensions:Ut};const v=["get","post","put","delete","patch"];const R=v.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");const O=e("head");function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e instanceof Element&&e.getAttribute(t)}function s(e,t){return!!e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){const t=e.parentElement;if(!t&&e.parentNode instanceof ShadowRoot)return e.parentNode;return t}function ne(){return document}function H(e,t){return e.getRootNode?e.getRootNode({composed:t}):ne()}function T(e,t){while(e&&!t(e)){e=u(e)}return e||null}function q(e,t,n){const r=te(t,n);const o=te(t,"hx-disinherit");var i=te(t,"hx-inherit");if(e!==t){if(Q.config.disableInheritance){if(i&&(i==="*"||i.split(" ").indexOf(n)>=0)){return r}else{return null}}if(o&&(o==="*"||o.split(" ").indexOf(n)>=0)){return"unset"}}return r}function re(t,n){let r=null;T(t,function(e){return!!(r=q(t,ce(e),n))});if(r!=="unset"){return r}}function a(e,t){const n=e instanceof Element&&(e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector);return!!n&&n.call(e,t)}function L(e){const t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;const n=t.exec(e);if(n){return n[1].toLowerCase()}else{return""}}function N(e){const t=new DOMParser;return t.parseFromString(e,"text/html")}function A(e,t){while(t.childNodes.length>0){e.append(t.childNodes[0])}}function I(e){const t=ne().createElement("script");se(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}return t}function P(e){return e.matches("script")&&(e.type==="text/javascript"||e.type==="module"||e.type==="")}function k(e){Array.from(e.querySelectorAll("script")).forEach(e=>{if(P(e)){const t=I(e);const n=e.parentNode;try{n.insertBefore(t,e)}catch(e){w(e)}finally{e.remove()}}})}function D(e){const t=e.replace(O,"");const n=L(t);let r;if(n==="html"){r=new DocumentFragment;const i=N(e);A(r,i.body);r.title=i.title}else if(n==="body"){r=new DocumentFragment;const i=N(t);A(r,i.body);r.title=i.title}else{const i=N('<body><template class="internal-htmx-wrapper">'+t+"</template></body>");r=i.querySelector("template").content;r.title=i.title;var o=r.querySelector("title");if(o&&o.parentNode===r){o.remove();r.title=o.innerText}}if(r){if(Q.config.allowScriptTags){k(r)}else{r.querySelectorAll("script").forEach(e=>e.remove())}}return r}function oe(e){if(e){e()}}function t(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function M(e){return typeof e==="function"}function X(e){return t(e,"Object")}function ie(e){const t="htmx-internal-data";let n=e[t];if(!n){n=e[t]={}}return n}function F(t){const n=[];if(t){for(let e=0;e<t.length;e++){n.push(t[e])}}return n}function se(t,n){if(t){for(let e=0;e<t.length;e++){n(t[e])}}}function U(e){const t=e.getBoundingClientRect();const n=t.top;const r=t.bottom;return n<window.innerHeight&&r>=0}function le(e){const t=e.getRootNode&&e.getRootNode();if(t&&t instanceof window.ShadowRoot){return ne().body.contains(t.host)}else{return ne().body.contains(e)}}function B(e){return e.trim().split(/\s+/)}function ue(e,t){for(const n in t){if(t.hasOwnProperty(n)){e[n]=t[n]}}return e}function S(e){try{return JSON.parse(e)}catch(e){w(e);return null}}function j(){const e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function V(t){try{const e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function _(e){return vn(ne().body,function(){return eval(e)})}function $(t){const e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function z(){Q.logger=function(e,t,n){if(console){console.log(t,e,n)}}}function J(){Q.logger=null}function r(e,t){if(typeof e!=="string"){return e.querySelector(t)}else{return r(ne(),e)}}function p(e,t){if(typeof e!=="string"){return e.querySelectorAll(t)}else{return p(ne(),e)}}function E(){return window}function K(e,t){e=y(e);if(t){E().setTimeout(function(){K(e);e=null},t)}else{u(e).removeChild(e)}}function ce(e){return e instanceof Element?e:null}function G(e){return e instanceof HTMLElement?e:null}function Z(e){return typeof e==="string"?e:null}function h(e){return e instanceof Element||e instanceof Document||e instanceof DocumentFragment?e:null}function W(e,t,n){e=ce(y(e));if(!e){return}if(n){E().setTimeout(function(){W(e,t);e=null},n)}else{e.classList&&e.classList.add(t)}}function o(e,t,n){let r=ce(y(e));if(!r){return}if(n){E().setTimeout(function(){o(r,t);r=null},n)}else{if(r.classList){r.classList.remove(t);if(r.classList.length===0){r.removeAttribute("class")}}}}function Y(e,t){e=y(e);e.classList.toggle(t)}function ge(e,t){e=y(e);se(e.parentElement.children,function(e){o(e,t)});W(ce(e),t)}function g(e,t){e=ce(y(e));if(e&&e.closest){return e.closest(t)}else{do{if(e==null||a(e,t)){return e}}while(e=e&&ce(u(e)));return null}}function l(e,t){return e.substring(0,t.length)===t}function pe(e,t){return e.substring(e.length-t.length)===t}function i(e){const t=e.trim();if(l(t,"<")&&pe(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function m(e,t,n){e=y(e);if(t.indexOf("closest ")===0){return[g(ce(e),i(t.substr(8)))]}else if(t.indexOf("find ")===0){return[r(h(e),i(t.substr(5)))]}else if(t==="next"){return[ce(e).nextElementSibling]}else if(t.indexOf("next ")===0){return[me(e,i(t.substr(5)),!!n)]}else if(t==="previous"){return[ce(e).previousElementSibling]}else if(t.indexOf("previous ")===0){return[ye(e,i(t.substr(9)),!!n)]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else if(t==="root"){return[H(e,!!n)]}else if(t.indexOf("global ")===0){return m(e,t.slice(7),true)}else{return F(h(H(e,!!n)).querySelectorAll(i(t)))}}var me=function(t,e,n){const r=h(H(t,n)).querySelectorAll(e);for(let e=0;e<r.length;e++){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_PRECEDING){return o}}};var ye=function(t,e,n){const r=h(H(t,n)).querySelectorAll(e);for(let e=r.length-1;e>=0;e--){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_FOLLOWING){return o}}};function fe(e,t){if(typeof e!=="string"){return m(e,t)[0]}else{return m(ne().body,e)[0]}}function y(e,t){if(typeof e==="string"){return r(h(t)||document,e)}else{return e}}function xe(e,t,n){if(M(t)){return{target:ne().body,event:Z(e),listener:t}}else{return{target:y(e),event:Z(t),listener:n}}}function be(t,n,r){_n(function(){const e=xe(t,n,r);e.target.addEventListener(e.event,e.listener)});const e=M(n);return e?n:r}function we(t,n,r){_n(function(){const e=xe(t,n,r);e.target.removeEventListener(e.event,e.listener)});return M(n)?n:r}const ve=ne().createElement("output");function Se(e,t){const n=re(e,t);if(n){if(n==="this"){return[Ee(e,t)]}else{const r=m(e,n);if(r.length===0){w('The selector "'+n+'" on '+t+" returned no matches!");return[ve]}else{return r}}}}function Ee(e,t){return ce(T(e,function(e){return te(ce(e),t)!=null}))}function Ce(e){const t=re(e,"hx-target");if(t){if(t==="this"){return Ee(e,"hx-target")}else{return fe(e,t)}}else{const n=ie(e);if(n.boosted){return ne().body}else{return e}}}function Re(t){const n=Q.config.attributesToSettle;for(let e=0;e<n.length;e++){if(t===n[e]){return true}}return false}function Oe(t,n){se(t.attributes,function(e){if(!n.hasAttribute(e.name)&&Re(e.name)){t.removeAttribute(e.name)}});se(n.attributes,function(e){if(Re(e.name)){t.setAttribute(e.name,e.value)}})}function He(t,e){const n=jn(e);for(let e=0;e<n.length;e++){const r=n[e];try{if(r.isInlineSwap(t)){return true}}catch(e){w(e)}}return t==="outerHTML"}function Te(e,o,i){let t="#"+ee(o,"id");let s="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){s=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{s=e}const n=ne().querySelectorAll(t);if(n){se(n,function(e){let t;const n=o.cloneNode(true);t=ne().createDocumentFragment();t.appendChild(n);if(!He(s,e)){t=h(n)}const r={shouldSwap:true,target:e,fragment:t};if(!he(e,"htmx:oobBeforeSwap",r))return;e=r.target;if(r.shouldSwap){_e(s,e,e,t,i)}se(i.elts,function(e){he(e,"htmx:oobAfterSwap",r)})});o.parentNode.removeChild(o)}else{o.parentNode.removeChild(o);ae(ne().body,"htmx:oobErrorNoTarget",{content:o})}return e}function qe(e){se(p(e,"[hx-preserve], [data-hx-preserve]"),function(e){const t=te(e,"id");const n=ne().getElementById(t);if(n!=null){e.parentNode.replaceChild(n,e)}})}function Le(l,e,u){se(e.querySelectorAll("[id]"),function(t){const n=ee(t,"id");if(n&&n.length>0){const r=n.replace("'","\\'");const o=t.tagName.replace(":","\\:");const e=h(l);const i=e&&e.querySelector(o+"[id='"+r+"']");if(i&&i!==e){const s=t.cloneNode();Oe(t,i);u.tasks.push(function(){Oe(t,s)})}}})}function Ne(e){return function(){o(e,Q.config.addedClass);Dt(ce(e));Ae(h(e));he(e,"htmx:load")}}function Ae(e){const t="[autofocus]";const n=G(a(e,t)?e:e.querySelector(t));if(n!=null){n.focus()}}function c(e,t,n,r){Le(e,n,r);while(n.childNodes.length>0){const o=n.firstChild;W(ce(o),Q.config.addedClass);e.insertBefore(o,t);if(o.nodeType!==Node.TEXT_NODE&&o.nodeType!==Node.COMMENT_NODE){r.tasks.push(Ne(o))}}}function Ie(e,t){let n=0;while(n<e.length){t=(t<<5)-t+e.charCodeAt(n++)|0}return t}function Pe(t){let n=0;if(t.attributes){for(let e=0;e<t.attributes.length;e++){const r=t.attributes[e];if(r.value){n=Ie(r.name,n);n=Ie(r.value,n)}}}return n}function ke(t){const n=ie(t);if(n.onHandlers){for(let e=0;e<n.onHandlers.length;e++){const r=n.onHandlers[e];we(t,r.event,r.listener)}delete n.onHandlers}}function De(e){const t=ie(e);if(t.timeout){clearTimeout(t.timeout)}if(t.listenerInfos){se(t.listenerInfos,function(e){if(e.on){we(e.on,e.trigger,e.listener)}})}ke(e);se(Object.keys(t),function(e){delete t[e]})}function f(e){he(e,"htmx:beforeCleanupElement");De(e);if(e.children){se(e.children,function(e){f(e)})}}function Me(t,e,n){let r;const o=t.previousSibling;c(u(t),t,e,n);if(o==null){r=u(t).firstChild}else{r=o.nextSibling}n.elts=n.elts.filter(function(e){return e!==t});while(r&&r!==t){if(r instanceof Element){n.elts.push(r);r=r.nextElementSibling}else{r=null}}f(t);if(t instanceof Element){t.remove()}else{t.parentNode.removeChild(t)}}function Xe(e,t,n){return c(e,e.firstChild,t,n)}function Fe(e,t,n){return c(u(e),e,t,n)}function Ue(e,t,n){return c(e,null,t,n)}function Be(e,t,n){return c(u(e),e.nextSibling,t,n)}function je(e){f(e);return u(e).removeChild(e)}function Ve(e,t,n){const r=e.firstChild;c(e,r,t,n);if(r){while(r.nextSibling){f(r.nextSibling);e.removeChild(r.nextSibling)}f(r);e.removeChild(r)}}function _e(t,e,n,r,o){switch(t){case"none":return;case"outerHTML":Me(n,r,o);return;case"afterbegin":Xe(n,r,o);return;case"beforebegin":Fe(n,r,o);return;case"beforeend":Ue(n,r,o);return;case"afterend":Be(n,r,o);return;case"delete":je(n);return;default:var i=jn(e);for(let e=0;e<i.length;e++){const s=i[e];try{const l=s.handleSwap(t,n,r,o);if(l){if(typeof l.length!=="undefined"){for(let e=0;e<l.length;e++){const u=l[e];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){o.tasks.push(Ne(u))}}}return}}catch(e){w(e)}}if(t==="innerHTML"){Ve(n,r,o)}else{_e(Q.config.defaultSwapStyle,e,n,r,o)}}}function $e(e,n){se(p(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){if(Q.config.allowNestedOobSwaps||e.parentElement===null){const t=te(e,"hx-swap-oob");if(t!=null){Te(t,e,n)}}else{e.removeAttribute("hx-swap-oob");e.removeAttribute("data-hx-swap-oob")}})}function ze(e,t,r,o){if(!o){o={}}e=y(e);const n=document.activeElement;let i={};try{i={elt:n,start:n?n.selectionStart:null,end:n?n.selectionEnd:null}}catch(e){}const s=xn(e);if(r.swapStyle==="textContent"){e.textContent=t}else{let n=D(t);s.title=n.title;if(o.selectOOB){const u=o.selectOOB.split(",");for(let t=0;t<u.length;t++){const c=u[t].split(":",2);let e=c[0].trim();if(e.indexOf("#")===0){e=e.substring(1)}const f=c[1]||"true";const a=n.querySelector("#"+e);if(a){Te(f,a,s)}}}$e(n,s);se(p(n,"template"),function(e){$e(e.content,s);if(e.content.childElementCount===0){e.remove()}});if(o.select){const h=ne().createDocumentFragment();se(n.querySelectorAll(o.select),function(e){h.appendChild(e)});n=h}qe(n);_e(r.swapStyle,o.contextElement,e,n,s)}if(i.elt&&!le(i.elt)&&ee(i.elt,"id")){const d=document.getElementById(ee(i.elt,"id"));const g={preventScroll:r.focusScroll!==undefined?!r.focusScroll:!Q.config.defaultFocusScroll};if(d){if(i.start&&d.setSelectionRange){try{d.setSelectionRange(i.start,i.end)}catch(e){}}d.focus(g)}}e.classList.remove(Q.config.swappingClass);se(s.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}he(e,"htmx:afterSwap",o.eventInfo)});if(o.afterSwapCallback){o.afterSwapCallback()}if(!r.ignoreTitle){Dn(s.title)}const l=function(){se(s.tasks,function(e){e.call()});se(s.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}he(e,"htmx:afterSettle",o.eventInfo)});if(o.anchor){const e=ce(y("#"+o.anchor));if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}bn(s.elts,r);if(o.afterSettleCallback){o.afterSettleCallback()}};if(r.settleDelay>0){E().setTimeout(l,r.settleDelay)}else{l()}}function Je(e,t,n){const r=e.getResponseHeader(t);if(r.indexOf("{")===0){const o=S(r);for(const i in o){if(o.hasOwnProperty(i)){let e=o[i];if(!X(e)){e={value:e}}he(n,i,e)}}}else{const s=r.split(",");for(let e=0;e<s.length;e++){he(n,s[e].trim(),[])}}}const Ke=/\s/;const x=/[\s,]/;const Ge=/[_$a-zA-Z]/;const Ze=/[_$a-zA-Z0-9]/;const We=['"',"'","/"];const Ye=/[^\s]/;const Qe=/[{(]/;const et=/[})]/;function tt(e){const t=[];let n=0;while(n<e.length){if(Ge.exec(e.charAt(n))){var r=n;while(Ze.exec(e.charAt(n+1))){n++}t.push(e.substr(r,n-r+1))}else if(We.indexOf(e.charAt(n))!==-1){const o=e.charAt(n);var r=n;n++;while(n<e.length&&e.charAt(n)!==o){if(e.charAt(n)==="\\"){n++}n++}t.push(e.substr(r,n-r+1))}else{const i=e.charAt(n);t.push(i)}n++}return t}function nt(e,t,n){return Ge.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==n&&t!=="."}function rt(r,o,i){if(o[0]==="["){o.shift();let e=1;let t=" return (function("+i+"){ return (";let n=null;while(o.length>0){const s=o[0];if(s==="]"){e--;if(e===0){if(n===null){t=t+"true"}o.shift();t+=")})";try{const l=vn(r,function(){return Function(t)()},function(){return true});l.source=t;return l}catch(e){ae(ne().body,"htmx:syntax:error",{error:e,source:t});return null}}}else if(s==="["){e++}if(nt(s,n,i)){t+="(("+i+"."+s+") ? ("+i+"."+s+") : (window."+s+"))"}else{t=t+s}n=o.shift()}}}function b(e,t){let n="";while(e.length>0&&!t.test(e[0])){n+=e.shift()}return n}function ot(e){let t;if(e.length>0&&Qe.test(e[0])){e.shift();t=b(e,et).trim();e.shift()}else{t=b(e,x)}return t}const it="input, textarea, select";function st(e,t,n){const r=[];const o=tt(t);do{b(o,Ye);const l=o.length;const u=b(o,/[,\[\s]/);if(u!==""){if(u==="every"){const c={trigger:"every"};b(o,Ye);c.pollInterval=d(b(o,/[,\[\s]/));b(o,Ye);var i=rt(e,o,"event");if(i){c.eventFilter=i}r.push(c)}else{const f={trigger:u};var i=rt(e,o,"event");if(i){f.eventFilter=i}while(o.length>0&&o[0]!==","){b(o,Ye);const a=o.shift();if(a==="changed"){f.changed=true}else if(a==="once"){f.once=true}else if(a==="consume"){f.consume=true}else if(a==="delay"&&o[0]===":"){o.shift();f.delay=d(b(o,x))}else if(a==="from"&&o[0]===":"){o.shift();if(Qe.test(o[0])){var s=ot(o)}else{var s=b(o,x);if(s==="closest"||s==="find"||s==="next"||s==="previous"){o.shift();const h=ot(o);if(h.length>0){s+=" "+h}}}f.from=s}else if(a==="target"&&o[0]===":"){o.shift();f.target=ot(o)}else if(a==="throttle"&&o[0]===":"){o.shift();f.throttle=d(b(o,x))}else if(a==="queue"&&o[0]===":"){o.shift();f.queue=b(o,x)}else if(a==="root"&&o[0]===":"){o.shift();f[a]=ot(o)}else if(a==="threshold"&&o[0]===":"){o.shift();f[a]=b(o,x)}else{ae(e,"htmx:syntax:error",{token:o.shift()})}}r.push(f)}}if(o.length===l){ae(e,"htmx:syntax:error",{token:o.shift()})}b(o,Ye)}while(o[0]===","&&o.shift());if(n){n[t]=r}return r}function lt(e){const t=te(e,"hx-trigger");let n=[];if(t){const r=Q.config.triggerSpecsCache;n=r&&r[t]||st(e,t,r)}if(n.length>0){return n}else if(a(e,"form")){return[{trigger:"submit"}]}else if(a(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(a(e,it)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function ut(e){ie(e).cancelled=true}function ct(e,t,n){const r=ie(e);r.timeout=E().setTimeout(function(){if(le(e)&&r.cancelled!==true){if(!pt(n,e,Xt("hx:poll:trigger",{triggerSpec:n,target:e}))){t(e)}ct(e,t,n)}},n.pollInterval)}function ft(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function at(e){return g(e,Q.config.disableSelector)}function ht(t,n,e){if(t instanceof HTMLAnchorElement&&ft(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){n.boosted=true;let r,o;if(t.tagName==="A"){r="get";o=ee(t,"href")}else{const i=ee(t,"method");r=i?i.toLowerCase():"get";if(r==="get"){}o=ee(t,"action")}e.forEach(function(e){mt(t,function(e,t){const n=ce(e);if(at(n)){f(n);return}de(r,o,n,t)},n,e,true)})}}function dt(e,t){const n=ce(t);if(!n){return false}if(e.type==="submit"||e.type==="click"){if(n.tagName==="FORM"){return true}if(a(n,'input[type="submit"], button')&&g(n,"form")!==null){return true}if(n instanceof HTMLAnchorElement&&n.href&&(n.getAttribute("href")==="#"||n.getAttribute("href").indexOf("#")!==0)){return true}}return false}function gt(e,t){return ie(e).boosted&&e instanceof HTMLAnchorElement&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function pt(e,t,n){const r=e.eventFilter;if(r){try{return r.call(t,n)!==true}catch(e){const o=r.source;ae(ne().body,"htmx:eventFilter:error",{error:e,source:o});return true}}return false}function mt(s,l,e,u,c){const f=ie(s);let t;if(u.from){t=m(s,u.from)}else{t=[s]}if(u.changed){t.forEach(function(e){const t=ie(e);t.lastValue=e.value})}se(t,function(o){const i=function(e){if(!le(s)){o.removeEventListener(u.trigger,i);return}if(gt(s,e)){return}if(c||dt(e,s)){e.preventDefault()}if(pt(u,s,e)){return}const t=ie(e);t.triggerSpec=u;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(s)<0){t.handledFor.push(s);if(u.consume){e.stopPropagation()}if(u.target&&e.target){if(!a(ce(e.target),u.target)){return}}if(u.once){if(f.triggeredOnce){return}else{f.triggeredOnce=true}}if(u.changed){const n=ie(o);const r=o.value;if(n.lastValue===r){return}n.lastValue=r}if(f.delayed){clearTimeout(f.delayed)}if(f.throttle){return}if(u.throttle>0){if(!f.throttle){l(s,e);f.throttle=E().setTimeout(function(){f.throttle=null},u.throttle)}}else if(u.delay>0){f.delayed=E().setTimeout(function(){l(s,e)},u.delay)}else{he(s,"htmx:trigger");l(s,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:u.trigger,listener:i,on:o});o.addEventListener(u.trigger,i)})}let yt=false;let xt=null;function bt(){if(!xt){xt=function(){yt=true};window.addEventListener("scroll",xt);setInterval(function(){if(yt){yt=false;se(ne().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"),function(e){wt(e)})}},200)}}function wt(e){if(!s(e,"data-hx-revealed")&&U(e)){e.setAttribute("data-hx-revealed","true");const t=ie(e);if(t.initHash){he(e,"revealed")}else{e.addEventListener("htmx:afterProcessNode",function(){he(e,"revealed")},{once:true})}}}function vt(e,t,n,r){const o=function(){if(!n.loaded){n.loaded=true;t(e)}};if(r>0){E().setTimeout(o,r)}else{o()}}function St(t,n,e){let i=false;se(v,function(r){if(s(t,"hx-"+r)){const o=te(t,"hx-"+r);i=true;n.path=o;n.verb=r;e.forEach(function(e){Et(t,e,n,function(e,t){const n=ce(e);if(g(n,Q.config.disableSelector)){f(n);return}de(r,o,n,t)})})}});return i}function Et(r,e,t,n){if(e.trigger==="revealed"){bt();mt(r,n,t,e);wt(ce(r))}else if(e.trigger==="intersect"){const o={};if(e.root){o.root=fe(r,e.root)}if(e.threshold){o.threshold=parseFloat(e.threshold)}const i=new IntersectionObserver(function(t){for(let e=0;e<t.length;e++){const n=t[e];if(n.isIntersecting){he(r,"intersect");break}}},o);i.observe(ce(r));mt(ce(r),n,t,e)}else if(e.trigger==="load"){if(!pt(e,r,Xt("load",{elt:r}))){vt(ce(r),n,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ct(ce(r),n,e)}else{mt(r,n,t,e)}}function Ct(e){const t=ce(e);if(!t){return false}const n=t.attributes;for(let e=0;e<n.length;e++){const r=n[e].name;if(l(r,"hx-on:")||l(r,"data-hx-on:")||l(r,"hx-on-")||l(r,"data-hx-on-")){return true}}return false}const Rt=(new XPathEvaluator).createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]');function Ot(e,t){if(Ct(e)){t.push(ce(e))}const n=Rt.evaluate(e);let r=null;while(r=n.iterateNext())t.push(ce(r))}function Ht(e){const t=[];if(e instanceof DocumentFragment){for(const n of e.childNodes){Ot(n,t)}}else{Ot(e,t)}return t}function Tt(e){if(e.querySelectorAll){const n=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";const r=[];for(const i in Xn){const s=Xn[i];if(s.getSelectors){var t=s.getSelectors();if(t){r.push(t)}}}const o=e.querySelectorAll(R+n+", form, [type='submit'],"+" [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]"+r.flat().map(e=>", "+e).join(""));return o}else{return[]}}function qt(e){const t=g(ce(e.target),"button, input[type='submit']");const n=Nt(e);if(n){n.lastButtonClicked=t}}function Lt(e){const t=Nt(e);if(t){t.lastButtonClicked=null}}function Nt(e){const t=g(ce(e.target),"button, input[type='submit']");if(!t){return}const n=y("#"+ee(t,"form"),t.getRootNode())||g(t,"form");if(!n){return}return ie(n)}function At(e){e.addEventListener("click",qt);e.addEventListener("focusin",qt);e.addEventListener("focusout",Lt)}function It(t,e,n){const r=ie(t);if(!Array.isArray(r.onHandlers)){r.onHandlers=[]}let o;const i=function(e){vn(t,function(){if(at(t)){return}if(!o){o=new Function("event",n)}o.call(t,e)})};t.addEventListener(e,i);r.onHandlers.push({event:e,listener:i})}function Pt(t){ke(t);for(let e=0;e<t.attributes.length;e++){const n=t.attributes[e].name;const r=t.attributes[e].value;if(l(n,"hx-on")||l(n,"data-hx-on")){const o=n.indexOf("-on")+3;const i=n.slice(o,o+1);if(i==="-"||i===":"){let e=n.slice(o+1);if(l(e,":")){e="htmx"+e}else if(l(e,"-")){e="htmx:"+e.slice(1)}else if(l(e,"htmx-")){e="htmx:"+e.slice(5)}It(t,e,r)}}}}function kt(t){if(g(t,Q.config.disableSelector)){f(t);return}const n=ie(t);if(n.initHash!==Pe(t)){De(t);n.initHash=Pe(t);he(t,"htmx:beforeProcessNode");if(t.value){n.lastValue=t.value}const e=lt(t);const r=St(t,n,e);if(!r){if(re(t,"hx-boost")==="true"){ht(t,n,e)}else if(s(t,"hx-trigger")){e.forEach(function(e){Et(t,e,n,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&s(t,"form")){At(t)}he(t,"htmx:afterProcessNode")}}function Dt(e){e=y(e);if(g(e,Q.config.disableSelector)){f(e);return}kt(e);se(Tt(e),function(e){kt(e)});se(Ht(e),Pt)}function Mt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Xt(e,t){let n;if(window.CustomEvent&&typeof window.CustomEvent==="function"){n=new CustomEvent(e,{bubbles:true,cancelable:true,composed:true,detail:t})}else{n=ne().createEvent("CustomEvent");n.initCustomEvent(e,true,true,t)}return n}function ae(e,t,n){he(e,t,ue({error:t},n))}function Ft(e){return e==="htmx:afterProcessNode"}function Ut(e,t){se(jn(e),function(e){try{t(e)}catch(e){w(e)}})}function w(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function he(e,t,n){e=y(e);if(n==null){n={}}n.elt=e;const r=Xt(t,n);if(Q.logger&&!Ft(t)){Q.logger(e,t,n)}if(n.error){w(n.error);he(e,"htmx:error",{errorInfo:n})}let o=e.dispatchEvent(r);const i=Mt(t);if(o&&i!==t){const s=Xt(i,r.detail);o=o&&e.dispatchEvent(s)}Ut(ce(e),function(e){o=o&&(e.onEvent(t,r)!==false&&!r.defaultPrevented)});return o}let Bt=location.pathname+location.search;function jt(){const e=ne().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||ne().body}function Vt(t,e){if(!j()){return}const n=$t(e);const r=ne().title;const o=window.scrollY;if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}t=V(t);const i=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e<i.length;e++){if(i[e].url===t){i.splice(e,1);break}}const s={url:t,content:n,title:r,scroll:o};he(ne().body,"htmx:historyItemCreated",{item:s,cache:i});i.push(s);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ae(ne().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function _t(t){if(!j()){return null}t=V(t);const n=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e<n.length;e++){if(n[e].url===t){return n[e]}}return null}function $t(e){const t=Q.config.requestClass;const n=e.cloneNode(true);se(p(n,"."+t),function(e){o(e,t)});return n.innerHTML}function zt(){const e=jt();const t=Bt||location.pathname+location.search;let n;try{n=ne().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){n=ne().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!n){he(ne().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Vt(t,e)}if(Q.config.historyEnabled)history.replaceState({htmx:true},ne().title,window.location.href)}function Jt(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(pe(e,"&")||pe(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Bt=e}function Kt(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Bt=e}function Gt(e){se(e,function(e){e.call(undefined)})}function Zt(o){const e=new XMLHttpRequest;const i={path:o,xhr:e};he(ne().body,"htmx:historyCacheMiss",i);e.open("GET",o,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",ne().location.href);e.onload=function(){if(this.status>=200&&this.status<400){he(ne().body,"htmx:historyCacheMissLoad",i);const e=D(this.response);const t=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;const n=jt();const r=xn(n);Dn(e.title);Ve(n,t,r);Gt(r.tasks);Bt=o;he(ne().body,"htmx:historyRestore",{path:o,cacheMiss:true,serverResponse:this.response})}else{ae(ne().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Wt(e){zt();e=e||location.pathname+location.search;const t=_t(e);if(t){const n=D(t.content);const r=jt();const o=xn(r);Dn(n.title);Ve(r,n,o);Gt(o.tasks);E().setTimeout(function(){window.scrollTo(0,t.scroll)},0);Bt=e;he(ne().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{Zt(e)}}}function Yt(e){let t=Se(e,"hx-indicator");if(t==null){t=[e]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.classList.add.call(e.classList,Q.config.requestClass)});return t}function Qt(e){let t=Se(e,"hx-disabled-elt");if(t==null){t=[]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function en(e,t){se(e,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList.remove.call(e.classList,Q.config.requestClass)}});se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function tn(t,n){for(let e=0;e<t.length;e++){const r=t[e];if(r.isSameNode(n)){return true}}return false}function nn(e){const t=e;if(t.name===""||t.name==null||t.disabled||g(t,"fieldset[disabled]")){return false}if(t.type==="button"||t.type==="submit"||t.tagName==="image"||t.tagName==="reset"||t.tagName==="file"){return false}if(t.type==="checkbox"||t.type==="radio"){return t.checked}return true}function rn(t,e,n){if(t!=null&&e!=null){if(Array.isArray(e)){e.forEach(function(e){n.append(t,e)})}else{n.append(t,e)}}}function on(t,n,r){if(t!=null&&n!=null){let e=r.getAll(t);if(Array.isArray(n)){e=e.filter(e=>n.indexOf(e)<0)}else{e=e.filter(e=>e!==n)}r.delete(t);se(e,e=>r.append(t,e))}}function sn(t,n,r,o,i){if(o==null||tn(t,o)){return}else{t.push(o)}if(nn(o)){const s=ee(o,"name");let e=o.value;if(o instanceof HTMLSelectElement&&o.multiple){e=F(o.querySelectorAll("option:checked")).map(function(e){return e.value})}if(o instanceof HTMLInputElement&&o.files){e=F(o.files)}rn(s,e,n);if(i){ln(o,r)}}if(o instanceof HTMLFormElement){se(o.elements,function(e){if(t.indexOf(e)>=0){on(e.name,e.value,n)}else{t.push(e)}if(i){ln(e,r)}});new FormData(o).forEach(function(e,t){if(e instanceof File&&e.name===""){return}rn(t,e,n)})}}function ln(e,t){const n=e;if(n.willValidate){he(n,"htmx:validation:validate");if(!n.checkValidity()){t.push({elt:n,message:n.validationMessage,validity:n.validity});he(n,"htmx:validation:failed",{message:n.validationMessage,validity:n.validity})}}}function un(t,e){for(const n of e.keys()){t.delete(n);e.getAll(n).forEach(function(e){t.append(n,e)})}return t}function cn(e,t){const n=[];const r=new FormData;const o=new FormData;const i=[];const s=ie(e);if(s.lastButtonClicked&&!le(s.lastButtonClicked)){s.lastButtonClicked=null}let l=e instanceof HTMLFormElement&&e.noValidate!==true||te(e,"hx-validate")==="true";if(s.lastButtonClicked){l=l&&s.lastButtonClicked.formNoValidate!==true}if(t!=="get"){sn(n,o,i,g(e,"form"),l)}sn(n,r,i,e,l);if(s.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){const c=s.lastButtonClicked||e;const f=ee(c,"name");rn(f,c.value,o)}const u=Se(e,"hx-include");se(u,function(e){sn(n,r,i,ce(e),l);if(!a(e,"form")){se(h(e).querySelectorAll(it),function(e){sn(n,r,i,e,l)})}});un(r,o);return{errors:i,formData:r,values:An(r)}}function fn(e,t,n){if(e!==""){e+="&"}if(String(n)==="[object Object]"){n=JSON.stringify(n)}const r=encodeURIComponent(n);e+=encodeURIComponent(t)+"="+r;return e}function an(e){e=Ln(e);let n="";e.forEach(function(e,t){n=fn(n,t,e)});return n}function hn(e,t,n){const r={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":ne().location.href};wn(e,"hx-headers",false,r);if(n!==undefined){r["HX-Prompt"]=n}if(ie(e).boosted){r["HX-Boosted"]="true"}return r}function dn(n,e){const t=re(e,"hx-params");if(t){if(t==="none"){return new FormData}else if(t==="*"){return n}else if(t.indexOf("not ")===0){se(t.substr(4).split(","),function(e){e=e.trim();n.delete(e)});return n}else{const r=new FormData;se(t.split(","),function(t){t=t.trim();if(n.has(t)){n.getAll(t).forEach(function(e){r.append(t,e)})}});return r}}else{return n}}function gn(e){return!!ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function pn(e,t){const n=t||re(e,"hx-swap");const r={swapStyle:ie(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ie(e).boosted&&!gn(e)){r.show="top"}if(n){const s=B(n);if(s.length>0){for(let e=0;e<s.length;e++){const l=s[e];if(l.indexOf("swap:")===0){r.swapDelay=d(l.substr(5))}else if(l.indexOf("settle:")===0){r.settleDelay=d(l.substr(7))}else if(l.indexOf("transition:")===0){r.transition=l.substr(11)==="true"}else if(l.indexOf("ignoreTitle:")===0){r.ignoreTitle=l.substr(12)==="true"}else if(l.indexOf("scroll:")===0){const u=l.substr(7);var o=u.split(":");const c=o.pop();var i=o.length>0?o.join(":"):null;r.scroll=c;r.scrollTarget=i}else if(l.indexOf("show:")===0){const f=l.substr(5);var o=f.split(":");const a=o.pop();var i=o.length>0?o.join(":"):null;r.show=a;r.showTarget=i}else if(l.indexOf("focus-scroll:")===0){const h=l.substr("focus-scroll:".length);r.focusScroll=h=="true"}else if(e==0){r.swapStyle=l}else{w("Unknown modifier in hx-swap: "+l)}}}}return r}function mn(e){return re(e,"hx-encoding")==="multipart/form-data"||a(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function yn(t,n,r){let o=null;Ut(n,function(e){if(o==null){o=e.encodeParameters(t,r,n)}});if(o!=null){return o}else{if(mn(n)){return un(new FormData,Ln(r))}else{return an(r)}}}function xn(e){return{tasks:[],elts:[e]}}function bn(e,t){const n=e[0];const r=e[e.length-1];if(t.scroll){var o=null;if(t.scrollTarget){o=ce(fe(n,t.scrollTarget))}if(t.scroll==="top"&&(n||o)){o=o||n;o.scrollTop=0}if(t.scroll==="bottom"&&(r||o)){o=o||r;o.scrollTop=o.scrollHeight}}if(t.show){var o=null;if(t.showTarget){let e=t.showTarget;if(t.showTarget==="window"){e="body"}o=ce(fe(n,e))}if(t.show==="top"&&(n||o)){o=o||n;o.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(r||o)){o=o||r;o.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function wn(r,e,o,i){if(i==null){i={}}if(r==null){return i}const s=te(r,e);if(s){let e=s.trim();let t=o;if(e==="unset"){return null}if(e.indexOf("javascript:")===0){e=e.substr(11);t=true}else if(e.indexOf("js:")===0){e=e.substr(3);t=true}if(e.indexOf("{")!==0){e="{"+e+"}"}let n;if(t){n=vn(r,function(){return Function("return ("+e+")")()},{})}else{n=S(e)}for(const l in n){if(n.hasOwnProperty(l)){if(i[l]==null){i[l]=n[l]}}}}return wn(ce(u(r)),e,o,i)}function vn(e,t,n){if(Q.config.allowEval){return t()}else{ae(e,"htmx:evalDisallowedError");return n}}function Sn(e,t){return wn(e,"hx-vars",true,t)}function En(e,t){return wn(e,"hx-vals",false,t)}function Cn(e){return ue(Sn(e),En(e))}function Rn(t,n,r){if(r!==null){try{t.setRequestHeader(n,r)}catch(e){t.setRequestHeader(n,encodeURIComponent(r));t.setRequestHeader(n+"-URI-AutoEncoded","true")}}}function On(t){if(t.responseURL&&typeof URL!=="undefined"){try{const e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ae(ne().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function C(e,t){return t.test(e.getAllResponseHeaders())}function Hn(e,t,n){e=e.toLowerCase();if(n){if(n instanceof Element||typeof n==="string"){return de(e,t,null,null,{targetOverride:y(n),returnPromise:true})}else{return de(e,t,y(n.source),n.event,{handler:n.handler,headers:n.headers,values:n.values,targetOverride:y(n.target),swapOverride:n.swap,select:n.select,returnPromise:true})}}else{return de(e,t,null,null,{returnPromise:true})}}function Tn(e){const t=[];while(e){t.push(e);e=e.parentElement}return t}function qn(e,t,n){let r;let o;if(typeof URL==="function"){o=new URL(t,document.location.href);const i=document.location.origin;r=i===o.origin}else{o=t;r=l(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!r){return false}}return he(e,"htmx:validateUrl",ue({url:o,sameHost:r},n))}function Ln(e){if(e instanceof FormData)return e;const t=new FormData;for(const n in e){if(e.hasOwnProperty(n)){if(typeof e[n].forEach==="function"){e[n].forEach(function(e){t.append(n,e)})}else if(typeof e[n]==="object"){t.append(n,JSON.stringify(e[n]))}else{t.append(n,e[n])}}}return t}function Nn(r,o,e){return new Proxy(e,{get:function(t,e){if(typeof e==="number")return t[e];if(e==="length")return t.length;if(e==="push"){return function(e){t.push(e);r.append(o,e)}}if(typeof t[e]==="function"){return function(){t[e].apply(t,arguments);r.delete(o);t.forEach(function(e){r.append(o,e)})}}if(t[e]&&t[e].length===1){return t[e][0]}else{return t[e]}},set:function(e,t,n){e[t]=n;r.delete(o);e.forEach(function(e){r.append(o,e)});return true}})}function An(r){return new Proxy(r,{get:function(e,t){if(typeof t==="symbol"){return Reflect.get(e,t)}if(t==="toJSON"){return()=>Object.fromEntries(r)}if(t in e){if(typeof e[t]==="function"){return function(){return r[t].apply(r,arguments)}}else{return e[t]}}const n=r.getAll(t);if(n.length===0){return undefined}else if(n.length===1){return n[0]}else{return Nn(e,t,n)}},set:function(t,n,e){if(typeof n!=="string"){return false}t.delete(n);if(typeof e.forEach==="function"){e.forEach(function(e){t.append(n,e)})}else{t.append(n,e)}return true},deleteProperty:function(e,t){if(typeof t==="string"){e.delete(t)}return true},ownKeys:function(e){return Reflect.ownKeys(Object.fromEntries(e))},getOwnPropertyDescriptor:function(e,t){return Reflect.getOwnPropertyDescriptor(Object.fromEntries(e),t)}})}function de(t,n,r,o,i,D){let s=null;let l=null;i=i!=null?i:{};if(i.returnPromise&&typeof Promise!=="undefined"){var e=new Promise(function(e,t){s=e;l=t})}if(r==null){r=ne().body}const M=i.handler||Mn;const X=i.select||null;if(!le(r)){oe(s);return e}const u=i.targetOverride||ce(Ce(r));if(u==null||u==ve){ae(r,"htmx:targetError",{target:te(r,"hx-target")});oe(l);return e}let c=ie(r);const f=c.lastButtonClicked;if(f){const L=ee(f,"formaction");if(L!=null){n=L}const N=ee(f,"formmethod");if(N!=null){if(N.toLowerCase()!=="dialog"){t=N}}}const a=re(r,"hx-confirm");if(D===undefined){const K=function(e){return de(t,n,r,o,i,!!e)};const G={target:u,elt:r,path:n,verb:t,triggeringEvent:o,etc:i,issueRequest:K,question:a};if(he(r,"htmx:confirm",G)===false){oe(s);return e}}let h=r;let d=re(r,"hx-sync");let g=null;let F=false;if(d){const A=d.split(":");const I=A[0].trim();if(I==="this"){h=Ee(r,"hx-sync")}else{h=ce(fe(r,I))}d=(A[1]||"drop").trim();c=ie(h);if(d==="drop"&&c.xhr&&c.abortable!==true){oe(s);return e}else if(d==="abort"){if(c.xhr){oe(s);return e}else{F=true}}else if(d==="replace"){he(h,"htmx:abort")}else if(d.indexOf("queue")===0){const Z=d.split(" ");g=(Z[1]||"last").trim()}}if(c.xhr){if(c.abortable){he(h,"htmx:abort")}else{if(g==null){if(o){const P=ie(o);if(P&&P.triggerSpec&&P.triggerSpec.queue){g=P.triggerSpec.queue}}if(g==null){g="last"}}if(c.queuedRequests==null){c.queuedRequests=[]}if(g==="first"&&c.queuedRequests.length===0){c.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="all"){c.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="last"){c.queuedRequests=[];c.queuedRequests.push(function(){de(t,n,r,o,i)})}oe(s);return e}}const p=new XMLHttpRequest;c.xhr=p;c.abortable=F;const m=function(){c.xhr=null;c.abortable=false;if(c.queuedRequests!=null&&c.queuedRequests.length>0){const e=c.queuedRequests.shift();e()}};const U=re(r,"hx-prompt");if(U){var y=prompt(U);if(y===null||!he(r,"htmx:prompt",{prompt:y,target:u})){oe(s);m();return e}}if(a&&!D){if(!confirm(a)){oe(s);m();return e}}let x=hn(r,u,y);if(t!=="get"&&!mn(r)){x["Content-Type"]="application/x-www-form-urlencoded"}if(i.headers){x=ue(x,i.headers)}const B=cn(r,t);let b=B.errors;const j=B.formData;if(i.values){un(j,Ln(i.values))}const V=Ln(Cn(r));const w=un(j,V);let v=dn(w,r);if(Q.config.getCacheBusterParam&&t==="get"){v.set("org.htmx.cache-buster",ee(u,"id")||"true")}if(n==null||n===""){n=ne().location.href}const S=wn(r,"hx-request");const _=ie(r).boosted;let E=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;const C={boosted:_,useUrlParams:E,formData:v,parameters:An(v),unfilteredFormData:w,unfilteredParameters:An(w),headers:x,target:u,verb:t,errors:b,withCredentials:i.credentials||S.credentials||Q.config.withCredentials,timeout:i.timeout||S.timeout||Q.config.timeout,path:n,triggeringEvent:o};if(!he(r,"htmx:configRequest",C)){oe(s);m();return e}n=C.path;t=C.verb;x=C.headers;v=Ln(C.parameters);b=C.errors;E=C.useUrlParams;if(b&&b.length>0){he(r,"htmx:validation:halted",C);oe(s);m();return e}const $=n.split("#");const z=$[0];const R=$[1];let O=n;if(E){O=z;const W=!v.keys().next().done;if(W){if(O.indexOf("?")<0){O+="?"}else{O+="&"}O+=an(v);if(R){O+="#"+R}}}if(!qn(r,O,C)){ae(r,"htmx:invalidPath",C);oe(l);return e}p.open(t.toUpperCase(),O,true);p.overrideMimeType("text/html");p.withCredentials=C.withCredentials;p.timeout=C.timeout;if(S.noHeaders){}else{for(const k in x){if(x.hasOwnProperty(k)){const Y=x[k];Rn(p,k,Y)}}}const H={xhr:p,target:u,requestConfig:C,etc:i,boosted:_,select:X,pathInfo:{requestPath:n,finalRequestPath:O,responsePath:null,anchor:R}};p.onload=function(){try{const t=Tn(r);H.pathInfo.responsePath=On(p);M(r,H);en(T,q);he(r,"htmx:afterRequest",H);he(r,"htmx:afterOnLoad",H);if(!le(r)){let e=null;while(t.length>0&&e==null){const n=t.shift();if(le(n)){e=n}}if(e){he(e,"htmx:afterRequest",H);he(e,"htmx:afterOnLoad",H)}}oe(s);m()}catch(e){ae(r,"htmx:onLoadError",ue({error:e},H));throw e}};p.onerror=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:sendError",H);oe(l);m()};p.onabort=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:sendAbort",H);oe(l);m()};p.ontimeout=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:timeout",H);oe(l);m()};if(!he(r,"htmx:beforeRequest",H)){oe(s);m();return e}var T=Yt(r);var q=Qt(r);se(["loadstart","loadend","progress","abort"],function(t){se([p,p.upload],function(e){e.addEventListener(t,function(e){he(r,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});he(r,"htmx:beforeSend",H);const J=E?null:yn(p,r,v);p.send(J);return e}function In(e,t){const n=t.xhr;let r=null;let o=null;if(C(n,/HX-Push:/i)){r=n.getResponseHeader("HX-Push");o="push"}else if(C(n,/HX-Push-Url:/i)){r=n.getResponseHeader("HX-Push-Url");o="push"}else if(C(n,/HX-Replace-Url:/i)){r=n.getResponseHeader("HX-Replace-Url");o="replace"}if(r){if(r==="false"){return{}}else{return{type:o,path:r}}}const i=t.pathInfo.finalRequestPath;const s=t.pathInfo.responsePath;const l=re(e,"hx-push-url");const u=re(e,"hx-replace-url");const c=ie(e).boosted;let f=null;let a=null;if(l){f="push";a=l}else if(u){f="replace";a=u}else if(c){f="push";a=s||i}if(a){if(a==="false"){return{}}if(a==="true"){a=s||i}if(t.pathInfo.anchor&&a.indexOf("#")===-1){a=a+"#"+t.pathInfo.anchor}return{type:f,path:a}}else{return{}}}function Pn(e,t){var n=new RegExp(e.code);return n.test(t.toString(10))}function kn(e){for(var t=0;t<Q.config.responseHandling.length;t++){var n=Q.config.responseHandling[t];if(Pn(n,e.status)){return n}}return{swap:false}}function Dn(e){if(e){const t=r("title");if(t){t.innerHTML=e}else{window.document.title=e}}}function Mn(o,i){const s=i.xhr;let l=i.target;const e=i.etc;const u=i.select;if(!he(o,"htmx:beforeOnLoad",i))return;if(C(s,/HX-Trigger:/i)){Je(s,"HX-Trigger",o)}if(C(s,/HX-Location:/i)){zt();let e=s.getResponseHeader("HX-Location");var t;if(e.indexOf("{")===0){t=S(e);e=t.path;delete t.path}Hn("get",e,t).then(function(){Jt(e)});return}const n=C(s,/HX-Refresh:/i)&&s.getResponseHeader("HX-Refresh")==="true";if(C(s,/HX-Redirect:/i)){location.href=s.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(C(s,/HX-Retarget:/i)){if(s.getResponseHeader("HX-Retarget")==="this"){i.target=o}else{i.target=ce(fe(o,s.getResponseHeader("HX-Retarget")))}}const c=In(o,i);const r=kn(s);const f=r.swap;let a=!!r.error;let h=Q.config.ignoreTitle||r.ignoreTitle;let d=r.select;if(r.target){i.target=ce(fe(o,r.target))}var g=e.swapOverride;if(g==null&&r.swapOverride){g=r.swapOverride}if(C(s,/HX-Retarget:/i)){if(s.getResponseHeader("HX-Retarget")==="this"){i.target=o}else{i.target=ce(fe(o,s.getResponseHeader("HX-Retarget")))}}if(C(s,/HX-Reswap:/i)){g=s.getResponseHeader("HX-Reswap")}var p=s.response;var m=ue({shouldSwap:f,serverResponse:p,isError:a,ignoreTitle:h,selectOverride:d},i);if(r.event&&!he(l,r.event,m))return;if(!he(l,"htmx:beforeSwap",m))return;l=m.target;p=m.serverResponse;a=m.isError;h=m.ignoreTitle;d=m.selectOverride;i.target=l;i.failed=a;i.successful=!a;if(m.shouldSwap){if(s.status===286){ut(o)}Ut(o,function(e){p=e.transformResponse(p,s,o)});if(c.type){zt()}if(C(s,/HX-Reswap:/i)){g=s.getResponseHeader("HX-Reswap")}var y=pn(o,g);if(!y.hasOwnProperty("ignoreTitle")){y.ignoreTitle=h}l.classList.add(Q.config.swappingClass);let n=null;let r=null;if(u){d=u}if(C(s,/HX-Reselect:/i)){d=s.getResponseHeader("HX-Reselect")}const x=re(o,"hx-select-oob");const b=re(o,"hx-select");let e=function(){try{if(c.type){he(ne().body,"htmx:beforeHistoryUpdate",ue({history:c},i));if(c.type==="push"){Jt(c.path);he(ne().body,"htmx:pushedIntoHistory",{path:c.path})}else{Kt(c.path);he(ne().body,"htmx:replacedInHistory",{path:c.path})}}ze(l,p,y,{select:d||b,selectOOB:x,eventInfo:i,anchor:i.pathInfo.anchor,contextElement:o,afterSwapCallback:function(){if(C(s,/HX-Trigger-After-Swap:/i)){let e=o;if(!le(o)){e=ne().body}Je(s,"HX-Trigger-After-Swap",e)}},afterSettleCallback:function(){if(C(s,/HX-Trigger-After-Settle:/i)){let e=o;if(!le(o)){e=ne().body}Je(s,"HX-Trigger-After-Settle",e)}oe(n)}})}catch(e){ae(o,"htmx:swapError",i);oe(r);throw e}};let t=Q.config.globalViewTransitions;if(y.hasOwnProperty("transition")){t=y.transition}if(t&&he(o,"htmx:beforeTransition",i)&&typeof Promise!=="undefined"&&document.startViewTransition){const w=new Promise(function(e,t){n=e;r=t});const v=e;e=function(){document.startViewTransition(function(){v();return w})}}if(y.swapDelay>0){E().setTimeout(e,y.swapDelay)}else{e()}}if(a){ae(o,"htmx:responseError",ue({error:"Response Status Error Code "+s.status+" from "+i.pathInfo.requestPath},i))}}const Xn={};function Fn(){return{init:function(e){return null},getSelectors:function(){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,n){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,n,r){return false},encodeParameters:function(e,t,n){return null}}}function Un(e,t){if(t.init){t.init(n)}Xn[e]=ue(Fn(),t)}function Bn(e){delete Xn[e]}function jn(e,n,r){if(n==undefined){n=[]}if(e==undefined){return n}if(r==undefined){r=[]}const t=te(e,"hx-ext");if(t){se(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){r.push(e.slice(7));return}if(r.indexOf(e)<0){const t=Xn[e];if(t&&n.indexOf(t)<0){n.push(t)}}})}return jn(ce(u(e)),n,r)}var Vn=false;ne().addEventListener("DOMContentLoaded",function(){Vn=true});function _n(e){if(Vn||ne().readyState==="complete"){e()}else{ne().addEventListener("DOMContentLoaded",e)}}function $n(){if(Q.config.includeIndicatorStyles!==false){const e=Q.config.inlineStyleNonce?` nonce="${Q.config.inlineStyleNonce}"`:"";ne().head.insertAdjacentHTML("beforeend","<style"+e+"> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zn(){const e=ne().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function Jn(){const e=zn();if(e){Q.config=ue(Q.config,e)}}_n(function(){Jn();$n();let e=ne().body;Dt(e);const t=ne().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){const t=e.target;const n=ie(t);if(n&&n.xhr){n.xhr.abort()}});const n=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){Wt();se(t,function(e){he(e,"htmx:restored",{document:ne(),triggerEvent:he})})}else{if(n){n(e)}}};E().setTimeout(function(){he(e,"htmx:load",{});e=null},0)});return Q}(); \ No newline at end of file diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/templates/shared/_layout.html b/code/ch7_infinite_scroll/ch7_final_video_collector/templates/shared/_layout.html index 4a255e6..3dac19b 100644 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/templates/shared/_layout.html +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/templates/shared/_layout.html @@ -52,7 +52,7 @@ </footer> -<script src="/https/github.com/static/js/htmx.min.js?v=1.5.0"></script> +<script src="/https/github.com/static/js/htmx.min.js?v=2.0.0"></script> <script src="/https/github.com/static/js/jquery-3.5.1.slim.min.js"></script> <script src="/https/github.com/static/js/popper-1.16.1.min.js"></script> diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.d.ts b/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.d.ts new file mode 100644 index 0000000..3775459 --- /dev/null +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.d.ts @@ -0,0 +1,195 @@ +declare namespace htmx { + const onLoad: (callback: (elt: Node) => void) => EventListener; + const process: (elt: string | Element) => void; + const on: (arg1: string | EventTarget, arg2: string | EventListener, arg3?: EventListener) => EventListener; + const off: (arg1: string | EventTarget, arg2: string | EventListener, arg3?: EventListener) => EventListener; + const trigger: (elt: string | EventTarget, eventName: string, detail?: any) => boolean; + const ajax: (verb: HttpVerb, path: string, context: string | Element | HtmxAjaxHelperContext) => Promise<void>; + const find: (eltOrSelector: string | ParentNode, selector?: string) => Element; + const findAll: (eltOrSelector: string | ParentNode, selector?: string) => NodeListOf<Element>; + const closest: (elt: string | Element, selector: string) => Element; + function values(elt: Element, type: HttpVerb): any; + const remove: (elt: Node, delay?: number) => void; + const addClass: (elt: string | Element, clazz: string, delay?: number) => void; + const removeClass: (node: string | Node, clazz: string, delay?: number) => void; + const toggleClass: (elt: string | Element, clazz: string) => void; + const takeClass: (elt: string | Node, clazz: string) => void; + const swap: (target: string | Element, content: string, swapSpec: HtmxSwapSpecification, swapOptions?: SwapOptions) => void; + const defineExtension: (name: string, extension: any) => void; + const removeExtension: (name: string) => void; + const logAll: () => void; + const logNone: () => void; + const logger: any; + namespace config { + const historyEnabled: boolean; + const historyCacheSize: number; + const refreshOnHistoryMiss: boolean; + const defaultSwapStyle: HtmxSwapStyle; + const defaultSwapDelay: number; + const defaultSettleDelay: number; + const includeIndicatorStyles: boolean; + const indicatorClass: string; + const requestClass: string; + const addedClass: string; + const settlingClass: string; + const swappingClass: string; + const allowEval: boolean; + const allowScriptTags: boolean; + const inlineScriptNonce: string; + const inlineStyleNonce: string; + const attributesToSettle: string[]; + const withCredentials: boolean; + const timeout: number; + const wsReconnectDelay: "full-jitter" | ((retryCount: number) => number); + const wsBinaryType: BinaryType; + const disableSelector: string; + const scrollBehavior: 'auto' | 'instant' | 'smooth'; + const defaultFocusScroll: boolean; + const getCacheBusterParam: boolean; + const globalViewTransitions: boolean; + const methodsThatUseUrlParams: (HttpVerb)[]; + const selfRequestsOnly: boolean; + const ignoreTitle: boolean; + const scrollIntoViewOnBoost: boolean; + const triggerSpecsCache: any | null; + const disableInheritance: boolean; + const responseHandling: HtmxResponseHandlingConfig[]; + const allowNestedOobSwaps: boolean; + } + const parseInterval: (str: string) => number; + const _: (str: string) => any; + const version: string; +} +type HttpVerb = 'get' | 'head' | 'post' | 'put' | 'delete' | 'connect' | 'options' | 'trace' | 'patch'; +type SwapOptions = { + select?: string; + selectOOB?: string; + eventInfo?: any; + anchor?: string; + contextElement?: Element; + afterSwapCallback?: swapCallback; + afterSettleCallback?: swapCallback; +}; +type swapCallback = () => any; +type HtmxSwapStyle = 'innerHTML' | 'outerHTML' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'delete' | 'none' | string; +type HtmxSwapSpecification = { + swapStyle: HtmxSwapStyle; + swapDelay: number; + settleDelay: number; + transition?: boolean; + ignoreTitle?: boolean; + head?: string; + scroll?: 'top' | 'bottom'; + scrollTarget?: string; + show?: string; + showTarget?: string; + focusScroll?: boolean; +}; +type ConditionalFunction = ((this: Node, evt: Event) => boolean) & { + source: string; +}; +type HtmxTriggerSpecification = { + trigger: string; + pollInterval?: number; + eventFilter?: ConditionalFunction; + changed?: boolean; + once?: boolean; + consume?: boolean; + delay?: number; + from?: string; + target?: string; + throttle?: number; + queue?: string; + root?: string; + threshold?: string; +}; +type HtmxElementValidationError = { + elt: Element; + message: string; + validity: ValidityState; +}; +type HtmxHeaderSpecification = Record<string, string>; +type HtmxAjaxHelperContext = { + source?: Element | string; + event?: Event; + handler?: HtmxAjaxHandler; + target: Element | string; + swap?: HtmxSwapStyle; + values?: any | FormData; + headers?: Record<string, string>; + select?: string; +}; +type HtmxRequestConfig = { + boosted: boolean; + useUrlParams: boolean; + formData: FormData; + /** + * formData proxy + */ + parameters: any; + unfilteredFormData: FormData; + /** + * unfilteredFormData proxy + */ + unfilteredParameters: any; + headers: HtmxHeaderSpecification; + target: Element; + verb: HttpVerb; + errors: HtmxElementValidationError[]; + withCredentials: boolean; + timeout: number; + path: string; + triggeringEvent: Event; +}; +type HtmxResponseInfo = { + xhr: XMLHttpRequest; + target: Element; + requestConfig: HtmxRequestConfig; + etc: HtmxAjaxEtc; + boosted: boolean; + select: string; + pathInfo: { + requestPath: string; + finalRequestPath: string; + responsePath: string | null; + anchor: string; + }; + failed?: boolean; + successful?: boolean; +}; +type HtmxAjaxEtc = { + returnPromise?: boolean; + handler?: HtmxAjaxHandler; + select?: string; + targetOverride?: Element; + swapOverride?: HtmxSwapStyle; + headers?: Record<string, string>; + values?: any | FormData; + credentials?: boolean; + timeout?: number; +}; +type HtmxResponseHandlingConfig = { + code?: string; + swap: boolean; + error?: boolean; + ignoreTitle?: boolean; + select?: string; + target?: string; + swapOverride?: string; + event?: string; +}; +type HtmxBeforeSwapDetails = HtmxResponseInfo & { + shouldSwap: boolean; + serverResponse: any; + isError: boolean; + ignoreTitle: boolean; + selectOverride: string; +}; +type HtmxAjaxHandler = (elt: Element, responseInfo: HtmxResponseInfo) => any; +type HtmxSettleTask = (() => void); +type HtmxSettleInfo = { + tasks: HtmxSettleTask[]; + elts: Element[]; + title?: string; +}; +type HtmxExtension = any; diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.js b/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.js index 86e7668..c57bcd7 100644 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.js +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.js @@ -1,3909 +1,5131 @@ -// /////////////////////////////////////////////////////////////////// -// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.js -// - -// UMD insanity -// This code sets up support for (in order) AMD, ES6 modules, and globals. -(function (root, factory) { - //@ts-ignore - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - //@ts-ignore - define([], factory); - } else if (typeof module === 'object' && module.exports) { - // Node. Does not work with strict CommonJS, but - // only CommonJS-like environments that support module.exports, - // like Node. - module.exports = factory(); - } else { - // Browser globals - root.htmx = root.htmx || factory(); - } -}(typeof self !== 'undefined' ? self : this, function () { -return (function () { - 'use strict'; - - // Public API - //** @type {import("./htmx").HtmxApi} */ - // TODO: list all methods in public API - var htmx = { - onLoad: onLoadHelper, - process: processNode, - on: addEventListenerImpl, - off: removeEventListenerImpl, - trigger : triggerEvent, - ajax : ajaxHelper, - find : find, - findAll : findAll, - closest : closest, - values : function(elt, type){ - var inputValues = getInputValues(elt, type || "post"); - return inputValues.values; - }, - remove : removeElement, - addClass : addClassToElement, - removeClass : removeClassFromElement, - toggleClass : toggleClassOnElement, - takeClass : takeClassForElement, - defineExtension : defineExtension, - removeExtension : removeExtension, - logAll : logAll, - logNone : logNone, - logger : null, - config : { - historyEnabled:true, - historyCacheSize:10, - refreshOnHistoryMiss:false, - defaultSwapStyle:'innerHTML', - defaultSwapDelay:0, - defaultSettleDelay:20, - includeIndicatorStyles:true, - indicatorClass:'htmx-indicator', - requestClass:'htmx-request', - addedClass:'htmx-added', - settlingClass:'htmx-settling', - swappingClass:'htmx-swapping', - allowEval:true, - allowScriptTags:true, - inlineScriptNonce:'', - attributesToSettle:["class", "style", "width", "height"], - withCredentials:false, - timeout:0, - wsReconnectDelay: 'full-jitter', - wsBinaryType: 'blob', - disableSelector: "[hx-disable], [data-hx-disable]", - useTemplateFragments: false, - scrollBehavior: 'smooth', - defaultFocusScroll: false, - getCacheBusterParam: false, - globalViewTransitions: false, - methodsThatUseUrlParams: ["get"], - selfRequestsOnly: false, - ignoreTitle: false, - scrollIntoViewOnBoost: true, - triggerSpecsCache: null, - }, - parseInterval:parseInterval, - _:internalEval, - createEventSource: function(url){ - return new EventSource(url, {withCredentials:true}) - }, - createWebSocket: function(url){ - var sock = new WebSocket(url, []); - sock.binaryType = htmx.config.wsBinaryType; - return sock; - }, - version: "1.9.10" - }; - - /** @type {import("./htmx").HtmxInternalApi} */ - var internalAPI = { - addTriggerHandler: addTriggerHandler, - bodyContains: bodyContains, - canAccessLocalStorage: canAccessLocalStorage, - findThisElement: findThisElement, - filterValues: filterValues, - hasAttribute: hasAttribute, - getAttributeValue: getAttributeValue, - getClosestAttributeValue: getClosestAttributeValue, - getClosestMatch: getClosestMatch, - getExpressionVars: getExpressionVars, - getHeaders: getHeaders, - getInputValues: getInputValues, - getInternalData: getInternalData, - getSwapSpecification: getSwapSpecification, - getTriggerSpecs: getTriggerSpecs, - getTarget: getTarget, - makeFragment: makeFragment, - mergeObjects: mergeObjects, - makeSettleInfo: makeSettleInfo, - oobSwap: oobSwap, - querySelectorExt: querySelectorExt, - selectAndSwap: selectAndSwap, - settleImmediately: settleImmediately, - shouldCancel: shouldCancel, - triggerEvent: triggerEvent, - triggerErrorEvent: triggerErrorEvent, - withExtensions: withExtensions, - } - - var VERBS = ['get', 'post', 'put', 'delete', 'patch']; - var VERB_SELECTOR = VERBS.map(function(verb){ - return "[hx-" + verb + "], [data-hx-" + verb + "]" - }).join(", "); - - var HEAD_TAG_REGEX = makeTagRegEx('head'), - TITLE_TAG_REGEX = makeTagRegEx('title'), - SVG_TAGS_REGEX = makeTagRegEx('svg', true); - - //==================================================================== - // Utilities - //==================================================================== - - /** - * @param {string} tag - * @param {boolean} global - * @returns {RegExp} - */ - function makeTagRegEx(tag, global = false) { - return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, - global ? 'gim' : 'im'); - } - - function parseInterval(str) { - if (str == undefined) { - return undefined; - } - - let interval = NaN; - if (str.slice(-2) == "ms") { - interval = parseFloat(str.slice(0, -2)); - } else if (str.slice(-1) == "s") { - interval = parseFloat(str.slice(0, -1)) * 1000; - } else if (str.slice(-1) == "m") { - interval = parseFloat(str.slice(0, -1)) * 1000 * 60; - } else { - interval = parseFloat(str); - } - return isNaN(interval) ? undefined : interval; - } - - /** - * @param {HTMLElement} elt - * @param {string} name - * @returns {(string | null)} - */ - function getRawAttribute(elt, name) { - return elt.getAttribute && elt.getAttribute(name); - } - - // resolve with both hx and data-hx prefixes - function hasAttribute(elt, qualifiedName) { - return elt.hasAttribute && (elt.hasAttribute(qualifiedName) || - elt.hasAttribute("data-" + qualifiedName)); - } - - /** - * - * @param {HTMLElement} elt - * @param {string} qualifiedName - * @returns {(string | null)} - */ - function getAttributeValue(elt, qualifiedName) { - return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); - } - - /** - * @param {HTMLElement} elt - * @returns {HTMLElement | null} - */ - function parentElt(elt) { - return elt.parentElement; - } - - /** - * @returns {Document} - */ - function getDocument() { - return document; - } - - /** - * @param {HTMLElement} elt - * @param {(e:HTMLElement) => boolean} condition - * @returns {HTMLElement | null} - */ - function getClosestMatch(elt, condition) { - while (elt && !condition(elt)) { - elt = parentElt(elt); - } - - return elt ? elt : null; - } - - function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ - var attributeValue = getAttributeValue(ancestor, attributeName); - var disinherit = getAttributeValue(ancestor, "hx-disinherit"); - if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) { - return "unset"; - } else { - return attributeValue - } - } - - /** - * @param {HTMLElement} elt - * @param {string} attributeName - * @returns {string | null} - */ - function getClosestAttributeValue(elt, attributeName) { - var closestAttr = null; - getClosestMatch(elt, function (e) { - return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName); - }); - if (closestAttr !== "unset") { - return closestAttr; - } - } - - /** - * @param {HTMLElement} elt - * @param {string} selector - * @returns {boolean} - */ - function matches(elt, selector) { - // @ts-ignore: non-standard properties for browser compatibility - // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; - return matchesFunction && matchesFunction.call(elt, selector); - } - - /** - * @param {string} str - * @returns {string} - */ - 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 ""; - } - } - - /** - * - * @param {string} resp - * @param {number} depth - * @returns {Element} - */ - function parseHTML(resp, depth) { - var parser = new DOMParser(); - var responseDoc = parser.parseFromString(resp, "text/html"); - - /** @type {Element} */ - var responseNode = responseDoc.body; - while (depth > 0) { - depth--; - // @ts-ignore - responseNode = responseNode.firstChild; - } - if (responseNode == null) { - // @ts-ignore - responseNode = getDocument().createDocumentFragment(); - } - return responseNode; - } - - function aFullPageResponse(resp) { - return /<body/.test(resp) - } +// v2.0.0 from https://github.com/bigskysoftware/htmx/releases + +var htmx = (function() { + 'use strict' + + // Public API + const htmx = { + // Tsc madness here, assigning the functions directly results in an invalid TypeScript output, but reassigning is fine + /* Event processing */ + /** @type {typeof onLoadHelper} */ + onLoad: null, + /** @type {typeof processNode} */ + process: null, + /** @type {typeof addEventListenerImpl} */ + on: null, + /** @type {typeof removeEventListenerImpl} */ + off: null, + /** @type {typeof triggerEvent} */ + trigger: null, + /** @type {typeof ajaxHelper} */ + ajax: null, + /* DOM querying helpers */ + /** @type {typeof find} */ + find: null, + /** @type {typeof findAll} */ + findAll: null, + /** @type {typeof closest} */ + closest: null, + /** + * Returns the input values that would resolve for a given element via the htmx value resolution mechanism + * + * @see https://htmx.org/api/#values + * + * @param {Element} elt the element to resolve values on + * @param {HttpVerb} type the request type (e.g. **get** or **post**) non-GET's will include the enclosing form of the element. Defaults to **post** + * @returns {Object} + */ + values: function(elt, type) { + const inputValues = getInputValues(elt, type || 'post') + return inputValues.values + }, + /* DOM manipulation helpers */ + /** @type {typeof removeElement} */ + remove: null, + /** @type {typeof addClassToElement} */ + addClass: null, + /** @type {typeof removeClassFromElement} */ + removeClass: null, + /** @type {typeof toggleClassOnElement} */ + toggleClass: null, + /** @type {typeof takeClassForElement} */ + takeClass: null, + /** @type {typeof swap} */ + swap: null, + /* Extension entrypoints */ + /** @type {typeof defineExtension} */ + defineExtension: null, + /** @type {typeof removeExtension} */ + removeExtension: null, + /* Debugging */ + /** @type {typeof logAll} */ + logAll: null, + /** @type {typeof logNone} */ + logNone: null, + /* Debugging */ + /** + * The logger htmx uses to log with + * + * @see https://htmx.org/api/#logger + */ + logger: null, + /** + * A property holding the configuration htmx uses at runtime. + * + * Note that using a [meta tag](https://htmx.org/docs/#config) is the preferred mechanism for setting these properties. + * + * @see https://htmx.org/api/#config + */ + config: { + /** + * Whether to use history. + * @type boolean + * @default true + */ + historyEnabled: true, + /** + * The number of pages to keep in **localStorage** for history support. + * @type number + * @default 10 + */ + historyCacheSize: 10, + /** + * @type boolean + * @default false + */ + refreshOnHistoryMiss: false, + /** + * The default swap style to use if **[hx-swap](https://htmx.org/attributes/hx-swap)** is omitted. + * @type HtmxSwapStyle + * @default 'innerHTML' + */ + defaultSwapStyle: 'innerHTML', + /** + * The default delay between receiving a response from the server and doing the swap. + * @type number + * @default 0 + */ + defaultSwapDelay: 0, + /** + * The default delay between completing the content swap and settling attributes. + * @type number + * @default 20 + */ + defaultSettleDelay: 20, + /** + * If true, htmx will inject a small amount of CSS into the page to make indicators invisible unless the **htmx-indicator** class is present. + * @type boolean + * @default true + */ + includeIndicatorStyles: true, + /** + * The class to place on indicators when a request is in flight. + * @type string + * @default 'htmx-indicator' + */ + indicatorClass: 'htmx-indicator', + /** + * The class to place on triggering elements when a request is in flight. + * @type string + * @default 'htmx-request' + */ + requestClass: 'htmx-request', + /** + * The class to temporarily place on elements that htmx has added to the DOM. + * @type string + * @default 'htmx-added' + */ + addedClass: 'htmx-added', + /** + * The class to place on target elements when htmx is in the settling phase. + * @type string + * @default 'htmx-settling' + */ + settlingClass: 'htmx-settling', + /** + * The class to place on target elements when htmx is in the swapping phase. + * @type string + * @default 'htmx-swapping' + */ + swappingClass: 'htmx-swapping', + /** + * Allows the use of eval-like functionality in htmx, to enable **hx-vars**, trigger conditions & script tag evaluation. Can be set to **false** for CSP compatibility. + * @type boolean + * @default true + */ + allowEval: true, + /** + * If set to false, disables the interpretation of script tags. + * @type boolean + * @default true + */ + allowScriptTags: true, + /** + * If set, the nonce will be added to inline scripts. + * @type string + * @default '' + */ + inlineScriptNonce: '', + /** + * If set, the nonce will be added to inline styles. + * @type string + * @default '' + */ + inlineStyleNonce: '', + /** + * The attributes to settle during the settling phase. + * @type string[] + * @default ['class', 'style', 'width', 'height'] + */ + attributesToSettle: ['class', 'style', 'width', 'height'], + /** + * Allow cross-site Access-Control requests using credentials such as cookies, authorization headers or TLS client certificates. + * @type boolean + * @default false + */ + withCredentials: false, + /** + * @type number + * @default 0 + */ + timeout: 0, + /** + * The default implementation of **getWebSocketReconnectDelay** for reconnecting after unexpected connection loss by the event code **Abnormal Closure**, **Service Restart** or **Try Again Later**. + * @type {'full-jitter' | ((retryCount:number) => number)} + * @default "full-jitter" + */ + wsReconnectDelay: 'full-jitter', + /** + * The type of binary data being received over the WebSocket connection + * @type BinaryType + * @default 'blob' + */ + wsBinaryType: 'blob', + /** + * @type string + * @default '[hx-disable], [data-hx-disable]' + */ + disableSelector: '[hx-disable], [data-hx-disable]', + /** + * @type {'auto' | 'instant' | 'smooth'} + * @default 'smooth' + */ + scrollBehavior: 'instant', + /** + * If the focused element should be scrolled into view. + * @type boolean + * @default false + */ + defaultFocusScroll: false, + /** + * If set to true htmx will include a cache-busting parameter in GET requests to avoid caching partial responses by the browser + * @type boolean + * @default false + */ + getCacheBusterParam: false, + /** + * If set to true, htmx will use the View Transition API when swapping in new content. + * @type boolean + * @default false + */ + globalViewTransitions: false, + /** + * htmx will format requests with these methods by encoding their parameters in the URL, not the request body + * @type {(HttpVerb)[]} + * @default ['get', 'delete'] + */ + methodsThatUseUrlParams: ['get', 'delete'], + /** + * If set to true, disables htmx-based requests to non-origin hosts. + * @type boolean + * @default false + */ + selfRequestsOnly: true, + /** + * If set to true htmx will not update the title of the document when a title tag is found in new content + * @type boolean + * @default false + */ + ignoreTitle: false, + /** + * Whether the target of a boosted element is scrolled into the viewport. + * @type boolean + * @default true + */ + scrollIntoViewOnBoost: true, + /** + * The cache to store evaluated trigger specifications into. + * You may define a simple object to use a never-clearing cache, or implement your own system using a [proxy object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Proxy) + * @type {Object|null} + * @default null + */ + triggerSpecsCache: null, + /** @type boolean */ + disableInheritance: false, + /** @type HtmxResponseHandlingConfig[] */ + responseHandling: [ + { code: '204', swap: false }, + { code: '[23]..', swap: true }, + { code: '[45]..', swap: false, error: true } + ], + /** + * Whether to process OOB swaps on elements that are nested within the main response element. + * @type boolean + * @default true + */ + allowNestedOobSwaps: true + }, + /** @type {typeof parseInterval} */ + parseInterval: null, + /** @type {typeof internalEval} */ + _: null, + version: '2.0.0' + } + // Tsc madness part 2 + htmx.onLoad = onLoadHelper + htmx.process = processNode + htmx.on = addEventListenerImpl + htmx.off = removeEventListenerImpl + htmx.trigger = triggerEvent + htmx.ajax = ajaxHelper + htmx.find = find + htmx.findAll = findAll + htmx.closest = closest + htmx.remove = removeElement + htmx.addClass = addClassToElement + htmx.removeClass = removeClassFromElement + htmx.toggleClass = toggleClassOnElement + htmx.takeClass = takeClassForElement + htmx.swap = swap + htmx.defineExtension = defineExtension + htmx.removeExtension = removeExtension + htmx.logAll = logAll + htmx.logNone = logNone + htmx.parseInterval = parseInterval + htmx._ = internalEval + + const internalAPI = { + addTriggerHandler, + bodyContains, + canAccessLocalStorage, + findThisElement, + filterValues, + swap, + hasAttribute, + getAttributeValue, + getClosestAttributeValue, + getClosestMatch, + getExpressionVars, + getHeaders, + getInputValues, + getInternalData, + getSwapSpecification, + getTriggerSpecs, + getTarget, + makeFragment, + mergeObjects, + makeSettleInfo, + oobSwap, + querySelectorExt, + settleImmediately, + shouldCancel, + triggerEvent, + triggerErrorEvent, + withExtensions + } + + const VERBS = ['get', 'post', 'put', 'delete', 'patch'] + const VERB_SELECTOR = VERBS.map(function(verb) { + return '[hx-' + verb + '], [data-hx-' + verb + ']' + }).join(', ') + + const HEAD_TAG_REGEX = makeTagRegEx('head') + + //= =================================================================== + // Utilities + //= =================================================================== + + /** + * @param {string} tag + * @param {boolean} global + * @returns {RegExp} + */ + function makeTagRegEx(tag, global = false) { + return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, + global ? 'gim' : 'im') + } + + /** + * Parses an interval string consistent with the way htmx does. Useful for plugins that have timing-related attributes. + * + * Caution: Accepts an int followed by either **s** or **ms**. All other values use **parseFloat** + * + * @see https://htmx.org/api/#parseInterval + * + * @param {string} str timing string + * @returns {number|undefined} + */ + function parseInterval(str) { + if (str == undefined) { + return undefined + } - /** - * - * @param {string} response - * @returns {Element} - */ - function makeFragment(response) { - var partialResponse = !aFullPageResponse(response); - var startTag = getStartTag(response); - var content = response; - if (startTag === 'head') { - content = content.replace(HEAD_TAG_REGEX, ''); - } - if (htmx.config.useTemplateFragments && partialResponse) { - var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0); - // @ts-ignore type mismatch between DocumentFragment and Element. - // TODO: Are these close enough for htmx to use interchangeably? - return documentFragment.querySelector('template').content; - } - switch (startTag) { - case "thead": - case "tbody": - case "tfoot": - case "colgroup": - case "caption": - return parseHTML("<table>" + content + "</table>", 1); - case "col": - return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2); - case "tr": - return parseHTML("<table><tbody>" + content + "</tbody></table>", 2); - case "td": - case "th": - return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3); - case "script": - case "style": - return parseHTML("<div>" + content + "</div>", 1); - default: - return parseHTML(content, 0); - } - } + let interval = NaN + if (str.slice(-2) == 'ms') { + interval = parseFloat(str.slice(0, -2)) + } else if (str.slice(-1) == 's') { + interval = parseFloat(str.slice(0, -1)) * 1000 + } else if (str.slice(-1) == 'm') { + interval = parseFloat(str.slice(0, -1)) * 1000 * 60 + } else { + interval = parseFloat(str) + } + return isNaN(interval) ? undefined : interval + } + + /** + * @param {Node} elt + * @param {string} name + * @returns {(string | null)} + */ + function getRawAttribute(elt, name) { + return elt instanceof Element && elt.getAttribute(name) + } + + /** + * @param {Element} elt + * @param {string} qualifiedName + * @returns {boolean} + */ + // resolve with both hx and data-hx prefixes + function hasAttribute(elt, qualifiedName) { + return !!elt.hasAttribute && (elt.hasAttribute(qualifiedName) || + elt.hasAttribute('data-' + qualifiedName)) + } + + /** + * + * @param {Node} elt + * @param {string} qualifiedName + * @returns {(string | null)} + */ + function getAttributeValue(elt, qualifiedName) { + return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, 'data-' + qualifiedName) + } + + /** + * @param {Node} elt + * @returns {Node | null} + */ + function parentElt(elt) { + const parent = elt.parentElement + if (!parent && elt.parentNode instanceof ShadowRoot) return elt.parentNode + return parent + } + + /** + * @returns {Document} + */ + function getDocument() { + return document + } + + /** + * @param {Node} elt + * @param {boolean} global + * @returns {Node|Document} + */ + function getRootNode(elt, global) { + return elt.getRootNode ? elt.getRootNode({ composed: global }) : getDocument() + } + + /** + * @param {Node} elt + * @param {(e:Node) => boolean} condition + * @returns {Node | null} + */ + function getClosestMatch(elt, condition) { + while (elt && !condition(elt)) { + elt = parentElt(elt) + } - /** - * @param {Function} func - */ - function maybeCall(func){ - if(func) { - func(); - } + return elt || null + } + + /** + * @param {Element} initialElement + * @param {Element} ancestor + * @param {string} attributeName + * @returns {string|null} + */ + function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName) { + const attributeValue = getAttributeValue(ancestor, attributeName) + const disinherit = getAttributeValue(ancestor, 'hx-disinherit') + var inherit = getAttributeValue(ancestor, 'hx-inherit') + if (initialElement !== ancestor) { + if (htmx.config.disableInheritance) { + if (inherit && (inherit === '*' || inherit.split(' ').indexOf(attributeName) >= 0)) { + return attributeValue + } else { + return null + } + } + if (disinherit && (disinherit === '*' || disinherit.split(' ').indexOf(attributeName) >= 0)) { + return 'unset' + } + } + return attributeValue + } + + /** + * @param {Element} elt + * @param {string} attributeName + * @returns {string | null} + */ + function getClosestAttributeValue(elt, attributeName) { + let closestAttr = null + getClosestMatch(elt, function(e) { + return !!(closestAttr = getAttributeValueWithDisinheritance(elt, asElement(e), attributeName)) + }) + if (closestAttr !== 'unset') { + return closestAttr + } + } + + /** + * @param {Node} elt + * @param {string} selector + * @returns {boolean} + */ + function matches(elt, selector) { + // @ts-ignore: non-standard properties for browser compatibility + // noinspection JSUnresolvedVariable + const matchesFunction = elt instanceof Element && (elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector) + return !!matchesFunction && matchesFunction.call(elt, selector) + } + + /** + * @param {string} str + * @returns {string} + */ + function getStartTag(str) { + const tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i + const match = tagMatcher.exec(str) + if (match) { + return match[1].toLowerCase() + } else { + return '' + } + } + + /** + * @param {string} resp + * @returns {Document} + */ + function parseHTML(resp) { + const parser = new DOMParser() + return parser.parseFromString(resp, 'text/html') + } + + /** + * @param {DocumentFragment} fragment + * @param {Node} elt + */ + function takeChildrenFor(fragment, elt) { + while (elt.childNodes.length > 0) { + fragment.append(elt.childNodes[0]) + } + } + + /** + * @param {HTMLScriptElement} script + * @returns {HTMLScriptElement} + */ + function duplicateScript(script) { + const newScript = getDocument().createElement('script') + forEach(script.attributes, function(attr) { + newScript.setAttribute(attr.name, attr.value) + }) + newScript.textContent = script.textContent + newScript.async = false + if (htmx.config.inlineScriptNonce) { + newScript.nonce = htmx.config.inlineScriptNonce + } + return newScript + } + + /** + * @param {HTMLScriptElement} script + * @returns {boolean} + */ + function isJavaScriptScriptNode(script) { + return script.matches('script') && (script.type === 'text/javascript' || script.type === 'module' || script.type === '') + } + + /** + * we have to make new copies of script tags that we are going to insert because + * SOME browsers (not saying who, but it involves an element and an animal) don't + * execute scripts created in <template> tags when they are inserted into the DOM + * and all the others do lmao + * @param {DocumentFragment} fragment + */ + function normalizeScriptTags(fragment) { + Array.from(fragment.querySelectorAll('script')).forEach(/** @param {HTMLScriptElement} script */ (script) => { + if (isJavaScriptScriptNode(script)) { + const newScript = duplicateScript(script) + const parent = script.parentNode + try { + parent.insertBefore(newScript, script) + } catch (e) { + logError(e) + } finally { + script.remove() + } + } + }) + } + + /** + * @typedef {DocumentFragment & {title?: string}} DocumentFragmentWithTitle + * @description a document fragment representing the response HTML, including + * a `title` property for any title information found + */ + + /** + * @param {string} response HTML + * @returns {DocumentFragmentWithTitle} + */ + function makeFragment(response) { + // strip head tag to determine shape of response we are dealing with + const responseWithNoHead = response.replace(HEAD_TAG_REGEX, '') + const startTag = getStartTag(responseWithNoHead) + /** @type DocumentFragmentWithTitle */ + let fragment + if (startTag === 'html') { + // if it is a full document, parse it and return the body + fragment = /** @type DocumentFragmentWithTitle */ (new DocumentFragment()) + const doc = parseHTML(response) + takeChildrenFor(fragment, doc.body) + fragment.title = doc.title + } else if (startTag === 'body') { + // parse body w/o wrapping in template + fragment = /** @type DocumentFragmentWithTitle */ (new DocumentFragment()) + const doc = parseHTML(responseWithNoHead) + takeChildrenFor(fragment, doc.body) + fragment.title = doc.title + } else { + // otherwise we have non-body partial HTML content, so wrap it in a template to maximize parsing flexibility + const doc = parseHTML('<body><template class="internal-htmx-wrapper">' + responseWithNoHead + '</template></body>') + fragment = /** @type DocumentFragmentWithTitle */ (doc.querySelector('template').content) + // extract title into fragment for later processing + fragment.title = doc.title + + // for legacy reasons we support a title tag at the root level of non-body responses, so we need to handle it + var titleElement = fragment.querySelector('title') + if (titleElement && titleElement.parentNode === fragment) { + titleElement.remove() + fragment.title = titleElement.innerText + } + } + if (fragment) { + if (htmx.config.allowScriptTags) { + normalizeScriptTags(fragment) + } else { + // remove all script tags if scripts are disabled + fragment.querySelectorAll('script').forEach((script) => script.remove()) + } + } + return fragment + } + + /** + * @param {Function} func + */ + function maybeCall(func) { + if (func) { + func() + } + } + + /** + * @param {any} o + * @param {string} type + * @returns + */ + function isType(o, type) { + return Object.prototype.toString.call(o) === '[object ' + type + ']' + } + + /** + * @param {*} o + * @returns {o is Function} + */ + function isFunction(o) { + return typeof o === 'function' + } + + /** + * @param {*} o + * @returns {o is Object} + */ + function isRawObject(o) { + return isType(o, 'Object') + } + + /** + * @typedef {Object} OnHandler + * @property {(keyof HTMLElementEventMap)|string} event + * @property {EventListener} listener + */ + + /** + * @typedef {Object} ListenerInfo + * @property {string} trigger + * @property {EventListener} listener + * @property {EventTarget} on + */ + + /** + * @typedef {Object} HtmxNodeInternalData + * Element data + * @property {number} [initHash] + * @property {boolean} [boosted] + * @property {OnHandler[]} [onHandlers] + * @property {number} [timeout] + * @property {ListenerInfo[]} [listenerInfos] + * @property {boolean} [cancelled] + * @property {boolean} [triggeredOnce] + * @property {number} [delayed] + * @property {number|null} [throttle] + * @property {string} [lastValue] + * @property {boolean} [loaded] + * @property {string} [path] + * @property {string} [verb] + * @property {boolean} [polling] + * @property {HTMLButtonElement|HTMLInputElement|null} [lastButtonClicked] + * @property {number} [requestCount] + * @property {XMLHttpRequest} [xhr] + * @property {(() => void)[]} [queuedRequests] + * @property {boolean} [abortable] + * + * Event data + * @property {HtmxTriggerSpecification} [triggerSpec] + * @property {EventTarget[]} [handledFor] + */ + + /** + * getInternalData retrieves "private" data stored by htmx within an element + * @param {EventTarget|Event} elt + * @returns {HtmxNodeInternalData} + */ + function getInternalData(elt) { + const dataProp = 'htmx-internal-data' + let data = elt[dataProp] + if (!data) { + data = elt[dataProp] = {} + } + return data + } + + /** + * toArray converts an ArrayLike object into a real array. + * @template T + * @param {ArrayLike<T>} arr + * @returns {T[]} + */ + function toArray(arr) { + const returnArr = [] + if (arr) { + for (let i = 0; i < arr.length; i++) { + returnArr.push(arr[i]) + } + } + return returnArr + } + + /** + * @template T + * @param {T[]|NamedNodeMap|HTMLCollection|HTMLFormControlsCollection|ArrayLike<T>} arr + * @param {(T) => void} func + */ + function forEach(arr, func) { + if (arr) { + for (let i = 0; i < arr.length; i++) { + func(arr[i]) + } + } + } + + /** + * @param {Element} el + * @returns {boolean} + */ + function isScrolledIntoView(el) { + const rect = el.getBoundingClientRect() + const elemTop = rect.top + const elemBottom = rect.bottom + return elemTop < window.innerHeight && elemBottom >= 0 + } + + /** + * @param {Node} elt + * @returns {boolean} + */ + function bodyContains(elt) { + // IE Fix + const rootNode = elt.getRootNode && elt.getRootNode() + if (rootNode && rootNode instanceof window.ShadowRoot) { + return getDocument().body.contains(rootNode.host) + } else { + return getDocument().body.contains(elt) + } + } + + /** + * @param {string} trigger + * @returns {string[]} + */ + function splitOnWhitespace(trigger) { + return trigger.trim().split(/\s+/) + } + + /** + * mergeObjects takes all the keys from + * obj2 and duplicates them into obj1 + * @template T1 + * @template T2 + * @param {T1} obj1 + * @param {T2} obj2 + * @returns {T1 & T2} + */ + function mergeObjects(obj1, obj2) { + for (const key in obj2) { + if (obj2.hasOwnProperty(key)) { + // @ts-ignore tsc doesn't seem to properly handle types merging + obj1[key] = obj2[key] + } + } + // @ts-ignore tsc doesn't seem to properly handle types merging + return obj1 + } + + /** + * @param {string} jString + * @returns {any|null} + */ + function parseJSON(jString) { + try { + return JSON.parse(jString) + } catch (error) { + logError(error) + return null + } + } + + /** + * @returns {boolean} + */ + function canAccessLocalStorage() { + const test = 'htmx:localStorageTest' + try { + localStorage.setItem(test, test) + localStorage.removeItem(test) + return true + } catch (e) { + return false + } + } + + /** + * @param {string} path + * @returns {string} + */ + function normalizePath(path) { + try { + const url = new URL(path) + if (url) { + path = url.pathname + url.search + } + // remove trailing slash, unless index page + if (!(/^\/$/.test(path))) { + path = path.replace(/\/+$/, '') + } + return path + } catch (e) { + // be kind to IE11, which doesn't support URL() + return path + } + } + + //= ========================================================================================= + // public API + //= ========================================================================================= + + /** + * @param {string} str + * @returns {any} + */ + function internalEval(str) { + return maybeEval(getDocument().body, function() { + return eval(str) + }) + } + + /** + * Adds a callback for the **htmx:load** event. This can be used to process new content, for example initializing the content with a javascript library + * + * @see https://htmx.org/api/#onLoad + * + * @param {(elt: Node) => void} callback the callback to call on newly loaded content + * @returns {EventListener} + */ + function onLoadHelper(callback) { + const value = htmx.on('htmx:load', /** @param {CustomEvent} evt */ function(evt) { + callback(evt.detail.elt) + }) + return value + } + + /** + * Log all htmx events, useful for debugging. + * + * @see https://htmx.org/api/#logAll + */ + function logAll() { + htmx.logger = function(elt, event, data) { + if (console) { + console.log(event, elt, data) + } + } + } + + function logNone() { + htmx.logger = null + } + + /** + * Finds an element matching the selector + * + * @see https://htmx.org/api/#find + * + * @param {ParentNode|string} eltOrSelector the root element to find the matching element in, inclusive | the selector to match + * @param {string} [selector] the selector to match + * @returns {Element|null} + */ + function find(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return eltOrSelector.querySelector(selector) + } else { + return find(getDocument(), eltOrSelector) + } + } + + /** + * Finds all elements matching the selector + * + * @see https://htmx.org/api/#findAll + * + * @param {ParentNode|string} eltOrSelector the root element to find the matching elements in, inclusive | the selector to match + * @param {string} [selector] the selector to match + * @returns {NodeListOf<Element>} + */ + function findAll(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return eltOrSelector.querySelectorAll(selector) + } else { + return findAll(getDocument(), eltOrSelector) + } + } + + /** + * @returns Window + */ + function getWindow() { + return window + } + + /** + * Removes an element from the DOM + * + * @see https://htmx.org/api/#remove + * + * @param {Node} elt + * @param {number} [delay] + */ + function removeElement(elt, delay) { + elt = resolveTarget(elt) + if (delay) { + getWindow().setTimeout(function() { + removeElement(elt) + elt = null + }, delay) + } else { + parentElt(elt).removeChild(elt) + } + } + + /** + * @param {any} elt + * @return {Element|null} + */ + function asElement(elt) { + return elt instanceof Element ? elt : null + } + + /** + * @param {any} elt + * @return {HTMLElement|null} + */ + function asHtmlElement(elt) { + return elt instanceof HTMLElement ? elt : null + } + + /** + * @param {any} value + * @return {string|null} + */ + function asString(value) { + return typeof value === 'string' ? value : null + } + + /** + * @param {EventTarget} elt + * @return {ParentNode|null} + */ + function asParentNode(elt) { + return elt instanceof Element || elt instanceof Document || elt instanceof DocumentFragment ? elt : null + } + + /** + * This method adds a class to the given element. + * + * @see https://htmx.org/api/#addClass + * + * @param {Element|string} elt the element to add the class to + * @param {string} clazz the class to add + * @param {number} [delay] the delay (in milliseconds) before class is added + */ + function addClassToElement(elt, clazz, delay) { + elt = asElement(resolveTarget(elt)) + if (!elt) { + return + } + if (delay) { + getWindow().setTimeout(function() { + addClassToElement(elt, clazz) + elt = null + }, delay) + } else { + elt.classList && elt.classList.add(clazz) + } + } + + /** + * Removes a class from the given element + * + * @see https://htmx.org/api/#removeClass + * + * @param {Node|string} node element to remove the class from + * @param {string} clazz the class to remove + * @param {number} [delay] the delay (in milliseconds before class is removed) + */ + function removeClassFromElement(node, clazz, delay) { + let elt = asElement(resolveTarget(node)) + if (!elt) { + return + } + if (delay) { + getWindow().setTimeout(function() { + removeClassFromElement(elt, clazz) + elt = null + }, delay) + } else { + if (elt.classList) { + elt.classList.remove(clazz) + // if there are no classes left, remove the class attribute + if (elt.classList.length === 0) { + elt.removeAttribute('class') } + } + } + } + + /** + * Toggles the given class on an element + * + * @see https://htmx.org/api/#toggleClass + * + * @param {Element|string} elt the element to toggle the class on + * @param {string} clazz the class to toggle + */ + function toggleClassOnElement(elt, clazz) { + elt = resolveTarget(elt) + elt.classList.toggle(clazz) + } + + /** + * Takes the given class from its siblings, so that among its siblings, only the given element will have the class. + * + * @see https://htmx.org/api/#takeClass + * + * @param {Node|string} elt the element that will take the class + * @param {string} clazz the class to take + */ + function takeClassForElement(elt, clazz) { + elt = resolveTarget(elt) + forEach(elt.parentElement.children, function(child) { + removeClassFromElement(child, clazz) + }) + addClassToElement(asElement(elt), clazz) + } + + /** + * Finds the closest matching element in the given elements parentage, inclusive of the element + * + * @see https://htmx.org/api/#closest + * + * @param {Element|string} elt the element to find the selector from + * @param {string} selector the selector to find + * @returns {Element|null} + */ + function closest(elt, selector) { + elt = asElement(resolveTarget(elt)) + if (elt && elt.closest) { + return elt.closest(selector) + } else { + // TODO remove when IE goes away + do { + if (elt == null || matches(elt, selector)) { + return elt + } + } + while (elt = elt && asElement(parentElt(elt))) + return null + } + } + + /** + * @param {string} str + * @param {string} prefix + * @returns {boolean} + */ + function startsWith(str, prefix) { + return str.substring(0, prefix.length) === prefix + } + + /** + * @param {string} str + * @param {string} suffix + * @returns {boolean} + */ + function endsWith(str, suffix) { + return str.substring(str.length - suffix.length) === suffix + } + + /** + * @param {string} selector + * @returns {string} + */ + function normalizeSelector(selector) { + const trimmedSelector = selector.trim() + if (startsWith(trimmedSelector, '<') && endsWith(trimmedSelector, '/>')) { + return trimmedSelector.substring(1, trimmedSelector.length - 2) + } else { + return trimmedSelector + } + } + + /** + * @param {Node|Element|Document|string} elt + * @param {string} selector + * @param {boolean=} global + * @returns {(Node|Window)[]} + */ + function querySelectorAllExt(elt, selector, global) { + elt = resolveTarget(elt) + if (selector.indexOf('closest ') === 0) { + return [closest(asElement(elt), normalizeSelector(selector.substr(8)))] + } else if (selector.indexOf('find ') === 0) { + return [find(asParentNode(elt), normalizeSelector(selector.substr(5)))] + } else if (selector === 'next') { + return [asElement(elt).nextElementSibling] + } else if (selector.indexOf('next ') === 0) { + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)), !!global)] + } else if (selector === 'previous') { + return [asElement(elt).previousElementSibling] + } else if (selector.indexOf('previous ') === 0) { + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)), !!global)] + } else if (selector === 'document') { + return [document] + } else if (selector === 'window') { + return [window] + } else if (selector === 'body') { + return [document.body] + } else if (selector === 'root') { + return [getRootNode(elt, !!global)] + } else if (selector.indexOf('global ') === 0) { + return querySelectorAllExt(elt, selector.slice(7), true) + } else { + return toArray(asParentNode(getRootNode(elt, !!global)).querySelectorAll(normalizeSelector(selector))) + } + } + + /** + * @param {Node} start + * @param {string} match + * @param {boolean} global + * @returns {Element} + */ + var scanForwardQuery = function(start, match, global) { + const results = asParentNode(getRootNode(start, global)).querySelectorAll(match) + for (let i = 0; i < results.length; i++) { + const elt = results[i] + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { + return elt + } + } + } + + /** + * @param {Node} start + * @param {string} match + * @param {boolean} global + * @returns {Element} + */ + var scanBackwardsQuery = function(start, match, global) { + const results = asParentNode(getRootNode(start, global)).querySelectorAll(match) + for (let i = results.length - 1; i >= 0; i--) { + const elt = results[i] + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { + return elt + } + } + } + + /** + * @param {Node|string} eltOrSelector + * @param {string=} selector + * @returns {Node|Window} + */ + function querySelectorExt(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return querySelectorAllExt(eltOrSelector, selector)[0] + } else { + return querySelectorAllExt(getDocument().body, eltOrSelector)[0] + } + } + + /** + * @template {EventTarget} T + * @param {T|string} eltOrSelector + * @param {T} [context] + * @returns {Element|T|null} + */ + function resolveTarget(eltOrSelector, context) { + if (typeof eltOrSelector === 'string') { + return find(asParentNode(context) || document, eltOrSelector) + } else { + return eltOrSelector + } + } + + /** + * @typedef {keyof HTMLElementEventMap|string} AnyEventName + */ + + /** + * @typedef {Object} EventArgs + * @property {EventTarget} target + * @property {AnyEventName} event + * @property {EventListener} listener + */ + + /** + * @param {EventTarget|AnyEventName} arg1 + * @param {AnyEventName|EventListener} arg2 + * @param {EventListener} [arg3] + * @returns {EventArgs} + */ + function processEventArgs(arg1, arg2, arg3) { + if (isFunction(arg2)) { + return { + target: getDocument().body, + event: asString(arg1), + listener: arg2 + } + } else { + return { + target: resolveTarget(arg1), + event: asString(arg2), + listener: arg3 + } + } + } + + /** + * Adds an event listener to an element + * + * @see https://htmx.org/api/#on + * + * @param {EventTarget|string} arg1 the element to add the listener to | the event name to add the listener for + * @param {string|EventListener} arg2 the event name to add the listener for | the listener to add + * @param {EventListener} [arg3] the listener to add + * @returns {EventListener} + */ + function addEventListenerImpl(arg1, arg2, arg3) { + ready(function() { + const eventArgs = processEventArgs(arg1, arg2, arg3) + eventArgs.target.addEventListener(eventArgs.event, eventArgs.listener) + }) + const b = isFunction(arg2) + return b ? arg2 : arg3 + } + + /** + * Removes an event listener from an element + * + * @see https://htmx.org/api/#off + * + * @param {EventTarget|string} arg1 the element to remove the listener from | the event name to remove the listener from + * @param {string|EventListener} arg2 the event name to remove the listener from | the listener to remove + * @param {EventListener} [arg3] the listener to remove + * @returns {EventListener} + */ + function removeEventListenerImpl(arg1, arg2, arg3) { + ready(function() { + const eventArgs = processEventArgs(arg1, arg2, arg3) + eventArgs.target.removeEventListener(eventArgs.event, eventArgs.listener) + }) + return isFunction(arg2) ? arg2 : arg3 + } + + //= =================================================================== + // Node processing + //= =================================================================== + + const DUMMY_ELT = getDocument().createElement('output') // dummy element for bad selectors + /** + * @param {Element} elt + * @param {string} attrName + * @returns {(Node|Window)[]} + */ + function findAttributeTargets(elt, attrName) { + const attrTarget = getClosestAttributeValue(elt, attrName) + if (attrTarget) { + if (attrTarget === 'this') { + return [findThisElement(elt, attrName)] + } else { + const result = querySelectorAllExt(elt, attrTarget) + if (result.length === 0) { + logError('The selector "' + attrTarget + '" on ' + attrName + ' returned no matches!') + return [DUMMY_ELT] + } else { + return result + } + } + } + } + + /** + * @param {Element} elt + * @param {string} attribute + * @returns {Element|null} + */ + function findThisElement(elt, attribute) { + return asElement(getClosestMatch(elt, function(elt) { + return getAttributeValue(asElement(elt), attribute) != null + })) + } + + /** + * @param {Element} elt + * @returns {Node|Window|null} + */ + function getTarget(elt) { + const targetStr = getClosestAttributeValue(elt, 'hx-target') + if (targetStr) { + if (targetStr === 'this') { + return findThisElement(elt, 'hx-target') + } else { + return querySelectorExt(elt, targetStr) + } + } else { + const data = getInternalData(elt) + if (data.boosted) { + return getDocument().body + } else { + return elt + } + } + } + + /** + * @param {string} name + * @returns {boolean} + */ + function shouldSettleAttribute(name) { + const attributesToSettle = htmx.config.attributesToSettle + for (let i = 0; i < attributesToSettle.length; i++) { + if (name === attributesToSettle[i]) { + return true + } + } + return false + } + + /** + * @param {Element} mergeTo + * @param {Element} mergeFrom + */ + function cloneAttributes(mergeTo, mergeFrom) { + forEach(mergeTo.attributes, function(attr) { + if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) { + mergeTo.removeAttribute(attr.name) + } + }) + forEach(mergeFrom.attributes, function(attr) { + if (shouldSettleAttribute(attr.name)) { + mergeTo.setAttribute(attr.name, attr.value) + } + }) + } + + /** + * @param {HtmxSwapStyle} swapStyle + * @param {Element} target + * @returns {boolean} + */ + function isInlineSwap(swapStyle, target) { + const extensions = getExtensions(target) + for (let i = 0; i < extensions.length; i++) { + const extension = extensions[i] + try { + if (extension.isInlineSwap(swapStyle)) { + return true + } + } catch (e) { + logError(e) + } + } + return swapStyle === 'outerHTML' + } + + /** + * @param {string} oobValue + * @param {Element} oobElement + * @param {HtmxSettleInfo} settleInfo + * @returns + */ + function oobSwap(oobValue, oobElement, settleInfo) { + let selector = '#' + getRawAttribute(oobElement, 'id') + /** @type HtmxSwapStyle */ + let swapStyle = 'outerHTML' + if (oobValue === 'true') { + // do nothing + } else if (oobValue.indexOf(':') > 0) { + swapStyle = oobValue.substr(0, oobValue.indexOf(':')) + selector = oobValue.substr(oobValue.indexOf(':') + 1, oobValue.length) + } else { + swapStyle = oobValue + } - /** - * @param {any} o - * @param {string} type - * @returns - */ - function isType(o, type) { - return Object.prototype.toString.call(o) === "[object " + type + "]"; - } - - /** - * @param {*} o - * @returns {o is Function} - */ - function isFunction(o) { - return isType(o, "Function"); - } - - /** - * @param {*} o - * @returns {o is Object} - */ - function isRawObject(o) { - return isType(o, "Object"); - } - - /** - * getInternalData retrieves "private" data stored by htmx within an element - * @param {HTMLElement} elt - * @returns {*} - */ - function getInternalData(elt) { - var dataProp = 'htmx-internal-data'; - var data = elt[dataProp]; - if (!data) { - data = elt[dataProp] = {}; - } - return data; - } - - /** - * toArray converts an ArrayLike object into a real array. - * @param {ArrayLike} arr - * @returns {any[]} - */ - function toArray(arr) { - var returnArr = []; - if (arr) { - for (var i = 0; i < arr.length; i++) { - returnArr.push(arr[i]); - } - } - return returnArr + const targets = getDocument().querySelectorAll(selector) + if (targets) { + forEach( + targets, + function(target) { + let fragment + const oobElementClone = oobElement.cloneNode(true) + fragment = getDocument().createDocumentFragment() + fragment.appendChild(oobElementClone) + if (!isInlineSwap(swapStyle, target)) { + fragment = asParentNode(oobElementClone) // if this is not an inline swap, we use the content of the node, not the node itself + } + + const beforeSwapDetails = { shouldSwap: true, target, fragment } + if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return + + target = beforeSwapDetails.target // allow re-targeting + if (beforeSwapDetails.shouldSwap) { + swapWithStyle(swapStyle, target, target, fragment, settleInfo) + } + forEach(settleInfo.elts, function(elt) { + triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails) + }) + } + ) + oobElement.parentNode.removeChild(oobElement) + } else { + oobElement.parentNode.removeChild(oobElement) + triggerErrorEvent(getDocument().body, 'htmx:oobErrorNoTarget', { content: oobElement }) + } + return oobValue + } + + /** + * @param {DocumentFragment} fragment + */ + function handlePreservedElements(fragment) { + forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function(preservedElt) { + const id = getAttributeValue(preservedElt, 'id') + const oldElt = getDocument().getElementById(id) + if (oldElt != null) { + preservedElt.parentNode.replaceChild(oldElt, preservedElt) + } + }) + } + + /** + * @param {Node} parentNode + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function handleAttributes(parentNode, fragment, settleInfo) { + forEach(fragment.querySelectorAll('[id]'), function(newNode) { + const id = getRawAttribute(newNode, 'id') + if (id && id.length > 0) { + const normalizedId = id.replace("'", "\\'") + const normalizedTag = newNode.tagName.replace(':', '\\:') + const parentElt = asParentNode(parentNode) + const oldNode = parentElt && parentElt.querySelector(normalizedTag + "[id='" + normalizedId + "']") + if (oldNode && oldNode !== parentElt) { + const newAttributes = newNode.cloneNode() + cloneAttributes(newNode, oldNode) + settleInfo.tasks.push(function() { + cloneAttributes(newNode, newAttributes) + }) + } + } + }) + } + + /** + * @param {Node} child + * @returns {HtmxSettleTask} + */ + function makeAjaxLoadTask(child) { + return function() { + removeClassFromElement(child, htmx.config.addedClass) + processNode(asElement(child)) + processFocus(asParentNode(child)) + triggerEvent(child, 'htmx:load') + } + } + + /** + * @param {ParentNode} child + */ + function processFocus(child) { + const autofocus = '[autofocus]' + const autoFocusedElt = asHtmlElement(matches(child, autofocus) ? child : child.querySelector(autofocus)) + if (autoFocusedElt != null) { + autoFocusedElt.focus() + } + } + + /** + * @param {Node} parentNode + * @param {Node} insertBefore + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) { + handleAttributes(parentNode, fragment, settleInfo) + while (fragment.childNodes.length > 0) { + const child = fragment.firstChild + addClassToElement(asElement(child), htmx.config.addedClass) + parentNode.insertBefore(child, insertBefore) + if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { + settleInfo.tasks.push(makeAjaxLoadTask(child)) + } + } + } + + /** + * based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, + * derived from Java's string hashcode implementation + * @param {string} string + * @param {number} hash + * @returns {number} + */ + function stringHash(string, hash) { + let char = 0 + while (char < string.length) { + hash = (hash << 5) - hash + string.charCodeAt(char++) | 0 // bitwise or ensures we have a 32-bit int + } + return hash + } + + /** + * @param {Element} elt + * @returns {number} + */ + function attributeHash(elt) { + let hash = 0 + // IE fix + if (elt.attributes) { + for (let i = 0; i < elt.attributes.length; i++) { + const attribute = elt.attributes[i] + if (attribute.value) { // only include attributes w/ actual values (empty is same as non-existent) + hash = stringHash(attribute.name, hash) + hash = stringHash(attribute.value, hash) + } + } + } + return hash + } + + /** + * @param {EventTarget} elt + */ + function deInitOnHandlers(elt) { + const internalData = getInternalData(elt) + if (internalData.onHandlers) { + for (let i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i] + removeEventListenerImpl(elt, handlerInfo.event, handlerInfo.listener) + } + delete internalData.onHandlers + } + } + + /** + * @param {Node} element + */ + function deInitNode(element) { + const internalData = getInternalData(element) + if (internalData.timeout) { + clearTimeout(internalData.timeout) + } + if (internalData.listenerInfos) { + forEach(internalData.listenerInfos, function(info) { + if (info.on) { + removeEventListenerImpl(info.on, info.trigger, info.listener) } - - function forEach(arr, func) { - if (arr) { - for (var i = 0; i < arr.length; i++) { - func(arr[i]); - } - } + }) + } + deInitOnHandlers(element) + forEach(Object.keys(internalData), function(key) { delete internalData[key] }) + } + + /** + * @param {Node} element + */ + function cleanUpElement(element) { + triggerEvent(element, 'htmx:beforeCleanupElement') + deInitNode(element) + // @ts-ignore IE11 code + // noinspection JSUnresolvedReference + if (element.children) { // IE + // @ts-ignore + forEach(element.children, function(child) { cleanUpElement(child) }) + } + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapOuterHTML(target, fragment, settleInfo) { + /** @type {Node} */ + let newElt + const eltBeforeNewContent = target.previousSibling + insertNodesBefore(parentElt(target), target, fragment, settleInfo) + if (eltBeforeNewContent == null) { + newElt = parentElt(target).firstChild + } else { + newElt = eltBeforeNewContent.nextSibling + } + settleInfo.elts = settleInfo.elts.filter(function(e) { return e !== target }) + while (newElt && newElt !== target) { + if (newElt instanceof Element) { + settleInfo.elts.push(newElt) + newElt = newElt.nextElementSibling + } else { + newElt = null + } + } + cleanUpElement(target) + if (target instanceof Element) { + target.remove() + } else { + target.parentNode.removeChild(target) + } + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapAfterBegin(target, fragment, settleInfo) { + return insertNodesBefore(target, target.firstChild, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapBeforeBegin(target, fragment, settleInfo) { + return insertNodesBefore(parentElt(target), target, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapBeforeEnd(target, fragment, settleInfo) { + return insertNodesBefore(target, null, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapAfterEnd(target, fragment, settleInfo) { + return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo) + } + + /** + * @param {Node} target + */ + function swapDelete(target) { + cleanUpElement(target) + return parentElt(target).removeChild(target) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapInnerHTML(target, fragment, settleInfo) { + const firstChild = target.firstChild + insertNodesBefore(target, firstChild, fragment, settleInfo) + if (firstChild) { + while (firstChild.nextSibling) { + cleanUpElement(firstChild.nextSibling) + target.removeChild(firstChild.nextSibling) + } + cleanUpElement(firstChild) + target.removeChild(firstChild) + } + } + + /** + * @param {HtmxSwapStyle} swapStyle + * @param {Element} elt + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapWithStyle(swapStyle, elt, target, fragment, settleInfo) { + switch (swapStyle) { + case 'none': + return + case 'outerHTML': + swapOuterHTML(target, fragment, settleInfo) + return + case 'afterbegin': + swapAfterBegin(target, fragment, settleInfo) + return + case 'beforebegin': + swapBeforeBegin(target, fragment, settleInfo) + return + case 'beforeend': + swapBeforeEnd(target, fragment, settleInfo) + return + case 'afterend': + swapAfterEnd(target, fragment, settleInfo) + return + case 'delete': + swapDelete(target) + return + default: + var extensions = getExtensions(elt) + for (let i = 0; i < extensions.length; i++) { + const ext = extensions[i] + try { + const newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo) + if (newElements) { + if (typeof newElements.length !== 'undefined') { + // if handleSwap returns an array (like) of elements, we handle them + for (let j = 0; j < newElements.length; j++) { + const child = newElements[j] + if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { + settleInfo.tasks.push(makeAjaxLoadTask(child)) + } + } + } + return + } + } catch (e) { + logError(e) + } + } + if (swapStyle === 'innerHTML') { + swapInnerHTML(target, fragment, settleInfo) + } else { + swapWithStyle(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo) } + } + } + + /** + * @param {DocumentFragment} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function findAndSwapOobElements(fragment, settleInfo) { + forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function(oobElement) { + if (htmx.config.allowNestedOobSwaps || oobElement.parentElement === null) { + const oobValue = getAttributeValue(oobElement, 'hx-swap-oob') + if (oobValue != null) { + oobSwap(oobValue, oobElement, settleInfo) + } + } else { + oobElement.removeAttribute('hx-swap-oob') + oobElement.removeAttribute('data-hx-swap-oob') + } + }) + } + + /** + * Implements complete swapping pipeline, including: focus and selection preservation, + * title updates, scroll, OOB swapping, normal swapping and settling + * @param {string|Element} target + * @param {string} content + * @param {HtmxSwapSpecification} swapSpec + * @param {SwapOptions} [swapOptions] + */ + function swap(target, content, swapSpec, swapOptions) { + if (!swapOptions) { + swapOptions = {} + } - function isScrolledIntoView(el) { - var rect = el.getBoundingClientRect(); - var elemTop = rect.top; - var elemBottom = rect.bottom; - return elemTop < window.innerHeight && elemBottom >= 0; - } + target = resolveTarget(target) + + // preserve focus and selection + const activeElt = document.activeElement + let selectionInfo = {} + try { + selectionInfo = { + elt: activeElt, + // @ts-ignore + start: activeElt ? activeElt.selectionStart : null, + // @ts-ignore + end: activeElt ? activeElt.selectionEnd : null + } + } catch (e) { + // safari issue - see https://github.com/microsoft/playwright/issues/5894 + } + const settleInfo = makeSettleInfo(target) - function bodyContains(elt) { - // IE Fix - if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) { - return getDocument().body.contains(elt.getRootNode().host); - } else { - return getDocument().body.contains(elt); - } - } + // For text content swaps, don't parse the response as HTML, just insert it + if (swapSpec.swapStyle === 'textContent') { + target.textContent = content + // Otherwise, make the fragment and process it + } else { + let fragment = makeFragment(content) + + settleInfo.title = fragment.title + + // select-oob swaps + if (swapOptions.selectOOB) { + const oobSelectValues = swapOptions.selectOOB.split(',') + for (let i = 0; i < oobSelectValues.length; i++) { + const oobSelectValue = oobSelectValues[i].split(':', 2) + let id = oobSelectValue[0].trim() + if (id.indexOf('#') === 0) { + id = id.substring(1) + } + const oobValue = oobSelectValue[1] || 'true' + const oobElement = fragment.querySelector('#' + id) + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo) + } + } + } + // oob swaps + findAndSwapOobElements(fragment, settleInfo) + forEach(findAll(fragment, 'template'), /** @param {HTMLTemplateElement} template */function(template) { + findAndSwapOobElements(template.content, settleInfo) + if (template.content.childElementCount === 0) { + // Avoid polluting the DOM with empty templates that were only used to encapsulate oob swap + template.remove() + } + }) + + // normal swap + if (swapOptions.select) { + const newFragment = getDocument().createDocumentFragment() + forEach(fragment.querySelectorAll(swapOptions.select), function(node) { + newFragment.appendChild(node) + }) + fragment = newFragment + } + handlePreservedElements(fragment) + swapWithStyle(swapSpec.swapStyle, swapOptions.contextElement, target, fragment, settleInfo) + } - function splitOnWhitespace(trigger) { - return trigger.trim().split(/\s+/); - } + // apply saved focus and selection information to swapped content + if (selectionInfo.elt && + !bodyContains(selectionInfo.elt) && + getRawAttribute(selectionInfo.elt, 'id')) { + const newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, 'id')) + const focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll } + if (newActiveElt) { + // @ts-ignore + if (selectionInfo.start && newActiveElt.setSelectionRange) { + try { + // @ts-ignore + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end) + } catch (e) { + // the setSelectionRange method is present on fields that don't support it, so just let this fail + } + } + newActiveElt.focus(focusOptions) + } + } - /** - * mergeObjects takes all of the keys from - * obj2 and duplicates them into obj1 - * @param {Object} obj1 - * @param {Object} obj2 - * @returns {Object} - */ - function mergeObjects(obj1, obj2) { - for (var key in obj2) { - if (obj2.hasOwnProperty(key)) { - obj1[key] = obj2[key]; - } - } - return obj1; - } + target.classList.remove(htmx.config.swappingClass) + forEach(settleInfo.elts, function(elt) { + if (elt.classList) { + elt.classList.add(htmx.config.settlingClass) + } + triggerEvent(elt, 'htmx:afterSwap', swapOptions.eventInfo) + }) + if (swapOptions.afterSwapCallback) { + swapOptions.afterSwapCallback() + } - function parseJSON(jString) { - try { - return JSON.parse(jString); - } catch(error) { - logError(error); - return null; - } - } + // merge in new title after swap but before settle + if (!swapSpec.ignoreTitle) { + handleTitle(settleInfo.title) + } - function canAccessLocalStorage() { - var test = 'htmx:localStorageTest'; - try { - localStorage.setItem(test, test); - localStorage.removeItem(test); - return true; - } catch(e) { - return false; - } - } + // settle + const doSettle = function() { + forEach(settleInfo.tasks, function(task) { + task.call() + }) + forEach(settleInfo.elts, function(elt) { + if (elt.classList) { + elt.classList.remove(htmx.config.settlingClass) + } + triggerEvent(elt, 'htmx:afterSettle', swapOptions.eventInfo) + }) + + if (swapOptions.anchor) { + const anchorTarget = asElement(resolveTarget('#' + swapOptions.anchor)) + if (anchorTarget) { + anchorTarget.scrollIntoView({ block: 'start', behavior: 'auto' }) + } + } + + updateScrollState(settleInfo.elts, swapSpec) + if (swapOptions.afterSettleCallback) { + swapOptions.afterSettleCallback() + } + } - function normalizePath(path) { + if (swapSpec.settleDelay > 0) { + getWindow().setTimeout(doSettle, swapSpec.settleDelay) + } else { + doSettle() + } + } + + /** + * @param {XMLHttpRequest} xhr + * @param {string} header + * @param {EventTarget} elt + */ + function handleTriggerHeader(xhr, header, elt) { + const triggerBody = xhr.getResponseHeader(header) + if (triggerBody.indexOf('{') === 0) { + const triggers = parseJSON(triggerBody) + for (const eventName in triggers) { + if (triggers.hasOwnProperty(eventName)) { + let detail = triggers[eventName] + if (!isRawObject(detail)) { + detail = { value: detail } + } + triggerEvent(elt, eventName, detail) + } + } + } else { + const eventNames = triggerBody.split(',') + for (let i = 0; i < eventNames.length; i++) { + triggerEvent(elt, eventNames[i].trim(), []) + } + } + } + + const WHITESPACE = /\s/ + const WHITESPACE_OR_COMMA = /[\s,]/ + const SYMBOL_START = /[_$a-zA-Z]/ + const SYMBOL_CONT = /[_$a-zA-Z0-9]/ + const STRINGISH_START = ['"', "'", '/'] + const NOT_WHITESPACE = /[^\s]/ + const COMBINED_SELECTOR_START = /[{(]/ + const COMBINED_SELECTOR_END = /[})]/ + + /** + * @param {string} str + * @returns {string[]} + */ + function tokenizeString(str) { + /** @type string[] */ + const tokens = [] + let position = 0 + while (position < str.length) { + if (SYMBOL_START.exec(str.charAt(position))) { + var startPosition = position + while (SYMBOL_CONT.exec(str.charAt(position + 1))) { + position++ + } + tokens.push(str.substr(startPosition, position - startPosition + 1)) + } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) { + const startChar = str.charAt(position) + var startPosition = position + position++ + while (position < str.length && str.charAt(position) !== startChar) { + if (str.charAt(position) === '\\') { + position++ + } + position++ + } + tokens.push(str.substr(startPosition, position - startPosition + 1)) + } else { + const symbol = str.charAt(position) + tokens.push(symbol) + } + position++ + } + return tokens + } + + /** + * @param {string} token + * @param {string|null} last + * @param {string} paramName + * @returns {boolean} + */ + function isPossibleRelativeReference(token, last, paramName) { + return SYMBOL_START.exec(token.charAt(0)) && + token !== 'true' && + token !== 'false' && + token !== 'this' && + token !== paramName && + last !== '.' + } + + /** + * @param {EventTarget|string} elt + * @param {string[]} tokens + * @param {string} paramName + * @returns {ConditionalFunction|null} + */ + function maybeGenerateConditional(elt, tokens, paramName) { + if (tokens[0] === '[') { + tokens.shift() + let bracketCount = 1 + let conditionalSource = ' return (function(' + paramName + '){ return (' + let last = null + while (tokens.length > 0) { + const token = tokens[0] + // @ts-ignore For some reason tsc doesn't understand the shift call, and thinks we're comparing the same value here, i.e. '[' vs ']' + if (token === ']') { + bracketCount-- + if (bracketCount === 0) { + if (last === null) { + conditionalSource = conditionalSource + 'true' + } + tokens.shift() + conditionalSource += ')})' try { - var url = new URL(path); - if (url) { - path = url.pathname + url.search; - } - // remove trailing slash, unless index page - if (!(/^\/$/.test(path))) { - path = path.replace(/\/+$/, ''); - } - return path; + const conditionFunction = maybeEval(elt, function() { + return Function(conditionalSource)() + }, + function() { return true }) + conditionFunction.source = conditionalSource + return conditionFunction } catch (e) { - // be kind to IE11, which doesn't support URL() - return path; - } - } - - //========================================================================================== - // public API - //========================================================================================== - - function internalEval(str){ - return maybeEval(getDocument().body, function () { - return eval(str); - }); - } - - function onLoadHelper(callback) { - var value = htmx.on("htmx:load", function(evt) { - callback(evt.detail.elt); - }); - return value; - } - - function logAll(){ - htmx.logger = function(elt, event, data) { - if(console) { - console.log(event, elt, data); - } - } - } - - function logNone() { - htmx.logger = null - } - - function find(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelector(selector); - } else { - return find(getDocument(), eltOrSelector); - } - } - - function findAll(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelectorAll(selector); - } else { - return findAll(getDocument(), eltOrSelector); - } - } - - function removeElement(elt, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - removeElement(elt); - elt = null; - }, delay); - } else { - elt.parentElement.removeChild(elt); - } - } - - function addClassToElement(elt, clazz, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - addClassToElement(elt, clazz); - elt = null; - }, delay); - } else { - elt.classList && elt.classList.add(clazz); - } - } - - function removeClassFromElement(elt, clazz, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - removeClassFromElement(elt, clazz); - elt = null; - }, delay); - } else { - if (elt.classList) { - elt.classList.remove(clazz); - // if there are no classes left, remove the class attribute - if (elt.classList.length === 0) { - elt.removeAttribute("class"); - } - } - } - } - - function toggleClassOnElement(elt, clazz) { - elt = resolveTarget(elt); - elt.classList.toggle(clazz); - } - - function takeClassForElement(elt, clazz) { - elt = resolveTarget(elt); - forEach(elt.parentElement.children, function(child){ - removeClassFromElement(child, clazz); - }) - addClassToElement(elt, clazz); - } - - function closest(elt, selector) { - elt = resolveTarget(elt); - if (elt.closest) { - return elt.closest(selector); - } else { - // TODO remove when IE goes away - do{ - if (elt == null || matches(elt, selector)){ - return elt; - } - } - while (elt = elt && parentElt(elt)); - return null; - } - } - - function startsWith(str, prefix) { - return str.substring(0, prefix.length) === prefix - } - - function endsWith(str, suffix) { - return str.substring(str.length - suffix.length) === suffix - } - - function normalizeSelector(selector) { - var trimmedSelector = selector.trim(); - if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) { - return trimmedSelector.substring(1, trimmedSelector.length - 2); - } else { - return trimmedSelector; - } - } - - function querySelectorAllExt(elt, selector) { - if (selector.indexOf("closest ") === 0) { - return [closest(elt, normalizeSelector(selector.substr(8)))]; - } else if (selector.indexOf("find ") === 0) { - return [find(elt, normalizeSelector(selector.substr(5)))]; - } else if (selector === "next") { - return [elt.nextElementSibling] - } else if (selector.indexOf("next ") === 0) { - return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; - } else if (selector === "previous") { - return [elt.previousElementSibling] - } else if (selector.indexOf("previous ") === 0) { - return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; - } else if (selector === 'document') { - return [document]; - } else if (selector === 'window') { - return [window]; - } else if (selector === 'body') { - return [document.body]; - } else { - return getDocument().querySelectorAll(normalizeSelector(selector)); - } - } - - var scanForwardQuery = function(start, match) { - var results = getDocument().querySelectorAll(match); - for (var i = 0; i < results.length; i++) { - var elt = results[i]; - if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { - return elt; - } - } - } - - var scanBackwardsQuery = function(start, match) { - var results = getDocument().querySelectorAll(match); - for (var i = results.length - 1; i >= 0; i--) { - var elt = results[i]; - if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { - return elt; - } - } - } - - function querySelectorExt(eltOrSelector, selector) { - if (selector) { - return querySelectorAllExt(eltOrSelector, selector)[0]; - } else { - return querySelectorAllExt(getDocument().body, eltOrSelector)[0]; - } - } - - function resolveTarget(arg2) { - if (isType(arg2, 'String')) { - return find(arg2); - } else { - return arg2; - } - } - - function processEventArgs(arg1, arg2, arg3) { - if (isFunction(arg2)) { - return { - target: getDocument().body, - event: arg1, - listener: arg2 - } - } else { - return { - target: resolveTarget(arg1), - event: arg2, - listener: arg3 - } - } - - } - - function addEventListenerImpl(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 removeEventListenerImpl(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 - //==================================================================== - - var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors - function findAttributeTargets(elt, attrName) { - var attrTarget = getClosestAttributeValue(elt, attrName); - if (attrTarget) { - if (attrTarget === "this") { - return [findThisElement(elt, attrName)]; - } else { - var result = querySelectorAllExt(elt, attrTarget); - if (result.length === 0) { - logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!"); - return [DUMMY_ELT] - } else { - return result; - } - } - } - } - - function findThisElement(elt, attribute){ - return getClosestMatch(elt, function (elt) { - return getAttributeValue(elt, attribute) != null; - }) - } - - function getTarget(elt) { - var targetStr = getClosestAttributeValue(elt, "hx-target"); - if (targetStr) { - if (targetStr === "this") { - return findThisElement(elt,'hx-target'); - } else { - return querySelectorExt(elt, targetStr) - } - } else { - var data = getInternalData(elt); - if (data.boosted) { - return getDocument().body; - } else { - return elt; - } - } - } - - function shouldSettleAttribute(name) { - var attributesToSettle = htmx.config.attributesToSettle; - for (var i = 0; i < attributesToSettle.length; i++) { - if (name === attributesToSettle[i]) { - return true; - } - } - return false; - } - - function cloneAttributes(mergeTo, mergeFrom) { - forEach(mergeTo.attributes, function (attr) { - if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) { - mergeTo.removeAttribute(attr.name) - } - }); - forEach(mergeFrom.attributes, function (attr) { - if (shouldSettleAttribute(attr.name)) { - mergeTo.setAttribute(attr.name, attr.value); - } - }); - } - - function isInlineSwap(swapStyle, target) { - var extensions = getExtensions(target); - for (var i = 0; i < extensions.length; i++) { - var extension = extensions[i]; - try { - if (extension.isInlineSwap(swapStyle)) { - return true; - } - } catch(e) { - logError(e); - } - } - return swapStyle === "outerHTML"; - } - - /** - * - * @param {string} oobValue - * @param {HTMLElement} oobElement - * @param {*} settleInfo - * @returns - */ - function oobSwap(oobValue, oobElement, settleInfo) { - var selector = "#" + getRawAttribute(oobElement, "id"); - var swapStyle = "outerHTML"; - if (oobValue === "true") { - // do nothing - } else if (oobValue.indexOf(":") > 0) { - swapStyle = oobValue.substr(0, oobValue.indexOf(":")); - selector = oobValue.substr(oobValue.indexOf(":") + 1, oobValue.length); - } else { - swapStyle = oobValue; - } - - var targets = getDocument().querySelectorAll(selector); - if (targets) { - forEach( - targets, - function (target) { - var fragment; - var oobElementClone = oobElement.cloneNode(true); - fragment = getDocument().createDocumentFragment(); - fragment.appendChild(oobElementClone); - if (!isInlineSwap(swapStyle, target)) { - fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself - } - - var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment }; - if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return; - - target = beforeSwapDetails.target; // allow re-targeting - if (beforeSwapDetails['shouldSwap']){ - swap(swapStyle, target, target, fragment, settleInfo); - } - forEach(settleInfo.elts, function (elt) { - triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails); - }); - } - ); - oobElement.parentNode.removeChild(oobElement); - } else { - oobElement.parentNode.removeChild(oobElement); - triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}); - } - return oobValue; - } - - function handleOutOfBandSwaps(elt, fragment, settleInfo) { - var oobSelects = getClosestAttributeValue(elt, "hx-select-oob"); - if (oobSelects) { - var oobSelectValues = oobSelects.split(","); - for (var i = 0; i < oobSelectValues.length; i++) { - var oobSelectValue = oobSelectValues[i].split(":", 2); - var id = oobSelectValue[0].trim(); - if (id.indexOf("#") === 0) { - id = id.substring(1); - } - var oobValue = oobSelectValue[1] || "true"; - var oobElement = fragment.querySelector("#" + id); - if (oobElement) { - oobSwap(oobValue, oobElement, settleInfo); - } - } - } - forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) { - var oobValue = getAttributeValue(oobElement, "hx-swap-oob"); - if (oobValue != null) { - oobSwap(oobValue, oobElement, settleInfo); - } - }); - } - - function handlePreservedElements(fragment) { - forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function (preservedElt) { - var id = getAttributeValue(preservedElt, "id"); - var oldElt = getDocument().getElementById(id); - if (oldElt != null) { - preservedElt.parentNode.replaceChild(oldElt, preservedElt); - } - }); - } - - function handleAttributes(parentNode, fragment, settleInfo) { - forEach(fragment.querySelectorAll("[id]"), function (newNode) { - var id = getRawAttribute(newNode, "id") - if (id && id.length > 0) { - var normalizedId = id.replace("'", "\\'"); - var normalizedTag = newNode.tagName.replace(':', '\\:'); - var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']"); - if (oldNode && oldNode !== parentNode) { - var newAttributes = newNode.cloneNode(); - cloneAttributes(newNode, oldNode); - settleInfo.tasks.push(function () { - cloneAttributes(newNode, newAttributes); - }); - } - } - }); - } - - function makeAjaxLoadTask(child) { - return function () { - removeClassFromElement(child, htmx.config.addedClass); - processNode(child); - processScripts(child); - processFocus(child) - triggerEvent(child, 'htmx:load'); - }; - } - - function processFocus(child) { - var autofocus = "[autofocus]"; - var autoFocusedElt = matches(child, autofocus) ? child : child.querySelector(autofocus) - if (autoFocusedElt != null) { - autoFocusedElt.focus(); - } - } - - function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) { - handleAttributes(parentNode, fragment, settleInfo); - while(fragment.childNodes.length > 0){ - var child = fragment.firstChild; - addClassToElement(child, htmx.config.addedClass); - parentNode.insertBefore(child, insertBefore); - if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { - settleInfo.tasks.push(makeAjaxLoadTask(child)); - } - } - } - - // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, - // derived from Java's string hashcode implementation - function stringHash(string, hash) { - var char = 0; - while (char < string.length){ - hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int - } - return hash; - } - - function attributeHash(elt) { - var hash = 0; - // IE fix - if (elt.attributes) { - for (var i = 0; i < elt.attributes.length; i++) { - var attribute = elt.attributes[i]; - if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent) - hash = stringHash(attribute.name, hash); - hash = stringHash(attribute.value, hash); - } - } - } - return hash; - } - - function deInitOnHandlers(elt) { - var internalData = getInternalData(elt); - if (internalData.onHandlers) { - for (var i = 0; i < internalData.onHandlers.length; i++) { - const handlerInfo = internalData.onHandlers[i]; - elt.removeEventListener(handlerInfo.event, handlerInfo.listener); - } - delete internalData.onHandlers - } - } - - function deInitNode(element) { - var internalData = getInternalData(element); - if (internalData.timeout) { - clearTimeout(internalData.timeout); - } - if (internalData.webSocket) { - internalData.webSocket.close(); - } - if (internalData.sseEventSource) { - internalData.sseEventSource.close(); - } - if (internalData.listenerInfos) { - forEach(internalData.listenerInfos, function (info) { - if (info.on) { - info.on.removeEventListener(info.trigger, info.listener); - } - }); - } - deInitOnHandlers(element); - forEach(Object.keys(internalData), function(key) { delete internalData[key] }); - } - - function cleanUpElement(element) { - triggerEvent(element, "htmx:beforeCleanupElement") - deInitNode(element); - if (element.children) { // IE - forEach(element.children, function(child) { cleanUpElement(child) }); - } - } - - function swapOuterHTML(target, fragment, settleInfo) { - if (target.tagName === "BODY") { - return swapInnerHTML(target, fragment, settleInfo); - } else { - // @type {HTMLElement} - var newElt - var eltBeforeNewContent = target.previousSibling; - insertNodesBefore(parentElt(target), target, fragment, settleInfo); - if (eltBeforeNewContent == null) { - newElt = parentElt(target).firstChild; - } else { - newElt = eltBeforeNewContent.nextSibling; - } - settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target }); - while(newElt && newElt !== target) { - if (newElt.nodeType === Node.ELEMENT_NODE) { - settleInfo.elts.push(newElt); - } - newElt = newElt.nextElementSibling; - } - cleanUpElement(target); - parentElt(target).removeChild(target); - } - } - - function swapAfterBegin(target, fragment, settleInfo) { - return insertNodesBefore(target, target.firstChild, fragment, settleInfo); - } - - function swapBeforeBegin(target, fragment, settleInfo) { - return insertNodesBefore(parentElt(target), target, fragment, settleInfo); - } - - function swapBeforeEnd(target, fragment, settleInfo) { - return insertNodesBefore(target, null, fragment, settleInfo); - } - - function swapAfterEnd(target, fragment, settleInfo) { - return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo); - } - function swapDelete(target, fragment, settleInfo) { - cleanUpElement(target); - return parentElt(target).removeChild(target); - } - - function swapInnerHTML(target, fragment, settleInfo) { - var firstChild = target.firstChild; - insertNodesBefore(target, firstChild, fragment, settleInfo); - if (firstChild) { - while (firstChild.nextSibling) { - cleanUpElement(firstChild.nextSibling) - target.removeChild(firstChild.nextSibling); - } - cleanUpElement(firstChild) - target.removeChild(firstChild); - } - } - - function maybeSelectFromResponse(elt, fragment, selectOverride) { - var selector = selectOverride || getClosestAttributeValue(elt, "hx-select"); - if (selector) { - var newFragment = getDocument().createDocumentFragment(); - forEach(fragment.querySelectorAll(selector), function (node) { - newFragment.appendChild(node); - }); - fragment = newFragment; - } - return fragment; - } - - function swap(swapStyle, elt, target, fragment, settleInfo) { - switch (swapStyle) { - case "none": - return; - case "outerHTML": - swapOuterHTML(target, fragment, settleInfo); - return; - case "afterbegin": - swapAfterBegin(target, fragment, settleInfo); - return; - case "beforebegin": - swapBeforeBegin(target, fragment, settleInfo); - return; - case "beforeend": - swapBeforeEnd(target, fragment, settleInfo); - return; - case "afterend": - swapAfterEnd(target, fragment, settleInfo); - return; - case "delete": - swapDelete(target, fragment, settleInfo); - return; - default: - var extensions = getExtensions(elt); - for (var i = 0; i < extensions.length; i++) { - var ext = extensions[i]; - try { - var newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo); - if (newElements) { - if (typeof newElements.length !== 'undefined') { - // if handleSwap returns an array (like) of elements, we handle them - for (var j = 0; j < newElements.length; j++) { - var child = newElements[j]; - if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { - settleInfo.tasks.push(makeAjaxLoadTask(child)); - } - } - } - return; - } - } catch (e) { - logError(e); - } - } - if (swapStyle === "innerHTML") { - swapInnerHTML(target, fragment, settleInfo); - } else { - swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo); - } - } - } - - function findTitle(content) { - if (content.indexOf('<title') > -1) { - var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, ''); - var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX); - if (result) { - return result[2]; - } - } - } - - function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) { - settleInfo.title = findTitle(responseText); - var fragment = makeFragment(responseText); - if (fragment) { - handleOutOfBandSwaps(elt, fragment, settleInfo); - fragment = maybeSelectFromResponse(elt, fragment, selectOverride); - handlePreservedElements(fragment); - return swap(swapStyle, elt, target, fragment, settleInfo); - } - } - - function handleTrigger(xhr, header, elt) { - var triggerBody = xhr.getResponseHeader(header); - if (triggerBody.indexOf("{") === 0) { - var triggers = parseJSON(triggerBody); - for (var eventName in triggers) { - if (triggers.hasOwnProperty(eventName)) { - var detail = triggers[eventName]; - if (!isRawObject(detail)) { - detail = {"value": detail} - } - triggerEvent(elt, eventName, detail); - } - } - } else { - var eventNames = triggerBody.split(",") - for (var i = 0; i < eventNames.length; i++) { - triggerEvent(elt, eventNames[i].trim(), []); - } - } - } - - var WHITESPACE = /\s/; - var WHITESPACE_OR_COMMA = /[\s,]/; - var SYMBOL_START = /[_$a-zA-Z]/; - var SYMBOL_CONT = /[_$a-zA-Z0-9]/; - var STRINGISH_START = ['"', "'", "/"]; - var NOT_WHITESPACE = /[^\s]/; - var COMBINED_SELECTOR_START = /[{(]/; - var COMBINED_SELECTOR_END = /[})]/; - function tokenizeString(str) { - var tokens = []; - var position = 0; - while (position < str.length) { - if(SYMBOL_START.exec(str.charAt(position))) { - var startPosition = position; - while (SYMBOL_CONT.exec(str.charAt(position + 1))) { - position++; - } - tokens.push(str.substr(startPosition, position - startPosition + 1)); - } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) { - var startChar = str.charAt(position); - var startPosition = position; - position++; - while (position < str.length && str.charAt(position) !== startChar ) { - if (str.charAt(position) === "\\") { - position++; - } - position++; - } - tokens.push(str.substr(startPosition, position - startPosition + 1)); - } else { - var symbol = str.charAt(position); - tokens.push(symbol); - } - position++; - } - return tokens; - } - - function isPossibleRelativeReference(token, last, paramName) { - return SYMBOL_START.exec(token.charAt(0)) && - token !== "true" && - token !== "false" && - token !== "this" && - token !== paramName && - last !== "."; - } - - function maybeGenerateConditional(elt, tokens, paramName) { - if (tokens[0] === '[') { - tokens.shift(); - var bracketCount = 1; - var conditionalSource = " return (function(" + paramName + "){ return ("; - var last = null; - while (tokens.length > 0) { - var token = tokens[0]; - if (token === "]") { - bracketCount--; - if (bracketCount === 0) { - if (last === null) { - conditionalSource = conditionalSource + "true"; - } - tokens.shift(); - conditionalSource += ")})"; - try { - var conditionFunction = maybeEval(elt,function () { - return Function(conditionalSource)(); - }, - function(){return true}) - conditionFunction.source = conditionalSource; - return conditionFunction; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:syntax:error", {error:e, source:conditionalSource}) - return null; - } - } - } else if (token === "[") { - bracketCount++; - } - if (isPossibleRelativeReference(token, last, paramName)) { - conditionalSource += "((" + paramName + "." + token + ") ? (" + paramName + "." + token + ") : (window." + token + "))"; - } else { - conditionalSource = conditionalSource + token; - } - last = tokens.shift(); - } - } - } - - function consumeUntil(tokens, match) { - var result = ""; - while (tokens.length > 0 && !match.test(tokens[0])) { - result += tokens.shift(); - } - return result; - } - - function consumeCSSSelector(tokens) { - var result; - if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { - tokens.shift(); - result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim(); - tokens.shift(); - } else { - result = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } - return result; - } - - var INPUT_SELECTOR = 'input, textarea, select'; - - /** - * @param {HTMLElement} elt - * @param {string} explicitTrigger - * @param {cache} cache for trigger specs - * @returns {import("./htmx").HtmxTriggerSpecification[]} - */ - function parseAndCacheTrigger(elt, explicitTrigger, cache) { - var triggerSpecs = []; - var tokens = tokenizeString(explicitTrigger); - do { - consumeUntil(tokens, NOT_WHITESPACE); - var initialLength = tokens.length; - var trigger = consumeUntil(tokens, /[,\[\s]/); - if (trigger !== "") { - if (trigger === "every") { - var every = {trigger: 'every'}; - consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); - consumeUntil(tokens, NOT_WHITESPACE); - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - every.eventFilter = eventFilter; - } - triggerSpecs.push(every); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); - } else { - var triggerSpec = {trigger: trigger}; - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - triggerSpec.eventFilter = eventFilter; - } - while (tokens.length > 0 && tokens[0] !== ",") { - consumeUntil(tokens, NOT_WHITESPACE) - var token = tokens.shift(); - if (token === "changed") { - triggerSpec.changed = true; - } else if (token === "once") { - triggerSpec.once = true; - } else if (token === "consume") { - triggerSpec.consume = true; - } else if (token === "delay" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "from" && tokens[0] === ":") { - tokens.shift(); - if (COMBINED_SELECTOR_START.test(tokens[0])) { - var from_arg = consumeCSSSelector(tokens); - } else { - var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); - if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") { - tokens.shift(); - var selector = consumeCSSSelector(tokens); - // `next` and `previous` allow a selector-less syntax - if (selector.length > 0) { - from_arg += " " + selector; - } - } - } - triggerSpec.from = from_arg; - } else if (token === "target" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.target = consumeCSSSelector(tokens); - } else if (token === "throttle" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "queue" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if (token === "root" && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeCSSSelector(tokens); - } else if (token === "threshold" && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - } - triggerSpecs.push(triggerSpec); - } - } - if (tokens.length === initialLength) { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - consumeUntil(tokens, NOT_WHITESPACE); - } while (tokens[0] === "," && tokens.shift()) - if (cache) { - cache[explicitTrigger] = triggerSpecs - } - return triggerSpecs - } - - /** - * @param {HTMLElement} elt - * @returns {import("./htmx").HtmxTriggerSpecification[]} - */ - function getTriggerSpecs(elt) { - var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); - var triggerSpecs = []; - if (explicitTrigger) { - var cache = htmx.config.triggerSpecsCache - triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) - } - - if (triggerSpecs.length > 0) { - return triggerSpecs; - } else if (matches(elt, 'form')) { - return [{trigger: 'submit'}]; - } else if (matches(elt, 'input[type="button"], input[type="submit"]')){ - return [{trigger: 'click'}]; - } else if (matches(elt, INPUT_SELECTOR)) { - return [{trigger: 'change'}]; - } else { - return [{trigger: 'click'}]; - } - } - - function cancelPolling(elt) { - getInternalData(elt).cancelled = true; - } - - function processPolling(elt, handler, spec) { - var nodeData = getInternalData(elt); - nodeData.timeout = setTimeout(function () { - if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { - triggerSpec: spec, - target: elt - }))) { - handler(elt); - } - processPolling(elt, handler, spec); - } - }, spec.pollInterval); - } - - function isLocalLink(elt) { - return location.hostname === elt.hostname && - getRawAttribute(elt,'href') && - getRawAttribute(elt,'href').indexOf("#") !== 0; - } - - function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || 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"; - if (verb === "get") { - } - path = getRawAttribute(elt, 'action'); - } - triggerSpecs.forEach(function(triggerSpec) { - addEventListener(elt, function(elt, evt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return - } - issueAjaxRequest(verb, path, elt, evt) - }, nodeData, triggerSpec, true); - }); - } - } - - /** - * - * @param {Event} evt - * @param {HTMLElement} elt - * @returns - */ - function shouldCancel(evt, elt) { - if (evt.type === "submit" || evt.type === "click") { - if (elt.tagName === "FORM") { - return true; - } - if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { - return true; - } - if (elt.tagName === "A" && elt.href && - (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) { - return true; - } - } - return false; - } - - function ignoreBoostedAnchorCtrlClick(elt, evt) { - return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); - } - - function maybeFilterEvent(triggerSpec, elt, evt) { - var eventFilter = triggerSpec.eventFilter; - if(eventFilter){ - try { - return eventFilter.call(elt, evt) !== true; - } catch(e) { - triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); - return true; - } - } - return false; - } - - function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { - var elementData = getInternalData(elt); - var eltsToListenOn; - if (triggerSpec.from) { - eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); - } else { - eltsToListenOn = [elt]; - } - // store the initial values of the elements, so we can tell if they change - if (triggerSpec.changed) { - eltsToListenOn.forEach(function (eltToListenOn) { - var eltToListenOnData = getInternalData(eltToListenOn); - eltToListenOnData.lastValue = eltToListenOn.value; - }) - } - forEach(eltsToListenOn, function (eltToListenOn) { - var eventListener = function (evt) { - if (!bodyContains(elt)) { - eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); - return; - } - if (ignoreBoostedAnchorCtrlClick(elt, evt)) { - return; - } - if (explicitCancel || shouldCancel(evt, elt)) { - evt.preventDefault(); - } - if (maybeFilterEvent(triggerSpec, elt, evt)) { - return; - } - var eventData = getInternalData(evt); - eventData.triggerSpec = triggerSpec; - if (eventData.handledFor == null) { - eventData.handledFor = []; - } - if (eventData.handledFor.indexOf(elt) < 0) { - eventData.handledFor.push(elt); - if (triggerSpec.consume) { - evt.stopPropagation(); - } - if (triggerSpec.target && evt.target) { - if (!matches(evt.target, triggerSpec.target)) { - return; - } - } - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } - } - if (triggerSpec.changed) { - var eltToListenOnData = getInternalData(eltToListenOn) - if (eltToListenOnData.lastValue === eltToListenOn.value) { - return; - } - eltToListenOnData.lastValue = eltToListenOn.value - } - if (elementData.delayed) { - clearTimeout(elementData.delayed); - } - if (elementData.throttle) { - return; - } - - if (triggerSpec.throttle > 0) { - if (!elementData.throttle) { - handler(elt, evt); - elementData.throttle = setTimeout(function () { - elementData.throttle = null; - }, triggerSpec.throttle); - } - } else if (triggerSpec.delay > 0) { - elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); - } else { - triggerEvent(elt, 'htmx:trigger') - handler(elt, evt); - } - } - }; - if (nodeData.listenerInfos == null) { - nodeData.listenerInfos = []; - } - nodeData.listenerInfos.push({ - trigger: triggerSpec.trigger, - listener: eventListener, - on: eltToListenOn - }) - eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); - }); - } - - var windowIsScrolling = false // used by initScrollHandler - var scrollHandler = null; - function initScrollHandler() { - if (!scrollHandler) { - scrollHandler = function() { - windowIsScrolling = true - }; - window.addEventListener("scroll", scrollHandler) - setInterval(function() { - if (windowIsScrolling) { - windowIsScrolling = false; - forEach(getDocument().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"), function (elt) { - maybeReveal(elt); - }) - } - }, 200); - } - } - - function maybeReveal(elt) { - if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { - elt.setAttribute('data-hx-revealed', 'true'); - var nodeData = getInternalData(elt); - if (nodeData.initHash) { - triggerEvent(elt, 'revealed'); - } else { - // if the node isn't initialized, wait for it before triggering the request - elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true}); - } - } - } - - //==================================================================== - // Web Sockets - //==================================================================== - - function processWebSocketInfo(elt, nodeData, info) { - var values = splitOnWhitespace(info); - for (var i = 0; i < values.length; i++) { - var value = values[i].split(/:(.+)/); - if (value[0] === "connect") { - ensureWebSocket(elt, value[1], 0); - } - if (value[0] === "send") { - processWebSocketSend(elt); - } - } - } - - function ensureWebSocket(elt, wssSource, retryCount) { - if (!bodyContains(elt)) { - return; // stop ensuring websocket connection when socket bearing element ceases to exist - } - - if (wssSource.indexOf("/") == 0) { // complete absolute paths only - var base_part = location.hostname + (location.port ? ':'+location.port: ''); - if (location.protocol == 'https:') { - wssSource = "wss://" + base_part + wssSource; - } else if (location.protocol == 'http:') { - wssSource = "ws://" + base_part + wssSource; - } - } - var socket = htmx.createWebSocket(wssSource); - socket.onerror = function (e) { - triggerErrorEvent(elt, "htmx:wsError", {error:e, socket:socket}); - maybeCloseWebSocketSource(elt); - }; - - socket.onclose = function (e) { - if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later - var delay = getWebSocketReconnectDelay(retryCount); - setTimeout(function() { - ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout - }, delay); - } - }; - socket.onopen = function (e) { - retryCount = 0; - } - - getInternalData(elt).webSocket = socket; - socket.addEventListener('message', function (event) { - if (maybeCloseWebSocketSource(elt)) { - return; - } - - var response = event.data; - withExtensions(elt, function(extension){ - response = extension.transformResponse(response, null, elt); - }); - - var settleInfo = makeSettleInfo(elt); - var fragment = makeFragment(response); - var children = toArray(fragment.children); - for (var i = 0; i < children.length; i++) { - var child = children[i]; - oobSwap(getAttributeValue(child, "hx-swap-oob") || "true", child, settleInfo); - } - - settleImmediately(settleInfo.tasks); - }); - } - - function maybeCloseWebSocketSource(elt) { - if (!bodyContains(elt)) { - getInternalData(elt).webSocket.close(); - return true; - } - } - - function processWebSocketSend(elt) { - var webSocketSourceElt = getClosestMatch(elt, function (parent) { - return getInternalData(parent).webSocket != null; - }); - if (webSocketSourceElt) { - elt.addEventListener(getTriggerSpecs(elt)[0].trigger, function (evt) { - var webSocket = getInternalData(webSocketSourceElt).webSocket; - var headers = getHeaders(elt, webSocketSourceElt); - var results = getInputValues(elt, 'post'); - var errors = results.errors; - var rawParameters = results.values; - var expressionVars = getExpressionVars(elt); - var allParameters = mergeObjects(rawParameters, expressionVars); - var filteredParameters = filterValues(allParameters, elt); - filteredParameters['HEADERS'] = headers; - if (errors && errors.length > 0) { - triggerEvent(elt, 'htmx:validation:halted', errors); - return; - } - webSocket.send(JSON.stringify(filteredParameters)); - if(shouldCancel(evt, elt)){ - evt.preventDefault(); - } - }); - } else { - triggerErrorEvent(elt, "htmx:noWebSocketSourceError"); - } - } - - function getWebSocketReconnectDelay(retryCount) { - var delay = htmx.config.wsReconnectDelay; - if (typeof delay === 'function') { - // @ts-ignore - return delay(retryCount); - } - if (delay === 'full-jitter') { - var exp = Math.min(retryCount, 6); - var maxDelay = 1000 * Math.pow(2, exp); - return maxDelay * Math.random(); - } - logError('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"'); - } - - //==================================================================== - // Server Sent Events - //==================================================================== - - function processSSEInfo(elt, nodeData, info) { - var values = splitOnWhitespace(info); - for (var i = 0; i < values.length; i++) { - var value = values[i].split(/:(.+)/); - if (value[0] === "connect") { - processSSESource(elt, value[1]); - } - - if ((value[0] === "swap")) { - processSSESwap(elt, value[1]) - } - } - } - - function processSSESource(elt, sseSrc) { - var source = htmx.createEventSource(sseSrc); - source.onerror = function (e) { - triggerErrorEvent(elt, "htmx:sseError", {error:e, source:source}); - maybeCloseSSESource(elt); - }; - getInternalData(elt).sseEventSource = source; - } - - function processSSESwap(elt, sseEventName) { - var sseSourceElt = getClosestMatch(elt, hasEventSource); - if (sseSourceElt) { - var sseEventSource = getInternalData(sseSourceElt).sseEventSource; - var sseListener = function (event) { - if (maybeCloseSSESource(sseSourceElt)) { - return; - } - if (!bodyContains(elt)) { - sseEventSource.removeEventListener(sseEventName, sseListener); - return; - } - - /////////////////////////// - // TODO: merge this code with AJAX and WebSockets code in the future. - - var response = event.data; - withExtensions(elt, function(extension){ - response = extension.transformResponse(response, null, elt); - }); - - var swapSpec = getSwapSpecification(elt) - var target = getTarget(elt) - var settleInfo = makeSettleInfo(elt); - - selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) - settleImmediately(settleInfo.tasks) - triggerEvent(elt, "htmx:sseMessage", event) - }; - - getInternalData(elt).sseListener = sseListener; - sseEventSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "htmx:noSSESourceError"); - } - } - - function processSSETrigger(elt, handler, sseEventName) { - var sseSourceElt = getClosestMatch(elt, hasEventSource); - if (sseSourceElt) { - var sseEventSource = getInternalData(sseSourceElt).sseEventSource; - var sseListener = function () { - if (!maybeCloseSSESource(sseSourceElt)) { - if (bodyContains(elt)) { - handler(elt); - } else { - sseEventSource.removeEventListener(sseEventName, sseListener); - } - } - }; - getInternalData(elt).sseListener = sseListener; - sseEventSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "htmx:noSSESourceError"); - } - } - - function maybeCloseSSESource(elt) { - if (!bodyContains(elt)) { - getInternalData(elt).sseEventSource.close(); - return true; - } - } - - function hasEventSource(node) { - return getInternalData(node).sseEventSource != null; - } - - //==================================================================== - - function loadImmediately(elt, handler, nodeData, delay) { - var load = function(){ - if (!nodeData.loaded) { - nodeData.loaded = true; - handler(elt); - } - } - if (delay > 0) { - setTimeout(load, delay); - } else { - load(); - } - } - - function processVerbs(elt, nodeData, triggerSpecs) { - var explicitAction = false; - forEach(VERBS, function (verb) { - if (hasAttribute(elt,'hx-' + verb)) { - var path = getAttributeValue(elt, 'hx-' + verb); - explicitAction = true; - nodeData.path = path; - nodeData.verb = verb; - triggerSpecs.forEach(function(triggerSpec) { - addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return - } - issueAjaxRequest(verb, path, elt, evt) - }) - }); - } - }); - return explicitAction; - } - - function addTriggerHandler(elt, triggerSpec, nodeData, handler) { - if (triggerSpec.sseEvent) { - processSSETrigger(elt, handler, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - addEventListener(elt, handler, nodeData, triggerSpec); - maybeReveal(elt); - } else if (triggerSpec.trigger === "intersect") { - var observerOptions = {}; - if (triggerSpec.root) { - observerOptions.root = querySelectorExt(elt, triggerSpec.root) - } - if (triggerSpec.threshold) { - observerOptions.threshold = parseFloat(triggerSpec.threshold); - } - var observer = new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - if (entry.isIntersecting) { - triggerEvent(elt, "intersect"); - break; - } - } - }, observerOptions); - observer.observe(elt); - addEventListener(elt, handler, nodeData, triggerSpec); - } else if (triggerSpec.trigger === "load") { - if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { - loadImmediately(elt, handler, nodeData, triggerSpec.delay); - } - } else if (triggerSpec.pollInterval > 0) { - nodeData.polling = true; - processPolling(elt, handler, triggerSpec); - } else { - addEventListener(elt, handler, nodeData, triggerSpec); - } - } - - function evalScript(script) { - if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) { - var newScript = getDocument().createElement("script"); - forEach(script.attributes, function (attr) { - newScript.setAttribute(attr.name, attr.value); - }); - newScript.textContent = script.textContent; - newScript.async = false; - if (htmx.config.inlineScriptNonce) { - newScript.nonce = htmx.config.inlineScriptNonce; - } - var parent = script.parentElement; - - try { - parent.insertBefore(newScript, script); - } catch (e) { - logError(e); - } finally { - // remove old script element, but only if it is still in DOM - if (script.parentElement) { - script.parentElement.removeChild(script); - } - } - } - } - - function processScripts(elt) { - if (matches(elt, "script")) { - evalScript(elt); - } - forEach(findAll(elt, "script"), function (script) { - evalScript(script); - }); - } - - function shouldProcessHxOn(elt) { - var attributes = elt.attributes - for (var j = 0; j < attributes.length; j++) { - var attrName = attributes[j].name - if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") || - startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) { - return true - } - } - return false - } - - function findHxOnWildcardElements(elt) { - var node = null - var elements = [] - - if (shouldProcessHxOn(elt)) { - elements.push(elt) - } - - if (document.evaluate) { - var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + - ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt) - while (node = iter.iterateNext()) elements.push(node) - } else { - var allElements = elt.getElementsByTagName("*") - for (var i = 0; i < allElements.length; i++) { - if (shouldProcessHxOn(allElements[i])) { - elements.push(allElements[i]) - } - } - } - - return elements - } - - function findElementsToProcess(elt) { - if (elt.querySelectorAll) { - var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; - var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]"); - return results; - } else { - return []; - } - } - - // Handle submit buttons/inputs that have the form attribute set - // see https://developer.mozilla.org/docs/Web/HTML/Element/button - function maybeSetLastButtonClicked(evt) { - var elt = closest(evt.target, "button, input[type='submit']"); - var internalData = getRelatedFormData(evt) - if (internalData) { - internalData.lastButtonClicked = elt; - } - }; - function maybeUnsetLastButtonClicked(evt){ - var internalData = getRelatedFormData(evt) - if (internalData) { - internalData.lastButtonClicked = null; - } - } - function getRelatedFormData(evt) { - var elt = closest(evt.target, "button, input[type='submit']"); - if (!elt) { - return; - } - var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form'); - if (!form) { - return; - } - return getInternalData(form); - } - function initButtonTracking(elt) { - // need to handle both click and focus in: - // focusin - in case someone tabs in to a button and hits the space bar - // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 - elt.addEventListener('click', maybeSetLastButtonClicked) - elt.addEventListener('focusin', maybeSetLastButtonClicked) - elt.addEventListener('focusout', maybeUnsetLastButtonClicked) - } - - function countCurlies(line) { - var tokens = tokenizeString(line); - var netCurlies = 0; - for (var i = 0; i < tokens.length; i++) { - const token = tokens[i]; - if (token === "{") { - netCurlies++; - } else if (token === "}") { - netCurlies--; - } - } - return netCurlies; - } - - function addHxOnEventHandler(elt, eventName, code) { - var nodeData = getInternalData(elt); - if (!Array.isArray(nodeData.onHandlers)) { - nodeData.onHandlers = []; - } - var func; - var listener = function (e) { - return maybeEval(elt, function() { - if (!func) { - func = new Function("event", code); - } - func.call(elt, e); - }); - }; - elt.addEventListener(eventName, listener); - nodeData.onHandlers.push({event:eventName, listener:listener}); - } - - function processHxOn(elt) { - var hxOnValue = getAttributeValue(elt, 'hx-on'); - if (hxOnValue) { - var handlers = {} - var lines = hxOnValue.split("\n"); - var currentEvent = null; - var curlyCount = 0; - while (lines.length > 0) { - var line = lines.shift(); - var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/); - if (curlyCount === 0 && match) { - line.split(":") - currentEvent = match[1].slice(0, -1); // strip last colon - handlers[currentEvent] = match[2]; - } else { - handlers[currentEvent] += line; - } - curlyCount += countCurlies(line); - } - - for (var eventName in handlers) { - addHxOnEventHandler(elt, eventName, handlers[eventName]); - } - } - } - - function processHxOnWildcard(elt) { - // wipe any previous on handlers so that this function takes precedence - deInitOnHandlers(elt) - - for (var i = 0; i < elt.attributes.length; i++) { - var name = elt.attributes[i].name - var value = elt.attributes[i].value - if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) { - var afterOnPosition = name.indexOf("-on") + 3; - var nextChar = name.slice(afterOnPosition, afterOnPosition + 1); - if (nextChar === "-" || nextChar === ":") { - var eventName = name.slice(afterOnPosition + 1); - // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support - if (startsWith(eventName, ":")) { - eventName = "htmx" + eventName - } else if (startsWith(eventName, "-")) { - eventName = "htmx:" + eventName.slice(1); - } else if (startsWith(eventName, "htmx-")) { - eventName = "htmx:" + eventName.slice(5); - } - - addHxOnEventHandler(elt, eventName, value) - } - } - } - } - - function initNode(elt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return; - } - var nodeData = getInternalData(elt); - if (nodeData.initHash !== attributeHash(elt)) { - // clean up any previously processed info - deInitNode(elt); - - nodeData.initHash = attributeHash(elt); - - processHxOn(elt); - - triggerEvent(elt, "htmx:beforeProcessNode") - - if (elt.value) { - nodeData.lastValue = elt.value; - } - - var triggerSpecs = getTriggerSpecs(elt); - var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs); - - if (!hasExplicitHttpAction) { - if (getClosestAttributeValue(elt, "hx-boost") === "true") { - boostElement(elt, nodeData, triggerSpecs); - } else if (hasAttribute(elt, 'hx-trigger')) { - triggerSpecs.forEach(function (triggerSpec) { - // For "naked" triggers, don't do anything at all - addTriggerHandler(elt, triggerSpec, nodeData, function () { - }) - }) - } - } - - // Handle submit buttons/inputs that have the form attribute set - // see https://developer.mozilla.org/docs/Web/HTML/Element/button - if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) { - initButtonTracking(elt) - } - - var sseInfo = getAttributeValue(elt, 'hx-sse'); - if (sseInfo) { - processSSEInfo(elt, nodeData, sseInfo); - } - - var wsInfo = getAttributeValue(elt, 'hx-ws'); - if (wsInfo) { - processWebSocketInfo(elt, nodeData, wsInfo); - } - triggerEvent(elt, "htmx:afterProcessNode"); - } - } - - function processNode(elt) { - elt = resolveTarget(elt); - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return; - } - initNode(elt); - forEach(findElementsToProcess(elt), function(child) { initNode(child) }); - // Because it happens second, the new way of adding onHandlers superseeds the old one - // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored - forEach(findHxOnWildcardElements(elt), processHxOnWildcard); - } - - //==================================================================== - // Event/Log Support - //==================================================================== - - function kebabEventName(str) { - return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase(); - } - - 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({error:eventName}, detail)); - } - - function ignoreEventForLogging(eventName) { - return eventName === "htmx:afterProcessNode" - } - - /** - * `withExtensions` locates all active extensions for a provided element, then - * executes the provided function using each of the active extensions. It should - * be called internally at every extendable execution point in htmx. - * - * @param {HTMLElement} elt - * @param {(extension:import("./htmx").HtmxExtension) => void} toDo - * @returns void - */ - function withExtensions(elt, toDo) { - forEach(getExtensions(elt), function(extension){ - try { - toDo(extension); - } catch (e) { - logError(e); - } - }); - } - - function logError(msg) { - if(console.error) { - console.error(msg); - } else if (console.log) { - console.log("ERROR: ", msg); - } - } - - function triggerEvent(elt, eventName, detail) { - elt = resolveTarget(elt); - if (detail == null) { - detail = {}; - } - detail["elt"] = elt; - var event = makeEvent(eventName, detail); - if (htmx.logger && !ignoreEventForLogging(eventName)) { - htmx.logger(elt, eventName, detail); - } - if (detail.error) { - logError(detail.error); - triggerEvent(elt, "htmx:error", {errorInfo:detail}) - } - var eventResult = elt.dispatchEvent(event); - var kebabName = kebabEventName(eventName); - if (eventResult && kebabName !== eventName) { - var kebabedEvent = makeEvent(kebabName, event.detail); - eventResult = eventResult && elt.dispatchEvent(kebabedEvent) - } - withExtensions(elt, function (extension) { - eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) - }); - return eventResult; - } - - //==================================================================== - // History Support - //==================================================================== - var currentPathForHistory = location.pathname+location.search; - - function getHistoryElement() { - var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]'); - return historyElt || getDocument().body; - } - - function saveToHistoryCache(url, content, title, scroll) { - if (!canAccessLocalStorage()) { - return; - } - - if (htmx.config.historyCacheSize <= 0) { - // make sure that an eventually already existing cache is purged - localStorage.removeItem("htmx-history-cache"); - return; - } - - url = normalizePath(url); - - var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - historyCache.splice(i, 1); - break; - } - } - var newHistoryItem = {url:url, content: content, title:title, scroll:scroll}; - triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache}) - historyCache.push(newHistoryItem) - while (historyCache.length > htmx.config.historyCacheSize) { - historyCache.shift(); - } - while(historyCache.length > 0){ - try { - localStorage.setItem("htmx-history-cache", JSON.stringify(historyCache)); - break; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:historyCacheError", {cause:e, cache: historyCache}) - historyCache.shift(); // shrink the cache and retry - } - } - } - - function getCachedHistory(url) { - if (!canAccessLocalStorage()) { - return null; - } - - url = normalizePath(url); - - var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - return historyCache[i]; - } - } - return null; - } - - function cleanInnerHtmlForHistory(elt) { - var className = htmx.config.requestClass; - var clone = elt.cloneNode(true); - forEach(findAll(clone, "." + className), function(child){ - removeClassFromElement(child, className); - }); - return clone.innerHTML; - } - - function saveCurrentPageToHistory() { - var elt = getHistoryElement(); - var path = currentPathForHistory || location.pathname+location.search; - - // Allow history snapshot feature to be disabled where hx-history="false" - // is present *anywhere* in the current document we're about to save, - // so we can prevent privileged data entering the cache. - // The page will still be reachable as a history entry, but htmx will fetch it - // live from the server onpopstate rather than look in the localStorage cache - var disableHistoryCache - try { - disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') - } catch (e) { - // IE11: insensitive modifier not supported so fallback to case sensitive selector - disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') - } - if (!disableHistoryCache) { - triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt}); - saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); - } - - if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href); - } - - function pushUrlIntoHistory(path) { - // remove the cache buster parameter, if any - if (htmx.config.getCacheBusterParam) { - path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') - if (endsWith(path, '&') || endsWith(path, "?")) { - path = path.slice(0, -1); - } - } - if(htmx.config.historyEnabled) { - history.pushState({htmx:true}, "", path); - } - currentPathForHistory = path; - } - - function replaceUrlInHistory(path) { - if(htmx.config.historyEnabled) history.replaceState({htmx:true}, "", path); - currentPathForHistory = path; - } - - function settleImmediately(tasks) { - forEach(tasks, function (task) { - task.call(); - }); - } - - function loadHistoryFromServer(path) { - var request = new XMLHttpRequest(); - var details = {path: path, xhr:request}; - triggerEvent(getDocument().body, "htmx:historyCacheMiss", details); - request.open('GET', path, true); - request.setRequestHeader("HX-Request", "true"); - request.setRequestHeader("HX-History-Restore-Request", "true"); - request.setRequestHeader("HX-Current-URL", getDocument().location.href); - request.onload = function () { - if (this.status >= 200 && this.status < 400) { - triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); - var fragment = makeFragment(this.response); - // @ts-ignore - fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; - var historyElement = getHistoryElement(); - var settleInfo = makeSettleInfo(historyElement); - var title = findTitle(this.response); - if (title) { - var titleElt = find("title"); - if (titleElt) { - titleElt.innerHTML = title; - } else { - window.document.title = title; - } - } - // @ts-ignore - swapInnerHTML(historyElement, fragment, settleInfo) - settleImmediately(settleInfo.tasks); - currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response}); - } else { - triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details); - } - }; - request.send(); - } - - function restoreHistory(path) { - saveCurrentPageToHistory(); - path = path || location.pathname+location.search; - var cached = getCachedHistory(path); - if (cached) { - var fragment = makeFragment(cached.content); - var historyElement = getHistoryElement(); - var settleInfo = makeSettleInfo(historyElement); - swapInnerHTML(historyElement, fragment, settleInfo) - settleImmediately(settleInfo.tasks); - document.title = cached.title; - setTimeout(function () { - window.scrollTo(0, cached.scroll); - }, 0); // next 'tick', so browser has time to render layout - currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); - } else { - if (htmx.config.refreshOnHistoryMiss) { - - // @ts-ignore: optional parameter in reload() function throws error - window.location.reload(true); - } else { - loadHistoryFromServer(path); - } - } - } - - function addRequestIndicatorClasses(elt) { - var indicators = findAttributeTargets(elt, 'hx-indicator'); - if (indicators == null) { - indicators = [elt]; - } - forEach(indicators, function (ic) { - var internalData = getInternalData(ic); - internalData.requestCount = (internalData.requestCount || 0) + 1; - ic.classList["add"].call(ic.classList, htmx.config.requestClass); - }); - return indicators; - } - - function disableElements(elt) { - var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt'); - if (disabledElts == null) { - disabledElts = []; - } - forEach(disabledElts, function (disabledElement) { - var internalData = getInternalData(disabledElement); - internalData.requestCount = (internalData.requestCount || 0) + 1; - disabledElement.setAttribute("disabled", ""); - }); - return disabledElts; - } - - function removeRequestIndicators(indicators, disabled) { - forEach(indicators, function (ic) { - var internalData = getInternalData(ic); - internalData.requestCount = (internalData.requestCount || 0) - 1; - if (internalData.requestCount === 0) { - ic.classList["remove"].call(ic.classList, htmx.config.requestClass); - } - }); - forEach(disabled, function (disabledElement) { - var internalData = getInternalData(disabledElement); - internalData.requestCount = (internalData.requestCount || 0) - 1; - if (internalData.requestCount === 0) { - disabledElement.removeAttribute('disabled'); - } - }); - } - - //==================================================================== - // 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 || closest(elt, "fieldset[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 addValueToValues(name, value, values) { - // This is a little ugly because both the current value of the named value in the form - // and the new value could be arrays, so we have to handle all four cases :/ - if (name != null && value != null) { - var current = values[name]; - if (current === undefined) { - values[name] = value; - } else if (Array.isArray(current)) { - if (Array.isArray(value)) { - values[name] = current.concat(value); - } else { - current.push(value); - } - } else { - if (Array.isArray(value)) { - values[name] = [current].concat(value); - } else { - values[name] = [current, value]; - } - } - } - } - - function processInputValue(processed, values, errors, elt, validate) { - if (elt == null || haveSeenNode(processed, elt)) { - return; - } else { - processed.push(elt); - } - if (shouldInclude(elt)) { - var name = getRawAttribute(elt,"name"); - var value = elt.value; - if (elt.multiple && elt.tagName === "SELECT") { - value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value }); - } - // include file inputs - if (elt.files) { - value = toArray(elt.files); - } - addValueToValues(name, value, values); - if (validate) { - validateElement(elt, errors); - } - } - if (matches(elt, 'form')) { - var inputs = elt.elements; - forEach(inputs, function(input) { - processInputValue(processed, values, errors, input, validate); - }); - } - } - - function validateElement(element, errors) { - if (element.willValidate) { - triggerEvent(element, "htmx:validation:validate") - if (!element.checkValidity()) { - errors.push({elt: element, message:element.validationMessage, validity:element.validity}); - triggerEvent(element, "htmx:validation:failed", {message:element.validationMessage, validity:element.validity}) - } - } - } - - /** - * @param {HTMLElement} elt - * @param {string} verb - */ - function getInputValues(elt, verb) { - var processed = []; - var values = {}; - var formValues = {}; - var errors = []; - var internalData = getInternalData(elt); - if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { - internalData.lastButtonClicked = null - } - - // only validate when form is directly submitted and novalidate or formnovalidate are not set - // or if the element has an explicit hx-validate="true" on it - var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true"; - if (internalData.lastButtonClicked) { - validate = validate && internalData.lastButtonClicked.formNoValidate !== true; - } - - // for a non-GET include the closest form - if (verb !== 'get') { - processInputValue(processed, formValues, errors, closest(elt, 'form'), validate); - } - - // include the element itself - processInputValue(processed, values, errors, elt, validate); - - // if a button or submit was clicked last, include its value - if (internalData.lastButtonClicked || elt.tagName === "BUTTON" || - (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) { - var button = internalData.lastButtonClicked || elt - var name = getRawAttribute(button, "name") - addValueToValues(name, button.value, formValues) - } - - // include any explicit includes - var includes = findAttributeTargets(elt, "hx-include"); - forEach(includes, function(node) { - processInputValue(processed, values, errors, node, validate); - // if a non-form is included, include any input values within it - if (!matches(node, 'form')) { - forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { - processInputValue(processed, values, errors, descendant, validate); - }) - } - }); - - // form values take precedence, overriding the regular values - values = mergeObjects(values, formValues); - - return {errors:errors, values:values}; - } - - function appendParam(returnStr, name, realValue) { - if (returnStr !== "") { - returnStr += "&"; - } - if (String(realValue) === "[object Object]") { - realValue = JSON.stringify(realValue); - } - var s = encodeURIComponent(realValue); - returnStr += encodeURIComponent(name) + "=" + s; - 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; - } - - function makeFormData(values) { - var formData = new FormData(); - for (var name in values) { - if (values.hasOwnProperty(name)) { - var value = values[name]; - if (Array.isArray(value)) { - forEach(value, function(v) { - formData.append(name, v); - }); - } else { - formData.append(name, value); - } - } - } - return formData; - } - - //==================================================================== - // Ajax - //==================================================================== - - /** - * @param {HTMLElement} elt - * @param {HTMLElement} target - * @param {string} prompt - * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification - */ - function getHeaders(elt, target, prompt) { - var headers = { - "HX-Request" : "true", - "HX-Trigger" : getRawAttribute(elt, "id"), - "HX-Trigger-Name" : getRawAttribute(elt, "name"), - "HX-Target" : getAttributeValue(target, "id"), - "HX-Current-URL" : getDocument().location.href, - } - getValuesForElement(elt, "hx-headers", false, headers) - if (prompt !== undefined) { - headers["HX-Prompt"] = prompt; - } - if (getInternalData(elt).boosted) { - headers["HX-Boosted"] = "true"; - } - return headers; - } - - /** - * filterValues takes an object containing form input values - * and returns a new object that only contains keys that are - * specified by the closest "hx-params" attribute - * @param {Object} inputValues - * @param {HTMLElement} elt - * @returns {Object} - */ - function filterValues(inputValues, elt) { - var paramsValue = getClosestAttributeValue(elt, "hx-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 isAnchorLink(elt) { - return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0 - } - - /** - * - * @param {HTMLElement} elt - * @param {string} swapInfoOverride - * @returns {import("./htmx").HtmxSwapSpecification} - */ - function getSwapSpecification(elt, swapInfoOverride) { - var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap"); - var swapSpec = { - "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, - "swapDelay" : htmx.config.defaultSwapDelay, - "settleDelay" : htmx.config.defaultSettleDelay - } - if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { - swapSpec["show"] = "top" - } - if (swapInfo) { - var split = splitOnWhitespace(swapInfo); - if (split.length > 0) { - for (var i = 0; i < split.length; i++) { - var value = split[i]; - if (value.indexOf("swap:") === 0) { - swapSpec["swapDelay"] = parseInterval(value.substr(5)); - } else if (value.indexOf("settle:") === 0) { - swapSpec["settleDelay"] = parseInterval(value.substr(7)); - } else if (value.indexOf("transition:") === 0) { - swapSpec["transition"] = value.substr(11) === "true"; - } else if (value.indexOf("ignoreTitle:") === 0) { - swapSpec["ignoreTitle"] = value.substr(12) === "true"; - } else if (value.indexOf("scroll:") === 0) { - var scrollSpec = value.substr(7); - var splitSpec = scrollSpec.split(":"); - var scrollVal = splitSpec.pop(); - var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; - swapSpec["scroll"] = scrollVal; - swapSpec["scrollTarget"] = selectorVal; - } else if (value.indexOf("show:") === 0) { - var showSpec = value.substr(5); - var splitSpec = showSpec.split(":"); - var showVal = splitSpec.pop(); - var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; - swapSpec["show"] = showVal; - swapSpec["showTarget"] = selectorVal; - } else if (value.indexOf("focus-scroll:") === 0) { - var focusScrollVal = value.substr("focus-scroll:".length); - swapSpec["focusScroll"] = focusScrollVal == "true"; - } else if (i == 0) { - swapSpec["swapStyle"] = value; - } else { - logError('Unknown modifier in hx-swap: ' + value); - } - } - } - } - return swapSpec; - } - - function usesFormData(elt) { - return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || - (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data"); - } - - function encodeParamsForBody(xhr, elt, filteredParameters) { - var encodedParameters = null; - withExtensions(elt, function (extension) { - if (encodedParameters == null) { - encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt); - } - }); - if (encodedParameters != null) { - return encodedParameters; - } else { - if (usesFormData(elt)) { - return makeFormData(filteredParameters); - } else { - return urlEncode(filteredParameters); - } - } - } - - /** - * - * @param {Element} target - * @returns {import("./htmx").HtmxSettleInfo} - */ - function makeSettleInfo(target) { - return {tasks: [], elts: [target]}; - } - - function updateScrollState(content, swapSpec) { - var first = content[0]; - var last = content[content.length - 1]; - if (swapSpec.scroll) { - var target = null; - if (swapSpec.scrollTarget) { - target = querySelectorExt(first, swapSpec.scrollTarget); - } - if (swapSpec.scroll === "top" && (first || target)) { - target = target || first; - target.scrollTop = 0; - } - if (swapSpec.scroll === "bottom" && (last || target)) { - target = target || last; - target.scrollTop = target.scrollHeight; - } - } - if (swapSpec.show) { - var target = null; - if (swapSpec.showTarget) { - var targetStr = swapSpec.showTarget; - if (swapSpec.showTarget === "window") { - targetStr = "body"; - } - target = querySelectorExt(first, targetStr); - } - if (swapSpec.show === "top" && (first || target)) { - target = target || first; - target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior}); - } - if (swapSpec.show === "bottom" && (last || target)) { - target = target || last; - target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior}); - } - } - } - - /** - * @param {HTMLElement} elt - * @param {string} attr - * @param {boolean=} evalAsDefault - * @param {Object=} values - * @returns {Object} - */ - function getValuesForElement(elt, attr, evalAsDefault, values) { - if (values == null) { - values = {}; - } - if (elt == null) { - return values; - } - var attributeValue = getAttributeValue(elt, attr); - if (attributeValue) { - var str = attributeValue.trim(); - var evaluateValue = evalAsDefault; - if (str === "unset") { - return null; - } - if (str.indexOf("javascript:") === 0) { - str = str.substr(11); - evaluateValue = true; - } else if (str.indexOf("js:") === 0) { - str = str.substr(3); - evaluateValue = true; - } - if (str.indexOf('{') !== 0) { - str = "{" + str + "}"; - } - var varsValues; - if (evaluateValue) { - varsValues = maybeEval(elt,function () {return Function("return (" + str + ")")();}, {}); - } else { - varsValues = parseJSON(str); - } - for (var key in varsValues) { - if (varsValues.hasOwnProperty(key)) { - if (values[key] == null) { - values[key] = varsValues[key]; - } - } - } - } - return getValuesForElement(parentElt(elt), attr, evalAsDefault, values); - } - - function maybeEval(elt, toEval, defaultVal) { - if (htmx.config.allowEval) { - return toEval(); - } else { - triggerErrorEvent(elt, 'htmx:evalDisallowedError'); - return defaultVal; - } - } - - /** - * @param {HTMLElement} elt - * @param {*} expressionVars - * @returns - */ - function getHXVarsForElement(elt, expressionVars) { - return getValuesForElement(elt, "hx-vars", true, expressionVars); - } - - /** - * @param {HTMLElement} elt - * @param {*} expressionVars - * @returns - */ - function getHXValsForElement(elt, expressionVars) { - return getValuesForElement(elt, "hx-vals", false, expressionVars); - } - - /** - * @param {HTMLElement} elt - * @returns {Object} - */ - function getExpressionVars(elt) { - return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)); - } - - function safelySetHeaderValue(xhr, header, headerValue) { - if (headerValue !== null) { - try { - xhr.setRequestHeader(header, headerValue); - } catch (e) { - // On an exception, try to set the header URI encoded instead - xhr.setRequestHeader(header, encodeURIComponent(headerValue)); - xhr.setRequestHeader(header + "-URI-AutoEncoded", "true"); - } - } - } - - function getPathFromResponse(xhr) { - // NB: IE11 does not support this stuff - if (xhr.responseURL && typeof(URL) !== "undefined") { - try { - var url = new URL(xhr.responseURL); - return url.pathname + url.search; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:badResponseUrl", {url: xhr.responseURL}); - } - } - } - - function hasHeader(xhr, regexp) { - return regexp.test(xhr.getAllResponseHeaders()) - } - - function ajaxHelper(verb, path, context) { - verb = verb.toLowerCase(); - if (context) { - if (context instanceof Element || isType(context, 'String')) { - return issueAjaxRequest(verb, path, null, null, { - targetOverride: resolveTarget(context), - returnPromise: true - }); - } else { - return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, - { - handler : context.handler, - headers : context.headers, - values : context.values, - targetOverride: resolveTarget(context.target), - swapOverride: context.swap, - select: context.select, - returnPromise: true - }); - } - } else { - return issueAjaxRequest(verb, path, null, null, { - returnPromise: true - }); - } - } - - function hierarchyForElt(elt) { - var arr = []; - while (elt) { - arr.push(elt); - elt = elt.parentElement; - } - return arr; - } - - function verifyPath(elt, path, requestConfig) { - var sameHost - var url - if (typeof URL === "function") { - url = new URL(path, document.location.href); - var origin = document.location.origin; - sameHost = origin === url.origin; - } else { - // IE11 doesn't support URL - url = path - sameHost = startsWith(path, document.location.origin) - } - - if (htmx.config.selfRequestsOnly) { - if (!sameHost) { - return false; - } - } - return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig)); - } - - function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { - var resolve = null; - var reject = null; - etc = etc != null ? etc : {}; - if(etc.returnPromise && typeof Promise !== "undefined"){ - var promise = new Promise(function (_resolve, _reject) { - resolve = _resolve; - reject = _reject; - }); - } - if(elt == null) { - elt = getDocument().body; - } - var responseHandler = etc.handler || handleAjaxResponse; - var select = etc.select || null; - - if (!bodyContains(elt)) { - // do not issue requests for elements removed from the DOM - maybeCall(resolve); - return promise; - } - var target = etc.targetOverride || getTarget(elt); - if (target == null || target == DUMMY_ELT) { - triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); - maybeCall(reject); - return promise; - } - - var eltData = getInternalData(elt); - var submitter = eltData.lastButtonClicked; - - if (submitter) { - var buttonPath = getRawAttribute(submitter, "formaction"); - if (buttonPath != null) { - path = buttonPath; - } - - var buttonVerb = getRawAttribute(submitter, "formmethod") - if (buttonVerb != null) { - // ignore buttons with formmethod="dialog" - if (buttonVerb.toLowerCase() !== "dialog") { - verb = buttonVerb; - } - } - } - - var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); - // allow event-based confirmation w/ a callback - if (confirmed === undefined) { - var issueRequest = function(skipConfirmation) { - return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation); - } - var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion}; - if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { - maybeCall(resolve); - return promise; - } - } - - var syncElt = elt; - var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); - var queueStrategy = null; - var abortable = false; - if (syncStrategy) { - var syncStrings = syncStrategy.split(":"); - var selector = syncStrings[0].trim(); - if (selector === "this") { - syncElt = findThisElement(elt, 'hx-sync'); - } else { - syncElt = querySelectorExt(elt, selector); - } - // default to the drop strategy - syncStrategy = (syncStrings[1] || 'drop').trim(); - eltData = getInternalData(syncElt); - if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { - maybeCall(resolve); - return promise; - } else if (syncStrategy === "abort") { - if (eltData.xhr) { - maybeCall(resolve); - return promise; - } else { - abortable = true; - } - } else if (syncStrategy === "replace") { - triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue - } else if (syncStrategy.indexOf("queue") === 0) { - var queueStrArray = syncStrategy.split(" "); - queueStrategy = (queueStrArray[1] || "last").trim(); - } - } - - if (eltData.xhr) { - if (eltData.abortable) { - triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue - } else { - if(queueStrategy == null){ - if (event) { - var eventData = getInternalData(event); - if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { - queueStrategy = eventData.triggerSpec.queue; - } - } - if (queueStrategy == null) { - queueStrategy = "last"; - } - } - if (eltData.queuedRequests == null) { - eltData.queuedRequests = []; - } - if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } else if (queueStrategy === "all") { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } else if (queueStrategy === "last") { - eltData.queuedRequests = []; // dump existing queue - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } - maybeCall(resolve); - return promise; - } - } - - var xhr = new XMLHttpRequest(); - eltData.xhr = xhr; - eltData.abortable = abortable; - var endRequestLock = function(){ - eltData.xhr = null; - eltData.abortable = false; - if (eltData.queuedRequests != null && - eltData.queuedRequests.length > 0) { - var queuedRequest = eltData.queuedRequests.shift(); - queuedRequest(); - } - } - var promptQuestion = getClosestAttributeValue(elt, "hx-prompt"); - if (promptQuestion) { - var promptResponse = prompt(promptQuestion); - // prompt returns null if cancelled and empty string if accepted with no entry - if (promptResponse === null || - !triggerEvent(elt, 'htmx:prompt', {prompt: promptResponse, target:target})) { - maybeCall(resolve); - endRequestLock(); - return promise; - } + triggerErrorEvent(getDocument().body, 'htmx:syntax:error', { error: e, source: conditionalSource }) + return null } + } + } else if (token === '[') { + bracketCount++ + } + if (isPossibleRelativeReference(token, last, paramName)) { + conditionalSource += '((' + paramName + '.' + token + ') ? (' + paramName + '.' + token + ') : (window.' + token + '))' + } else { + conditionalSource = conditionalSource + token + } + last = tokens.shift() + } + } + } + + /** + * @param {string[]} tokens + * @param {RegExp} match + * @returns {string} + */ + function consumeUntil(tokens, match) { + let result = '' + while (tokens.length > 0 && !match.test(tokens[0])) { + result += tokens.shift() + } + return result + } + + /** + * @param {string[]} tokens + * @returns {string} + */ + function consumeCSSSelector(tokens) { + let result + if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { + tokens.shift() + result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim() + tokens.shift() + } else { + result = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } + return result + } + + const INPUT_SELECTOR = 'input, textarea, select' + + /** + * @param {Element} elt + * @param {string} explicitTrigger + * @param {Object} cache for trigger specs + * @returns {HtmxTriggerSpecification[]} + */ + function parseAndCacheTrigger(elt, explicitTrigger, cache) { + /** @type HtmxTriggerSpecification[] */ + const triggerSpecs = [] + const tokens = tokenizeString(explicitTrigger) + do { + consumeUntil(tokens, NOT_WHITESPACE) + const initialLength = tokens.length + const trigger = consumeUntil(tokens, /[,\[\s]/) + if (trigger !== '') { + if (trigger === 'every') { + /** @type HtmxTriggerSpecification */ + const every = { trigger: 'every' } + consumeUntil(tokens, NOT_WHITESPACE) + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)) + consumeUntil(tokens, NOT_WHITESPACE) + var eventFilter = maybeGenerateConditional(elt, tokens, 'event') + if (eventFilter) { + every.eventFilter = eventFilter + } + triggerSpecs.push(every) + } else { + /** @type HtmxTriggerSpecification */ + const triggerSpec = { trigger } + var eventFilter = maybeGenerateConditional(elt, tokens, 'event') + if (eventFilter) { + triggerSpec.eventFilter = eventFilter + } + while (tokens.length > 0 && tokens[0] !== ',') { + consumeUntil(tokens, NOT_WHITESPACE) + const token = tokens.shift() + if (token === 'changed') { + triggerSpec.changed = true + } else if (token === 'once') { + triggerSpec.once = true + } else if (token === 'consume') { + triggerSpec.consume = true + } else if (token === 'delay' && tokens[0] === ':') { + tokens.shift() + triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)) + } else if (token === 'from' && tokens[0] === ':') { + tokens.shift() + if (COMBINED_SELECTOR_START.test(tokens[0])) { + var from_arg = consumeCSSSelector(tokens) + } else { + var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA) + if (from_arg === 'closest' || from_arg === 'find' || from_arg === 'next' || from_arg === 'previous') { + tokens.shift() + const selector = consumeCSSSelector(tokens) + // `next` and `previous` allow a selector-less syntax + if (selector.length > 0) { + from_arg += ' ' + selector + } + } + } + triggerSpec.from = from_arg + } else if (token === 'target' && tokens[0] === ':') { + tokens.shift() + triggerSpec.target = consumeCSSSelector(tokens) + } else if (token === 'throttle' && tokens[0] === ':') { + tokens.shift() + triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)) + } else if (token === 'queue' && tokens[0] === ':') { + tokens.shift() + triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } else if (token === 'root' && tokens[0] === ':') { + tokens.shift() + triggerSpec[token] = consumeCSSSelector(tokens) + } else if (token === 'threshold' && tokens[0] === ':') { + tokens.shift() + triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } else { + triggerErrorEvent(elt, 'htmx:syntax:error', { token: tokens.shift() }) + } + } + triggerSpecs.push(triggerSpec) + } + } + if (tokens.length === initialLength) { + triggerErrorEvent(elt, 'htmx:syntax:error', { token: tokens.shift() }) + } + consumeUntil(tokens, NOT_WHITESPACE) + } while (tokens[0] === ',' && tokens.shift()) + if (cache) { + cache[explicitTrigger] = triggerSpecs + } + return triggerSpecs + } + + /** + * @param {Element} elt + * @returns {HtmxTriggerSpecification[]} + */ + function getTriggerSpecs(elt) { + const explicitTrigger = getAttributeValue(elt, 'hx-trigger') + let triggerSpecs = [] + if (explicitTrigger) { + const cache = htmx.config.triggerSpecsCache + triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) + } - if (confirmQuestion && !confirmed) { - if(!confirm(confirmQuestion)) { - maybeCall(resolve); - endRequestLock() - return promise; - } + if (triggerSpecs.length > 0) { + return triggerSpecs + } else if (matches(elt, 'form')) { + return [{ trigger: 'submit' }] + } else if (matches(elt, 'input[type="button"], input[type="submit"]')) { + return [{ trigger: 'click' }] + } else if (matches(elt, INPUT_SELECTOR)) { + return [{ trigger: 'change' }] + } else { + return [{ trigger: 'click' }] + } + } + + /** + * @param {Element} elt + */ + function cancelPolling(elt) { + getInternalData(elt).cancelled = true + } + + /** + * @param {Element} elt + * @param {TriggerHandler} handler + * @param {HtmxTriggerSpecification} spec + */ + function processPolling(elt, handler, spec) { + const nodeData = getInternalData(elt) + nodeData.timeout = getWindow().setTimeout(function() { + if (bodyContains(elt) && nodeData.cancelled !== true) { + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { + handler(elt) + } + processPolling(elt, handler, spec) + } + }, spec.pollInterval) + } + + /** + * @param {HTMLAnchorElement} elt + * @returns {boolean} + */ + function isLocalLink(elt) { + return location.hostname === elt.hostname && + getRawAttribute(elt, 'href') && + getRawAttribute(elt, 'href').indexOf('#') !== 0 + } + + /** + * @param {Element} elt + */ + function eltIsDisabled(elt) { + return closest(elt, htmx.config.disableSelector) + } + + /** + * @param {Element} elt + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification[]} triggerSpecs + */ + function boostElement(elt, nodeData, triggerSpecs) { + if ((elt instanceof HTMLAnchorElement && isLocalLink(elt) && (elt.target === '' || elt.target === '_self')) || elt.tagName === 'FORM') { + nodeData.boosted = true + let verb, path + if (elt.tagName === 'A') { + verb = 'get' + path = getRawAttribute(elt, 'href') + } else { + const rawAttribute = getRawAttribute(elt, 'method') + verb = rawAttribute ? rawAttribute.toLowerCase() : 'get' + if (verb === 'get') { + } + path = getRawAttribute(elt, 'action') + } + triggerSpecs.forEach(function(triggerSpec) { + addEventListener(elt, function(node, evt) { + const elt = asElement(node) + if (eltIsDisabled(elt)) { + cleanUpElement(elt) + return + } + issueAjaxRequest(verb, path, elt, evt) + }, nodeData, triggerSpec, true) + }) + } + } + + /** + * @param {Event} evt + * @param {Node} node + * @returns {boolean} + */ + function shouldCancel(evt, node) { + const elt = asElement(node) + if (!elt) { + return false + } + if (evt.type === 'submit' || evt.type === 'click') { + if (elt.tagName === 'FORM') { + return true + } + if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { + return true + } + if (elt instanceof HTMLAnchorElement && elt.href && + (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf('#') !== 0)) { + return true + } + } + return false + } + + /** + * @param {Node} elt + * @param {Event|MouseEvent|KeyboardEvent|TouchEvent} evt + * @returns {boolean} + */ + function ignoreBoostedAnchorCtrlClick(elt, evt) { + return getInternalData(elt).boosted && elt instanceof HTMLAnchorElement && evt.type === 'click' && + // @ts-ignore this will resolve to undefined for events that don't define those properties, which is fine + (evt.ctrlKey || evt.metaKey) + } + + /** + * @param {HtmxTriggerSpecification} triggerSpec + * @param {Node} elt + * @param {Event} evt + * @returns {boolean} + */ + function maybeFilterEvent(triggerSpec, elt, evt) { + const eventFilter = triggerSpec.eventFilter + if (eventFilter) { + try { + return eventFilter.call(elt, evt) !== true + } catch (e) { + const source = eventFilter.source + triggerErrorEvent(getDocument().body, 'htmx:eventFilter:error', { error: e, source }) + return true + } + } + return false + } + + /** + * @param {Node} elt + * @param {TriggerHandler} handler + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification} triggerSpec + * @param {boolean} [explicitCancel] + */ + function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { + const elementData = getInternalData(elt) + /** @type {(Node|Window)[]} */ + let eltsToListenOn + if (triggerSpec.from) { + eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from) + } else { + eltsToListenOn = [elt] + } + // store the initial values of the elements, so we can tell if they change + if (triggerSpec.changed) { + eltsToListenOn.forEach(function(eltToListenOn) { + const eltToListenOnData = getInternalData(eltToListenOn) + // @ts-ignore value will be undefined for non-input elements, which is fine + eltToListenOnData.lastValue = eltToListenOn.value + }) + } + forEach(eltsToListenOn, function(eltToListenOn) { + /** @type EventListener */ + const eventListener = function(evt) { + if (!bodyContains(elt)) { + eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener) + return + } + if (ignoreBoostedAnchorCtrlClick(elt, evt)) { + return + } + if (explicitCancel || shouldCancel(evt, elt)) { + evt.preventDefault() + } + if (maybeFilterEvent(triggerSpec, elt, evt)) { + return + } + const eventData = getInternalData(evt) + eventData.triggerSpec = triggerSpec + if (eventData.handledFor == null) { + eventData.handledFor = [] + } + if (eventData.handledFor.indexOf(elt) < 0) { + eventData.handledFor.push(elt) + if (triggerSpec.consume) { + evt.stopPropagation() + } + if (triggerSpec.target && evt.target) { + if (!matches(asElement(evt.target), triggerSpec.target)) { + return + } + } + if (triggerSpec.once) { + if (elementData.triggeredOnce) { + return + } else { + elementData.triggeredOnce = true + } + } + if (triggerSpec.changed) { + const eltToListenOnData = getInternalData(eltToListenOn) + // @ts-ignore value will be undefined for non-input elements, which is fine + const value = eltToListenOn.value + if (eltToListenOnData.lastValue === value) { + return + } + eltToListenOnData.lastValue = value + } + if (elementData.delayed) { + clearTimeout(elementData.delayed) + } + if (elementData.throttle) { + return + } + + if (triggerSpec.throttle > 0) { + if (!elementData.throttle) { + handler(elt, evt) + elementData.throttle = getWindow().setTimeout(function() { + elementData.throttle = null + }, triggerSpec.throttle) + } + } else if (triggerSpec.delay > 0) { + elementData.delayed = getWindow().setTimeout(function() { handler(elt, evt) }, triggerSpec.delay) + } else { + triggerEvent(elt, 'htmx:trigger') + handler(elt, evt) + } + } + } + if (nodeData.listenerInfos == null) { + nodeData.listenerInfos = [] + } + nodeData.listenerInfos.push({ + trigger: triggerSpec.trigger, + listener: eventListener, + on: eltToListenOn + }) + eltToListenOn.addEventListener(triggerSpec.trigger, eventListener) + }) + } + + let windowIsScrolling = false // used by initScrollHandler + let scrollHandler = null + function initScrollHandler() { + if (!scrollHandler) { + scrollHandler = function() { + windowIsScrolling = true + } + window.addEventListener('scroll', scrollHandler) + setInterval(function() { + if (windowIsScrolling) { + windowIsScrolling = false + forEach(getDocument().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"), function(elt) { + maybeReveal(elt) + }) + } + }, 200) + } + } + + /** + * @param {Element} elt + */ + function maybeReveal(elt) { + if (!hasAttribute(elt, 'data-hx-revealed') && isScrolledIntoView(elt)) { + elt.setAttribute('data-hx-revealed', 'true') + const nodeData = getInternalData(elt) + if (nodeData.initHash) { + triggerEvent(elt, 'revealed') + } else { + // if the node isn't initialized, wait for it before triggering the request + elt.addEventListener('htmx:afterProcessNode', function() { triggerEvent(elt, 'revealed') }, { once: true }) + } + } + } + + //= =================================================================== + + /** + * @param {Element} elt + * @param {TriggerHandler} handler + * @param {HtmxNodeInternalData} nodeData + * @param {number} delay + */ + function loadImmediately(elt, handler, nodeData, delay) { + const load = function() { + if (!nodeData.loaded) { + nodeData.loaded = true + handler(elt) + } + } + if (delay > 0) { + getWindow().setTimeout(load, delay) + } else { + load() + } + } + + /** + * @param {Element} elt + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification[]} triggerSpecs + * @returns {boolean} + */ + function processVerbs(elt, nodeData, triggerSpecs) { + let explicitAction = false + forEach(VERBS, function(verb) { + if (hasAttribute(elt, 'hx-' + verb)) { + const path = getAttributeValue(elt, 'hx-' + verb) + explicitAction = true + nodeData.path = path + nodeData.verb = verb + triggerSpecs.forEach(function(triggerSpec) { + addTriggerHandler(elt, triggerSpec, nodeData, function(node, evt) { + const elt = asElement(node) + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return } + issueAjaxRequest(verb, path, elt, evt) + }) + }) + } + }) + return explicitAction + } + + /** + * @callback TriggerHandler + * @param {Node} elt + * @param {Event} [evt] + */ + + /** + * @param {Node} elt + * @param {HtmxTriggerSpecification} triggerSpec + * @param {HtmxNodeInternalData} nodeData + * @param {TriggerHandler} handler + */ + function addTriggerHandler(elt, triggerSpec, nodeData, handler) { + if (triggerSpec.trigger === 'revealed') { + initScrollHandler() + addEventListener(elt, handler, nodeData, triggerSpec) + maybeReveal(asElement(elt)) + } else if (triggerSpec.trigger === 'intersect') { + const observerOptions = {} + if (triggerSpec.root) { + observerOptions.root = querySelectorExt(elt, triggerSpec.root) + } + if (triggerSpec.threshold) { + observerOptions.threshold = parseFloat(triggerSpec.threshold) + } + const observer = new IntersectionObserver(function(entries) { + for (let i = 0; i < entries.length; i++) { + const entry = entries[i] + if (entry.isIntersecting) { + triggerEvent(elt, 'intersect') + break + } + } + }, observerOptions) + observer.observe(asElement(elt)) + addEventListener(asElement(elt), handler, nodeData, triggerSpec) + } else if (triggerSpec.trigger === 'load') { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent('load', { elt }))) { + loadImmediately(asElement(elt), handler, nodeData, triggerSpec.delay) + } + } else if (triggerSpec.pollInterval > 0) { + nodeData.polling = true + processPolling(asElement(elt), handler, triggerSpec) + } else { + addEventListener(elt, handler, nodeData, triggerSpec) + } + } + + /** + * @param {Node} node + * @returns {boolean} + */ + function shouldProcessHxOn(node) { + const elt = asElement(node) + if (!elt) { + return false + } + const attributes = elt.attributes + for (let j = 0; j < attributes.length; j++) { + const attrName = attributes[j].name + if (startsWith(attrName, 'hx-on:') || startsWith(attrName, 'data-hx-on:') || + startsWith(attrName, 'hx-on-') || startsWith(attrName, 'data-hx-on-')) { + return true + } + } + return false + } + + /** + * @param {Node} elt + * @returns {Element[]} + */ + const HX_ON_QUERY = new XPathEvaluator() + .createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + + ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]') + + function processHXOnRoot(elt, elements) { + if (shouldProcessHxOn(elt)) { + elements.push(asElement(elt)) + } + const iter = HX_ON_QUERY.evaluate(elt) + let node = null + while (node = iter.iterateNext()) elements.push(asElement(node)) + } + + function findHxOnWildcardElements(elt) { + /** @type {Element[]} */ + const elements = [] + if (elt instanceof DocumentFragment) { + for (const child of elt.childNodes) { + processHXOnRoot(child, elements) + } + } else { + processHXOnRoot(elt, elements) + } + return elements + } + + /** + * @param {Element} elt + * @returns {NodeListOf<Element>|[]} + */ + function findElementsToProcess(elt) { + if (elt.querySelectorAll) { + const boostedSelector = ', [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]' + + const extensionSelectors = [] + for (const e in extensions) { + const extension = extensions[e] + if (extension.getSelectors) { + var selectors = extension.getSelectors() + if (selectors) { + extensionSelectors.push(selectors) + } + } + } + + const results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit']," + + ' [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]' + extensionSelectors.flat().map(s => ', ' + s).join('')) + + return results + } else { + return [] + } + } + + /** + * Handle submit buttons/inputs that have the form attribute set + * see https://developer.mozilla.org/docs/Web/HTML/Element/button + * @param {Event} evt + */ + function maybeSetLastButtonClicked(evt) { + const elt = /** @type {HTMLButtonElement|HTMLInputElement} */ (closest(asElement(evt.target), "button, input[type='submit']")) + const internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = elt + } + } + + /** + * @param {Event} evt + */ + function maybeUnsetLastButtonClicked(evt) { + const internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = null + } + } + + /** + * @param {Event} evt + * @returns {HtmxNodeInternalData|undefined} + */ + function getRelatedFormData(evt) { + const elt = closest(asElement(evt.target), "button, input[type='submit']") + if (!elt) { + return + } + const form = resolveTarget('#' + getRawAttribute(elt, 'form'), elt.getRootNode()) || closest(elt, 'form') + if (!form) { + return + } + return getInternalData(form) + } + + /** + * @param {EventTarget} elt + */ + function initButtonTracking(elt) { + // need to handle both click and focus in: + // focusin - in case someone tabs in to a button and hits the space bar + // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + elt.addEventListener('click', maybeSetLastButtonClicked) + elt.addEventListener('focusin', maybeSetLastButtonClicked) + elt.addEventListener('focusout', maybeUnsetLastButtonClicked) + } + + /** + * @param {Element} elt + * @param {string} eventName + * @param {string} code + */ + function addHxOnEventHandler(elt, eventName, code) { + const nodeData = getInternalData(elt) + if (!Array.isArray(nodeData.onHandlers)) { + nodeData.onHandlers = [] + } + let func + /** @type EventListener */ + const listener = function(e) { + maybeEval(elt, function() { + if (eltIsDisabled(elt)) { + return + } + if (!func) { + func = new Function('event', code) + } + func.call(elt, e) + }) + } + elt.addEventListener(eventName, listener) + nodeData.onHandlers.push({ event: eventName, listener }) + } + + /** + * @param {Element} elt + */ + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (let i = 0; i < elt.attributes.length; i++) { + const name = elt.attributes[i].name + const value = elt.attributes[i].value + if (startsWith(name, 'hx-on') || startsWith(name, 'data-hx-on')) { + const afterOnPosition = name.indexOf('-on') + 3 + const nextChar = name.slice(afterOnPosition, afterOnPosition + 1) + if (nextChar === '-' || nextChar === ':') { + let eventName = name.slice(afterOnPosition + 1) + // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support + if (startsWith(eventName, ':')) { + eventName = 'htmx' + eventName + } else if (startsWith(eventName, '-')) { + eventName = 'htmx:' + eventName.slice(1) + } else if (startsWith(eventName, 'htmx-')) { + eventName = 'htmx:' + eventName.slice(5) + } + + addHxOnEventHandler(elt, eventName, value) + } + } + } + } + + /** + * @param {Element|HTMLInputElement} elt + */ + function initNode(elt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + const nodeData = getInternalData(elt) + if (nodeData.initHash !== attributeHash(elt)) { + // clean up any previously processed info + deInitNode(elt) + + nodeData.initHash = attributeHash(elt) + + triggerEvent(elt, 'htmx:beforeProcessNode') + + // @ts-ignore value will be undefined for non-input elements, which is fine + if (elt.value) { + // @ts-ignore + nodeData.lastValue = elt.value + } + + const triggerSpecs = getTriggerSpecs(elt) + const hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs) + + if (!hasExplicitHttpAction) { + if (getClosestAttributeValue(elt, 'hx-boost') === 'true') { + boostElement(elt, nodeData, triggerSpecs) + } else if (hasAttribute(elt, 'hx-trigger')) { + triggerSpecs.forEach(function(triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function() { + }) + }) + } + } + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + if (elt.tagName === 'FORM' || (getRawAttribute(elt, 'type') === 'submit' && hasAttribute(elt, 'form'))) { + initButtonTracking(elt) + } - var headers = getHeaders(elt, target, promptResponse); - - if (verb !== 'get' && !usesFormData(elt)) { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; - } + triggerEvent(elt, 'htmx:afterProcessNode') + } + } + + /** + * Processes new content, enabling htmx behavior. This can be useful if you have content that is added to the DOM outside of the normal htmx request cycle but still want htmx attributes to work. + * + * @see https://htmx.org/api/#process + * + * @param {Element|string} elt element to process + */ + function processNode(elt) { + elt = resolveTarget(elt) + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + initNode(elt) + forEach(findElementsToProcess(elt), function(child) { initNode(child) }) + forEach(findHxOnWildcardElements(elt), processHxOnWildcard) + } + + //= =================================================================== + // Event/Log Support + //= =================================================================== + + /** + * @param {string} str + * @returns {string} + */ + function kebabEventName(str) { + return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase() + } + + /** + * @param {string} eventName + * @param {any} detail + * @returns {CustomEvent} + */ + function makeEvent(eventName, detail) { + let evt + if (window.CustomEvent && typeof window.CustomEvent === 'function') { + // TODO: `composed: true` here is a hack to make global event handlers work with events in shadow DOM + // This breaks expected encapsulation but needs to be here until decided otherwise by core devs + evt = new CustomEvent(eventName, { bubbles: true, cancelable: true, composed: true, detail }) + } else { + evt = getDocument().createEvent('CustomEvent') + evt.initCustomEvent(eventName, true, true, detail) + } + return evt + } + + /** + * @param {EventTarget|string} elt + * @param {string} eventName + * @param {any=} detail + */ + function triggerErrorEvent(elt, eventName, detail) { + triggerEvent(elt, eventName, mergeObjects({ error: eventName }, detail)) + } + + /** + * @param {string} eventName + * @returns {boolean} + */ + function ignoreEventForLogging(eventName) { + return eventName === 'htmx:afterProcessNode' + } + + /** + * `withExtensions` locates all active extensions for a provided element, then + * executes the provided function using each of the active extensions. It should + * be called internally at every extendable execution point in htmx. + * + * @param {Element} elt + * @param {(extension:HtmxExtension) => void} toDo + * @returns void + */ + function withExtensions(elt, toDo) { + forEach(getExtensions(elt), function(extension) { + try { + toDo(extension) + } catch (e) { + logError(e) + } + }) + } + + function logError(msg) { + if (console.error) { + console.error(msg) + } else if (console.log) { + console.log('ERROR: ', msg) + } + } + + /** + * Triggers a given event on an element + * + * @see https://htmx.org/api/#trigger + * + * @param {EventTarget|string} elt the element to trigger the event on + * @param {string} eventName the name of the event to trigger + * @param {any=} detail details for the event + * @returns {boolean} + */ + function triggerEvent(elt, eventName, detail) { + elt = resolveTarget(elt) + if (detail == null) { + detail = {} + } + detail.elt = elt + const event = makeEvent(eventName, detail) + if (htmx.logger && !ignoreEventForLogging(eventName)) { + htmx.logger(elt, eventName, detail) + } + if (detail.error) { + logError(detail.error) + triggerEvent(elt, 'htmx:error', { errorInfo: detail }) + } + let eventResult = elt.dispatchEvent(event) + const kebabName = kebabEventName(eventName) + if (eventResult && kebabName !== eventName) { + const kebabedEvent = makeEvent(kebabName, event.detail) + eventResult = eventResult && elt.dispatchEvent(kebabedEvent) + } + withExtensions(asElement(elt), function(extension) { + eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) + }) + return eventResult + } + + //= =================================================================== + // History Support + //= =================================================================== + let currentPathForHistory = location.pathname + location.search + + /** + * @returns {Element} + */ + function getHistoryElement() { + const historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]') + return historyElt || getDocument().body + } + + /** + * @param {string} url + * @param {Element} rootElt + */ + function saveToHistoryCache(url, rootElt) { + if (!canAccessLocalStorage()) { + return + } - if (etc.headers) { - headers = mergeObjects(headers, etc.headers); - } - var results = getInputValues(elt, verb); - var errors = results.errors; - var rawParameters = results.values; - if (etc.values) { - rawParameters = mergeObjects(rawParameters, etc.values); - } - var expressionVars = getExpressionVars(elt); - var allParameters = mergeObjects(rawParameters, expressionVars); - var filteredParameters = filterValues(allParameters, elt); + // get state to save + const innerHTML = cleanInnerHtmlForHistory(rootElt) + const title = getDocument().title + const scroll = window.scrollY - if (htmx.config.getCacheBusterParam && verb === 'get') { - filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true"; - } + if (htmx.config.historyCacheSize <= 0) { + // make sure that an eventually already existing cache is purged + localStorage.removeItem('htmx-history-cache') + return + } - // behavior of anchors w/ empty href is to use the current URL - if (path == null || path === "") { - path = getDocument().location.href; - } + url = normalizePath(url) + const historyCache = parseJSON(localStorage.getItem('htmx-history-cache')) || [] + for (let i = 0; i < historyCache.length; i++) { + if (historyCache[i].url === url) { + historyCache.splice(i, 1) + break + } + } - var requestAttrValues = getValuesForElement(elt, 'hx-request'); + /** @type HtmxHistoryItem */ + const newHistoryItem = { url, content: innerHTML, title, scroll } - var eltIsBoosted = getInternalData(elt).boosted; + triggerEvent(getDocument().body, 'htmx:historyItemCreated', { item: newHistoryItem, cache: historyCache }) - var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + historyCache.push(newHistoryItem) + while (historyCache.length > htmx.config.historyCacheSize) { + historyCache.shift() + } - var requestConfig = { - boosted: eltIsBoosted, - useUrlParams: useUrlParams, - parameters: filteredParameters, - unfilteredParameters: allParameters, - headers:headers, - target:target, - verb:verb, - errors:errors, - withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, - timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, - path:path, - triggeringEvent:event - }; + // keep trying to save the cache until it succeeds or is empty + while (historyCache.length > 0) { + try { + localStorage.setItem('htmx-history-cache', JSON.stringify(historyCache)) + break + } catch (e) { + triggerErrorEvent(getDocument().body, 'htmx:historyCacheError', { cause: e, cache: historyCache }) + historyCache.shift() // shrink the cache and retry + } + } + } + + /** + * @typedef {Object} HtmxHistoryItem + * @property {string} url + * @property {string} content + * @property {string} title + * @property {number} scroll + */ + + /** + * @param {string} url + * @returns {HtmxHistoryItem|null} + */ + function getCachedHistory(url) { + if (!canAccessLocalStorage()) { + return null + } - if(!triggerEvent(elt, 'htmx:configRequest', requestConfig)){ - maybeCall(resolve); - endRequestLock(); - return promise; - } + url = normalizePath(url) - // copy out in case the object was overwritten - path = requestConfig.path; - verb = requestConfig.verb; - headers = requestConfig.headers; - filteredParameters = requestConfig.parameters; - errors = requestConfig.errors; - useUrlParams = requestConfig.useUrlParams; - - if(errors && errors.length > 0){ - triggerEvent(elt, 'htmx:validation:halted', requestConfig) - maybeCall(resolve); - endRequestLock(); - return promise; - } + const historyCache = parseJSON(localStorage.getItem('htmx-history-cache')) || [] + for (let i = 0; i < historyCache.length; i++) { + if (historyCache[i].url === url) { + return historyCache[i] + } + } + return null + } + + /** + * @param {Element} elt + * @returns {string} + */ + function cleanInnerHtmlForHistory(elt) { + const className = htmx.config.requestClass + const clone = /** @type Element */ (elt.cloneNode(true)) + forEach(findAll(clone, '.' + className), function(child) { + removeClassFromElement(child, className) + }) + return clone.innerHTML + } + + function saveCurrentPageToHistory() { + const elt = getHistoryElement() + const path = currentPathForHistory || location.pathname + location.search + + // Allow history snapshot feature to be disabled where hx-history="false" + // is present *anywhere* in the current document we're about to save, + // so we can prevent privileged data entering the cache. + // The page will still be reachable as a history entry, but htmx will fetch it + // live from the server onpopstate rather than look in the localStorage cache + let disableHistoryCache + try { + disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') + } catch (e) { + // IE11: insensitive modifier not supported so fallback to case sensitive selector + disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') + } + if (!disableHistoryCache) { + triggerEvent(getDocument().body, 'htmx:beforeHistorySave', { path, historyElt: elt }) + saveToHistoryCache(path, elt) + } - var splitPath = path.split("#"); - var pathNoAnchor = splitPath[0]; - var anchor = splitPath[1]; - - var finalPath = path - if (useUrlParams) { - finalPath = pathNoAnchor; - var values = Object.keys(filteredParameters).length !== 0; - if (values) { - if (finalPath.indexOf("?") < 0) { - finalPath += "?"; - } else { - finalPath += "&"; - } - finalPath += urlEncode(filteredParameters); - if (anchor) { - finalPath += "#" + anchor; - } - } - } + if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, getDocument().title, window.location.href) + } + + /** + * @param {string} path + */ + function pushUrlIntoHistory(path) { + // remove the cache buster parameter, if any + if (htmx.config.getCacheBusterParam) { + path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') + if (endsWith(path, '&') || endsWith(path, '?')) { + path = path.slice(0, -1) + } + } + if (htmx.config.historyEnabled) { + history.pushState({ htmx: true }, '', path) + } + currentPathForHistory = path + } + + /** + * @param {string} path + */ + function replaceUrlInHistory(path) { + if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, '', path) + currentPathForHistory = path + } + + /** + * @param {HtmxSettleTask[]} tasks + */ + function settleImmediately(tasks) { + forEach(tasks, function(task) { + task.call(undefined) + }) + } + + /** + * @param {string} path + */ + function loadHistoryFromServer(path) { + const request = new XMLHttpRequest() + const details = { path, xhr: request } + triggerEvent(getDocument().body, 'htmx:historyCacheMiss', details) + request.open('GET', path, true) + request.setRequestHeader('HX-Request', 'true') + request.setRequestHeader('HX-History-Restore-Request', 'true') + request.setRequestHeader('HX-Current-URL', getDocument().location.href) + request.onload = function() { + if (this.status >= 200 && this.status < 400) { + triggerEvent(getDocument().body, 'htmx:historyCacheMissLoad', details) + const fragment = makeFragment(this.response) + /** @type ParentNode */ + const content = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment + const historyElement = getHistoryElement() + const settleInfo = makeSettleInfo(historyElement) + handleTitle(fragment.title) + + swapInnerHTML(historyElement, content, settleInfo) + settleImmediately(settleInfo.tasks) + currentPathForHistory = path + triggerEvent(getDocument().body, 'htmx:historyRestore', { path, cacheMiss: true, serverResponse: this.response }) + } else { + triggerErrorEvent(getDocument().body, 'htmx:historyCacheMissLoadError', details) + } + } + request.send() + } + + /** + * @param {string} [path] + */ + function restoreHistory(path) { + saveCurrentPageToHistory() + path = path || location.pathname + location.search + const cached = getCachedHistory(path) + if (cached) { + const fragment = makeFragment(cached.content) + const historyElement = getHistoryElement() + const settleInfo = makeSettleInfo(historyElement) + handleTitle(fragment.title) + swapInnerHTML(historyElement, fragment, settleInfo) + settleImmediately(settleInfo.tasks) + getWindow().setTimeout(function() { + window.scrollTo(0, cached.scroll) + }, 0) // next 'tick', so browser has time to render layout + currentPathForHistory = path + triggerEvent(getDocument().body, 'htmx:historyRestore', { path, item: cached }) + } else { + if (htmx.config.refreshOnHistoryMiss) { + // @ts-ignore: optional parameter in reload() function throws error + // noinspection JSUnresolvedReference + window.location.reload(true) + } else { + loadHistoryFromServer(path) + } + } + } + + /** + * @param {Element} elt + * @returns {Element[]} + */ + function addRequestIndicatorClasses(elt) { + let indicators = /** @type Element[] */ (findAttributeTargets(elt, 'hx-indicator')) + if (indicators == null) { + indicators = [elt] + } + forEach(indicators, function(ic) { + const internalData = getInternalData(ic) + internalData.requestCount = (internalData.requestCount || 0) + 1 + ic.classList.add.call(ic.classList, htmx.config.requestClass) + }) + return indicators + } + + /** + * @param {Element} elt + * @returns {Element[]} + */ + function disableElements(elt) { + let disabledElts = /** @type Element[] */ (findAttributeTargets(elt, 'hx-disabled-elt')) + if (disabledElts == null) { + disabledElts = [] + } + forEach(disabledElts, function(disabledElement) { + const internalData = getInternalData(disabledElement) + internalData.requestCount = (internalData.requestCount || 0) + 1 + disabledElement.setAttribute('disabled', '') + }) + return disabledElts + } + + /** + * @param {Element[]} indicators + * @param {Element[]} disabled + */ + function removeRequestIndicators(indicators, disabled) { + forEach(indicators, function(ic) { + const internalData = getInternalData(ic) + internalData.requestCount = (internalData.requestCount || 0) - 1 + if (internalData.requestCount === 0) { + ic.classList.remove.call(ic.classList, htmx.config.requestClass) + } + }) + forEach(disabled, function(disabledElement) { + const internalData = getInternalData(disabledElement) + internalData.requestCount = (internalData.requestCount || 0) - 1 + if (internalData.requestCount === 0) { + disabledElement.removeAttribute('disabled') + } + }) + } + + //= =================================================================== + // Input Value Processing + //= =================================================================== + + /** + * @param {Element[]} processed + * @param {Element} elt + * @returns {boolean} + */ + function haveSeenNode(processed, elt) { + for (let i = 0; i < processed.length; i++) { + const node = processed[i] + if (node.isSameNode(elt)) { + return true + } + } + return false + } + + /** + * @param {Element} element + * @return {boolean} + */ + function shouldInclude(element) { + // Cast to trick tsc, undefined values will work fine here + const elt = /** @type {HTMLInputElement} */ (element) + if (elt.name === '' || elt.name == null || elt.disabled || closest(elt, 'fieldset[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 + } + + /** @param {string} name + * @param {string|Array|FormDataEntryValue} value + * @param {FormData} formData */ + function addValueToFormData(name, value, formData) { + if (name != null && value != null) { + if (Array.isArray(value)) { + value.forEach(function(v) { formData.append(name, v) }) + } else { + formData.append(name, value) + } + } + } + + /** @param {string} name + * @param {string|Array} value + * @param {FormData} formData */ + function removeValueFromFormData(name, value, formData) { + if (name != null && value != null) { + let values = formData.getAll(name) + if (Array.isArray(value)) { + values = values.filter(v => value.indexOf(v) < 0) + } else { + values = values.filter(v => v !== value) + } + formData.delete(name) + forEach(values, v => formData.append(name, v)) + } + } + + /** + * @param {Element[]} processed + * @param {FormData} formData + * @param {HtmxElementValidationError[]} errors + * @param {Element|HTMLInputElement|HTMLSelectElement|HTMLFormElement} elt + * @param {boolean} validate + */ + function processInputValue(processed, formData, errors, elt, validate) { + if (elt == null || haveSeenNode(processed, elt)) { + return + } else { + processed.push(elt) + } + if (shouldInclude(elt)) { + const name = getRawAttribute(elt, 'name') + // @ts-ignore value will be undefined for non-input elements, which is fine + let value = elt.value + if (elt instanceof HTMLSelectElement && elt.multiple) { + value = toArray(elt.querySelectorAll('option:checked')).map(function(e) { return (/** @type HTMLOptionElement */(e)).value }) + } + // include file inputs + if (elt instanceof HTMLInputElement && elt.files) { + value = toArray(elt.files) + } + addValueToFormData(name, value, formData) + if (validate) { + validateElement(elt, errors) + } + } + if (elt instanceof HTMLFormElement) { + forEach(elt.elements, function(input) { + if (processed.indexOf(input) >= 0) { + // The input has already been processed and added to the values, but the FormData that will be + // constructed right after on the form, will include it once again. So remove that input's value + // now to avoid duplicates + removeValueFromFormData(input.name, input.value, formData) + } else { + processed.push(input) + } + if (validate) { + validateElement(input, errors) + } + }) + new FormData(elt).forEach(function(value, name) { + if (value instanceof File && value.name === '') { + return // ignore no-name files + } + addValueToFormData(name, value, formData) + }) + } + } + + /** + * + * @param {Element} elt + * @param {HtmxElementValidationError[]} errors + */ + function validateElement(elt, errors) { + const element = /** @type {HTMLElement & ElementInternals} */ (elt) + if (element.willValidate) { + triggerEvent(element, 'htmx:validation:validate') + if (!element.checkValidity()) { + errors.push({ elt: element, message: element.validationMessage, validity: element.validity }) + triggerEvent(element, 'htmx:validation:failed', { message: element.validationMessage, validity: element.validity }) + } + } + } + + /** + * Override values in the one FormData with those from another. + * @param {FormData} receiver the formdata that will be mutated + * @param {FormData} donor the formdata that will provide the overriding values + * @returns {FormData} the {@linkcode receiver} + */ + function overrideFormData(receiver, donor) { + for (const key of donor.keys()) { + receiver.delete(key) + donor.getAll(key).forEach(function(value) { + receiver.append(key, value) + }) + } + return receiver + } + + /** + * @param {Element|HTMLFormElement} elt + * @param {HttpVerb} verb + * @returns {{errors: HtmxElementValidationError[], formData: FormData, values: Object}} + */ + function getInputValues(elt, verb) { + /** @type Element[] */ + const processed = [] + const formData = new FormData() + const priorityFormData = new FormData() + /** @type HtmxElementValidationError[] */ + const errors = [] + const internalData = getInternalData(elt) + if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { + internalData.lastButtonClicked = null + } - if (!verifyPath(elt, finalPath, requestConfig)) { - triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) - maybeCall(reject); - return promise; - }; + // only validate when form is directly submitted and novalidate or formnovalidate are not set + // or if the element has an explicit hx-validate="true" on it + let validate = (elt instanceof HTMLFormElement && elt.noValidate !== true) || getAttributeValue(elt, 'hx-validate') === 'true' + if (internalData.lastButtonClicked) { + validate = validate && internalData.lastButtonClicked.formNoValidate !== true + } - xhr.open(verb.toUpperCase(), finalPath, true); - xhr.overrideMimeType("text/html"); - xhr.withCredentials = requestConfig.withCredentials; - xhr.timeout = requestConfig.timeout; + // for a non-GET include the closest form + if (verb !== 'get') { + processInputValue(processed, priorityFormData, errors, closest(elt, 'form'), validate) + } - // request headers - if (requestAttrValues.noHeaders) { - // ignore all headers - } else { - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - var headerValue = headers[header]; - safelySetHeaderValue(xhr, header, headerValue); - } - } - } + // include the element itself + processInputValue(processed, formData, errors, elt, validate) - var responseInfo = { - xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select, - pathInfo: { - requestPath: path, - finalRequestPath: finalPath, - anchor: anchor - } - }; - - xhr.onload = function () { - try { - var hierarchy = hierarchyForElt(elt); - responseInfo.pathInfo.responsePath = getPathFromResponse(xhr); - responseHandler(elt, responseInfo); - removeRequestIndicators(indicators, disableElts); - triggerEvent(elt, 'htmx:afterRequest', responseInfo); - triggerEvent(elt, 'htmx:afterOnLoad', responseInfo); - // if the body no longer contains the element, trigger the event on the closest parent - // remaining in the DOM - if (!bodyContains(elt)) { - var secondaryTriggerElt = null; - while (hierarchy.length > 0 && secondaryTriggerElt == null) { - var parentEltInHierarchy = hierarchy.shift(); - if (bodyContains(parentEltInHierarchy)) { - secondaryTriggerElt = parentEltInHierarchy; - } - } - if (secondaryTriggerElt) { - triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo); - triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo); - } - } - maybeCall(resolve); - endRequestLock(); - } catch (e) { - triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({error:e}, responseInfo)); - throw e; - } - } - xhr.onerror = function () { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:sendError', responseInfo); - maybeCall(reject); - endRequestLock(); - } - xhr.onabort = function() { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo); - maybeCall(reject); - endRequestLock(); - } - xhr.ontimeout = function() { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:timeout', responseInfo); - maybeCall(reject); - endRequestLock(); - } - if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){ - maybeCall(resolve); - endRequestLock() - return promise - } - var indicators = addRequestIndicatorClasses(elt); - var disableElts = disableElements(elt); - - forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { - forEach([xhr, xhr.upload], function (target) { - target.addEventListener(eventName, function(event){ - triggerEvent(elt, "htmx:xhr:" + eventName, { - lengthComputable:event.lengthComputable, - loaded:event.loaded, - total:event.total - }); - }) - }); - }); - triggerEvent(elt, 'htmx:beforeSend', responseInfo); - var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) - xhr.send(params); - return promise; - } - - function determineHistoryUpdates(elt, responseInfo) { - - var xhr = responseInfo.xhr; - - //=========================================== - // First consult response headers - //=========================================== - var pathFromHeaders = null; - var typeFromHeaders = null; - if (hasHeader(xhr,/HX-Push:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Push"); - typeFromHeaders = "push"; - } else if (hasHeader(xhr,/HX-Push-Url:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Push-Url"); - typeFromHeaders = "push"; - } else if (hasHeader(xhr,/HX-Replace-Url:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url"); - typeFromHeaders = "replace"; - } + // if a button or submit was clicked last, include its value + if (internalData.lastButtonClicked || elt.tagName === 'BUTTON' || + (elt.tagName === 'INPUT' && getRawAttribute(elt, 'type') === 'submit')) { + const button = internalData.lastButtonClicked || (/** @type HTMLInputElement|HTMLButtonElement */(elt)) + const name = getRawAttribute(button, 'name') + addValueToFormData(name, button.value, priorityFormData) + } - // if there was a response header, that has priority - if (pathFromHeaders) { - if (pathFromHeaders === "false") { - return {} - } else { - return { - type: typeFromHeaders, - path : pathFromHeaders - } - } - } + // include any explicit includes + const includes = findAttributeTargets(elt, 'hx-include') + forEach(includes, function(node) { + processInputValue(processed, formData, errors, asElement(node), validate) + // if a non-form is included, include any input values within it + if (!matches(node, 'form')) { + forEach(asParentNode(node).querySelectorAll(INPUT_SELECTOR), function(descendant) { + processInputValue(processed, formData, errors, descendant, validate) + }) + } + }) + + // values from a <form> take precedence, overriding the regular values + overrideFormData(formData, priorityFormData) + + return { errors, formData, values: formDataProxy(formData) } + } + + /** + * @param {string} returnStr + * @param {string} name + * @param {any} realValue + * @returns {string} + */ + function appendParam(returnStr, name, realValue) { + if (returnStr !== '') { + returnStr += '&' + } + if (String(realValue) === '[object Object]') { + realValue = JSON.stringify(realValue) + } + const s = encodeURIComponent(realValue) + returnStr += encodeURIComponent(name) + '=' + s + return returnStr + } + + /** + * @param {FormData|Object} values + * @returns string + */ + function urlEncode(values) { + values = formDataFromObject(values) + let returnStr = '' + values.forEach(function(value, key) { + returnStr = appendParam(returnStr, key, value) + }) + return returnStr + } + + //= =================================================================== + // Ajax + //= =================================================================== + + /** + * @param {Element} elt + * @param {Element} target + * @param {string} prompt + * @returns {HtmxHeaderSpecification} + */ + function getHeaders(elt, target, prompt) { + /** @type HtmxHeaderSpecification */ + const headers = { + 'HX-Request': 'true', + 'HX-Trigger': getRawAttribute(elt, 'id'), + 'HX-Trigger-Name': getRawAttribute(elt, 'name'), + 'HX-Target': getAttributeValue(target, 'id'), + 'HX-Current-URL': getDocument().location.href + } + getValuesForElement(elt, 'hx-headers', false, headers) + if (prompt !== undefined) { + headers['HX-Prompt'] = prompt + } + if (getInternalData(elt).boosted) { + headers['HX-Boosted'] = 'true' + } + return headers + } + + /** + * filterValues takes an object containing form input values + * and returns a new object that only contains keys that are + * specified by the closest "hx-params" attribute + * @param {FormData} inputValues + * @param {Element} elt + * @returns {FormData} + */ + function filterValues(inputValues, elt) { + const paramsValue = getClosestAttributeValue(elt, 'hx-params') + if (paramsValue) { + if (paramsValue === 'none') { + return new FormData() + } else if (paramsValue === '*') { + return inputValues + } else if (paramsValue.indexOf('not ') === 0) { + forEach(paramsValue.substr(4).split(','), function(name) { + name = name.trim() + inputValues.delete(name) + }) + return inputValues + } else { + const newValues = new FormData() + forEach(paramsValue.split(','), function(name) { + name = name.trim() + if (inputValues.has(name)) { + inputValues.getAll(name).forEach(function(value) { newValues.append(name, value) }) + } + }) + return newValues + } + } else { + return inputValues + } + } + + /** + * @param {Element} elt + * @return {boolean} + */ + function isAnchorLink(elt) { + return !!getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf('#') >= 0 + } + + /** + * @param {Element} elt + * @param {HtmxSwapStyle} [swapInfoOverride] + * @returns {HtmxSwapSpecification} + */ + function getSwapSpecification(elt, swapInfoOverride) { + const swapInfo = swapInfoOverride || getClosestAttributeValue(elt, 'hx-swap') + /** @type HtmxSwapSpecification */ + const swapSpec = { + swapStyle: getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, + swapDelay: htmx.config.defaultSwapDelay, + settleDelay: htmx.config.defaultSettleDelay + } + if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { + swapSpec.show = 'top' + } + if (swapInfo) { + const split = splitOnWhitespace(swapInfo) + if (split.length > 0) { + for (let i = 0; i < split.length; i++) { + const value = split[i] + if (value.indexOf('swap:') === 0) { + swapSpec.swapDelay = parseInterval(value.substr(5)) + } else if (value.indexOf('settle:') === 0) { + swapSpec.settleDelay = parseInterval(value.substr(7)) + } else if (value.indexOf('transition:') === 0) { + swapSpec.transition = value.substr(11) === 'true' + } else if (value.indexOf('ignoreTitle:') === 0) { + swapSpec.ignoreTitle = value.substr(12) === 'true' + } else if (value.indexOf('scroll:') === 0) { + const scrollSpec = value.substr(7) + var splitSpec = scrollSpec.split(':') + const scrollVal = splitSpec.pop() + var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null + // @ts-ignore + swapSpec.scroll = scrollVal + swapSpec.scrollTarget = selectorVal + } else if (value.indexOf('show:') === 0) { + const showSpec = value.substr(5) + var splitSpec = showSpec.split(':') + const showVal = splitSpec.pop() + var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null + swapSpec.show = showVal + swapSpec.showTarget = selectorVal + } else if (value.indexOf('focus-scroll:') === 0) { + const focusScrollVal = value.substr('focus-scroll:'.length) + swapSpec.focusScroll = focusScrollVal == 'true' + } else if (i == 0) { + swapSpec.swapStyle = value + } else { + logError('Unknown modifier in hx-swap: ' + value) + } + } + } + } + return swapSpec + } + + /** + * @param {Element} elt + * @return {boolean} + */ + function usesFormData(elt) { + return getClosestAttributeValue(elt, 'hx-encoding') === 'multipart/form-data' || + (matches(elt, 'form') && getRawAttribute(elt, 'enctype') === 'multipart/form-data') + } + + /** + * @param {XMLHttpRequest} xhr + * @param {Element} elt + * @param {FormData} filteredParameters + * @returns {*|string|null} + */ + function encodeParamsForBody(xhr, elt, filteredParameters) { + let encodedParameters = null + withExtensions(elt, function(extension) { + if (encodedParameters == null) { + encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt) + } + }) + if (encodedParameters != null) { + return encodedParameters + } else { + if (usesFormData(elt)) { + // Force conversion to an actual FormData object in case filteredParameters is a formDataProxy + // See https://github.com/bigskysoftware/htmx/issues/2317 + return overrideFormData(new FormData(), formDataFromObject(filteredParameters)) + } else { + return urlEncode(filteredParameters) + } + } + } + + /** + * + * @param {Element} target + * @returns {HtmxSettleInfo} + */ + function makeSettleInfo(target) { + return { tasks: [], elts: [target] } + } + + /** + * @param {Element[]} content + * @param {HtmxSwapSpecification} swapSpec + */ + function updateScrollState(content, swapSpec) { + const first = content[0] + const last = content[content.length - 1] + if (swapSpec.scroll) { + var target = null + if (swapSpec.scrollTarget) { + target = asElement(querySelectorExt(first, swapSpec.scrollTarget)) + } + if (swapSpec.scroll === 'top' && (first || target)) { + target = target || first + target.scrollTop = 0 + } + if (swapSpec.scroll === 'bottom' && (last || target)) { + target = target || last + target.scrollTop = target.scrollHeight + } + } + if (swapSpec.show) { + var target = null + if (swapSpec.showTarget) { + let targetStr = swapSpec.showTarget + if (swapSpec.showTarget === 'window') { + targetStr = 'body' + } + target = asElement(querySelectorExt(first, targetStr)) + } + if (swapSpec.show === 'top' && (first || target)) { + target = target || first + // @ts-ignore For some reason tsc doesn't recognize "instant" as a valid option for now + target.scrollIntoView({ block: 'start', behavior: htmx.config.scrollBehavior }) + } + if (swapSpec.show === 'bottom' && (last || target)) { + target = target || last + // @ts-ignore For some reason tsc doesn't recognize "instant" as a valid option for now + target.scrollIntoView({ block: 'end', behavior: htmx.config.scrollBehavior }) + } + } + } + + /** + * @param {Element} elt + * @param {string} attr + * @param {boolean=} evalAsDefault + * @param {Object=} values + * @returns {Object} + */ + function getValuesForElement(elt, attr, evalAsDefault, values) { + if (values == null) { + values = {} + } + if (elt == null) { + return values + } + const attributeValue = getAttributeValue(elt, attr) + if (attributeValue) { + let str = attributeValue.trim() + let evaluateValue = evalAsDefault + if (str === 'unset') { + return null + } + if (str.indexOf('javascript:') === 0) { + str = str.substr(11) + evaluateValue = true + } else if (str.indexOf('js:') === 0) { + str = str.substr(3) + evaluateValue = true + } + if (str.indexOf('{') !== 0) { + str = '{' + str + '}' + } + let varsValues + if (evaluateValue) { + varsValues = maybeEval(elt, function() { return Function('return (' + str + ')')() }, {}) + } else { + varsValues = parseJSON(str) + } + for (const key in varsValues) { + if (varsValues.hasOwnProperty(key)) { + if (values[key] == null) { + values[key] = varsValues[key] + } + } + } + } + return getValuesForElement(asElement(parentElt(elt)), attr, evalAsDefault, values) + } + + /** + * @param {EventTarget|string} elt + * @param {() => any} toEval + * @param {any=} defaultVal + * @returns {any} + */ + function maybeEval(elt, toEval, defaultVal) { + if (htmx.config.allowEval) { + return toEval() + } else { + triggerErrorEvent(elt, 'htmx:evalDisallowedError') + return defaultVal + } + } + + /** + * @param {Element} elt + * @param {*?} expressionVars + * @returns + */ + function getHXVarsForElement(elt, expressionVars) { + return getValuesForElement(elt, 'hx-vars', true, expressionVars) + } + + /** + * @param {Element} elt + * @param {*?} expressionVars + * @returns + */ + function getHXValsForElement(elt, expressionVars) { + return getValuesForElement(elt, 'hx-vals', false, expressionVars) + } + + /** + * @param {Element} elt + * @returns {FormData} + */ + function getExpressionVars(elt) { + return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)) + } + + /** + * @param {XMLHttpRequest} xhr + * @param {string} header + * @param {string|null} headerValue + */ + function safelySetHeaderValue(xhr, header, headerValue) { + if (headerValue !== null) { + try { + xhr.setRequestHeader(header, headerValue) + } catch (e) { + // On an exception, try to set the header URI encoded instead + xhr.setRequestHeader(header, encodeURIComponent(headerValue)) + xhr.setRequestHeader(header + '-URI-AutoEncoded', 'true') + } + } + } + + /** + * @param {XMLHttpRequest} xhr + * @return {string} + */ + function getPathFromResponse(xhr) { + // NB: IE11 does not support this stuff + if (xhr.responseURL && typeof (URL) !== 'undefined') { + try { + const url = new URL(xhr.responseURL) + return url.pathname + url.search + } catch (e) { + triggerErrorEvent(getDocument().body, 'htmx:badResponseUrl', { url: xhr.responseURL }) + } + } + } + + /** + * @param {XMLHttpRequest} xhr + * @param {RegExp} regexp + * @return {boolean} + */ + function hasHeader(xhr, regexp) { + return regexp.test(xhr.getAllResponseHeaders()) + } + + /** + * Issues an htmx-style AJAX request + * + * @see https://htmx.org/api/#ajax + * + * @param {HttpVerb} verb + * @param {string} path the URL path to make the AJAX + * @param {Element|string|HtmxAjaxHelperContext} context the element to target (defaults to the **body**) | a selector for the target | a context object that contains any of the following + * @return {Promise<void>} Promise that resolves immediately if no request is sent, or when the request is complete + */ + function ajaxHelper(verb, path, context) { + verb = (/** @type HttpVerb */(verb.toLowerCase())) + if (context) { + if (context instanceof Element || typeof context === 'string') { + return issueAjaxRequest(verb, path, null, null, { + targetOverride: resolveTarget(context), + returnPromise: true + }) + } else { + return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, + { + handler: context.handler, + headers: context.headers, + values: context.values, + targetOverride: resolveTarget(context.target), + swapOverride: context.swap, + select: context.select, + returnPromise: true + }) + } + } else { + return issueAjaxRequest(verb, path, null, null, { + returnPromise: true + }) + } + } + + /** + * @param {Element} elt + * @return {Element[]} + */ + function hierarchyForElt(elt) { + const arr = [] + while (elt) { + arr.push(elt) + elt = elt.parentElement + } + return arr + } + + /** + * @param {Element} elt + * @param {string} path + * @param {HtmxRequestConfig} requestConfig + * @return {boolean} + */ + function verifyPath(elt, path, requestConfig) { + let sameHost + let url + if (typeof URL === 'function') { + url = new URL(path, document.location.href) + const origin = document.location.origin + sameHost = origin === url.origin + } else { + // IE11 doesn't support URL + url = path + sameHost = startsWith(path, document.location.origin) + } - //=========================================== - // Next resolve via DOM values - //=========================================== - var requestPath = responseInfo.pathInfo.finalRequestPath; - var responsePath = responseInfo.pathInfo.responsePath; - - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url"); - var elementIsBoosted = getInternalData(elt).boosted; - - var saveType = null; - var path = null; - - if (pushUrl) { - saveType = "push"; - path = pushUrl; - } else if (replaceUrl) { - saveType = "replace"; - path = replaceUrl; - } else if (elementIsBoosted) { - saveType = "push"; - path = responsePath || requestPath; // if there is no response path, go with the original request path - } + if (htmx.config.selfRequestsOnly) { + if (!sameHost) { + return false + } + } + return triggerEvent(elt, 'htmx:validateUrl', mergeObjects({ url, sameHost }, requestConfig)) + } + + /** + * @param {Object|FormData} obj + * @return {FormData} + */ + function formDataFromObject(obj) { + if (obj instanceof FormData) return obj + const formData = new FormData() + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + if (typeof obj[key].forEach === 'function') { + obj[key].forEach(function(v) { formData.append(key, v) }) + } else if (typeof obj[key] === 'object') { + formData.append(key, JSON.stringify(obj[key])) + } else { + formData.append(key, obj[key]) + } + } + } + return formData + } + + /** + * @param {FormData} formData + * @param {string} name + * @param {Array} array + * @returns {Array} + */ + function formDataArrayProxy(formData, name, array) { + // mutating the array should mutate the underlying form data + return new Proxy(array, { + get: function(target, key) { + if (typeof key === 'number') return target[key] + if (key === 'length') return target.length + if (key === 'push') { + return function(value) { + target.push(value) + formData.append(name, value) + } + } + if (typeof target[key] === 'function') { + return function() { + target[key].apply(target, arguments) + formData.delete(name) + target.forEach(function(v) { formData.append(name, v) }) + } + } + + if (target[key] && target[key].length === 1) { + return target[key][0] + } else { + return target[key] + } + }, + set: function(target, index, value) { + target[index] = value + formData.delete(name) + target.forEach(function(v) { formData.append(name, v) }) + return true + } + }) + } + + /** + * @param {FormData} formData + * @returns {Object} + */ + function formDataProxy(formData) { + return new Proxy(formData, { + get: function(target, name) { + if (typeof name === 'symbol') { + // Forward symbol calls to the FormData itself directly + return Reflect.get(target, name) + } + if (name === 'toJSON') { + // Support JSON.stringify call on proxy + return () => Object.fromEntries(formData) + } + if (name in target) { + // Wrap in function with apply to correctly bind the FormData context, as a direct call would result in an illegal invocation error + if (typeof target[name] === 'function') { + return function() { + return formData[name].apply(formData, arguments) + } + } else { + return target[name] + } + } + const array = formData.getAll(name) + // Those 2 undefined & single value returns are for retro-compatibility as we weren't using FormData before + if (array.length === 0) { + return undefined + } else if (array.length === 1) { + return array[0] + } else { + return formDataArrayProxy(target, name, array) + } + }, + set: function(target, name, value) { + if (typeof name !== 'string') { + return false + } + target.delete(name) + if (typeof value.forEach === 'function') { + value.forEach(function(v) { target.append(name, v) }) + } else { + target.append(name, value) + } + return true + }, + deleteProperty: function(target, name) { + if (typeof name === 'string') { + target.delete(name) + } + return true + }, + // Support Object.assign call from proxy + ownKeys: function(target) { + return Reflect.ownKeys(Object.fromEntries(target)) + }, + getOwnPropertyDescriptor: function(target, prop) { + return Reflect.getOwnPropertyDescriptor(Object.fromEntries(target), prop) + } + }) + } + + /** + * @param {HttpVerb} verb + * @param {string} path + * @param {Element} elt + * @param {Event} event + * @param {HtmxAjaxEtc} [etc] + * @param {boolean} [confirmed] + * @return {Promise<void>} + */ + function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { + let resolve = null + let reject = null + etc = etc != null ? etc : {} + if (etc.returnPromise && typeof Promise !== 'undefined') { + var promise = new Promise(function(_resolve, _reject) { + resolve = _resolve + reject = _reject + }) + } + if (elt == null) { + elt = getDocument().body + } + const responseHandler = etc.handler || handleAjaxResponse + const select = etc.select || null - if (path) { - // false indicates no push, return empty object - if (path === "false") { - return {}; - } + if (!bodyContains(elt)) { + // do not issue requests for elements removed from the DOM + maybeCall(resolve) + return promise + } + const target = etc.targetOverride || asElement(getTarget(elt)) + if (target == null || target == DUMMY_ELT) { + triggerErrorEvent(elt, 'htmx:targetError', { target: getAttributeValue(elt, 'hx-target') }) + maybeCall(reject) + return promise + } - // true indicates we want to follow wherever the server ended up sending us - if (path === "true") { - path = responsePath || requestPath; // if there is no response path, go with the original request path - } + let eltData = getInternalData(elt) + const submitter = eltData.lastButtonClicked - // restore any anchor associated with the request - if (responseInfo.pathInfo.anchor && - path.indexOf("#") === -1) { - path = path + "#" + responseInfo.pathInfo.anchor; - } + if (submitter) { + const buttonPath = getRawAttribute(submitter, 'formaction') + if (buttonPath != null) { + path = buttonPath + } - return { - type:saveType, - path: path - } - } else { - return {}; - } + const buttonVerb = getRawAttribute(submitter, 'formmethod') + if (buttonVerb != null) { + // ignore buttons with formmethod="dialog" + if (buttonVerb.toLowerCase() !== 'dialog') { + verb = (/** @type HttpVerb */(buttonVerb)) } + } + } - function handleAjaxResponse(elt, responseInfo) { - var xhr = responseInfo.xhr; - var target = responseInfo.target; - var etc = responseInfo.etc; - var requestConfig = responseInfo.requestConfig; - var select = responseInfo.select; + const confirmQuestion = getClosestAttributeValue(elt, 'hx-confirm') + // allow event-based confirmation w/ a callback + if (confirmed === undefined) { + const issueRequest = function(skipConfirmation) { + return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation) + } + const confirmDetails = { target, elt, path, verb, triggeringEvent: event, etc, issueRequest, question: confirmQuestion } + if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { + maybeCall(resolve) + return promise + } + } - if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; + let syncElt = elt + let syncStrategy = getClosestAttributeValue(elt, 'hx-sync') + let queueStrategy = null + let abortable = false + if (syncStrategy) { + const syncStrings = syncStrategy.split(':') + const selector = syncStrings[0].trim() + if (selector === 'this') { + syncElt = findThisElement(elt, 'hx-sync') + } else { + syncElt = asElement(querySelectorExt(elt, selector)) + } + // default to the drop strategy + syncStrategy = (syncStrings[1] || 'drop').trim() + eltData = getInternalData(syncElt) + if (syncStrategy === 'drop' && eltData.xhr && eltData.abortable !== true) { + maybeCall(resolve) + return promise + } else if (syncStrategy === 'abort') { + if (eltData.xhr) { + maybeCall(resolve) + return promise + } else { + abortable = true + } + } else if (syncStrategy === 'replace') { + triggerEvent(syncElt, 'htmx:abort') // abort the current request and continue + } else if (syncStrategy.indexOf('queue') === 0) { + const queueStrArray = syncStrategy.split(' ') + queueStrategy = (queueStrArray[1] || 'last').trim() + } + } - if (hasHeader(xhr, /HX-Trigger:/i)) { - handleTrigger(xhr, "HX-Trigger", elt); - } + if (eltData.xhr) { + if (eltData.abortable) { + triggerEvent(syncElt, 'htmx:abort') // abort the current request and continue + } else { + if (queueStrategy == null) { + if (event) { + const eventData = getInternalData(event) + if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { + queueStrategy = eventData.triggerSpec.queue + } + } + if (queueStrategy == null) { + queueStrategy = 'last' + } + } + if (eltData.queuedRequests == null) { + eltData.queuedRequests = [] + } + if (queueStrategy === 'first' && eltData.queuedRequests.length === 0) { + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } else if (queueStrategy === 'all') { + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } else if (queueStrategy === 'last') { + eltData.queuedRequests = [] // dump existing queue + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } + maybeCall(resolve) + return promise + } + } - if (hasHeader(xhr, /HX-Location:/i)) { - saveCurrentPageToHistory(); - var redirectPath = xhr.getResponseHeader("HX-Location"); - var swapSpec; - if (redirectPath.indexOf("{") === 0) { - swapSpec = parseJSON(redirectPath); - // what's the best way to throw an error if the user didn't include this - redirectPath = swapSpec['path']; - delete swapSpec['path']; - } - ajaxHelper('GET', redirectPath, swapSpec).then(function(){ - pushUrlIntoHistory(redirectPath); - }); - return; - } + const xhr = new XMLHttpRequest() + eltData.xhr = xhr + eltData.abortable = abortable + const endRequestLock = function() { + eltData.xhr = null + eltData.abortable = false + if (eltData.queuedRequests != null && + eltData.queuedRequests.length > 0) { + const queuedRequest = eltData.queuedRequests.shift() + queuedRequest() + } + } + const promptQuestion = getClosestAttributeValue(elt, 'hx-prompt') + if (promptQuestion) { + var promptResponse = prompt(promptQuestion) + // prompt returns null if cancelled and empty string if accepted with no entry + if (promptResponse === null || + !triggerEvent(elt, 'htmx:prompt', { prompt: promptResponse, target })) { + maybeCall(resolve) + endRequestLock() + return promise + } + } - var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh"); + if (confirmQuestion && !confirmed) { + if (!confirm(confirmQuestion)) { + maybeCall(resolve) + endRequestLock() + return promise + } + } - if (hasHeader(xhr, /HX-Redirect:/i)) { - location.href = xhr.getResponseHeader("HX-Redirect"); - shouldRefresh && location.reload(); - return; - } + let headers = getHeaders(elt, target, promptResponse) - if (shouldRefresh) { - location.reload(); - return; - } + if (verb !== 'get' && !usesFormData(elt)) { + headers['Content-Type'] = 'application/x-www-form-urlencoded' + } - if (hasHeader(xhr,/HX-Retarget:/i)) { - if (xhr.getResponseHeader("HX-Retarget") === "this") { - responseInfo.target = elt; - } else { - responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget")); - } - } + if (etc.headers) { + headers = mergeObjects(headers, etc.headers) + } + const results = getInputValues(elt, verb) + let errors = results.errors + const rawFormData = results.formData + if (etc.values) { + overrideFormData(rawFormData, formDataFromObject(etc.values)) + } + const expressionVars = formDataFromObject(getExpressionVars(elt)) + const allFormData = overrideFormData(rawFormData, expressionVars) + let filteredFormData = filterValues(allFormData, elt) - var historyUpdate = determineHistoryUpdates(elt, responseInfo); - - // by default htmx only swaps on 200 return codes and does not swap - // on 204 'No Content' - // this can be ovverriden by responding to the htmx:beforeSwap event and - // overriding the detail.shouldSwap property - var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; - var serverResponse = xhr.response; - var isError = xhr.status >= 400; - var ignoreTitle = htmx.config.ignoreTitle - var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo); - if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; - - target = beforeSwapDetails.target; // allow re-targeting - serverResponse = beforeSwapDetails.serverResponse; // allow updating content - isError = beforeSwapDetails.isError; // allow updating error - ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title - - responseInfo.target = target; // Make updated target available to response events - responseInfo.failed = isError; // Make failed property available to response events - responseInfo.successful = !isError; // Make successful property available to response events - - if (beforeSwapDetails.shouldSwap) { - if (xhr.status === 286) { - cancelPolling(elt); - } + if (htmx.config.getCacheBusterParam && verb === 'get') { + filteredFormData.set('org.htmx.cache-buster', getRawAttribute(target, 'id') || 'true') + } - withExtensions(elt, function (extension) { - serverResponse = extension.transformResponse(serverResponse, xhr, elt); - }); + // behavior of anchors w/ empty href is to use the current URL + if (path == null || path === '') { + path = getDocument().location.href + } - // Save current page if there will be a history update - if (historyUpdate.type) { - saveCurrentPageToHistory(); - } + /** + * @type {Object} + * @property {boolean} [credentials] + * @property {number} [timeout] + * @property {boolean} [noHeaders] + */ + const requestAttrValues = getValuesForElement(elt, 'hx-request') + + const eltIsBoosted = getInternalData(elt).boosted + + let useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + + /** @type HtmxRequestConfig */ + const requestConfig = { + boosted: eltIsBoosted, + useUrlParams, + formData: filteredFormData, + parameters: formDataProxy(filteredFormData), + unfilteredFormData: allFormData, + unfilteredParameters: formDataProxy(allFormData), + headers, + target, + verb, + errors, + withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, + timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, + path, + triggeringEvent: event + } - var swapOverride = etc.swapOverride; - if (hasHeader(xhr,/HX-Reswap:/i)) { - swapOverride = xhr.getResponseHeader("HX-Reswap"); - } - var swapSpec = getSwapSpecification(elt, swapOverride); + if (!triggerEvent(elt, 'htmx:configRequest', requestConfig)) { + maybeCall(resolve) + endRequestLock() + return promise + } - if (swapSpec.hasOwnProperty('ignoreTitle')) { - ignoreTitle = swapSpec.ignoreTitle; - } + // copy out in case the object was overwritten + path = requestConfig.path + verb = requestConfig.verb + headers = requestConfig.headers + filteredFormData = formDataFromObject(requestConfig.parameters) + errors = requestConfig.errors + useUrlParams = requestConfig.useUrlParams + + if (errors && errors.length > 0) { + triggerEvent(elt, 'htmx:validation:halted', requestConfig) + maybeCall(resolve) + endRequestLock() + return promise + } - target.classList.add(htmx.config.swappingClass); - - // optional transition API promise callbacks - var settleResolve = null; - var settleReject = null; - - var doSwap = function () { - try { - var activeElt = document.activeElement; - var selectionInfo = {}; - try { - selectionInfo = { - elt: activeElt, - // @ts-ignore - start: activeElt ? activeElt.selectionStart : null, - // @ts-ignore - end: activeElt ? activeElt.selectionEnd : null - }; - } catch (e) { - // safari issue - see https://github.com/microsoft/playwright/issues/5894 - } - - var selectOverride; - if (select) { - selectOverride = select; - } - - if (hasHeader(xhr, /HX-Reselect:/i)) { - selectOverride = xhr.getResponseHeader("HX-Reselect"); - } - - // if we need to save history, do so, before swapping so that relative resources have the correct base URL - if (historyUpdate.type) { - triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)); - if (historyUpdate.type === "push") { - pushUrlIntoHistory(historyUpdate.path); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path}); - } else { - replaceUrlInHistory(historyUpdate.path); - triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path}); - } - } - - var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride); - - if (selectionInfo.elt && - !bodyContains(selectionInfo.elt) && - getRawAttribute(selectionInfo.elt, "id")) { - var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id")); - var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; - if (newActiveElt) { - // @ts-ignore - if (selectionInfo.start && newActiveElt.setSelectionRange) { - // @ts-ignore - try { - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); - } catch (e) { - // the setSelectionRange method is present on fields that don't support it, so just let this fail - } - } - newActiveElt.focus(focusOptions); - } - } - - target.classList.remove(htmx.config.swappingClass); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.add(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSwap', responseInfo); - }); - - if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); - } - - var doSettle = function () { - forEach(settleInfo.tasks, function (task) { - task.call(); - }); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.remove(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSettle', responseInfo); - }); - - if (responseInfo.pathInfo.anchor) { - var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor); - if(anchorTarget) { - anchorTarget.scrollIntoView({block:'start', behavior: "auto"}); - } - } - - if(settleInfo.title && !ignoreTitle) { - var titleElt = find("title"); - if(titleElt) { - titleElt.innerHTML = settleInfo.title; - } else { - window.document.title = settleInfo.title; - } - } - - updateScrollState(settleInfo.elts, swapSpec); - - if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); - } - maybeCall(settleResolve); - } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'htmx:swapError', responseInfo); - maybeCall(settleReject); - throw e; - } - }; - - var shouldTransition = htmx.config.globalViewTransitions - if(swapSpec.hasOwnProperty('transition')){ - shouldTransition = swapSpec.transition; - } + const splitPath = path.split('#') + const pathNoAnchor = splitPath[0] + const anchor = splitPath[1] + + let finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor + const hasValues = !filteredFormData.keys().next().done + if (hasValues) { + if (finalPath.indexOf('?') < 0) { + finalPath += '?' + } else { + finalPath += '&' + } + finalPath += urlEncode(filteredFormData) + if (anchor) { + finalPath += '#' + anchor + } + } + } - if(shouldTransition && - triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && - typeof Promise !== "undefined" && document.startViewTransition){ - var settlePromise = new Promise(function (_resolve, _reject) { - settleResolve = _resolve; - settleReject = _reject; - }); - // wrap the original doSwap() in a call to startViewTransition() - var innerDoSwap = doSwap; - doSwap = function() { - document.startViewTransition(function () { - innerDoSwap(); - return settlePromise; - }); - } - } + if (!verifyPath(elt, finalPath, requestConfig)) { + triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) + maybeCall(reject) + return promise + } + xhr.open(verb.toUpperCase(), finalPath, true) + xhr.overrideMimeType('text/html') + xhr.withCredentials = requestConfig.withCredentials + xhr.timeout = requestConfig.timeout - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); - } - } - if (isError) { - triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo)); - } + // request headers + if (requestAttrValues.noHeaders) { + // ignore all headers + } else { + for (const header in headers) { + if (headers.hasOwnProperty(header)) { + const headerValue = headers[header] + safelySetHeaderValue(xhr, header, headerValue) } + } + } - //==================================================================== - // Extensions API - //==================================================================== - - /** @type {Object<string, import("./htmx").HtmxExtension>} */ - var extensions = {}; - - /** - * extensionBase defines the default functions for all extensions. - * @returns {import("./htmx").HtmxExtension} - */ - function extensionBase() { - return { - init: function(api) {return null;}, - onEvent : function(name, evt) {return true;}, - transformResponse : function(text, xhr, elt) {return text;}, - isInlineSwap : function(swapStyle) {return false;}, - handleSwap : function(swapStyle, target, fragment, settleInfo) {return false;}, - encodeParameters : function(xhr, parameters, elt) {return null;} - } - } + /** @type {HtmxResponseInfo} */ + const responseInfo = { + xhr, + target, + requestConfig, + etc, + boosted: eltIsBoosted, + select, + pathInfo: { + requestPath: path, + finalRequestPath: finalPath, + responsePath: null, + anchor + } + } - /** - * defineExtension initializes the extension and adds it to the htmx registry - * - * @param {string} name - * @param {import("./htmx").HtmxExtension} extension - */ - function defineExtension(name, extension) { - if(extension.init) { - extension.init(internalAPI) - } - extensions[name] = mergeObjects(extensionBase(), extension); - } + xhr.onload = function() { + try { + const hierarchy = hierarchyForElt(elt) + responseInfo.pathInfo.responsePath = getPathFromResponse(xhr) + responseHandler(elt, responseInfo) + removeRequestIndicators(indicators, disableElts) + triggerEvent(elt, 'htmx:afterRequest', responseInfo) + triggerEvent(elt, 'htmx:afterOnLoad', responseInfo) + // if the body no longer contains the element, trigger the event on the closest parent + // remaining in the DOM + if (!bodyContains(elt)) { + let secondaryTriggerElt = null + while (hierarchy.length > 0 && secondaryTriggerElt == null) { + const parentEltInHierarchy = hierarchy.shift() + if (bodyContains(parentEltInHierarchy)) { + secondaryTriggerElt = parentEltInHierarchy + } + } + if (secondaryTriggerElt) { + triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo) + triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo) + } + } + maybeCall(resolve) + endRequestLock() + } catch (e) { + triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({ error: e }, responseInfo)) + throw e + } + } + xhr.onerror = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:sendError', responseInfo) + maybeCall(reject) + endRequestLock() + } + xhr.onabort = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo) + maybeCall(reject) + endRequestLock() + } + xhr.ontimeout = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:timeout', responseInfo) + maybeCall(reject) + endRequestLock() + } + if (!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)) { + maybeCall(resolve) + endRequestLock() + return promise + } + var indicators = addRequestIndicatorClasses(elt) + var disableElts = disableElements(elt) + + forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { + forEach([xhr, xhr.upload], function(target) { + target.addEventListener(eventName, function(event) { + triggerEvent(elt, 'htmx:xhr:' + eventName, { + lengthComputable: event.lengthComputable, + loaded: event.loaded, + total: event.total + }) + }) + }) + }) + triggerEvent(elt, 'htmx:beforeSend', responseInfo) + const params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredFormData) + xhr.send(params) + return promise + } + + /** + * @typedef {Object} HtmxHistoryUpdate + * @property {string|null} [type] + * @property {string|null} [path] + */ + + /** + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + * @return {HtmxHistoryUpdate} + */ + function determineHistoryUpdates(elt, responseInfo) { + const xhr = responseInfo.xhr + + //= ========================================== + // First consult response headers + //= ========================================== + let pathFromHeaders = null + let typeFromHeaders = null + if (hasHeader(xhr, /HX-Push:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Push') + typeFromHeaders = 'push' + } else if (hasHeader(xhr, /HX-Push-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Push-Url') + typeFromHeaders = 'push' + } else if (hasHeader(xhr, /HX-Replace-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Replace-Url') + typeFromHeaders = 'replace' + } - /** - * removeExtension removes an extension from the htmx registry - * - * @param {string} name - */ - function removeExtension(name) { - delete extensions[name]; + // if there was a response header, that has priority + if (pathFromHeaders) { + if (pathFromHeaders === 'false') { + return {} + } else { + return { + type: typeFromHeaders, + path: pathFromHeaders } + } + } - /** - * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element - * - * @param {HTMLElement} elt - * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn - * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore - */ - function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + //= ========================================== + // Next resolve via DOM values + //= ========================================== + const requestPath = responseInfo.pathInfo.finalRequestPath + const responsePath = responseInfo.pathInfo.responsePath + + const pushUrl = getClosestAttributeValue(elt, 'hx-push-url') + const replaceUrl = getClosestAttributeValue(elt, 'hx-replace-url') + const elementIsBoosted = getInternalData(elt).boosted + + let saveType = null + let path = null + + if (pushUrl) { + saveType = 'push' + path = pushUrl + } else if (replaceUrl) { + saveType = 'replace' + path = replaceUrl + } else if (elementIsBoosted) { + saveType = 'push' + path = responsePath || requestPath // if there is no response path, go with the original request path + } - if (elt == undefined) { - return extensionsToReturn; - } - if (extensionsToReturn == undefined) { - extensionsToReturn = []; - } - if (extensionsToIgnore == undefined) { - extensionsToIgnore = []; - } - var extensionsForElement = getAttributeValue(elt, "hx-ext"); - if (extensionsForElement) { - forEach(extensionsForElement.split(","), function(extensionName){ - extensionName = extensionName.replace(/ /g, ''); - if (extensionName.slice(0, 7) == "ignore:") { - extensionsToIgnore.push(extensionName.slice(7)); - return; - } - if (extensionsToIgnore.indexOf(extensionName) < 0) { - var extension = extensions[extensionName]; - if (extension && extensionsToReturn.indexOf(extension) < 0) { - extensionsToReturn.push(extension); - } - } - }); - } - return getExtensions(parentElt(elt), extensionsToReturn, extensionsToIgnore); - } + if (path) { + // false indicates no push, return empty object + if (path === 'false') { + return {} + } + + // true indicates we want to follow wherever the server ended up sending us + if (path === 'true') { + path = responsePath || requestPath // if there is no response path, go with the original request path + } + + // restore any anchor associated with the request + if (responseInfo.pathInfo.anchor && path.indexOf('#') === -1) { + path = path + '#' + responseInfo.pathInfo.anchor + } + + return { + type: saveType, + path + } + } else { + return {} + } + } + + /** + * @param {HtmxResponseHandlingConfig} responseHandlingConfig + * @param {number} status + * @return {boolean} + */ + function codeMatches(responseHandlingConfig, status) { + var regExp = new RegExp(responseHandlingConfig.code) + return regExp.test(status.toString(10)) + } + + /** + * @param {XMLHttpRequest} xhr + * @return {HtmxResponseHandlingConfig} + */ + function resolveResponseHandling(xhr) { + for (var i = 0; i < htmx.config.responseHandling.length; i++) { + /** @type HtmxResponseHandlingConfig */ + var responseHandlingElement = htmx.config.responseHandling[i] + if (codeMatches(responseHandlingElement, xhr.status)) { + return responseHandlingElement + } + } + // no matches, return no swap + return { + swap: false + } + } + + /** + * @param {string} title + */ + function handleTitle(title) { + if (title) { + const titleElt = find('title') + if (titleElt) { + titleElt.innerHTML = title + } else { + window.document.title = title + } + } + } + + /** + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + */ + function handleAjaxResponse(elt, responseInfo) { + const xhr = responseInfo.xhr + let target = responseInfo.target + const etc = responseInfo.etc + const responseInfoSelect = responseInfo.select + + if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return + + if (hasHeader(xhr, /HX-Trigger:/i)) { + handleTriggerHeader(xhr, 'HX-Trigger', elt) + } - //==================================================================== - // Initialization - //==================================================================== - var isReady = false - getDocument().addEventListener('DOMContentLoaded', function() { - isReady = true - }) + if (hasHeader(xhr, /HX-Location:/i)) { + saveCurrentPageToHistory() + let redirectPath = xhr.getResponseHeader('HX-Location') + /** @type {HtmxAjaxHelperContext&{path:string}} */ + var redirectSwapSpec + if (redirectPath.indexOf('{') === 0) { + redirectSwapSpec = parseJSON(redirectPath) + // what's the best way to throw an error if the user didn't include this + redirectPath = redirectSwapSpec.path + delete redirectSwapSpec.path + } + ajaxHelper('get', redirectPath, redirectSwapSpec).then(function() { + pushUrlIntoHistory(redirectPath) + }) + return + } - /** - * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. - * - * This function uses isReady because there is no realiable way to ask the browswer whether - * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded - * firing and readystate=complete. - */ - function ready(fn) { - // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by - // some means other than the initial page load. - if (isReady || getDocument().readyState === 'complete') { - fn(); - } else { - getDocument().addEventListener('DOMContentLoaded', fn); - } - } + const shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && xhr.getResponseHeader('HX-Refresh') === 'true' - function insertIndicatorStyles() { - if (htmx.config.includeIndicatorStyles !== false) { - getDocument().head.insertAdjacentHTML("beforeend", - "<style>\ - ." + htmx.config.indicatorClass + "{opacity:0}\ - ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ - ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ - </style>"); - } - } + if (hasHeader(xhr, /HX-Redirect:/i)) { + location.href = xhr.getResponseHeader('HX-Redirect') + shouldRefresh && location.reload() + return + } - function getMetaConfig() { - var element = getDocument().querySelector('meta[name="htmx-config"]'); - if (element) { - // @ts-ignore - return parseJSON(element.content); - } else { - return null; - } - } + if (shouldRefresh) { + location.reload() + return + } - function mergeMetaConfig() { - var metaConfig = getMetaConfig(); - if (metaConfig) { - htmx.config = mergeObjects(htmx.config , metaConfig) - } - } + if (hasHeader(xhr, /HX-Retarget:/i)) { + if (xhr.getResponseHeader('HX-Retarget') === 'this') { + responseInfo.target = elt + } else { + responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget'))) + } + } - // initialize the document - ready(function () { - mergeMetaConfig(); - insertIndicatorStyles(); - var body = getDocument().body; - processNode(body); - var restoredElts = getDocument().querySelectorAll( - "[hx-trigger='restored'],[data-hx-trigger='restored']" - ); - body.addEventListener("htmx:abort", function (evt) { - var target = evt.target; - var internalData = getInternalData(target); - if (internalData && internalData.xhr) { - internalData.xhr.abort(); - } - }); - /** @type {(ev: PopStateEvent) => any} */ - const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null; - /** @type {(ev: PopStateEvent) => any} */ - window.onpopstate = function (event) { - if (event.state && event.state.htmx) { - restoreHistory(); - forEach(restoredElts, function(elt){ - triggerEvent(elt, 'htmx:restored', { - 'document': getDocument(), - 'triggerEvent': triggerEvent - }); - }); - } else { - if (originalPopstate) { - originalPopstate(event); - } - } - }; - setTimeout(function () { - triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event - body = null; // kill reference for gc - }, 0); + const historyUpdate = determineHistoryUpdates(elt, responseInfo) + + const responseHandling = resolveResponseHandling(xhr) + const shouldSwap = responseHandling.swap + let isError = !!responseHandling.error + let ignoreTitle = htmx.config.ignoreTitle || responseHandling.ignoreTitle + let selectOverride = responseHandling.select + if (responseHandling.target) { + responseInfo.target = asElement(querySelectorExt(elt, responseHandling.target)) + } + var swapOverride = etc.swapOverride + if (swapOverride == null && responseHandling.swapOverride) { + swapOverride = responseHandling.swapOverride + } + + // response headers override response handling config + if (hasHeader(xhr, /HX-Retarget:/i)) { + if (xhr.getResponseHeader('HX-Retarget') === 'this') { + responseInfo.target = elt + } else { + responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget'))) + } + } + if (hasHeader(xhr, /HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader('HX-Reswap') + } + + var serverResponse = xhr.response + /** @type HtmxBeforeSwapDetails */ + var beforeSwapDetails = mergeObjects({ + shouldSwap, + serverResponse, + isError, + ignoreTitle, + selectOverride + }, responseInfo) + + if (responseHandling.event && !triggerEvent(target, responseHandling.event, beforeSwapDetails)) return + + if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return + + target = beforeSwapDetails.target // allow re-targeting + serverResponse = beforeSwapDetails.serverResponse // allow updating content + isError = beforeSwapDetails.isError // allow updating error + ignoreTitle = beforeSwapDetails.ignoreTitle // allow updating ignoring title + selectOverride = beforeSwapDetails.selectOverride // allow updating select override + + responseInfo.target = target // Make updated target available to response events + responseInfo.failed = isError // Make failed property available to response events + responseInfo.successful = !isError // Make successful property available to response events + + if (beforeSwapDetails.shouldSwap) { + if (xhr.status === 286) { + cancelPolling(elt) + } + + withExtensions(elt, function(extension) { + serverResponse = extension.transformResponse(serverResponse, xhr, elt) + }) + + // Save current page if there will be a history update + if (historyUpdate.type) { + saveCurrentPageToHistory() + } + + if (hasHeader(xhr, /HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader('HX-Reswap') + } + var swapSpec = getSwapSpecification(elt, swapOverride) + + if (!swapSpec.hasOwnProperty('ignoreTitle')) { + swapSpec.ignoreTitle = ignoreTitle + } + + target.classList.add(htmx.config.swappingClass) + + // optional transition API promise callbacks + let settleResolve = null + let settleReject = null + + if (responseInfoSelect) { + selectOverride = responseInfoSelect + } + + if (hasHeader(xhr, /HX-Reselect:/i)) { + selectOverride = xhr.getResponseHeader('HX-Reselect') + } + + const selectOOB = getClosestAttributeValue(elt, 'hx-select-oob') + const select = getClosestAttributeValue(elt, 'hx-select') + + let doSwap = function() { + try { + // if we need to save history, do so, before swapping so that relative resources have the correct base URL + if (historyUpdate.type) { + triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)) + if (historyUpdate.type === 'push') { + pushUrlIntoHistory(historyUpdate.path) + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', { path: historyUpdate.path }) + } else { + replaceUrlInHistory(historyUpdate.path) + triggerEvent(getDocument().body, 'htmx:replacedInHistory', { path: historyUpdate.path }) + } + } + + swap(target, serverResponse, swapSpec, { + select: selectOverride || select, + selectOOB, + eventInfo: responseInfo, + anchor: responseInfo.pathInfo.anchor, + contextElement: elt, + afterSwapCallback: function() { + if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { + let finalElt = elt + if (!bodyContains(elt)) { + finalElt = getDocument().body + } + handleTriggerHeader(xhr, 'HX-Trigger-After-Swap', finalElt) + } + }, + afterSettleCallback: function() { + if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { + let finalElt = elt + if (!bodyContains(elt)) { + finalElt = getDocument().body + } + handleTriggerHeader(xhr, 'HX-Trigger-After-Settle', finalElt) + } + maybeCall(settleResolve) + } + }) + } catch (e) { + triggerErrorEvent(elt, 'htmx:swapError', responseInfo) + maybeCall(settleReject) + throw e + } + } + + let shouldTransition = htmx.config.globalViewTransitions + if (swapSpec.hasOwnProperty('transition')) { + shouldTransition = swapSpec.transition + } + + if (shouldTransition && + triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && + typeof Promise !== 'undefined' && + // @ts-ignore experimental feature atm + document.startViewTransition) { + const settlePromise = new Promise(function(_resolve, _reject) { + settleResolve = _resolve + settleReject = _reject }) + // wrap the original doSwap() in a call to startViewTransition() + const innerDoSwap = doSwap + doSwap = function() { + // @ts-ignore experimental feature atm + document.startViewTransition(function() { + innerDoSwap() + return settlePromise + }) + } + } + + if (swapSpec.swapDelay > 0) { + getWindow().setTimeout(doSwap, swapSpec.swapDelay) + } else { + doSwap() + } + } + if (isError) { + triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({ error: 'Response Status Error Code ' + xhr.status + ' from ' + responseInfo.pathInfo.requestPath }, responseInfo)) + } + } + + //= =================================================================== + // Extensions API + //= =================================================================== + + /** @type {Object<string, HtmxExtension>} */ + const extensions = {} + + /** + * extensionBase defines the default functions for all extensions. + * @returns {HtmxExtension} + */ + function extensionBase() { + return { + init: function(api) { return null }, + getSelectors: function() { return null }, + onEvent: function(name, evt) { return true }, + transformResponse: function(text, xhr, elt) { return text }, + isInlineSwap: function(swapStyle) { return false }, + handleSwap: function(swapStyle, target, fragment, settleInfo) { return false }, + encodeParameters: function(xhr, parameters, elt) { return null } + } + } + + /** + * defineExtension initializes the extension and adds it to the htmx registry + * + * @see https://htmx.org/api/#defineExtension + * + * @param {string} name the extension name + * @param {HtmxExtension} extension the extension definition + */ + function defineExtension(name, extension) { + if (extension.init) { + extension.init(internalAPI) + } + extensions[name] = mergeObjects(extensionBase(), extension) + } + + /** + * removeExtension removes an extension from the htmx registry + * + * @see https://htmx.org/api/#removeExtension + * + * @param {string} name + */ + function removeExtension(name) { + delete extensions[name] + } + + /** + * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element + * + * @param {Element} elt + * @param {HtmxExtension[]=} extensionsToReturn + * @param {string[]=} extensionsToIgnore + * @returns {HtmxExtension[]} + */ + function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + if (extensionsToReturn == undefined) { + extensionsToReturn = [] + } + if (elt == undefined) { + return extensionsToReturn + } + if (extensionsToIgnore == undefined) { + extensionsToIgnore = [] + } + const extensionsForElement = getAttributeValue(elt, 'hx-ext') + if (extensionsForElement) { + forEach(extensionsForElement.split(','), function(extensionName) { + extensionName = extensionName.replace(/ /g, '') + if (extensionName.slice(0, 7) == 'ignore:') { + extensionsToIgnore.push(extensionName.slice(7)) + return + } + if (extensionsToIgnore.indexOf(extensionName) < 0) { + const extension = extensions[extensionName] + if (extension && extensionsToReturn.indexOf(extension) < 0) { + extensionsToReturn.push(extension) + } + } + }) + } + return getExtensions(asElement(parentElt(elt)), extensionsToReturn, extensionsToIgnore) + } + + //= =================================================================== + // Initialization + //= =================================================================== + var isReady = false + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true + }) + + /** + * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. + * + * This function uses isReady because there is no reliable way to ask the browser whether + * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded + * firing and readystate=complete. + */ + function ready(fn) { + // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by + // some means other than the initial page load. + if (isReady || getDocument().readyState === 'complete') { + fn() + } else { + getDocument().addEventListener('DOMContentLoaded', fn) + } + } + + function insertIndicatorStyles() { + if (htmx.config.includeIndicatorStyles !== false) { + const nonceAttribute = htmx.config.inlineStyleNonce ? ` nonce="${htmx.config.inlineStyleNonce}"` : '' + getDocument().head.insertAdjacentHTML('beforeend', + '<style' + nonceAttribute + '>\ + .' + htmx.config.indicatorClass + '{opacity:0}\ + .' + htmx.config.requestClass + ' .' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\ + .' + htmx.config.requestClass + '.' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\ + </style>') + } + } + + function getMetaConfig() { + /** @type HTMLMetaElement */ + const element = getDocument().querySelector('meta[name="htmx-config"]') + if (element) { + return parseJSON(element.content) + } else { + return null + } + } - return htmx; + function mergeMetaConfig() { + const metaConfig = getMetaConfig() + if (metaConfig) { + htmx.config = mergeObjects(htmx.config, metaConfig) + } + } + + // initialize the document + ready(function() { + mergeMetaConfig() + insertIndicatorStyles() + let body = getDocument().body + processNode(body) + const restoredElts = getDocument().querySelectorAll( + "[hx-trigger='restored'],[data-hx-trigger='restored']" + ) + body.addEventListener('htmx:abort', function(evt) { + const target = evt.target + const internalData = getInternalData(target) + if (internalData && internalData.xhr) { + internalData.xhr.abort() + } + }) + /** @type {(ev: PopStateEvent) => any} */ + const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null + /** @type {(ev: PopStateEvent) => any} */ + window.onpopstate = function(event) { + if (event.state && event.state.htmx) { + restoreHistory() + forEach(restoredElts, function(elt) { + triggerEvent(elt, 'htmx:restored', { + document: getDocument(), + triggerEvent + }) + }) + } else { + if (originalPopstate) { + originalPopstate(event) + } + } } -)() -})); + getWindow().setTimeout(function() { + triggerEvent(body, 'htmx:load', {}) // give ready handlers a chance to load up before firing this event + body = null // kill reference for gc + }, 0) + }) + + return htmx +})() + +/** @typedef {'get'|'head'|'post'|'put'|'delete'|'connect'|'options'|'trace'|'patch'} HttpVerb */ + +/** + * @typedef {Object} SwapOptions + * @property {string} [select] + * @property {string} [selectOOB] + * @property {*} [eventInfo] + * @property {string} [anchor] + * @property {Element} [contextElement] + * @property {swapCallback} [afterSwapCallback] + * @property {swapCallback} [afterSettleCallback] + */ + +/** + * @callback swapCallback + */ + +/** + * @typedef {'innerHTML' | 'outerHTML' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'delete' | 'none' | string} HtmxSwapStyle + */ + +/** + * @typedef HtmxSwapSpecification + * @property {HtmxSwapStyle} swapStyle + * @property {number} swapDelay + * @property {number} settleDelay + * @property {boolean} [transition] + * @property {boolean} [ignoreTitle] + * @property {string} [head] + * @property {'top' | 'bottom'} [scroll] + * @property {string} [scrollTarget] + * @property {string} [show] + * @property {string} [showTarget] + * @property {boolean} [focusScroll] + */ + +/** + * @typedef {((this:Node, evt:Event) => boolean) & {source: string}} ConditionalFunction + */ + +/** + * @typedef {Object} HtmxTriggerSpecification + * @property {string} trigger + * @property {number} [pollInterval] + * @property {ConditionalFunction} [eventFilter] + * @property {boolean} [changed] + * @property {boolean} [once] + * @property {boolean} [consume] + * @property {number} [delay] + * @property {string} [from] + * @property {string} [target] + * @property {number} [throttle] + * @property {string} [queue] + * @property {string} [root] + * @property {string} [threshold] + */ + +/** + * @typedef {{elt: Element, message: string, validity: ValidityState}} HtmxElementValidationError + */ + +/** + * @typedef {Record<string, string>} HtmxHeaderSpecification + * @property {'true'} HX-Request + * @property {string|null} HX-Trigger + * @property {string|null} HX-Trigger-Name + * @property {string|null} HX-Target + * @property {string} HX-Current-URL + * @property {string} [HX-Prompt] + * @property {'true'} [HX-Boosted] + * @property {string} [Content-Type] + * @property {'true'} [HX-History-Restore-Request] + */ + +/** @typedef HtmxAjaxHelperContext + * @property {Element|string} [source] + * @property {Event} [event] + * @property {HtmxAjaxHandler} [handler] + * @property {Element|string} target + * @property {HtmxSwapStyle} [swap] + * @property {Object|FormData} [values] + * @property {Record<string,string>} [headers] + * @property {string} [select] + */ + +/** + * @typedef {Object} HtmxRequestConfig + * @property {boolean} boosted + * @property {boolean} useUrlParams + * @property {FormData} formData + * @property {Object} parameters formData proxy + * @property {FormData} unfilteredFormData + * @property {Object} unfilteredParameters unfilteredFormData proxy + * @property {HtmxHeaderSpecification} headers + * @property {Element} target + * @property {HttpVerb} verb + * @property {HtmxElementValidationError[]} errors + * @property {boolean} withCredentials + * @property {number} timeout + * @property {string} path + * @property {Event} triggeringEvent + */ + +/** + * @typedef {Object} HtmxResponseInfo + * @property {XMLHttpRequest} xhr + * @property {Element} target + * @property {HtmxRequestConfig} requestConfig + * @property {HtmxAjaxEtc} etc + * @property {boolean} boosted + * @property {string} select + * @property {{requestPath: string, finalRequestPath: string, responsePath: string|null, anchor: string}} pathInfo + * @property {boolean} [failed] + * @property {boolean} [successful] + */ + +/** + * @typedef {Object} HtmxAjaxEtc + * @property {boolean} [returnPromise] + * @property {HtmxAjaxHandler} [handler] + * @property {string} [select] + * @property {Element} [targetOverride] + * @property {HtmxSwapStyle} [swapOverride] + * @property {Record<string,string>} [headers] + * @property {Object|FormData} [values] + * @property {boolean} [credentials] + * @property {number} [timeout] + */ + +/** + * @typedef {Object} HtmxResponseHandlingConfig + * @property {string} [code] + * @property {boolean} swap + * @property {boolean} [error] + * @property {boolean} [ignoreTitle] + * @property {string} [select] + * @property {string} [target] + * @property {string} [swapOverride] + * @property {string} [event] + */ + +/** + * @typedef {HtmxResponseInfo & {shouldSwap: boolean, serverResponse: any, isError: boolean, ignoreTitle: boolean, selectOverride:string}} HtmxBeforeSwapDetails + */ + +/** + * @callback HtmxAjaxHandler + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + */ + +/** + * @typedef {(() => void)} HtmxSettleTask + */ + +/** + * @typedef {Object} HtmxSettleInfo + * @property {HtmxSettleTask[]} tasks + * @property {Element[]} elts + * @property {string} [title] + */ + +/** + * @typedef {Object} HtmxExtension + * @see https://htmx.org/extensions/#defining + * @property {(api: any) => void} init + * @property {(name: string, event: Event|CustomEvent) => boolean} onEvent + * @property {(text: string, xhr: XMLHttpRequest, elt: Element) => string} transformResponse + * @property {(swapStyle: HtmxSwapStyle) => boolean} isInlineSwap + * @property {(swapStyle: HtmxSwapStyle, target: Element, fragment: Node, settleInfo: HtmxSettleInfo) => boolean} handleSwap + * @property {(xhr: XMLHttpRequest, parameters: FormData, elt: Element) => *|string|null} encodeParameters + */ diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.min.js b/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.min.js index 53bbdf6..d66acce 100644 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.min.js +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/static/js/htmx.min.js @@ -1,4 +1,2 @@ -// /////////////////////////////////////////////////////////////////// -// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js -// -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(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 a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/<body/.test(e)}function l(e){var t=!N(e);var r=A(e);var n=e;if(r==="head"){n=n.replace(S,"")}if(Q.config.useTemplateFragments&&t){var i=a("<body><template>"+n+"</template></body>",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a("<table>"+n+"</table>",1);case"col":return a("<table><colgroup>"+n+"</colgroup></table>",2);case"tr":return a("<table><tbody>"+n+"</tbody></table>",2);case"td":case"th":return a("<table><tbody><tr>"+n+"</tr></tbody></table>",3);case"script":case"style":return a("<div>"+n+"</div>",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function oe(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function X(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var Y=function(e,t){var r=re().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function we(t,r){oe(t.attributes,function(e){if(!r.hasAttribute(e.name)&&be(e.name)){t.removeAttribute(e.name)}});oe(r.attributes,function(e){if(be(e.name)){t.setAttribute(e.name,e.value)}})}function Se(e,t){var r=Fr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){b(e)}}return e==="outerHTML"}function Ee(e,i,a){var t="#"+ee(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a<i.length;a++){var o=i[a].split(":",2);var s=o[0].trim();if(s.indexOf("#")===0){s=s.substring(1)}var l=o[1]||"true";var u=t.querySelector("#"+s);if(u){Ee(l,u,r)}}}oe(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=te(e,"hx-swap-oob");if(t!=null){Ee(t,e,r)}})}function Re(e){oe(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=te(e,"id");var r=re().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function Te(o,e,s){oe(e.querySelectorAll("[id]"),function(e){var t=ee(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Le(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=He(n.name,t);t=He(n.value,t)}}}return t}function Ae(e){var t=ae(e);if(t.onHandlers){for(var r=0;r<t.onHandlers.length;r++){const n=t.onHandlers[r];e.removeEventListener(n.event,n.listener)}delete t.onHandlers}}function Ne(e){var t=ae(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){oe(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}Ae(e);oe(Object.keys(t),function(e){delete t[e]})}function p(e){ce(e,"htmx:beforeCleanupElement");Ne(e);if(e.children){oe(e.children,function(e){p(e)})}}function Ie(t,e,r){if(t.tagName==="BODY"){return Ue(t,e,r)}else{var n;var i=t.previousSibling;m(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}p(t);u(t).removeChild(t)}}function ke(e,t,r){return m(e,e.firstChild,t,r)}function Pe(e,t,r){return m(u(e),e,t,r)}function Me(e,t,r){return m(e,null,t,r)}function Xe(e,t,r){return m(u(e),e.nextSibling,t,r)}function De(e,t,r){p(e);return u(e).removeChild(e)}function Ue(e,t,r){var n=e.firstChild;m(e,n,t,r);if(n){while(n.nextSibling){p(n.nextSibling);e.removeChild(n.nextSibling)}p(n);e.removeChild(n)}}function Be(e,t,r){var n=r||ne(e,"hx-select");if(n){var i=re().createDocumentFragment();oe(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function Fe(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Ie(r,n,i);return;case"afterbegin":ke(r,n,i);return;case"beforebegin":Pe(r,n,i);return;case"beforeend":Me(r,n,i);return;case"afterend":Xe(r,n,i);return;case"delete":De(r,n,i);return;default:var a=Fr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Oe(f))}}}return}}catch(e){b(e)}}if(e==="innerHTML"){Ue(r,n,i)}else{Fe(Q.config.defaultSwapStyle,t,r,n,i)}}}function Ve(e){if(e.indexOf("<title")>-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){ce(r,s[l].trim(),[])}}}var ze=/\s/;var x=/[\s,]/;var $e=/[_$a-zA-Z]/;var We=/[_$a-zA-Z0-9]/;var Ge=['"',"'","/"];var Je=/[^\s]/;var Ze=/[{(]/;var Ke=/[})]/;function Ye(e){var t=[];var r=0;while(r<e.length){if($e.exec(e.charAt(r))){var n=r;while(We.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ge.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function Qe(e,t,r){return $e.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function et(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){xt(e,a[1],0)}if(a[0]==="send"){bt(e)}}}function xt(s,r,n){if(!se(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=Q.createWebSocket(r);t.onerror=function(e){fe(s,"htmx:wsError",{error:e,socket:t});yt(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a<i.length;a++){var o=i[a];Ee(te(o,"hx-swap-oob")||"true",o,r)}nr(r.tasks)})}function yt(e){if(!se(e)){ae(e).webSocket.close();return true}}function bt(u){var f=c(u,function(e){return ae(e).webSocket!=null});if(f){u.addEventListener(it(u)[0].trigger,function(e){var t=ae(f).webSocket;var r=xr(u,f);var n=dr(u,"post");var i=n.errors;var a=n.values;var o=Hr(u);var s=le(a,o);var l=yr(s,u);l["HEADERS"]=r;if(i&&i.length>0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){Et(e,a[1])}if(a[0]==="swap"){Ct(e,a[1])}}}function Et(t,e){var r=Q.createEventSource(e);r.onerror=function(e){fe(t,"htmx:sseError",{error:e,source:r});Tt(t)};ae(t).sseEventSource=r}function Ct(a,o){var s=c(a,Ot);if(s){var l=ae(s).sseEventSource;var u=function(e){if(Tt(s)){return}if(!se(a)){l.removeEventListener(o,u);return}var t=e.data;R(a,function(e){t=e.transformResponse(t,null,a)});var r=wr(a);var n=ye(a);var i=T(a);je(r.swapStyle,n,a,t,i);nr(i.tasks);ce(a,"htmx:sseMessage",e)};ae(a).sseListener=u;l.addEventListener(o,u)}else{fe(a,"htmx:noSSESourceError")}}function Rt(e,t,r){var n=c(e,Ot);if(n){var i=ae(n).sseEventSource;var a=function(){if(!Tt(n)){if(se(e)){t(e)}else{i.removeEventListener(r,a)}}};ae(e).sseListener=a;i.addEventListener(r,a)}else{fe(e,"htmx:noSSESourceError")}}function Tt(e){if(!se(e)){ae(e).sseEventSource.close();return true}}function Ot(e){return ae(e).sseEventSource!=null}function qt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n>0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){ce(n,"intersect");break}}},i);a.observe(n);ht(n,r,t,e)}else if(e.trigger==="load"){if(!ct(e,n,Wt("load",{elt:n}))){qt(n,r,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r<t.length;r++){var n=t[r].name;if(s(n,"hx-on:")||s(n,"data-hx-on:")||s(n,"hx-on-")||s(n,"data-hx-on-")){return true}}return false}function kt(e){var t=null;var r=[];if(It(e)){r.push(e)}if(document.evaluate){var n=document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]',e);while(t=n.iterateNext())r.push(t)}else{var i=e.getElementsByTagName("*");for(var a=0;a<i.length;a++){if(It(i[a])){r.push(i[a])}}}return r}function Pt(e){if(e.querySelectorAll){var t=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";var r=e.querySelectorAll(i+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Mt(e){var t=v(e.target,"button, input[type='submit']");var r=Dt(e);if(r){r.lastButtonClicked=t}}function Xt(e){var t=Dt(e);if(t){t.lastButtonClicked=null}}function Dt(e){var t=v(e.target,"button, input[type='submit']");if(!t){return}var r=g("#"+ee(t,"form"))||v(t,"form");if(!r){return}return ae(r)}function Ut(e){e.addEventListener("click",Mt);e.addEventListener("focusin",Mt);e.addEventListener("focusout",Xt)}function Bt(e){var t=Ye(e);var r=0;for(var n=0;n<t.length;n++){const i=t[n];if(i==="{"){r++}else if(i==="}"){r--}}return r}function Ft(t,e,r){var n=ae(t);if(!Array.isArray(n.onHandlers)){n.onHandlers=[]}var i;var a=function(e){return Tr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Vt(e){var t=te(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;t<e.attributes.length;t++){var r=e.attributes[t].name;var n=e.attributes[t].value;if(s(r,"hx-on")||s(r,"data-hx-on")){var i=r.indexOf("-on")+3;var a=r.slice(i,i+1);if(a==="-"||a===":"){var o=r.slice(i+1);if(s(o,":")){o="htmx"+o}else if(s(o,"-")){o="htmx:"+o.slice(1)}else if(s(o,"htmx-")){o="htmx:"+o.slice(5)}Ft(e,o,n)}}}}function _t(t){if(v(t,Q.config.disableSelector)){p(t);return}var r=ae(t);if(r.initHash!==Le(t)){Ne(t);r.initHash=Le(t);Vt(t);ce(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=it(t);var n=Ht(t,r,e);if(!n){if(ne(t,"hx-boost")==="true"){lt(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){Lt(t,e,r,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&o(t,"form")){Ut(t)}var i=te(t,"hx-sse");if(i){St(t,r,i)}var a=te(t,"hx-ws");if(a){pt(t,r,a)}ce(t,"htmx:afterProcessNode")}}function zt(e){e=g(e);if(v(e,Q.config.disableSelector)){p(e);return}_t(e);oe(Pt(e),function(e){_t(e)});oe(kt(e),jt)}function $t(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=re().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function fe(e,t,r){ce(e,t,le({error:t},r))}function Gt(e){return e==="htmx:afterProcessNode"}function R(e,t){oe(Fr(e),function(e){try{t(e)}catch(e){b(e)}})}function b(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ce(e,t,r){e=g(e);if(r==null){r={}}r["elt"]=e;var n=Wt(t,r);if(Q.logger&&!Gt(t)){Q.logger(e,t,r)}if(r.error){b(r.error);ce(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=$t(t);if(i&&a!==t){var o=Wt(a,n.detail);i=i&&e.dispatchEvent(o)}R(e,function(e){i=i&&(e.onEvent(t,n)!==false&&!n.defaultPrevented)});return i}var Jt=location.pathname+location.search;function Zt(){var e=re().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||re().body}function Kt(e,t,r,n){if(!U()){return}if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}e=B(e);var i=E(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};ce(re().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Qt(e){var t=Q.config.requestClass;var r=e.cloneNode(true);oe(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function er(){var e=Zt();var t=Jt||location.pathname+location.search;var r;try{r=re().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){r=re().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!r){ce(re().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Kt(t,Qt(e),re().title,window.scrollY)}if(Q.config.historyEnabled)history.replaceState({htmx:true},re().title,window.location.href)}function tr(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(G(e,"&")||G(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Jt=e}function rr(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Jt=e}function nr(e){oe(e,function(e){e.call()})}function ir(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};ce(re().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",re().location.href);e.onload=function(){if(this.status>=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function fr(e){if(e.name===""||e.name==null||e.disabled||v(e,"fieldset[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 cr(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function hr(t,r,n,e,i){if(e==null||ur(t,e)){return}else{t.push(e)}if(fr(e)){var a=ee(e,"name");var o=e.value;if(e.multiple&&e.tagName==="SELECT"){o=M(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=M(e.files)}cr(a,o,r);if(i){vr(e,n)}}if(h(e,"form")){var s=e.elements;oe(s,function(e){hr(t,r,n,e,i)})}}function vr(e,t){if(e.willValidate){ce(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});ce(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function dr(e,t){var r=[];var n={};var i={};var a=[];var o=ae(e);if(o.lastButtonClicked&&!se(o.lastButtonClicked)){o.lastButtonClicked=null}var s=h(e,"form")&&e.noValidate!==true||te(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){hr(r,i,a,v(e,"form"),s)}hr(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=ee(l,"name");cr(u,l.value,i)}var f=pe(e,"hx-include");oe(f,function(e){hr(r,n,a,e,s);if(!h(e,"form")){oe(e.querySelectorAll(rt),function(e){hr(r,n,a,e,s)})}});n=le(n,i);return{errors:a,values:n}}function gr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function mr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t=gr(t,r,e)})}else{t=gr(t,r,n)}}}return t}function pr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function xr(e,t,r){var n={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":re().location.href};Rr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ae(e).boosted){n["HX-Boosted"]="true"}return n}function yr(t,e){var r=ne(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){oe(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};oe(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function br(e){return ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=d(o.substr(5))}else if(o.indexOf("settle:")===0){n["settleDelay"]=d(o.substr(7))}else if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}else if(o.indexOf("ignoreTitle:")===0){n["ignoreTitle"]=o.substr(12)==="true"}else if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","<style> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file +// v2.0.0 from https://github.com/bigskysoftware/htmx/releases +var htmx=function(){"use strict";const Q={onLoad:null,process:null,on:null,off:null,trigger:null,ajax:null,find:null,findAll:null,closest:null,values:function(e,t){const n=cn(e,t||"post");return n.values},remove:null,addClass:null,removeClass:null,toggleClass:null,takeClass:null,swap:null,defineExtension:null,removeExtension:null,logAll:null,logNone:null,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",inlineStyleNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",scrollBehavior:"instant",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get","delete"],selfRequestsOnly:true,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null,disableInheritance:false,responseHandling:[{code:"204",swap:false},{code:"[23]..",swap:true},{code:"[45]..",swap:false,error:true}],allowNestedOobSwaps:true},parseInterval:null,_:null,version:"2.0.0"};Q.onLoad=$;Q.process=Dt;Q.on=be;Q.off=we;Q.trigger=he;Q.ajax=Hn;Q.find=r;Q.findAll=p;Q.closest=g;Q.remove=K;Q.addClass=W;Q.removeClass=o;Q.toggleClass=Y;Q.takeClass=ge;Q.swap=ze;Q.defineExtension=Un;Q.removeExtension=Bn;Q.logAll=z;Q.logNone=J;Q.parseInterval=d;Q._=_;const n={addTriggerHandler:Et,bodyContains:le,canAccessLocalStorage:j,findThisElement:Ee,filterValues:dn,swap:ze,hasAttribute:s,getAttributeValue:te,getClosestAttributeValue:re,getClosestMatch:T,getExpressionVars:Cn,getHeaders:hn,getInputValues:cn,getInternalData:ie,getSwapSpecification:pn,getTriggerSpecs:lt,getTarget:Ce,makeFragment:D,mergeObjects:ue,makeSettleInfo:xn,oobSwap:Te,querySelectorExt:fe,settleImmediately:Gt,shouldCancel:dt,triggerEvent:he,triggerErrorEvent:ae,withExtensions:Ut};const v=["get","post","put","delete","patch"];const R=v.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");const O=e("head");function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e instanceof Element&&e.getAttribute(t)}function s(e,t){return!!e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){const t=e.parentElement;if(!t&&e.parentNode instanceof ShadowRoot)return e.parentNode;return t}function ne(){return document}function H(e,t){return e.getRootNode?e.getRootNode({composed:t}):ne()}function T(e,t){while(e&&!t(e)){e=u(e)}return e||null}function q(e,t,n){const r=te(t,n);const o=te(t,"hx-disinherit");var i=te(t,"hx-inherit");if(e!==t){if(Q.config.disableInheritance){if(i&&(i==="*"||i.split(" ").indexOf(n)>=0)){return r}else{return null}}if(o&&(o==="*"||o.split(" ").indexOf(n)>=0)){return"unset"}}return r}function re(t,n){let r=null;T(t,function(e){return!!(r=q(t,ce(e),n))});if(r!=="unset"){return r}}function a(e,t){const n=e instanceof Element&&(e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector);return!!n&&n.call(e,t)}function L(e){const t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;const n=t.exec(e);if(n){return n[1].toLowerCase()}else{return""}}function N(e){const t=new DOMParser;return t.parseFromString(e,"text/html")}function A(e,t){while(t.childNodes.length>0){e.append(t.childNodes[0])}}function I(e){const t=ne().createElement("script");se(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}return t}function P(e){return e.matches("script")&&(e.type==="text/javascript"||e.type==="module"||e.type==="")}function k(e){Array.from(e.querySelectorAll("script")).forEach(e=>{if(P(e)){const t=I(e);const n=e.parentNode;try{n.insertBefore(t,e)}catch(e){w(e)}finally{e.remove()}}})}function D(e){const t=e.replace(O,"");const n=L(t);let r;if(n==="html"){r=new DocumentFragment;const i=N(e);A(r,i.body);r.title=i.title}else if(n==="body"){r=new DocumentFragment;const i=N(t);A(r,i.body);r.title=i.title}else{const i=N('<body><template class="internal-htmx-wrapper">'+t+"</template></body>");r=i.querySelector("template").content;r.title=i.title;var o=r.querySelector("title");if(o&&o.parentNode===r){o.remove();r.title=o.innerText}}if(r){if(Q.config.allowScriptTags){k(r)}else{r.querySelectorAll("script").forEach(e=>e.remove())}}return r}function oe(e){if(e){e()}}function t(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function M(e){return typeof e==="function"}function X(e){return t(e,"Object")}function ie(e){const t="htmx-internal-data";let n=e[t];if(!n){n=e[t]={}}return n}function F(t){const n=[];if(t){for(let e=0;e<t.length;e++){n.push(t[e])}}return n}function se(t,n){if(t){for(let e=0;e<t.length;e++){n(t[e])}}}function U(e){const t=e.getBoundingClientRect();const n=t.top;const r=t.bottom;return n<window.innerHeight&&r>=0}function le(e){const t=e.getRootNode&&e.getRootNode();if(t&&t instanceof window.ShadowRoot){return ne().body.contains(t.host)}else{return ne().body.contains(e)}}function B(e){return e.trim().split(/\s+/)}function ue(e,t){for(const n in t){if(t.hasOwnProperty(n)){e[n]=t[n]}}return e}function S(e){try{return JSON.parse(e)}catch(e){w(e);return null}}function j(){const e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function V(t){try{const e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function _(e){return vn(ne().body,function(){return eval(e)})}function $(t){const e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function z(){Q.logger=function(e,t,n){if(console){console.log(t,e,n)}}}function J(){Q.logger=null}function r(e,t){if(typeof e!=="string"){return e.querySelector(t)}else{return r(ne(),e)}}function p(e,t){if(typeof e!=="string"){return e.querySelectorAll(t)}else{return p(ne(),e)}}function E(){return window}function K(e,t){e=y(e);if(t){E().setTimeout(function(){K(e);e=null},t)}else{u(e).removeChild(e)}}function ce(e){return e instanceof Element?e:null}function G(e){return e instanceof HTMLElement?e:null}function Z(e){return typeof e==="string"?e:null}function h(e){return e instanceof Element||e instanceof Document||e instanceof DocumentFragment?e:null}function W(e,t,n){e=ce(y(e));if(!e){return}if(n){E().setTimeout(function(){W(e,t);e=null},n)}else{e.classList&&e.classList.add(t)}}function o(e,t,n){let r=ce(y(e));if(!r){return}if(n){E().setTimeout(function(){o(r,t);r=null},n)}else{if(r.classList){r.classList.remove(t);if(r.classList.length===0){r.removeAttribute("class")}}}}function Y(e,t){e=y(e);e.classList.toggle(t)}function ge(e,t){e=y(e);se(e.parentElement.children,function(e){o(e,t)});W(ce(e),t)}function g(e,t){e=ce(y(e));if(e&&e.closest){return e.closest(t)}else{do{if(e==null||a(e,t)){return e}}while(e=e&&ce(u(e)));return null}}function l(e,t){return e.substring(0,t.length)===t}function pe(e,t){return e.substring(e.length-t.length)===t}function i(e){const t=e.trim();if(l(t,"<")&&pe(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function m(e,t,n){e=y(e);if(t.indexOf("closest ")===0){return[g(ce(e),i(t.substr(8)))]}else if(t.indexOf("find ")===0){return[r(h(e),i(t.substr(5)))]}else if(t==="next"){return[ce(e).nextElementSibling]}else if(t.indexOf("next ")===0){return[me(e,i(t.substr(5)),!!n)]}else if(t==="previous"){return[ce(e).previousElementSibling]}else if(t.indexOf("previous ")===0){return[ye(e,i(t.substr(9)),!!n)]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else if(t==="root"){return[H(e,!!n)]}else if(t.indexOf("global ")===0){return m(e,t.slice(7),true)}else{return F(h(H(e,!!n)).querySelectorAll(i(t)))}}var me=function(t,e,n){const r=h(H(t,n)).querySelectorAll(e);for(let e=0;e<r.length;e++){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_PRECEDING){return o}}};var ye=function(t,e,n){const r=h(H(t,n)).querySelectorAll(e);for(let e=r.length-1;e>=0;e--){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_FOLLOWING){return o}}};function fe(e,t){if(typeof e!=="string"){return m(e,t)[0]}else{return m(ne().body,e)[0]}}function y(e,t){if(typeof e==="string"){return r(h(t)||document,e)}else{return e}}function xe(e,t,n){if(M(t)){return{target:ne().body,event:Z(e),listener:t}}else{return{target:y(e),event:Z(t),listener:n}}}function be(t,n,r){_n(function(){const e=xe(t,n,r);e.target.addEventListener(e.event,e.listener)});const e=M(n);return e?n:r}function we(t,n,r){_n(function(){const e=xe(t,n,r);e.target.removeEventListener(e.event,e.listener)});return M(n)?n:r}const ve=ne().createElement("output");function Se(e,t){const n=re(e,t);if(n){if(n==="this"){return[Ee(e,t)]}else{const r=m(e,n);if(r.length===0){w('The selector "'+n+'" on '+t+" returned no matches!");return[ve]}else{return r}}}}function Ee(e,t){return ce(T(e,function(e){return te(ce(e),t)!=null}))}function Ce(e){const t=re(e,"hx-target");if(t){if(t==="this"){return Ee(e,"hx-target")}else{return fe(e,t)}}else{const n=ie(e);if(n.boosted){return ne().body}else{return e}}}function Re(t){const n=Q.config.attributesToSettle;for(let e=0;e<n.length;e++){if(t===n[e]){return true}}return false}function Oe(t,n){se(t.attributes,function(e){if(!n.hasAttribute(e.name)&&Re(e.name)){t.removeAttribute(e.name)}});se(n.attributes,function(e){if(Re(e.name)){t.setAttribute(e.name,e.value)}})}function He(t,e){const n=jn(e);for(let e=0;e<n.length;e++){const r=n[e];try{if(r.isInlineSwap(t)){return true}}catch(e){w(e)}}return t==="outerHTML"}function Te(e,o,i){let t="#"+ee(o,"id");let s="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){s=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{s=e}const n=ne().querySelectorAll(t);if(n){se(n,function(e){let t;const n=o.cloneNode(true);t=ne().createDocumentFragment();t.appendChild(n);if(!He(s,e)){t=h(n)}const r={shouldSwap:true,target:e,fragment:t};if(!he(e,"htmx:oobBeforeSwap",r))return;e=r.target;if(r.shouldSwap){_e(s,e,e,t,i)}se(i.elts,function(e){he(e,"htmx:oobAfterSwap",r)})});o.parentNode.removeChild(o)}else{o.parentNode.removeChild(o);ae(ne().body,"htmx:oobErrorNoTarget",{content:o})}return e}function qe(e){se(p(e,"[hx-preserve], [data-hx-preserve]"),function(e){const t=te(e,"id");const n=ne().getElementById(t);if(n!=null){e.parentNode.replaceChild(n,e)}})}function Le(l,e,u){se(e.querySelectorAll("[id]"),function(t){const n=ee(t,"id");if(n&&n.length>0){const r=n.replace("'","\\'");const o=t.tagName.replace(":","\\:");const e=h(l);const i=e&&e.querySelector(o+"[id='"+r+"']");if(i&&i!==e){const s=t.cloneNode();Oe(t,i);u.tasks.push(function(){Oe(t,s)})}}})}function Ne(e){return function(){o(e,Q.config.addedClass);Dt(ce(e));Ae(h(e));he(e,"htmx:load")}}function Ae(e){const t="[autofocus]";const n=G(a(e,t)?e:e.querySelector(t));if(n!=null){n.focus()}}function c(e,t,n,r){Le(e,n,r);while(n.childNodes.length>0){const o=n.firstChild;W(ce(o),Q.config.addedClass);e.insertBefore(o,t);if(o.nodeType!==Node.TEXT_NODE&&o.nodeType!==Node.COMMENT_NODE){r.tasks.push(Ne(o))}}}function Ie(e,t){let n=0;while(n<e.length){t=(t<<5)-t+e.charCodeAt(n++)|0}return t}function Pe(t){let n=0;if(t.attributes){for(let e=0;e<t.attributes.length;e++){const r=t.attributes[e];if(r.value){n=Ie(r.name,n);n=Ie(r.value,n)}}}return n}function ke(t){const n=ie(t);if(n.onHandlers){for(let e=0;e<n.onHandlers.length;e++){const r=n.onHandlers[e];we(t,r.event,r.listener)}delete n.onHandlers}}function De(e){const t=ie(e);if(t.timeout){clearTimeout(t.timeout)}if(t.listenerInfos){se(t.listenerInfos,function(e){if(e.on){we(e.on,e.trigger,e.listener)}})}ke(e);se(Object.keys(t),function(e){delete t[e]})}function f(e){he(e,"htmx:beforeCleanupElement");De(e);if(e.children){se(e.children,function(e){f(e)})}}function Me(t,e,n){let r;const o=t.previousSibling;c(u(t),t,e,n);if(o==null){r=u(t).firstChild}else{r=o.nextSibling}n.elts=n.elts.filter(function(e){return e!==t});while(r&&r!==t){if(r instanceof Element){n.elts.push(r);r=r.nextElementSibling}else{r=null}}f(t);if(t instanceof Element){t.remove()}else{t.parentNode.removeChild(t)}}function Xe(e,t,n){return c(e,e.firstChild,t,n)}function Fe(e,t,n){return c(u(e),e,t,n)}function Ue(e,t,n){return c(e,null,t,n)}function Be(e,t,n){return c(u(e),e.nextSibling,t,n)}function je(e){f(e);return u(e).removeChild(e)}function Ve(e,t,n){const r=e.firstChild;c(e,r,t,n);if(r){while(r.nextSibling){f(r.nextSibling);e.removeChild(r.nextSibling)}f(r);e.removeChild(r)}}function _e(t,e,n,r,o){switch(t){case"none":return;case"outerHTML":Me(n,r,o);return;case"afterbegin":Xe(n,r,o);return;case"beforebegin":Fe(n,r,o);return;case"beforeend":Ue(n,r,o);return;case"afterend":Be(n,r,o);return;case"delete":je(n);return;default:var i=jn(e);for(let e=0;e<i.length;e++){const s=i[e];try{const l=s.handleSwap(t,n,r,o);if(l){if(typeof l.length!=="undefined"){for(let e=0;e<l.length;e++){const u=l[e];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){o.tasks.push(Ne(u))}}}return}}catch(e){w(e)}}if(t==="innerHTML"){Ve(n,r,o)}else{_e(Q.config.defaultSwapStyle,e,n,r,o)}}}function $e(e,n){se(p(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){if(Q.config.allowNestedOobSwaps||e.parentElement===null){const t=te(e,"hx-swap-oob");if(t!=null){Te(t,e,n)}}else{e.removeAttribute("hx-swap-oob");e.removeAttribute("data-hx-swap-oob")}})}function ze(e,t,r,o){if(!o){o={}}e=y(e);const n=document.activeElement;let i={};try{i={elt:n,start:n?n.selectionStart:null,end:n?n.selectionEnd:null}}catch(e){}const s=xn(e);if(r.swapStyle==="textContent"){e.textContent=t}else{let n=D(t);s.title=n.title;if(o.selectOOB){const u=o.selectOOB.split(",");for(let t=0;t<u.length;t++){const c=u[t].split(":",2);let e=c[0].trim();if(e.indexOf("#")===0){e=e.substring(1)}const f=c[1]||"true";const a=n.querySelector("#"+e);if(a){Te(f,a,s)}}}$e(n,s);se(p(n,"template"),function(e){$e(e.content,s);if(e.content.childElementCount===0){e.remove()}});if(o.select){const h=ne().createDocumentFragment();se(n.querySelectorAll(o.select),function(e){h.appendChild(e)});n=h}qe(n);_e(r.swapStyle,o.contextElement,e,n,s)}if(i.elt&&!le(i.elt)&&ee(i.elt,"id")){const d=document.getElementById(ee(i.elt,"id"));const g={preventScroll:r.focusScroll!==undefined?!r.focusScroll:!Q.config.defaultFocusScroll};if(d){if(i.start&&d.setSelectionRange){try{d.setSelectionRange(i.start,i.end)}catch(e){}}d.focus(g)}}e.classList.remove(Q.config.swappingClass);se(s.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}he(e,"htmx:afterSwap",o.eventInfo)});if(o.afterSwapCallback){o.afterSwapCallback()}if(!r.ignoreTitle){Dn(s.title)}const l=function(){se(s.tasks,function(e){e.call()});se(s.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}he(e,"htmx:afterSettle",o.eventInfo)});if(o.anchor){const e=ce(y("#"+o.anchor));if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}bn(s.elts,r);if(o.afterSettleCallback){o.afterSettleCallback()}};if(r.settleDelay>0){E().setTimeout(l,r.settleDelay)}else{l()}}function Je(e,t,n){const r=e.getResponseHeader(t);if(r.indexOf("{")===0){const o=S(r);for(const i in o){if(o.hasOwnProperty(i)){let e=o[i];if(!X(e)){e={value:e}}he(n,i,e)}}}else{const s=r.split(",");for(let e=0;e<s.length;e++){he(n,s[e].trim(),[])}}}const Ke=/\s/;const x=/[\s,]/;const Ge=/[_$a-zA-Z]/;const Ze=/[_$a-zA-Z0-9]/;const We=['"',"'","/"];const Ye=/[^\s]/;const Qe=/[{(]/;const et=/[})]/;function tt(e){const t=[];let n=0;while(n<e.length){if(Ge.exec(e.charAt(n))){var r=n;while(Ze.exec(e.charAt(n+1))){n++}t.push(e.substr(r,n-r+1))}else if(We.indexOf(e.charAt(n))!==-1){const o=e.charAt(n);var r=n;n++;while(n<e.length&&e.charAt(n)!==o){if(e.charAt(n)==="\\"){n++}n++}t.push(e.substr(r,n-r+1))}else{const i=e.charAt(n);t.push(i)}n++}return t}function nt(e,t,n){return Ge.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==n&&t!=="."}function rt(r,o,i){if(o[0]==="["){o.shift();let e=1;let t=" return (function("+i+"){ return (";let n=null;while(o.length>0){const s=o[0];if(s==="]"){e--;if(e===0){if(n===null){t=t+"true"}o.shift();t+=")})";try{const l=vn(r,function(){return Function(t)()},function(){return true});l.source=t;return l}catch(e){ae(ne().body,"htmx:syntax:error",{error:e,source:t});return null}}}else if(s==="["){e++}if(nt(s,n,i)){t+="(("+i+"."+s+") ? ("+i+"."+s+") : (window."+s+"))"}else{t=t+s}n=o.shift()}}}function b(e,t){let n="";while(e.length>0&&!t.test(e[0])){n+=e.shift()}return n}function ot(e){let t;if(e.length>0&&Qe.test(e[0])){e.shift();t=b(e,et).trim();e.shift()}else{t=b(e,x)}return t}const it="input, textarea, select";function st(e,t,n){const r=[];const o=tt(t);do{b(o,Ye);const l=o.length;const u=b(o,/[,\[\s]/);if(u!==""){if(u==="every"){const c={trigger:"every"};b(o,Ye);c.pollInterval=d(b(o,/[,\[\s]/));b(o,Ye);var i=rt(e,o,"event");if(i){c.eventFilter=i}r.push(c)}else{const f={trigger:u};var i=rt(e,o,"event");if(i){f.eventFilter=i}while(o.length>0&&o[0]!==","){b(o,Ye);const a=o.shift();if(a==="changed"){f.changed=true}else if(a==="once"){f.once=true}else if(a==="consume"){f.consume=true}else if(a==="delay"&&o[0]===":"){o.shift();f.delay=d(b(o,x))}else if(a==="from"&&o[0]===":"){o.shift();if(Qe.test(o[0])){var s=ot(o)}else{var s=b(o,x);if(s==="closest"||s==="find"||s==="next"||s==="previous"){o.shift();const h=ot(o);if(h.length>0){s+=" "+h}}}f.from=s}else if(a==="target"&&o[0]===":"){o.shift();f.target=ot(o)}else if(a==="throttle"&&o[0]===":"){o.shift();f.throttle=d(b(o,x))}else if(a==="queue"&&o[0]===":"){o.shift();f.queue=b(o,x)}else if(a==="root"&&o[0]===":"){o.shift();f[a]=ot(o)}else if(a==="threshold"&&o[0]===":"){o.shift();f[a]=b(o,x)}else{ae(e,"htmx:syntax:error",{token:o.shift()})}}r.push(f)}}if(o.length===l){ae(e,"htmx:syntax:error",{token:o.shift()})}b(o,Ye)}while(o[0]===","&&o.shift());if(n){n[t]=r}return r}function lt(e){const t=te(e,"hx-trigger");let n=[];if(t){const r=Q.config.triggerSpecsCache;n=r&&r[t]||st(e,t,r)}if(n.length>0){return n}else if(a(e,"form")){return[{trigger:"submit"}]}else if(a(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(a(e,it)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function ut(e){ie(e).cancelled=true}function ct(e,t,n){const r=ie(e);r.timeout=E().setTimeout(function(){if(le(e)&&r.cancelled!==true){if(!pt(n,e,Xt("hx:poll:trigger",{triggerSpec:n,target:e}))){t(e)}ct(e,t,n)}},n.pollInterval)}function ft(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function at(e){return g(e,Q.config.disableSelector)}function ht(t,n,e){if(t instanceof HTMLAnchorElement&&ft(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){n.boosted=true;let r,o;if(t.tagName==="A"){r="get";o=ee(t,"href")}else{const i=ee(t,"method");r=i?i.toLowerCase():"get";if(r==="get"){}o=ee(t,"action")}e.forEach(function(e){mt(t,function(e,t){const n=ce(e);if(at(n)){f(n);return}de(r,o,n,t)},n,e,true)})}}function dt(e,t){const n=ce(t);if(!n){return false}if(e.type==="submit"||e.type==="click"){if(n.tagName==="FORM"){return true}if(a(n,'input[type="submit"], button')&&g(n,"form")!==null){return true}if(n instanceof HTMLAnchorElement&&n.href&&(n.getAttribute("href")==="#"||n.getAttribute("href").indexOf("#")!==0)){return true}}return false}function gt(e,t){return ie(e).boosted&&e instanceof HTMLAnchorElement&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function pt(e,t,n){const r=e.eventFilter;if(r){try{return r.call(t,n)!==true}catch(e){const o=r.source;ae(ne().body,"htmx:eventFilter:error",{error:e,source:o});return true}}return false}function mt(s,l,e,u,c){const f=ie(s);let t;if(u.from){t=m(s,u.from)}else{t=[s]}if(u.changed){t.forEach(function(e){const t=ie(e);t.lastValue=e.value})}se(t,function(o){const i=function(e){if(!le(s)){o.removeEventListener(u.trigger,i);return}if(gt(s,e)){return}if(c||dt(e,s)){e.preventDefault()}if(pt(u,s,e)){return}const t=ie(e);t.triggerSpec=u;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(s)<0){t.handledFor.push(s);if(u.consume){e.stopPropagation()}if(u.target&&e.target){if(!a(ce(e.target),u.target)){return}}if(u.once){if(f.triggeredOnce){return}else{f.triggeredOnce=true}}if(u.changed){const n=ie(o);const r=o.value;if(n.lastValue===r){return}n.lastValue=r}if(f.delayed){clearTimeout(f.delayed)}if(f.throttle){return}if(u.throttle>0){if(!f.throttle){l(s,e);f.throttle=E().setTimeout(function(){f.throttle=null},u.throttle)}}else if(u.delay>0){f.delayed=E().setTimeout(function(){l(s,e)},u.delay)}else{he(s,"htmx:trigger");l(s,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:u.trigger,listener:i,on:o});o.addEventListener(u.trigger,i)})}let yt=false;let xt=null;function bt(){if(!xt){xt=function(){yt=true};window.addEventListener("scroll",xt);setInterval(function(){if(yt){yt=false;se(ne().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"),function(e){wt(e)})}},200)}}function wt(e){if(!s(e,"data-hx-revealed")&&U(e)){e.setAttribute("data-hx-revealed","true");const t=ie(e);if(t.initHash){he(e,"revealed")}else{e.addEventListener("htmx:afterProcessNode",function(){he(e,"revealed")},{once:true})}}}function vt(e,t,n,r){const o=function(){if(!n.loaded){n.loaded=true;t(e)}};if(r>0){E().setTimeout(o,r)}else{o()}}function St(t,n,e){let i=false;se(v,function(r){if(s(t,"hx-"+r)){const o=te(t,"hx-"+r);i=true;n.path=o;n.verb=r;e.forEach(function(e){Et(t,e,n,function(e,t){const n=ce(e);if(g(n,Q.config.disableSelector)){f(n);return}de(r,o,n,t)})})}});return i}function Et(r,e,t,n){if(e.trigger==="revealed"){bt();mt(r,n,t,e);wt(ce(r))}else if(e.trigger==="intersect"){const o={};if(e.root){o.root=fe(r,e.root)}if(e.threshold){o.threshold=parseFloat(e.threshold)}const i=new IntersectionObserver(function(t){for(let e=0;e<t.length;e++){const n=t[e];if(n.isIntersecting){he(r,"intersect");break}}},o);i.observe(ce(r));mt(ce(r),n,t,e)}else if(e.trigger==="load"){if(!pt(e,r,Xt("load",{elt:r}))){vt(ce(r),n,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ct(ce(r),n,e)}else{mt(r,n,t,e)}}function Ct(e){const t=ce(e);if(!t){return false}const n=t.attributes;for(let e=0;e<n.length;e++){const r=n[e].name;if(l(r,"hx-on:")||l(r,"data-hx-on:")||l(r,"hx-on-")||l(r,"data-hx-on-")){return true}}return false}const Rt=(new XPathEvaluator).createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]');function Ot(e,t){if(Ct(e)){t.push(ce(e))}const n=Rt.evaluate(e);let r=null;while(r=n.iterateNext())t.push(ce(r))}function Ht(e){const t=[];if(e instanceof DocumentFragment){for(const n of e.childNodes){Ot(n,t)}}else{Ot(e,t)}return t}function Tt(e){if(e.querySelectorAll){const n=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";const r=[];for(const i in Xn){const s=Xn[i];if(s.getSelectors){var t=s.getSelectors();if(t){r.push(t)}}}const o=e.querySelectorAll(R+n+", form, [type='submit'],"+" [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]"+r.flat().map(e=>", "+e).join(""));return o}else{return[]}}function qt(e){const t=g(ce(e.target),"button, input[type='submit']");const n=Nt(e);if(n){n.lastButtonClicked=t}}function Lt(e){const t=Nt(e);if(t){t.lastButtonClicked=null}}function Nt(e){const t=g(ce(e.target),"button, input[type='submit']");if(!t){return}const n=y("#"+ee(t,"form"),t.getRootNode())||g(t,"form");if(!n){return}return ie(n)}function At(e){e.addEventListener("click",qt);e.addEventListener("focusin",qt);e.addEventListener("focusout",Lt)}function It(t,e,n){const r=ie(t);if(!Array.isArray(r.onHandlers)){r.onHandlers=[]}let o;const i=function(e){vn(t,function(){if(at(t)){return}if(!o){o=new Function("event",n)}o.call(t,e)})};t.addEventListener(e,i);r.onHandlers.push({event:e,listener:i})}function Pt(t){ke(t);for(let e=0;e<t.attributes.length;e++){const n=t.attributes[e].name;const r=t.attributes[e].value;if(l(n,"hx-on")||l(n,"data-hx-on")){const o=n.indexOf("-on")+3;const i=n.slice(o,o+1);if(i==="-"||i===":"){let e=n.slice(o+1);if(l(e,":")){e="htmx"+e}else if(l(e,"-")){e="htmx:"+e.slice(1)}else if(l(e,"htmx-")){e="htmx:"+e.slice(5)}It(t,e,r)}}}}function kt(t){if(g(t,Q.config.disableSelector)){f(t);return}const n=ie(t);if(n.initHash!==Pe(t)){De(t);n.initHash=Pe(t);he(t,"htmx:beforeProcessNode");if(t.value){n.lastValue=t.value}const e=lt(t);const r=St(t,n,e);if(!r){if(re(t,"hx-boost")==="true"){ht(t,n,e)}else if(s(t,"hx-trigger")){e.forEach(function(e){Et(t,e,n,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&s(t,"form")){At(t)}he(t,"htmx:afterProcessNode")}}function Dt(e){e=y(e);if(g(e,Q.config.disableSelector)){f(e);return}kt(e);se(Tt(e),function(e){kt(e)});se(Ht(e),Pt)}function Mt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Xt(e,t){let n;if(window.CustomEvent&&typeof window.CustomEvent==="function"){n=new CustomEvent(e,{bubbles:true,cancelable:true,composed:true,detail:t})}else{n=ne().createEvent("CustomEvent");n.initCustomEvent(e,true,true,t)}return n}function ae(e,t,n){he(e,t,ue({error:t},n))}function Ft(e){return e==="htmx:afterProcessNode"}function Ut(e,t){se(jn(e),function(e){try{t(e)}catch(e){w(e)}})}function w(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function he(e,t,n){e=y(e);if(n==null){n={}}n.elt=e;const r=Xt(t,n);if(Q.logger&&!Ft(t)){Q.logger(e,t,n)}if(n.error){w(n.error);he(e,"htmx:error",{errorInfo:n})}let o=e.dispatchEvent(r);const i=Mt(t);if(o&&i!==t){const s=Xt(i,r.detail);o=o&&e.dispatchEvent(s)}Ut(ce(e),function(e){o=o&&(e.onEvent(t,r)!==false&&!r.defaultPrevented)});return o}let Bt=location.pathname+location.search;function jt(){const e=ne().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||ne().body}function Vt(t,e){if(!j()){return}const n=$t(e);const r=ne().title;const o=window.scrollY;if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}t=V(t);const i=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e<i.length;e++){if(i[e].url===t){i.splice(e,1);break}}const s={url:t,content:n,title:r,scroll:o};he(ne().body,"htmx:historyItemCreated",{item:s,cache:i});i.push(s);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ae(ne().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function _t(t){if(!j()){return null}t=V(t);const n=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e<n.length;e++){if(n[e].url===t){return n[e]}}return null}function $t(e){const t=Q.config.requestClass;const n=e.cloneNode(true);se(p(n,"."+t),function(e){o(e,t)});return n.innerHTML}function zt(){const e=jt();const t=Bt||location.pathname+location.search;let n;try{n=ne().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){n=ne().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!n){he(ne().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Vt(t,e)}if(Q.config.historyEnabled)history.replaceState({htmx:true},ne().title,window.location.href)}function Jt(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(pe(e,"&")||pe(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Bt=e}function Kt(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Bt=e}function Gt(e){se(e,function(e){e.call(undefined)})}function Zt(o){const e=new XMLHttpRequest;const i={path:o,xhr:e};he(ne().body,"htmx:historyCacheMiss",i);e.open("GET",o,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",ne().location.href);e.onload=function(){if(this.status>=200&&this.status<400){he(ne().body,"htmx:historyCacheMissLoad",i);const e=D(this.response);const t=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;const n=jt();const r=xn(n);Dn(e.title);Ve(n,t,r);Gt(r.tasks);Bt=o;he(ne().body,"htmx:historyRestore",{path:o,cacheMiss:true,serverResponse:this.response})}else{ae(ne().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Wt(e){zt();e=e||location.pathname+location.search;const t=_t(e);if(t){const n=D(t.content);const r=jt();const o=xn(r);Dn(n.title);Ve(r,n,o);Gt(o.tasks);E().setTimeout(function(){window.scrollTo(0,t.scroll)},0);Bt=e;he(ne().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{Zt(e)}}}function Yt(e){let t=Se(e,"hx-indicator");if(t==null){t=[e]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.classList.add.call(e.classList,Q.config.requestClass)});return t}function Qt(e){let t=Se(e,"hx-disabled-elt");if(t==null){t=[]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function en(e,t){se(e,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList.remove.call(e.classList,Q.config.requestClass)}});se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function tn(t,n){for(let e=0;e<t.length;e++){const r=t[e];if(r.isSameNode(n)){return true}}return false}function nn(e){const t=e;if(t.name===""||t.name==null||t.disabled||g(t,"fieldset[disabled]")){return false}if(t.type==="button"||t.type==="submit"||t.tagName==="image"||t.tagName==="reset"||t.tagName==="file"){return false}if(t.type==="checkbox"||t.type==="radio"){return t.checked}return true}function rn(t,e,n){if(t!=null&&e!=null){if(Array.isArray(e)){e.forEach(function(e){n.append(t,e)})}else{n.append(t,e)}}}function on(t,n,r){if(t!=null&&n!=null){let e=r.getAll(t);if(Array.isArray(n)){e=e.filter(e=>n.indexOf(e)<0)}else{e=e.filter(e=>e!==n)}r.delete(t);se(e,e=>r.append(t,e))}}function sn(t,n,r,o,i){if(o==null||tn(t,o)){return}else{t.push(o)}if(nn(o)){const s=ee(o,"name");let e=o.value;if(o instanceof HTMLSelectElement&&o.multiple){e=F(o.querySelectorAll("option:checked")).map(function(e){return e.value})}if(o instanceof HTMLInputElement&&o.files){e=F(o.files)}rn(s,e,n);if(i){ln(o,r)}}if(o instanceof HTMLFormElement){se(o.elements,function(e){if(t.indexOf(e)>=0){on(e.name,e.value,n)}else{t.push(e)}if(i){ln(e,r)}});new FormData(o).forEach(function(e,t){if(e instanceof File&&e.name===""){return}rn(t,e,n)})}}function ln(e,t){const n=e;if(n.willValidate){he(n,"htmx:validation:validate");if(!n.checkValidity()){t.push({elt:n,message:n.validationMessage,validity:n.validity});he(n,"htmx:validation:failed",{message:n.validationMessage,validity:n.validity})}}}function un(t,e){for(const n of e.keys()){t.delete(n);e.getAll(n).forEach(function(e){t.append(n,e)})}return t}function cn(e,t){const n=[];const r=new FormData;const o=new FormData;const i=[];const s=ie(e);if(s.lastButtonClicked&&!le(s.lastButtonClicked)){s.lastButtonClicked=null}let l=e instanceof HTMLFormElement&&e.noValidate!==true||te(e,"hx-validate")==="true";if(s.lastButtonClicked){l=l&&s.lastButtonClicked.formNoValidate!==true}if(t!=="get"){sn(n,o,i,g(e,"form"),l)}sn(n,r,i,e,l);if(s.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){const c=s.lastButtonClicked||e;const f=ee(c,"name");rn(f,c.value,o)}const u=Se(e,"hx-include");se(u,function(e){sn(n,r,i,ce(e),l);if(!a(e,"form")){se(h(e).querySelectorAll(it),function(e){sn(n,r,i,e,l)})}});un(r,o);return{errors:i,formData:r,values:An(r)}}function fn(e,t,n){if(e!==""){e+="&"}if(String(n)==="[object Object]"){n=JSON.stringify(n)}const r=encodeURIComponent(n);e+=encodeURIComponent(t)+"="+r;return e}function an(e){e=Ln(e);let n="";e.forEach(function(e,t){n=fn(n,t,e)});return n}function hn(e,t,n){const r={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":ne().location.href};wn(e,"hx-headers",false,r);if(n!==undefined){r["HX-Prompt"]=n}if(ie(e).boosted){r["HX-Boosted"]="true"}return r}function dn(n,e){const t=re(e,"hx-params");if(t){if(t==="none"){return new FormData}else if(t==="*"){return n}else if(t.indexOf("not ")===0){se(t.substr(4).split(","),function(e){e=e.trim();n.delete(e)});return n}else{const r=new FormData;se(t.split(","),function(t){t=t.trim();if(n.has(t)){n.getAll(t).forEach(function(e){r.append(t,e)})}});return r}}else{return n}}function gn(e){return!!ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function pn(e,t){const n=t||re(e,"hx-swap");const r={swapStyle:ie(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ie(e).boosted&&!gn(e)){r.show="top"}if(n){const s=B(n);if(s.length>0){for(let e=0;e<s.length;e++){const l=s[e];if(l.indexOf("swap:")===0){r.swapDelay=d(l.substr(5))}else if(l.indexOf("settle:")===0){r.settleDelay=d(l.substr(7))}else if(l.indexOf("transition:")===0){r.transition=l.substr(11)==="true"}else if(l.indexOf("ignoreTitle:")===0){r.ignoreTitle=l.substr(12)==="true"}else if(l.indexOf("scroll:")===0){const u=l.substr(7);var o=u.split(":");const c=o.pop();var i=o.length>0?o.join(":"):null;r.scroll=c;r.scrollTarget=i}else if(l.indexOf("show:")===0){const f=l.substr(5);var o=f.split(":");const a=o.pop();var i=o.length>0?o.join(":"):null;r.show=a;r.showTarget=i}else if(l.indexOf("focus-scroll:")===0){const h=l.substr("focus-scroll:".length);r.focusScroll=h=="true"}else if(e==0){r.swapStyle=l}else{w("Unknown modifier in hx-swap: "+l)}}}}return r}function mn(e){return re(e,"hx-encoding")==="multipart/form-data"||a(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function yn(t,n,r){let o=null;Ut(n,function(e){if(o==null){o=e.encodeParameters(t,r,n)}});if(o!=null){return o}else{if(mn(n)){return un(new FormData,Ln(r))}else{return an(r)}}}function xn(e){return{tasks:[],elts:[e]}}function bn(e,t){const n=e[0];const r=e[e.length-1];if(t.scroll){var o=null;if(t.scrollTarget){o=ce(fe(n,t.scrollTarget))}if(t.scroll==="top"&&(n||o)){o=o||n;o.scrollTop=0}if(t.scroll==="bottom"&&(r||o)){o=o||r;o.scrollTop=o.scrollHeight}}if(t.show){var o=null;if(t.showTarget){let e=t.showTarget;if(t.showTarget==="window"){e="body"}o=ce(fe(n,e))}if(t.show==="top"&&(n||o)){o=o||n;o.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(r||o)){o=o||r;o.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function wn(r,e,o,i){if(i==null){i={}}if(r==null){return i}const s=te(r,e);if(s){let e=s.trim();let t=o;if(e==="unset"){return null}if(e.indexOf("javascript:")===0){e=e.substr(11);t=true}else if(e.indexOf("js:")===0){e=e.substr(3);t=true}if(e.indexOf("{")!==0){e="{"+e+"}"}let n;if(t){n=vn(r,function(){return Function("return ("+e+")")()},{})}else{n=S(e)}for(const l in n){if(n.hasOwnProperty(l)){if(i[l]==null){i[l]=n[l]}}}}return wn(ce(u(r)),e,o,i)}function vn(e,t,n){if(Q.config.allowEval){return t()}else{ae(e,"htmx:evalDisallowedError");return n}}function Sn(e,t){return wn(e,"hx-vars",true,t)}function En(e,t){return wn(e,"hx-vals",false,t)}function Cn(e){return ue(Sn(e),En(e))}function Rn(t,n,r){if(r!==null){try{t.setRequestHeader(n,r)}catch(e){t.setRequestHeader(n,encodeURIComponent(r));t.setRequestHeader(n+"-URI-AutoEncoded","true")}}}function On(t){if(t.responseURL&&typeof URL!=="undefined"){try{const e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ae(ne().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function C(e,t){return t.test(e.getAllResponseHeaders())}function Hn(e,t,n){e=e.toLowerCase();if(n){if(n instanceof Element||typeof n==="string"){return de(e,t,null,null,{targetOverride:y(n),returnPromise:true})}else{return de(e,t,y(n.source),n.event,{handler:n.handler,headers:n.headers,values:n.values,targetOverride:y(n.target),swapOverride:n.swap,select:n.select,returnPromise:true})}}else{return de(e,t,null,null,{returnPromise:true})}}function Tn(e){const t=[];while(e){t.push(e);e=e.parentElement}return t}function qn(e,t,n){let r;let o;if(typeof URL==="function"){o=new URL(t,document.location.href);const i=document.location.origin;r=i===o.origin}else{o=t;r=l(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!r){return false}}return he(e,"htmx:validateUrl",ue({url:o,sameHost:r},n))}function Ln(e){if(e instanceof FormData)return e;const t=new FormData;for(const n in e){if(e.hasOwnProperty(n)){if(typeof e[n].forEach==="function"){e[n].forEach(function(e){t.append(n,e)})}else if(typeof e[n]==="object"){t.append(n,JSON.stringify(e[n]))}else{t.append(n,e[n])}}}return t}function Nn(r,o,e){return new Proxy(e,{get:function(t,e){if(typeof e==="number")return t[e];if(e==="length")return t.length;if(e==="push"){return function(e){t.push(e);r.append(o,e)}}if(typeof t[e]==="function"){return function(){t[e].apply(t,arguments);r.delete(o);t.forEach(function(e){r.append(o,e)})}}if(t[e]&&t[e].length===1){return t[e][0]}else{return t[e]}},set:function(e,t,n){e[t]=n;r.delete(o);e.forEach(function(e){r.append(o,e)});return true}})}function An(r){return new Proxy(r,{get:function(e,t){if(typeof t==="symbol"){return Reflect.get(e,t)}if(t==="toJSON"){return()=>Object.fromEntries(r)}if(t in e){if(typeof e[t]==="function"){return function(){return r[t].apply(r,arguments)}}else{return e[t]}}const n=r.getAll(t);if(n.length===0){return undefined}else if(n.length===1){return n[0]}else{return Nn(e,t,n)}},set:function(t,n,e){if(typeof n!=="string"){return false}t.delete(n);if(typeof e.forEach==="function"){e.forEach(function(e){t.append(n,e)})}else{t.append(n,e)}return true},deleteProperty:function(e,t){if(typeof t==="string"){e.delete(t)}return true},ownKeys:function(e){return Reflect.ownKeys(Object.fromEntries(e))},getOwnPropertyDescriptor:function(e,t){return Reflect.getOwnPropertyDescriptor(Object.fromEntries(e),t)}})}function de(t,n,r,o,i,D){let s=null;let l=null;i=i!=null?i:{};if(i.returnPromise&&typeof Promise!=="undefined"){var e=new Promise(function(e,t){s=e;l=t})}if(r==null){r=ne().body}const M=i.handler||Mn;const X=i.select||null;if(!le(r)){oe(s);return e}const u=i.targetOverride||ce(Ce(r));if(u==null||u==ve){ae(r,"htmx:targetError",{target:te(r,"hx-target")});oe(l);return e}let c=ie(r);const f=c.lastButtonClicked;if(f){const L=ee(f,"formaction");if(L!=null){n=L}const N=ee(f,"formmethod");if(N!=null){if(N.toLowerCase()!=="dialog"){t=N}}}const a=re(r,"hx-confirm");if(D===undefined){const K=function(e){return de(t,n,r,o,i,!!e)};const G={target:u,elt:r,path:n,verb:t,triggeringEvent:o,etc:i,issueRequest:K,question:a};if(he(r,"htmx:confirm",G)===false){oe(s);return e}}let h=r;let d=re(r,"hx-sync");let g=null;let F=false;if(d){const A=d.split(":");const I=A[0].trim();if(I==="this"){h=Ee(r,"hx-sync")}else{h=ce(fe(r,I))}d=(A[1]||"drop").trim();c=ie(h);if(d==="drop"&&c.xhr&&c.abortable!==true){oe(s);return e}else if(d==="abort"){if(c.xhr){oe(s);return e}else{F=true}}else if(d==="replace"){he(h,"htmx:abort")}else if(d.indexOf("queue")===0){const Z=d.split(" ");g=(Z[1]||"last").trim()}}if(c.xhr){if(c.abortable){he(h,"htmx:abort")}else{if(g==null){if(o){const P=ie(o);if(P&&P.triggerSpec&&P.triggerSpec.queue){g=P.triggerSpec.queue}}if(g==null){g="last"}}if(c.queuedRequests==null){c.queuedRequests=[]}if(g==="first"&&c.queuedRequests.length===0){c.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="all"){c.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="last"){c.queuedRequests=[];c.queuedRequests.push(function(){de(t,n,r,o,i)})}oe(s);return e}}const p=new XMLHttpRequest;c.xhr=p;c.abortable=F;const m=function(){c.xhr=null;c.abortable=false;if(c.queuedRequests!=null&&c.queuedRequests.length>0){const e=c.queuedRequests.shift();e()}};const U=re(r,"hx-prompt");if(U){var y=prompt(U);if(y===null||!he(r,"htmx:prompt",{prompt:y,target:u})){oe(s);m();return e}}if(a&&!D){if(!confirm(a)){oe(s);m();return e}}let x=hn(r,u,y);if(t!=="get"&&!mn(r)){x["Content-Type"]="application/x-www-form-urlencoded"}if(i.headers){x=ue(x,i.headers)}const B=cn(r,t);let b=B.errors;const j=B.formData;if(i.values){un(j,Ln(i.values))}const V=Ln(Cn(r));const w=un(j,V);let v=dn(w,r);if(Q.config.getCacheBusterParam&&t==="get"){v.set("org.htmx.cache-buster",ee(u,"id")||"true")}if(n==null||n===""){n=ne().location.href}const S=wn(r,"hx-request");const _=ie(r).boosted;let E=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;const C={boosted:_,useUrlParams:E,formData:v,parameters:An(v),unfilteredFormData:w,unfilteredParameters:An(w),headers:x,target:u,verb:t,errors:b,withCredentials:i.credentials||S.credentials||Q.config.withCredentials,timeout:i.timeout||S.timeout||Q.config.timeout,path:n,triggeringEvent:o};if(!he(r,"htmx:configRequest",C)){oe(s);m();return e}n=C.path;t=C.verb;x=C.headers;v=Ln(C.parameters);b=C.errors;E=C.useUrlParams;if(b&&b.length>0){he(r,"htmx:validation:halted",C);oe(s);m();return e}const $=n.split("#");const z=$[0];const R=$[1];let O=n;if(E){O=z;const W=!v.keys().next().done;if(W){if(O.indexOf("?")<0){O+="?"}else{O+="&"}O+=an(v);if(R){O+="#"+R}}}if(!qn(r,O,C)){ae(r,"htmx:invalidPath",C);oe(l);return e}p.open(t.toUpperCase(),O,true);p.overrideMimeType("text/html");p.withCredentials=C.withCredentials;p.timeout=C.timeout;if(S.noHeaders){}else{for(const k in x){if(x.hasOwnProperty(k)){const Y=x[k];Rn(p,k,Y)}}}const H={xhr:p,target:u,requestConfig:C,etc:i,boosted:_,select:X,pathInfo:{requestPath:n,finalRequestPath:O,responsePath:null,anchor:R}};p.onload=function(){try{const t=Tn(r);H.pathInfo.responsePath=On(p);M(r,H);en(T,q);he(r,"htmx:afterRequest",H);he(r,"htmx:afterOnLoad",H);if(!le(r)){let e=null;while(t.length>0&&e==null){const n=t.shift();if(le(n)){e=n}}if(e){he(e,"htmx:afterRequest",H);he(e,"htmx:afterOnLoad",H)}}oe(s);m()}catch(e){ae(r,"htmx:onLoadError",ue({error:e},H));throw e}};p.onerror=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:sendError",H);oe(l);m()};p.onabort=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:sendAbort",H);oe(l);m()};p.ontimeout=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:timeout",H);oe(l);m()};if(!he(r,"htmx:beforeRequest",H)){oe(s);m();return e}var T=Yt(r);var q=Qt(r);se(["loadstart","loadend","progress","abort"],function(t){se([p,p.upload],function(e){e.addEventListener(t,function(e){he(r,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});he(r,"htmx:beforeSend",H);const J=E?null:yn(p,r,v);p.send(J);return e}function In(e,t){const n=t.xhr;let r=null;let o=null;if(C(n,/HX-Push:/i)){r=n.getResponseHeader("HX-Push");o="push"}else if(C(n,/HX-Push-Url:/i)){r=n.getResponseHeader("HX-Push-Url");o="push"}else if(C(n,/HX-Replace-Url:/i)){r=n.getResponseHeader("HX-Replace-Url");o="replace"}if(r){if(r==="false"){return{}}else{return{type:o,path:r}}}const i=t.pathInfo.finalRequestPath;const s=t.pathInfo.responsePath;const l=re(e,"hx-push-url");const u=re(e,"hx-replace-url");const c=ie(e).boosted;let f=null;let a=null;if(l){f="push";a=l}else if(u){f="replace";a=u}else if(c){f="push";a=s||i}if(a){if(a==="false"){return{}}if(a==="true"){a=s||i}if(t.pathInfo.anchor&&a.indexOf("#")===-1){a=a+"#"+t.pathInfo.anchor}return{type:f,path:a}}else{return{}}}function Pn(e,t){var n=new RegExp(e.code);return n.test(t.toString(10))}function kn(e){for(var t=0;t<Q.config.responseHandling.length;t++){var n=Q.config.responseHandling[t];if(Pn(n,e.status)){return n}}return{swap:false}}function Dn(e){if(e){const t=r("title");if(t){t.innerHTML=e}else{window.document.title=e}}}function Mn(o,i){const s=i.xhr;let l=i.target;const e=i.etc;const u=i.select;if(!he(o,"htmx:beforeOnLoad",i))return;if(C(s,/HX-Trigger:/i)){Je(s,"HX-Trigger",o)}if(C(s,/HX-Location:/i)){zt();let e=s.getResponseHeader("HX-Location");var t;if(e.indexOf("{")===0){t=S(e);e=t.path;delete t.path}Hn("get",e,t).then(function(){Jt(e)});return}const n=C(s,/HX-Refresh:/i)&&s.getResponseHeader("HX-Refresh")==="true";if(C(s,/HX-Redirect:/i)){location.href=s.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(C(s,/HX-Retarget:/i)){if(s.getResponseHeader("HX-Retarget")==="this"){i.target=o}else{i.target=ce(fe(o,s.getResponseHeader("HX-Retarget")))}}const c=In(o,i);const r=kn(s);const f=r.swap;let a=!!r.error;let h=Q.config.ignoreTitle||r.ignoreTitle;let d=r.select;if(r.target){i.target=ce(fe(o,r.target))}var g=e.swapOverride;if(g==null&&r.swapOverride){g=r.swapOverride}if(C(s,/HX-Retarget:/i)){if(s.getResponseHeader("HX-Retarget")==="this"){i.target=o}else{i.target=ce(fe(o,s.getResponseHeader("HX-Retarget")))}}if(C(s,/HX-Reswap:/i)){g=s.getResponseHeader("HX-Reswap")}var p=s.response;var m=ue({shouldSwap:f,serverResponse:p,isError:a,ignoreTitle:h,selectOverride:d},i);if(r.event&&!he(l,r.event,m))return;if(!he(l,"htmx:beforeSwap",m))return;l=m.target;p=m.serverResponse;a=m.isError;h=m.ignoreTitle;d=m.selectOverride;i.target=l;i.failed=a;i.successful=!a;if(m.shouldSwap){if(s.status===286){ut(o)}Ut(o,function(e){p=e.transformResponse(p,s,o)});if(c.type){zt()}if(C(s,/HX-Reswap:/i)){g=s.getResponseHeader("HX-Reswap")}var y=pn(o,g);if(!y.hasOwnProperty("ignoreTitle")){y.ignoreTitle=h}l.classList.add(Q.config.swappingClass);let n=null;let r=null;if(u){d=u}if(C(s,/HX-Reselect:/i)){d=s.getResponseHeader("HX-Reselect")}const x=re(o,"hx-select-oob");const b=re(o,"hx-select");let e=function(){try{if(c.type){he(ne().body,"htmx:beforeHistoryUpdate",ue({history:c},i));if(c.type==="push"){Jt(c.path);he(ne().body,"htmx:pushedIntoHistory",{path:c.path})}else{Kt(c.path);he(ne().body,"htmx:replacedInHistory",{path:c.path})}}ze(l,p,y,{select:d||b,selectOOB:x,eventInfo:i,anchor:i.pathInfo.anchor,contextElement:o,afterSwapCallback:function(){if(C(s,/HX-Trigger-After-Swap:/i)){let e=o;if(!le(o)){e=ne().body}Je(s,"HX-Trigger-After-Swap",e)}},afterSettleCallback:function(){if(C(s,/HX-Trigger-After-Settle:/i)){let e=o;if(!le(o)){e=ne().body}Je(s,"HX-Trigger-After-Settle",e)}oe(n)}})}catch(e){ae(o,"htmx:swapError",i);oe(r);throw e}};let t=Q.config.globalViewTransitions;if(y.hasOwnProperty("transition")){t=y.transition}if(t&&he(o,"htmx:beforeTransition",i)&&typeof Promise!=="undefined"&&document.startViewTransition){const w=new Promise(function(e,t){n=e;r=t});const v=e;e=function(){document.startViewTransition(function(){v();return w})}}if(y.swapDelay>0){E().setTimeout(e,y.swapDelay)}else{e()}}if(a){ae(o,"htmx:responseError",ue({error:"Response Status Error Code "+s.status+" from "+i.pathInfo.requestPath},i))}}const Xn={};function Fn(){return{init:function(e){return null},getSelectors:function(){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,n){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,n,r){return false},encodeParameters:function(e,t,n){return null}}}function Un(e,t){if(t.init){t.init(n)}Xn[e]=ue(Fn(),t)}function Bn(e){delete Xn[e]}function jn(e,n,r){if(n==undefined){n=[]}if(e==undefined){return n}if(r==undefined){r=[]}const t=te(e,"hx-ext");if(t){se(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){r.push(e.slice(7));return}if(r.indexOf(e)<0){const t=Xn[e];if(t&&n.indexOf(t)<0){n.push(t)}}})}return jn(ce(u(e)),n,r)}var Vn=false;ne().addEventListener("DOMContentLoaded",function(){Vn=true});function _n(e){if(Vn||ne().readyState==="complete"){e()}else{ne().addEventListener("DOMContentLoaded",e)}}function $n(){if(Q.config.includeIndicatorStyles!==false){const e=Q.config.inlineStyleNonce?` nonce="${Q.config.inlineStyleNonce}"`:"";ne().head.insertAdjacentHTML("beforeend","<style"+e+"> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zn(){const e=ne().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function Jn(){const e=zn();if(e){Q.config=ue(Q.config,e)}}_n(function(){Jn();$n();let e=ne().body;Dt(e);const t=ne().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){const t=e.target;const n=ie(t);if(n&&n.xhr){n.xhr.abort()}});const n=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){Wt();se(t,function(e){he(e,"htmx:restored",{document:ne(),triggerEvent:he})})}else{if(n){n(e)}}};E().setTimeout(function(){he(e,"htmx:load",{});e=null},0)});return Q}(); \ No newline at end of file diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/templates/shared/_layout.html b/code/ch7_infinite_scroll/ch7_starter_video_collector/templates/shared/_layout.html index a13399e..57e80e7 100644 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/templates/shared/_layout.html +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/templates/shared/_layout.html @@ -52,7 +52,7 @@ </footer> -<script src="/https/github.com/static/js/htmx.min.js?v=1.5.0"></script> +<script src="/https/github.com/static/js/htmx.min.js?v=2.0.0"></script> <script src="/https/github.com/static/js/jquery-3.5.1.slim.min.js"></script> <script src="/https/github.com/static/js/popper-1.16.1.min.js"></script> diff --git a/code/starter_video_collector/static/js/htmx.d.ts b/code/starter_video_collector/static/js/htmx.d.ts new file mode 100644 index 0000000..3775459 --- /dev/null +++ b/code/starter_video_collector/static/js/htmx.d.ts @@ -0,0 +1,195 @@ +declare namespace htmx { + const onLoad: (callback: (elt: Node) => void) => EventListener; + const process: (elt: string | Element) => void; + const on: (arg1: string | EventTarget, arg2: string | EventListener, arg3?: EventListener) => EventListener; + const off: (arg1: string | EventTarget, arg2: string | EventListener, arg3?: EventListener) => EventListener; + const trigger: (elt: string | EventTarget, eventName: string, detail?: any) => boolean; + const ajax: (verb: HttpVerb, path: string, context: string | Element | HtmxAjaxHelperContext) => Promise<void>; + const find: (eltOrSelector: string | ParentNode, selector?: string) => Element; + const findAll: (eltOrSelector: string | ParentNode, selector?: string) => NodeListOf<Element>; + const closest: (elt: string | Element, selector: string) => Element; + function values(elt: Element, type: HttpVerb): any; + const remove: (elt: Node, delay?: number) => void; + const addClass: (elt: string | Element, clazz: string, delay?: number) => void; + const removeClass: (node: string | Node, clazz: string, delay?: number) => void; + const toggleClass: (elt: string | Element, clazz: string) => void; + const takeClass: (elt: string | Node, clazz: string) => void; + const swap: (target: string | Element, content: string, swapSpec: HtmxSwapSpecification, swapOptions?: SwapOptions) => void; + const defineExtension: (name: string, extension: any) => void; + const removeExtension: (name: string) => void; + const logAll: () => void; + const logNone: () => void; + const logger: any; + namespace config { + const historyEnabled: boolean; + const historyCacheSize: number; + const refreshOnHistoryMiss: boolean; + const defaultSwapStyle: HtmxSwapStyle; + const defaultSwapDelay: number; + const defaultSettleDelay: number; + const includeIndicatorStyles: boolean; + const indicatorClass: string; + const requestClass: string; + const addedClass: string; + const settlingClass: string; + const swappingClass: string; + const allowEval: boolean; + const allowScriptTags: boolean; + const inlineScriptNonce: string; + const inlineStyleNonce: string; + const attributesToSettle: string[]; + const withCredentials: boolean; + const timeout: number; + const wsReconnectDelay: "full-jitter" | ((retryCount: number) => number); + const wsBinaryType: BinaryType; + const disableSelector: string; + const scrollBehavior: 'auto' | 'instant' | 'smooth'; + const defaultFocusScroll: boolean; + const getCacheBusterParam: boolean; + const globalViewTransitions: boolean; + const methodsThatUseUrlParams: (HttpVerb)[]; + const selfRequestsOnly: boolean; + const ignoreTitle: boolean; + const scrollIntoViewOnBoost: boolean; + const triggerSpecsCache: any | null; + const disableInheritance: boolean; + const responseHandling: HtmxResponseHandlingConfig[]; + const allowNestedOobSwaps: boolean; + } + const parseInterval: (str: string) => number; + const _: (str: string) => any; + const version: string; +} +type HttpVerb = 'get' | 'head' | 'post' | 'put' | 'delete' | 'connect' | 'options' | 'trace' | 'patch'; +type SwapOptions = { + select?: string; + selectOOB?: string; + eventInfo?: any; + anchor?: string; + contextElement?: Element; + afterSwapCallback?: swapCallback; + afterSettleCallback?: swapCallback; +}; +type swapCallback = () => any; +type HtmxSwapStyle = 'innerHTML' | 'outerHTML' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'delete' | 'none' | string; +type HtmxSwapSpecification = { + swapStyle: HtmxSwapStyle; + swapDelay: number; + settleDelay: number; + transition?: boolean; + ignoreTitle?: boolean; + head?: string; + scroll?: 'top' | 'bottom'; + scrollTarget?: string; + show?: string; + showTarget?: string; + focusScroll?: boolean; +}; +type ConditionalFunction = ((this: Node, evt: Event) => boolean) & { + source: string; +}; +type HtmxTriggerSpecification = { + trigger: string; + pollInterval?: number; + eventFilter?: ConditionalFunction; + changed?: boolean; + once?: boolean; + consume?: boolean; + delay?: number; + from?: string; + target?: string; + throttle?: number; + queue?: string; + root?: string; + threshold?: string; +}; +type HtmxElementValidationError = { + elt: Element; + message: string; + validity: ValidityState; +}; +type HtmxHeaderSpecification = Record<string, string>; +type HtmxAjaxHelperContext = { + source?: Element | string; + event?: Event; + handler?: HtmxAjaxHandler; + target: Element | string; + swap?: HtmxSwapStyle; + values?: any | FormData; + headers?: Record<string, string>; + select?: string; +}; +type HtmxRequestConfig = { + boosted: boolean; + useUrlParams: boolean; + formData: FormData; + /** + * formData proxy + */ + parameters: any; + unfilteredFormData: FormData; + /** + * unfilteredFormData proxy + */ + unfilteredParameters: any; + headers: HtmxHeaderSpecification; + target: Element; + verb: HttpVerb; + errors: HtmxElementValidationError[]; + withCredentials: boolean; + timeout: number; + path: string; + triggeringEvent: Event; +}; +type HtmxResponseInfo = { + xhr: XMLHttpRequest; + target: Element; + requestConfig: HtmxRequestConfig; + etc: HtmxAjaxEtc; + boosted: boolean; + select: string; + pathInfo: { + requestPath: string; + finalRequestPath: string; + responsePath: string | null; + anchor: string; + }; + failed?: boolean; + successful?: boolean; +}; +type HtmxAjaxEtc = { + returnPromise?: boolean; + handler?: HtmxAjaxHandler; + select?: string; + targetOverride?: Element; + swapOverride?: HtmxSwapStyle; + headers?: Record<string, string>; + values?: any | FormData; + credentials?: boolean; + timeout?: number; +}; +type HtmxResponseHandlingConfig = { + code?: string; + swap: boolean; + error?: boolean; + ignoreTitle?: boolean; + select?: string; + target?: string; + swapOverride?: string; + event?: string; +}; +type HtmxBeforeSwapDetails = HtmxResponseInfo & { + shouldSwap: boolean; + serverResponse: any; + isError: boolean; + ignoreTitle: boolean; + selectOverride: string; +}; +type HtmxAjaxHandler = (elt: Element, responseInfo: HtmxResponseInfo) => any; +type HtmxSettleTask = (() => void); +type HtmxSettleInfo = { + tasks: HtmxSettleTask[]; + elts: Element[]; + title?: string; +}; +type HtmxExtension = any; diff --git a/code/starter_video_collector/static/js/htmx.js b/code/starter_video_collector/static/js/htmx.js index 86e7668..c57bcd7 100644 --- a/code/starter_video_collector/static/js/htmx.js +++ b/code/starter_video_collector/static/js/htmx.js @@ -1,3909 +1,5131 @@ -// /////////////////////////////////////////////////////////////////// -// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.js -// - -// UMD insanity -// This code sets up support for (in order) AMD, ES6 modules, and globals. -(function (root, factory) { - //@ts-ignore - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - //@ts-ignore - define([], factory); - } else if (typeof module === 'object' && module.exports) { - // Node. Does not work with strict CommonJS, but - // only CommonJS-like environments that support module.exports, - // like Node. - module.exports = factory(); - } else { - // Browser globals - root.htmx = root.htmx || factory(); - } -}(typeof self !== 'undefined' ? self : this, function () { -return (function () { - 'use strict'; - - // Public API - //** @type {import("./htmx").HtmxApi} */ - // TODO: list all methods in public API - var htmx = { - onLoad: onLoadHelper, - process: processNode, - on: addEventListenerImpl, - off: removeEventListenerImpl, - trigger : triggerEvent, - ajax : ajaxHelper, - find : find, - findAll : findAll, - closest : closest, - values : function(elt, type){ - var inputValues = getInputValues(elt, type || "post"); - return inputValues.values; - }, - remove : removeElement, - addClass : addClassToElement, - removeClass : removeClassFromElement, - toggleClass : toggleClassOnElement, - takeClass : takeClassForElement, - defineExtension : defineExtension, - removeExtension : removeExtension, - logAll : logAll, - logNone : logNone, - logger : null, - config : { - historyEnabled:true, - historyCacheSize:10, - refreshOnHistoryMiss:false, - defaultSwapStyle:'innerHTML', - defaultSwapDelay:0, - defaultSettleDelay:20, - includeIndicatorStyles:true, - indicatorClass:'htmx-indicator', - requestClass:'htmx-request', - addedClass:'htmx-added', - settlingClass:'htmx-settling', - swappingClass:'htmx-swapping', - allowEval:true, - allowScriptTags:true, - inlineScriptNonce:'', - attributesToSettle:["class", "style", "width", "height"], - withCredentials:false, - timeout:0, - wsReconnectDelay: 'full-jitter', - wsBinaryType: 'blob', - disableSelector: "[hx-disable], [data-hx-disable]", - useTemplateFragments: false, - scrollBehavior: 'smooth', - defaultFocusScroll: false, - getCacheBusterParam: false, - globalViewTransitions: false, - methodsThatUseUrlParams: ["get"], - selfRequestsOnly: false, - ignoreTitle: false, - scrollIntoViewOnBoost: true, - triggerSpecsCache: null, - }, - parseInterval:parseInterval, - _:internalEval, - createEventSource: function(url){ - return new EventSource(url, {withCredentials:true}) - }, - createWebSocket: function(url){ - var sock = new WebSocket(url, []); - sock.binaryType = htmx.config.wsBinaryType; - return sock; - }, - version: "1.9.10" - }; - - /** @type {import("./htmx").HtmxInternalApi} */ - var internalAPI = { - addTriggerHandler: addTriggerHandler, - bodyContains: bodyContains, - canAccessLocalStorage: canAccessLocalStorage, - findThisElement: findThisElement, - filterValues: filterValues, - hasAttribute: hasAttribute, - getAttributeValue: getAttributeValue, - getClosestAttributeValue: getClosestAttributeValue, - getClosestMatch: getClosestMatch, - getExpressionVars: getExpressionVars, - getHeaders: getHeaders, - getInputValues: getInputValues, - getInternalData: getInternalData, - getSwapSpecification: getSwapSpecification, - getTriggerSpecs: getTriggerSpecs, - getTarget: getTarget, - makeFragment: makeFragment, - mergeObjects: mergeObjects, - makeSettleInfo: makeSettleInfo, - oobSwap: oobSwap, - querySelectorExt: querySelectorExt, - selectAndSwap: selectAndSwap, - settleImmediately: settleImmediately, - shouldCancel: shouldCancel, - triggerEvent: triggerEvent, - triggerErrorEvent: triggerErrorEvent, - withExtensions: withExtensions, - } - - var VERBS = ['get', 'post', 'put', 'delete', 'patch']; - var VERB_SELECTOR = VERBS.map(function(verb){ - return "[hx-" + verb + "], [data-hx-" + verb + "]" - }).join(", "); - - var HEAD_TAG_REGEX = makeTagRegEx('head'), - TITLE_TAG_REGEX = makeTagRegEx('title'), - SVG_TAGS_REGEX = makeTagRegEx('svg', true); - - //==================================================================== - // Utilities - //==================================================================== - - /** - * @param {string} tag - * @param {boolean} global - * @returns {RegExp} - */ - function makeTagRegEx(tag, global = false) { - return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, - global ? 'gim' : 'im'); - } - - function parseInterval(str) { - if (str == undefined) { - return undefined; - } - - let interval = NaN; - if (str.slice(-2) == "ms") { - interval = parseFloat(str.slice(0, -2)); - } else if (str.slice(-1) == "s") { - interval = parseFloat(str.slice(0, -1)) * 1000; - } else if (str.slice(-1) == "m") { - interval = parseFloat(str.slice(0, -1)) * 1000 * 60; - } else { - interval = parseFloat(str); - } - return isNaN(interval) ? undefined : interval; - } - - /** - * @param {HTMLElement} elt - * @param {string} name - * @returns {(string | null)} - */ - function getRawAttribute(elt, name) { - return elt.getAttribute && elt.getAttribute(name); - } - - // resolve with both hx and data-hx prefixes - function hasAttribute(elt, qualifiedName) { - return elt.hasAttribute && (elt.hasAttribute(qualifiedName) || - elt.hasAttribute("data-" + qualifiedName)); - } - - /** - * - * @param {HTMLElement} elt - * @param {string} qualifiedName - * @returns {(string | null)} - */ - function getAttributeValue(elt, qualifiedName) { - return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); - } - - /** - * @param {HTMLElement} elt - * @returns {HTMLElement | null} - */ - function parentElt(elt) { - return elt.parentElement; - } - - /** - * @returns {Document} - */ - function getDocument() { - return document; - } - - /** - * @param {HTMLElement} elt - * @param {(e:HTMLElement) => boolean} condition - * @returns {HTMLElement | null} - */ - function getClosestMatch(elt, condition) { - while (elt && !condition(elt)) { - elt = parentElt(elt); - } - - return elt ? elt : null; - } - - function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){ - var attributeValue = getAttributeValue(ancestor, attributeName); - var disinherit = getAttributeValue(ancestor, "hx-disinherit"); - if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) { - return "unset"; - } else { - return attributeValue - } - } - - /** - * @param {HTMLElement} elt - * @param {string} attributeName - * @returns {string | null} - */ - function getClosestAttributeValue(elt, attributeName) { - var closestAttr = null; - getClosestMatch(elt, function (e) { - return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName); - }); - if (closestAttr !== "unset") { - return closestAttr; - } - } - - /** - * @param {HTMLElement} elt - * @param {string} selector - * @returns {boolean} - */ - function matches(elt, selector) { - // @ts-ignore: non-standard properties for browser compatibility - // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector; - return matchesFunction && matchesFunction.call(elt, selector); - } - - /** - * @param {string} str - * @returns {string} - */ - 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 ""; - } - } - - /** - * - * @param {string} resp - * @param {number} depth - * @returns {Element} - */ - function parseHTML(resp, depth) { - var parser = new DOMParser(); - var responseDoc = parser.parseFromString(resp, "text/html"); - - /** @type {Element} */ - var responseNode = responseDoc.body; - while (depth > 0) { - depth--; - // @ts-ignore - responseNode = responseNode.firstChild; - } - if (responseNode == null) { - // @ts-ignore - responseNode = getDocument().createDocumentFragment(); - } - return responseNode; - } - - function aFullPageResponse(resp) { - return /<body/.test(resp) - } +// v2.0.0 from https://github.com/bigskysoftware/htmx/releases + +var htmx = (function() { + 'use strict' + + // Public API + const htmx = { + // Tsc madness here, assigning the functions directly results in an invalid TypeScript output, but reassigning is fine + /* Event processing */ + /** @type {typeof onLoadHelper} */ + onLoad: null, + /** @type {typeof processNode} */ + process: null, + /** @type {typeof addEventListenerImpl} */ + on: null, + /** @type {typeof removeEventListenerImpl} */ + off: null, + /** @type {typeof triggerEvent} */ + trigger: null, + /** @type {typeof ajaxHelper} */ + ajax: null, + /* DOM querying helpers */ + /** @type {typeof find} */ + find: null, + /** @type {typeof findAll} */ + findAll: null, + /** @type {typeof closest} */ + closest: null, + /** + * Returns the input values that would resolve for a given element via the htmx value resolution mechanism + * + * @see https://htmx.org/api/#values + * + * @param {Element} elt the element to resolve values on + * @param {HttpVerb} type the request type (e.g. **get** or **post**) non-GET's will include the enclosing form of the element. Defaults to **post** + * @returns {Object} + */ + values: function(elt, type) { + const inputValues = getInputValues(elt, type || 'post') + return inputValues.values + }, + /* DOM manipulation helpers */ + /** @type {typeof removeElement} */ + remove: null, + /** @type {typeof addClassToElement} */ + addClass: null, + /** @type {typeof removeClassFromElement} */ + removeClass: null, + /** @type {typeof toggleClassOnElement} */ + toggleClass: null, + /** @type {typeof takeClassForElement} */ + takeClass: null, + /** @type {typeof swap} */ + swap: null, + /* Extension entrypoints */ + /** @type {typeof defineExtension} */ + defineExtension: null, + /** @type {typeof removeExtension} */ + removeExtension: null, + /* Debugging */ + /** @type {typeof logAll} */ + logAll: null, + /** @type {typeof logNone} */ + logNone: null, + /* Debugging */ + /** + * The logger htmx uses to log with + * + * @see https://htmx.org/api/#logger + */ + logger: null, + /** + * A property holding the configuration htmx uses at runtime. + * + * Note that using a [meta tag](https://htmx.org/docs/#config) is the preferred mechanism for setting these properties. + * + * @see https://htmx.org/api/#config + */ + config: { + /** + * Whether to use history. + * @type boolean + * @default true + */ + historyEnabled: true, + /** + * The number of pages to keep in **localStorage** for history support. + * @type number + * @default 10 + */ + historyCacheSize: 10, + /** + * @type boolean + * @default false + */ + refreshOnHistoryMiss: false, + /** + * The default swap style to use if **[hx-swap](https://htmx.org/attributes/hx-swap)** is omitted. + * @type HtmxSwapStyle + * @default 'innerHTML' + */ + defaultSwapStyle: 'innerHTML', + /** + * The default delay between receiving a response from the server and doing the swap. + * @type number + * @default 0 + */ + defaultSwapDelay: 0, + /** + * The default delay between completing the content swap and settling attributes. + * @type number + * @default 20 + */ + defaultSettleDelay: 20, + /** + * If true, htmx will inject a small amount of CSS into the page to make indicators invisible unless the **htmx-indicator** class is present. + * @type boolean + * @default true + */ + includeIndicatorStyles: true, + /** + * The class to place on indicators when a request is in flight. + * @type string + * @default 'htmx-indicator' + */ + indicatorClass: 'htmx-indicator', + /** + * The class to place on triggering elements when a request is in flight. + * @type string + * @default 'htmx-request' + */ + requestClass: 'htmx-request', + /** + * The class to temporarily place on elements that htmx has added to the DOM. + * @type string + * @default 'htmx-added' + */ + addedClass: 'htmx-added', + /** + * The class to place on target elements when htmx is in the settling phase. + * @type string + * @default 'htmx-settling' + */ + settlingClass: 'htmx-settling', + /** + * The class to place on target elements when htmx is in the swapping phase. + * @type string + * @default 'htmx-swapping' + */ + swappingClass: 'htmx-swapping', + /** + * Allows the use of eval-like functionality in htmx, to enable **hx-vars**, trigger conditions & script tag evaluation. Can be set to **false** for CSP compatibility. + * @type boolean + * @default true + */ + allowEval: true, + /** + * If set to false, disables the interpretation of script tags. + * @type boolean + * @default true + */ + allowScriptTags: true, + /** + * If set, the nonce will be added to inline scripts. + * @type string + * @default '' + */ + inlineScriptNonce: '', + /** + * If set, the nonce will be added to inline styles. + * @type string + * @default '' + */ + inlineStyleNonce: '', + /** + * The attributes to settle during the settling phase. + * @type string[] + * @default ['class', 'style', 'width', 'height'] + */ + attributesToSettle: ['class', 'style', 'width', 'height'], + /** + * Allow cross-site Access-Control requests using credentials such as cookies, authorization headers or TLS client certificates. + * @type boolean + * @default false + */ + withCredentials: false, + /** + * @type number + * @default 0 + */ + timeout: 0, + /** + * The default implementation of **getWebSocketReconnectDelay** for reconnecting after unexpected connection loss by the event code **Abnormal Closure**, **Service Restart** or **Try Again Later**. + * @type {'full-jitter' | ((retryCount:number) => number)} + * @default "full-jitter" + */ + wsReconnectDelay: 'full-jitter', + /** + * The type of binary data being received over the WebSocket connection + * @type BinaryType + * @default 'blob' + */ + wsBinaryType: 'blob', + /** + * @type string + * @default '[hx-disable], [data-hx-disable]' + */ + disableSelector: '[hx-disable], [data-hx-disable]', + /** + * @type {'auto' | 'instant' | 'smooth'} + * @default 'smooth' + */ + scrollBehavior: 'instant', + /** + * If the focused element should be scrolled into view. + * @type boolean + * @default false + */ + defaultFocusScroll: false, + /** + * If set to true htmx will include a cache-busting parameter in GET requests to avoid caching partial responses by the browser + * @type boolean + * @default false + */ + getCacheBusterParam: false, + /** + * If set to true, htmx will use the View Transition API when swapping in new content. + * @type boolean + * @default false + */ + globalViewTransitions: false, + /** + * htmx will format requests with these methods by encoding their parameters in the URL, not the request body + * @type {(HttpVerb)[]} + * @default ['get', 'delete'] + */ + methodsThatUseUrlParams: ['get', 'delete'], + /** + * If set to true, disables htmx-based requests to non-origin hosts. + * @type boolean + * @default false + */ + selfRequestsOnly: true, + /** + * If set to true htmx will not update the title of the document when a title tag is found in new content + * @type boolean + * @default false + */ + ignoreTitle: false, + /** + * Whether the target of a boosted element is scrolled into the viewport. + * @type boolean + * @default true + */ + scrollIntoViewOnBoost: true, + /** + * The cache to store evaluated trigger specifications into. + * You may define a simple object to use a never-clearing cache, or implement your own system using a [proxy object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Proxy) + * @type {Object|null} + * @default null + */ + triggerSpecsCache: null, + /** @type boolean */ + disableInheritance: false, + /** @type HtmxResponseHandlingConfig[] */ + responseHandling: [ + { code: '204', swap: false }, + { code: '[23]..', swap: true }, + { code: '[45]..', swap: false, error: true } + ], + /** + * Whether to process OOB swaps on elements that are nested within the main response element. + * @type boolean + * @default true + */ + allowNestedOobSwaps: true + }, + /** @type {typeof parseInterval} */ + parseInterval: null, + /** @type {typeof internalEval} */ + _: null, + version: '2.0.0' + } + // Tsc madness part 2 + htmx.onLoad = onLoadHelper + htmx.process = processNode + htmx.on = addEventListenerImpl + htmx.off = removeEventListenerImpl + htmx.trigger = triggerEvent + htmx.ajax = ajaxHelper + htmx.find = find + htmx.findAll = findAll + htmx.closest = closest + htmx.remove = removeElement + htmx.addClass = addClassToElement + htmx.removeClass = removeClassFromElement + htmx.toggleClass = toggleClassOnElement + htmx.takeClass = takeClassForElement + htmx.swap = swap + htmx.defineExtension = defineExtension + htmx.removeExtension = removeExtension + htmx.logAll = logAll + htmx.logNone = logNone + htmx.parseInterval = parseInterval + htmx._ = internalEval + + const internalAPI = { + addTriggerHandler, + bodyContains, + canAccessLocalStorage, + findThisElement, + filterValues, + swap, + hasAttribute, + getAttributeValue, + getClosestAttributeValue, + getClosestMatch, + getExpressionVars, + getHeaders, + getInputValues, + getInternalData, + getSwapSpecification, + getTriggerSpecs, + getTarget, + makeFragment, + mergeObjects, + makeSettleInfo, + oobSwap, + querySelectorExt, + settleImmediately, + shouldCancel, + triggerEvent, + triggerErrorEvent, + withExtensions + } + + const VERBS = ['get', 'post', 'put', 'delete', 'patch'] + const VERB_SELECTOR = VERBS.map(function(verb) { + return '[hx-' + verb + '], [data-hx-' + verb + ']' + }).join(', ') + + const HEAD_TAG_REGEX = makeTagRegEx('head') + + //= =================================================================== + // Utilities + //= =================================================================== + + /** + * @param {string} tag + * @param {boolean} global + * @returns {RegExp} + */ + function makeTagRegEx(tag, global = false) { + return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, + global ? 'gim' : 'im') + } + + /** + * Parses an interval string consistent with the way htmx does. Useful for plugins that have timing-related attributes. + * + * Caution: Accepts an int followed by either **s** or **ms**. All other values use **parseFloat** + * + * @see https://htmx.org/api/#parseInterval + * + * @param {string} str timing string + * @returns {number|undefined} + */ + function parseInterval(str) { + if (str == undefined) { + return undefined + } - /** - * - * @param {string} response - * @returns {Element} - */ - function makeFragment(response) { - var partialResponse = !aFullPageResponse(response); - var startTag = getStartTag(response); - var content = response; - if (startTag === 'head') { - content = content.replace(HEAD_TAG_REGEX, ''); - } - if (htmx.config.useTemplateFragments && partialResponse) { - var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0); - // @ts-ignore type mismatch between DocumentFragment and Element. - // TODO: Are these close enough for htmx to use interchangeably? - return documentFragment.querySelector('template').content; - } - switch (startTag) { - case "thead": - case "tbody": - case "tfoot": - case "colgroup": - case "caption": - return parseHTML("<table>" + content + "</table>", 1); - case "col": - return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2); - case "tr": - return parseHTML("<table><tbody>" + content + "</tbody></table>", 2); - case "td": - case "th": - return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3); - case "script": - case "style": - return parseHTML("<div>" + content + "</div>", 1); - default: - return parseHTML(content, 0); - } - } + let interval = NaN + if (str.slice(-2) == 'ms') { + interval = parseFloat(str.slice(0, -2)) + } else if (str.slice(-1) == 's') { + interval = parseFloat(str.slice(0, -1)) * 1000 + } else if (str.slice(-1) == 'm') { + interval = parseFloat(str.slice(0, -1)) * 1000 * 60 + } else { + interval = parseFloat(str) + } + return isNaN(interval) ? undefined : interval + } + + /** + * @param {Node} elt + * @param {string} name + * @returns {(string | null)} + */ + function getRawAttribute(elt, name) { + return elt instanceof Element && elt.getAttribute(name) + } + + /** + * @param {Element} elt + * @param {string} qualifiedName + * @returns {boolean} + */ + // resolve with both hx and data-hx prefixes + function hasAttribute(elt, qualifiedName) { + return !!elt.hasAttribute && (elt.hasAttribute(qualifiedName) || + elt.hasAttribute('data-' + qualifiedName)) + } + + /** + * + * @param {Node} elt + * @param {string} qualifiedName + * @returns {(string | null)} + */ + function getAttributeValue(elt, qualifiedName) { + return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, 'data-' + qualifiedName) + } + + /** + * @param {Node} elt + * @returns {Node | null} + */ + function parentElt(elt) { + const parent = elt.parentElement + if (!parent && elt.parentNode instanceof ShadowRoot) return elt.parentNode + return parent + } + + /** + * @returns {Document} + */ + function getDocument() { + return document + } + + /** + * @param {Node} elt + * @param {boolean} global + * @returns {Node|Document} + */ + function getRootNode(elt, global) { + return elt.getRootNode ? elt.getRootNode({ composed: global }) : getDocument() + } + + /** + * @param {Node} elt + * @param {(e:Node) => boolean} condition + * @returns {Node | null} + */ + function getClosestMatch(elt, condition) { + while (elt && !condition(elt)) { + elt = parentElt(elt) + } - /** - * @param {Function} func - */ - function maybeCall(func){ - if(func) { - func(); - } + return elt || null + } + + /** + * @param {Element} initialElement + * @param {Element} ancestor + * @param {string} attributeName + * @returns {string|null} + */ + function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName) { + const attributeValue = getAttributeValue(ancestor, attributeName) + const disinherit = getAttributeValue(ancestor, 'hx-disinherit') + var inherit = getAttributeValue(ancestor, 'hx-inherit') + if (initialElement !== ancestor) { + if (htmx.config.disableInheritance) { + if (inherit && (inherit === '*' || inherit.split(' ').indexOf(attributeName) >= 0)) { + return attributeValue + } else { + return null + } + } + if (disinherit && (disinherit === '*' || disinherit.split(' ').indexOf(attributeName) >= 0)) { + return 'unset' + } + } + return attributeValue + } + + /** + * @param {Element} elt + * @param {string} attributeName + * @returns {string | null} + */ + function getClosestAttributeValue(elt, attributeName) { + let closestAttr = null + getClosestMatch(elt, function(e) { + return !!(closestAttr = getAttributeValueWithDisinheritance(elt, asElement(e), attributeName)) + }) + if (closestAttr !== 'unset') { + return closestAttr + } + } + + /** + * @param {Node} elt + * @param {string} selector + * @returns {boolean} + */ + function matches(elt, selector) { + // @ts-ignore: non-standard properties for browser compatibility + // noinspection JSUnresolvedVariable + const matchesFunction = elt instanceof Element && (elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector) + return !!matchesFunction && matchesFunction.call(elt, selector) + } + + /** + * @param {string} str + * @returns {string} + */ + function getStartTag(str) { + const tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i + const match = tagMatcher.exec(str) + if (match) { + return match[1].toLowerCase() + } else { + return '' + } + } + + /** + * @param {string} resp + * @returns {Document} + */ + function parseHTML(resp) { + const parser = new DOMParser() + return parser.parseFromString(resp, 'text/html') + } + + /** + * @param {DocumentFragment} fragment + * @param {Node} elt + */ + function takeChildrenFor(fragment, elt) { + while (elt.childNodes.length > 0) { + fragment.append(elt.childNodes[0]) + } + } + + /** + * @param {HTMLScriptElement} script + * @returns {HTMLScriptElement} + */ + function duplicateScript(script) { + const newScript = getDocument().createElement('script') + forEach(script.attributes, function(attr) { + newScript.setAttribute(attr.name, attr.value) + }) + newScript.textContent = script.textContent + newScript.async = false + if (htmx.config.inlineScriptNonce) { + newScript.nonce = htmx.config.inlineScriptNonce + } + return newScript + } + + /** + * @param {HTMLScriptElement} script + * @returns {boolean} + */ + function isJavaScriptScriptNode(script) { + return script.matches('script') && (script.type === 'text/javascript' || script.type === 'module' || script.type === '') + } + + /** + * we have to make new copies of script tags that we are going to insert because + * SOME browsers (not saying who, but it involves an element and an animal) don't + * execute scripts created in <template> tags when they are inserted into the DOM + * and all the others do lmao + * @param {DocumentFragment} fragment + */ + function normalizeScriptTags(fragment) { + Array.from(fragment.querySelectorAll('script')).forEach(/** @param {HTMLScriptElement} script */ (script) => { + if (isJavaScriptScriptNode(script)) { + const newScript = duplicateScript(script) + const parent = script.parentNode + try { + parent.insertBefore(newScript, script) + } catch (e) { + logError(e) + } finally { + script.remove() + } + } + }) + } + + /** + * @typedef {DocumentFragment & {title?: string}} DocumentFragmentWithTitle + * @description a document fragment representing the response HTML, including + * a `title` property for any title information found + */ + + /** + * @param {string} response HTML + * @returns {DocumentFragmentWithTitle} + */ + function makeFragment(response) { + // strip head tag to determine shape of response we are dealing with + const responseWithNoHead = response.replace(HEAD_TAG_REGEX, '') + const startTag = getStartTag(responseWithNoHead) + /** @type DocumentFragmentWithTitle */ + let fragment + if (startTag === 'html') { + // if it is a full document, parse it and return the body + fragment = /** @type DocumentFragmentWithTitle */ (new DocumentFragment()) + const doc = parseHTML(response) + takeChildrenFor(fragment, doc.body) + fragment.title = doc.title + } else if (startTag === 'body') { + // parse body w/o wrapping in template + fragment = /** @type DocumentFragmentWithTitle */ (new DocumentFragment()) + const doc = parseHTML(responseWithNoHead) + takeChildrenFor(fragment, doc.body) + fragment.title = doc.title + } else { + // otherwise we have non-body partial HTML content, so wrap it in a template to maximize parsing flexibility + const doc = parseHTML('<body><template class="internal-htmx-wrapper">' + responseWithNoHead + '</template></body>') + fragment = /** @type DocumentFragmentWithTitle */ (doc.querySelector('template').content) + // extract title into fragment for later processing + fragment.title = doc.title + + // for legacy reasons we support a title tag at the root level of non-body responses, so we need to handle it + var titleElement = fragment.querySelector('title') + if (titleElement && titleElement.parentNode === fragment) { + titleElement.remove() + fragment.title = titleElement.innerText + } + } + if (fragment) { + if (htmx.config.allowScriptTags) { + normalizeScriptTags(fragment) + } else { + // remove all script tags if scripts are disabled + fragment.querySelectorAll('script').forEach((script) => script.remove()) + } + } + return fragment + } + + /** + * @param {Function} func + */ + function maybeCall(func) { + if (func) { + func() + } + } + + /** + * @param {any} o + * @param {string} type + * @returns + */ + function isType(o, type) { + return Object.prototype.toString.call(o) === '[object ' + type + ']' + } + + /** + * @param {*} o + * @returns {o is Function} + */ + function isFunction(o) { + return typeof o === 'function' + } + + /** + * @param {*} o + * @returns {o is Object} + */ + function isRawObject(o) { + return isType(o, 'Object') + } + + /** + * @typedef {Object} OnHandler + * @property {(keyof HTMLElementEventMap)|string} event + * @property {EventListener} listener + */ + + /** + * @typedef {Object} ListenerInfo + * @property {string} trigger + * @property {EventListener} listener + * @property {EventTarget} on + */ + + /** + * @typedef {Object} HtmxNodeInternalData + * Element data + * @property {number} [initHash] + * @property {boolean} [boosted] + * @property {OnHandler[]} [onHandlers] + * @property {number} [timeout] + * @property {ListenerInfo[]} [listenerInfos] + * @property {boolean} [cancelled] + * @property {boolean} [triggeredOnce] + * @property {number} [delayed] + * @property {number|null} [throttle] + * @property {string} [lastValue] + * @property {boolean} [loaded] + * @property {string} [path] + * @property {string} [verb] + * @property {boolean} [polling] + * @property {HTMLButtonElement|HTMLInputElement|null} [lastButtonClicked] + * @property {number} [requestCount] + * @property {XMLHttpRequest} [xhr] + * @property {(() => void)[]} [queuedRequests] + * @property {boolean} [abortable] + * + * Event data + * @property {HtmxTriggerSpecification} [triggerSpec] + * @property {EventTarget[]} [handledFor] + */ + + /** + * getInternalData retrieves "private" data stored by htmx within an element + * @param {EventTarget|Event} elt + * @returns {HtmxNodeInternalData} + */ + function getInternalData(elt) { + const dataProp = 'htmx-internal-data' + let data = elt[dataProp] + if (!data) { + data = elt[dataProp] = {} + } + return data + } + + /** + * toArray converts an ArrayLike object into a real array. + * @template T + * @param {ArrayLike<T>} arr + * @returns {T[]} + */ + function toArray(arr) { + const returnArr = [] + if (arr) { + for (let i = 0; i < arr.length; i++) { + returnArr.push(arr[i]) + } + } + return returnArr + } + + /** + * @template T + * @param {T[]|NamedNodeMap|HTMLCollection|HTMLFormControlsCollection|ArrayLike<T>} arr + * @param {(T) => void} func + */ + function forEach(arr, func) { + if (arr) { + for (let i = 0; i < arr.length; i++) { + func(arr[i]) + } + } + } + + /** + * @param {Element} el + * @returns {boolean} + */ + function isScrolledIntoView(el) { + const rect = el.getBoundingClientRect() + const elemTop = rect.top + const elemBottom = rect.bottom + return elemTop < window.innerHeight && elemBottom >= 0 + } + + /** + * @param {Node} elt + * @returns {boolean} + */ + function bodyContains(elt) { + // IE Fix + const rootNode = elt.getRootNode && elt.getRootNode() + if (rootNode && rootNode instanceof window.ShadowRoot) { + return getDocument().body.contains(rootNode.host) + } else { + return getDocument().body.contains(elt) + } + } + + /** + * @param {string} trigger + * @returns {string[]} + */ + function splitOnWhitespace(trigger) { + return trigger.trim().split(/\s+/) + } + + /** + * mergeObjects takes all the keys from + * obj2 and duplicates them into obj1 + * @template T1 + * @template T2 + * @param {T1} obj1 + * @param {T2} obj2 + * @returns {T1 & T2} + */ + function mergeObjects(obj1, obj2) { + for (const key in obj2) { + if (obj2.hasOwnProperty(key)) { + // @ts-ignore tsc doesn't seem to properly handle types merging + obj1[key] = obj2[key] + } + } + // @ts-ignore tsc doesn't seem to properly handle types merging + return obj1 + } + + /** + * @param {string} jString + * @returns {any|null} + */ + function parseJSON(jString) { + try { + return JSON.parse(jString) + } catch (error) { + logError(error) + return null + } + } + + /** + * @returns {boolean} + */ + function canAccessLocalStorage() { + const test = 'htmx:localStorageTest' + try { + localStorage.setItem(test, test) + localStorage.removeItem(test) + return true + } catch (e) { + return false + } + } + + /** + * @param {string} path + * @returns {string} + */ + function normalizePath(path) { + try { + const url = new URL(path) + if (url) { + path = url.pathname + url.search + } + // remove trailing slash, unless index page + if (!(/^\/$/.test(path))) { + path = path.replace(/\/+$/, '') + } + return path + } catch (e) { + // be kind to IE11, which doesn't support URL() + return path + } + } + + //= ========================================================================================= + // public API + //= ========================================================================================= + + /** + * @param {string} str + * @returns {any} + */ + function internalEval(str) { + return maybeEval(getDocument().body, function() { + return eval(str) + }) + } + + /** + * Adds a callback for the **htmx:load** event. This can be used to process new content, for example initializing the content with a javascript library + * + * @see https://htmx.org/api/#onLoad + * + * @param {(elt: Node) => void} callback the callback to call on newly loaded content + * @returns {EventListener} + */ + function onLoadHelper(callback) { + const value = htmx.on('htmx:load', /** @param {CustomEvent} evt */ function(evt) { + callback(evt.detail.elt) + }) + return value + } + + /** + * Log all htmx events, useful for debugging. + * + * @see https://htmx.org/api/#logAll + */ + function logAll() { + htmx.logger = function(elt, event, data) { + if (console) { + console.log(event, elt, data) + } + } + } + + function logNone() { + htmx.logger = null + } + + /** + * Finds an element matching the selector + * + * @see https://htmx.org/api/#find + * + * @param {ParentNode|string} eltOrSelector the root element to find the matching element in, inclusive | the selector to match + * @param {string} [selector] the selector to match + * @returns {Element|null} + */ + function find(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return eltOrSelector.querySelector(selector) + } else { + return find(getDocument(), eltOrSelector) + } + } + + /** + * Finds all elements matching the selector + * + * @see https://htmx.org/api/#findAll + * + * @param {ParentNode|string} eltOrSelector the root element to find the matching elements in, inclusive | the selector to match + * @param {string} [selector] the selector to match + * @returns {NodeListOf<Element>} + */ + function findAll(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return eltOrSelector.querySelectorAll(selector) + } else { + return findAll(getDocument(), eltOrSelector) + } + } + + /** + * @returns Window + */ + function getWindow() { + return window + } + + /** + * Removes an element from the DOM + * + * @see https://htmx.org/api/#remove + * + * @param {Node} elt + * @param {number} [delay] + */ + function removeElement(elt, delay) { + elt = resolveTarget(elt) + if (delay) { + getWindow().setTimeout(function() { + removeElement(elt) + elt = null + }, delay) + } else { + parentElt(elt).removeChild(elt) + } + } + + /** + * @param {any} elt + * @return {Element|null} + */ + function asElement(elt) { + return elt instanceof Element ? elt : null + } + + /** + * @param {any} elt + * @return {HTMLElement|null} + */ + function asHtmlElement(elt) { + return elt instanceof HTMLElement ? elt : null + } + + /** + * @param {any} value + * @return {string|null} + */ + function asString(value) { + return typeof value === 'string' ? value : null + } + + /** + * @param {EventTarget} elt + * @return {ParentNode|null} + */ + function asParentNode(elt) { + return elt instanceof Element || elt instanceof Document || elt instanceof DocumentFragment ? elt : null + } + + /** + * This method adds a class to the given element. + * + * @see https://htmx.org/api/#addClass + * + * @param {Element|string} elt the element to add the class to + * @param {string} clazz the class to add + * @param {number} [delay] the delay (in milliseconds) before class is added + */ + function addClassToElement(elt, clazz, delay) { + elt = asElement(resolveTarget(elt)) + if (!elt) { + return + } + if (delay) { + getWindow().setTimeout(function() { + addClassToElement(elt, clazz) + elt = null + }, delay) + } else { + elt.classList && elt.classList.add(clazz) + } + } + + /** + * Removes a class from the given element + * + * @see https://htmx.org/api/#removeClass + * + * @param {Node|string} node element to remove the class from + * @param {string} clazz the class to remove + * @param {number} [delay] the delay (in milliseconds before class is removed) + */ + function removeClassFromElement(node, clazz, delay) { + let elt = asElement(resolveTarget(node)) + if (!elt) { + return + } + if (delay) { + getWindow().setTimeout(function() { + removeClassFromElement(elt, clazz) + elt = null + }, delay) + } else { + if (elt.classList) { + elt.classList.remove(clazz) + // if there are no classes left, remove the class attribute + if (elt.classList.length === 0) { + elt.removeAttribute('class') } + } + } + } + + /** + * Toggles the given class on an element + * + * @see https://htmx.org/api/#toggleClass + * + * @param {Element|string} elt the element to toggle the class on + * @param {string} clazz the class to toggle + */ + function toggleClassOnElement(elt, clazz) { + elt = resolveTarget(elt) + elt.classList.toggle(clazz) + } + + /** + * Takes the given class from its siblings, so that among its siblings, only the given element will have the class. + * + * @see https://htmx.org/api/#takeClass + * + * @param {Node|string} elt the element that will take the class + * @param {string} clazz the class to take + */ + function takeClassForElement(elt, clazz) { + elt = resolveTarget(elt) + forEach(elt.parentElement.children, function(child) { + removeClassFromElement(child, clazz) + }) + addClassToElement(asElement(elt), clazz) + } + + /** + * Finds the closest matching element in the given elements parentage, inclusive of the element + * + * @see https://htmx.org/api/#closest + * + * @param {Element|string} elt the element to find the selector from + * @param {string} selector the selector to find + * @returns {Element|null} + */ + function closest(elt, selector) { + elt = asElement(resolveTarget(elt)) + if (elt && elt.closest) { + return elt.closest(selector) + } else { + // TODO remove when IE goes away + do { + if (elt == null || matches(elt, selector)) { + return elt + } + } + while (elt = elt && asElement(parentElt(elt))) + return null + } + } + + /** + * @param {string} str + * @param {string} prefix + * @returns {boolean} + */ + function startsWith(str, prefix) { + return str.substring(0, prefix.length) === prefix + } + + /** + * @param {string} str + * @param {string} suffix + * @returns {boolean} + */ + function endsWith(str, suffix) { + return str.substring(str.length - suffix.length) === suffix + } + + /** + * @param {string} selector + * @returns {string} + */ + function normalizeSelector(selector) { + const trimmedSelector = selector.trim() + if (startsWith(trimmedSelector, '<') && endsWith(trimmedSelector, '/>')) { + return trimmedSelector.substring(1, trimmedSelector.length - 2) + } else { + return trimmedSelector + } + } + + /** + * @param {Node|Element|Document|string} elt + * @param {string} selector + * @param {boolean=} global + * @returns {(Node|Window)[]} + */ + function querySelectorAllExt(elt, selector, global) { + elt = resolveTarget(elt) + if (selector.indexOf('closest ') === 0) { + return [closest(asElement(elt), normalizeSelector(selector.substr(8)))] + } else if (selector.indexOf('find ') === 0) { + return [find(asParentNode(elt), normalizeSelector(selector.substr(5)))] + } else if (selector === 'next') { + return [asElement(elt).nextElementSibling] + } else if (selector.indexOf('next ') === 0) { + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)), !!global)] + } else if (selector === 'previous') { + return [asElement(elt).previousElementSibling] + } else if (selector.indexOf('previous ') === 0) { + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)), !!global)] + } else if (selector === 'document') { + return [document] + } else if (selector === 'window') { + return [window] + } else if (selector === 'body') { + return [document.body] + } else if (selector === 'root') { + return [getRootNode(elt, !!global)] + } else if (selector.indexOf('global ') === 0) { + return querySelectorAllExt(elt, selector.slice(7), true) + } else { + return toArray(asParentNode(getRootNode(elt, !!global)).querySelectorAll(normalizeSelector(selector))) + } + } + + /** + * @param {Node} start + * @param {string} match + * @param {boolean} global + * @returns {Element} + */ + var scanForwardQuery = function(start, match, global) { + const results = asParentNode(getRootNode(start, global)).querySelectorAll(match) + for (let i = 0; i < results.length; i++) { + const elt = results[i] + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { + return elt + } + } + } + + /** + * @param {Node} start + * @param {string} match + * @param {boolean} global + * @returns {Element} + */ + var scanBackwardsQuery = function(start, match, global) { + const results = asParentNode(getRootNode(start, global)).querySelectorAll(match) + for (let i = results.length - 1; i >= 0; i--) { + const elt = results[i] + if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { + return elt + } + } + } + + /** + * @param {Node|string} eltOrSelector + * @param {string=} selector + * @returns {Node|Window} + */ + function querySelectorExt(eltOrSelector, selector) { + if (typeof eltOrSelector !== 'string') { + return querySelectorAllExt(eltOrSelector, selector)[0] + } else { + return querySelectorAllExt(getDocument().body, eltOrSelector)[0] + } + } + + /** + * @template {EventTarget} T + * @param {T|string} eltOrSelector + * @param {T} [context] + * @returns {Element|T|null} + */ + function resolveTarget(eltOrSelector, context) { + if (typeof eltOrSelector === 'string') { + return find(asParentNode(context) || document, eltOrSelector) + } else { + return eltOrSelector + } + } + + /** + * @typedef {keyof HTMLElementEventMap|string} AnyEventName + */ + + /** + * @typedef {Object} EventArgs + * @property {EventTarget} target + * @property {AnyEventName} event + * @property {EventListener} listener + */ + + /** + * @param {EventTarget|AnyEventName} arg1 + * @param {AnyEventName|EventListener} arg2 + * @param {EventListener} [arg3] + * @returns {EventArgs} + */ + function processEventArgs(arg1, arg2, arg3) { + if (isFunction(arg2)) { + return { + target: getDocument().body, + event: asString(arg1), + listener: arg2 + } + } else { + return { + target: resolveTarget(arg1), + event: asString(arg2), + listener: arg3 + } + } + } + + /** + * Adds an event listener to an element + * + * @see https://htmx.org/api/#on + * + * @param {EventTarget|string} arg1 the element to add the listener to | the event name to add the listener for + * @param {string|EventListener} arg2 the event name to add the listener for | the listener to add + * @param {EventListener} [arg3] the listener to add + * @returns {EventListener} + */ + function addEventListenerImpl(arg1, arg2, arg3) { + ready(function() { + const eventArgs = processEventArgs(arg1, arg2, arg3) + eventArgs.target.addEventListener(eventArgs.event, eventArgs.listener) + }) + const b = isFunction(arg2) + return b ? arg2 : arg3 + } + + /** + * Removes an event listener from an element + * + * @see https://htmx.org/api/#off + * + * @param {EventTarget|string} arg1 the element to remove the listener from | the event name to remove the listener from + * @param {string|EventListener} arg2 the event name to remove the listener from | the listener to remove + * @param {EventListener} [arg3] the listener to remove + * @returns {EventListener} + */ + function removeEventListenerImpl(arg1, arg2, arg3) { + ready(function() { + const eventArgs = processEventArgs(arg1, arg2, arg3) + eventArgs.target.removeEventListener(eventArgs.event, eventArgs.listener) + }) + return isFunction(arg2) ? arg2 : arg3 + } + + //= =================================================================== + // Node processing + //= =================================================================== + + const DUMMY_ELT = getDocument().createElement('output') // dummy element for bad selectors + /** + * @param {Element} elt + * @param {string} attrName + * @returns {(Node|Window)[]} + */ + function findAttributeTargets(elt, attrName) { + const attrTarget = getClosestAttributeValue(elt, attrName) + if (attrTarget) { + if (attrTarget === 'this') { + return [findThisElement(elt, attrName)] + } else { + const result = querySelectorAllExt(elt, attrTarget) + if (result.length === 0) { + logError('The selector "' + attrTarget + '" on ' + attrName + ' returned no matches!') + return [DUMMY_ELT] + } else { + return result + } + } + } + } + + /** + * @param {Element} elt + * @param {string} attribute + * @returns {Element|null} + */ + function findThisElement(elt, attribute) { + return asElement(getClosestMatch(elt, function(elt) { + return getAttributeValue(asElement(elt), attribute) != null + })) + } + + /** + * @param {Element} elt + * @returns {Node|Window|null} + */ + function getTarget(elt) { + const targetStr = getClosestAttributeValue(elt, 'hx-target') + if (targetStr) { + if (targetStr === 'this') { + return findThisElement(elt, 'hx-target') + } else { + return querySelectorExt(elt, targetStr) + } + } else { + const data = getInternalData(elt) + if (data.boosted) { + return getDocument().body + } else { + return elt + } + } + } + + /** + * @param {string} name + * @returns {boolean} + */ + function shouldSettleAttribute(name) { + const attributesToSettle = htmx.config.attributesToSettle + for (let i = 0; i < attributesToSettle.length; i++) { + if (name === attributesToSettle[i]) { + return true + } + } + return false + } + + /** + * @param {Element} mergeTo + * @param {Element} mergeFrom + */ + function cloneAttributes(mergeTo, mergeFrom) { + forEach(mergeTo.attributes, function(attr) { + if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) { + mergeTo.removeAttribute(attr.name) + } + }) + forEach(mergeFrom.attributes, function(attr) { + if (shouldSettleAttribute(attr.name)) { + mergeTo.setAttribute(attr.name, attr.value) + } + }) + } + + /** + * @param {HtmxSwapStyle} swapStyle + * @param {Element} target + * @returns {boolean} + */ + function isInlineSwap(swapStyle, target) { + const extensions = getExtensions(target) + for (let i = 0; i < extensions.length; i++) { + const extension = extensions[i] + try { + if (extension.isInlineSwap(swapStyle)) { + return true + } + } catch (e) { + logError(e) + } + } + return swapStyle === 'outerHTML' + } + + /** + * @param {string} oobValue + * @param {Element} oobElement + * @param {HtmxSettleInfo} settleInfo + * @returns + */ + function oobSwap(oobValue, oobElement, settleInfo) { + let selector = '#' + getRawAttribute(oobElement, 'id') + /** @type HtmxSwapStyle */ + let swapStyle = 'outerHTML' + if (oobValue === 'true') { + // do nothing + } else if (oobValue.indexOf(':') > 0) { + swapStyle = oobValue.substr(0, oobValue.indexOf(':')) + selector = oobValue.substr(oobValue.indexOf(':') + 1, oobValue.length) + } else { + swapStyle = oobValue + } - /** - * @param {any} o - * @param {string} type - * @returns - */ - function isType(o, type) { - return Object.prototype.toString.call(o) === "[object " + type + "]"; - } - - /** - * @param {*} o - * @returns {o is Function} - */ - function isFunction(o) { - return isType(o, "Function"); - } - - /** - * @param {*} o - * @returns {o is Object} - */ - function isRawObject(o) { - return isType(o, "Object"); - } - - /** - * getInternalData retrieves "private" data stored by htmx within an element - * @param {HTMLElement} elt - * @returns {*} - */ - function getInternalData(elt) { - var dataProp = 'htmx-internal-data'; - var data = elt[dataProp]; - if (!data) { - data = elt[dataProp] = {}; - } - return data; - } - - /** - * toArray converts an ArrayLike object into a real array. - * @param {ArrayLike} arr - * @returns {any[]} - */ - function toArray(arr) { - var returnArr = []; - if (arr) { - for (var i = 0; i < arr.length; i++) { - returnArr.push(arr[i]); - } - } - return returnArr + const targets = getDocument().querySelectorAll(selector) + if (targets) { + forEach( + targets, + function(target) { + let fragment + const oobElementClone = oobElement.cloneNode(true) + fragment = getDocument().createDocumentFragment() + fragment.appendChild(oobElementClone) + if (!isInlineSwap(swapStyle, target)) { + fragment = asParentNode(oobElementClone) // if this is not an inline swap, we use the content of the node, not the node itself + } + + const beforeSwapDetails = { shouldSwap: true, target, fragment } + if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return + + target = beforeSwapDetails.target // allow re-targeting + if (beforeSwapDetails.shouldSwap) { + swapWithStyle(swapStyle, target, target, fragment, settleInfo) + } + forEach(settleInfo.elts, function(elt) { + triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails) + }) + } + ) + oobElement.parentNode.removeChild(oobElement) + } else { + oobElement.parentNode.removeChild(oobElement) + triggerErrorEvent(getDocument().body, 'htmx:oobErrorNoTarget', { content: oobElement }) + } + return oobValue + } + + /** + * @param {DocumentFragment} fragment + */ + function handlePreservedElements(fragment) { + forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function(preservedElt) { + const id = getAttributeValue(preservedElt, 'id') + const oldElt = getDocument().getElementById(id) + if (oldElt != null) { + preservedElt.parentNode.replaceChild(oldElt, preservedElt) + } + }) + } + + /** + * @param {Node} parentNode + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function handleAttributes(parentNode, fragment, settleInfo) { + forEach(fragment.querySelectorAll('[id]'), function(newNode) { + const id = getRawAttribute(newNode, 'id') + if (id && id.length > 0) { + const normalizedId = id.replace("'", "\\'") + const normalizedTag = newNode.tagName.replace(':', '\\:') + const parentElt = asParentNode(parentNode) + const oldNode = parentElt && parentElt.querySelector(normalizedTag + "[id='" + normalizedId + "']") + if (oldNode && oldNode !== parentElt) { + const newAttributes = newNode.cloneNode() + cloneAttributes(newNode, oldNode) + settleInfo.tasks.push(function() { + cloneAttributes(newNode, newAttributes) + }) + } + } + }) + } + + /** + * @param {Node} child + * @returns {HtmxSettleTask} + */ + function makeAjaxLoadTask(child) { + return function() { + removeClassFromElement(child, htmx.config.addedClass) + processNode(asElement(child)) + processFocus(asParentNode(child)) + triggerEvent(child, 'htmx:load') + } + } + + /** + * @param {ParentNode} child + */ + function processFocus(child) { + const autofocus = '[autofocus]' + const autoFocusedElt = asHtmlElement(matches(child, autofocus) ? child : child.querySelector(autofocus)) + if (autoFocusedElt != null) { + autoFocusedElt.focus() + } + } + + /** + * @param {Node} parentNode + * @param {Node} insertBefore + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) { + handleAttributes(parentNode, fragment, settleInfo) + while (fragment.childNodes.length > 0) { + const child = fragment.firstChild + addClassToElement(asElement(child), htmx.config.addedClass) + parentNode.insertBefore(child, insertBefore) + if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { + settleInfo.tasks.push(makeAjaxLoadTask(child)) + } + } + } + + /** + * based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, + * derived from Java's string hashcode implementation + * @param {string} string + * @param {number} hash + * @returns {number} + */ + function stringHash(string, hash) { + let char = 0 + while (char < string.length) { + hash = (hash << 5) - hash + string.charCodeAt(char++) | 0 // bitwise or ensures we have a 32-bit int + } + return hash + } + + /** + * @param {Element} elt + * @returns {number} + */ + function attributeHash(elt) { + let hash = 0 + // IE fix + if (elt.attributes) { + for (let i = 0; i < elt.attributes.length; i++) { + const attribute = elt.attributes[i] + if (attribute.value) { // only include attributes w/ actual values (empty is same as non-existent) + hash = stringHash(attribute.name, hash) + hash = stringHash(attribute.value, hash) + } + } + } + return hash + } + + /** + * @param {EventTarget} elt + */ + function deInitOnHandlers(elt) { + const internalData = getInternalData(elt) + if (internalData.onHandlers) { + for (let i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i] + removeEventListenerImpl(elt, handlerInfo.event, handlerInfo.listener) + } + delete internalData.onHandlers + } + } + + /** + * @param {Node} element + */ + function deInitNode(element) { + const internalData = getInternalData(element) + if (internalData.timeout) { + clearTimeout(internalData.timeout) + } + if (internalData.listenerInfos) { + forEach(internalData.listenerInfos, function(info) { + if (info.on) { + removeEventListenerImpl(info.on, info.trigger, info.listener) } - - function forEach(arr, func) { - if (arr) { - for (var i = 0; i < arr.length; i++) { - func(arr[i]); - } - } + }) + } + deInitOnHandlers(element) + forEach(Object.keys(internalData), function(key) { delete internalData[key] }) + } + + /** + * @param {Node} element + */ + function cleanUpElement(element) { + triggerEvent(element, 'htmx:beforeCleanupElement') + deInitNode(element) + // @ts-ignore IE11 code + // noinspection JSUnresolvedReference + if (element.children) { // IE + // @ts-ignore + forEach(element.children, function(child) { cleanUpElement(child) }) + } + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapOuterHTML(target, fragment, settleInfo) { + /** @type {Node} */ + let newElt + const eltBeforeNewContent = target.previousSibling + insertNodesBefore(parentElt(target), target, fragment, settleInfo) + if (eltBeforeNewContent == null) { + newElt = parentElt(target).firstChild + } else { + newElt = eltBeforeNewContent.nextSibling + } + settleInfo.elts = settleInfo.elts.filter(function(e) { return e !== target }) + while (newElt && newElt !== target) { + if (newElt instanceof Element) { + settleInfo.elts.push(newElt) + newElt = newElt.nextElementSibling + } else { + newElt = null + } + } + cleanUpElement(target) + if (target instanceof Element) { + target.remove() + } else { + target.parentNode.removeChild(target) + } + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapAfterBegin(target, fragment, settleInfo) { + return insertNodesBefore(target, target.firstChild, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapBeforeBegin(target, fragment, settleInfo) { + return insertNodesBefore(parentElt(target), target, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapBeforeEnd(target, fragment, settleInfo) { + return insertNodesBefore(target, null, fragment, settleInfo) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapAfterEnd(target, fragment, settleInfo) { + return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo) + } + + /** + * @param {Node} target + */ + function swapDelete(target) { + cleanUpElement(target) + return parentElt(target).removeChild(target) + } + + /** + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapInnerHTML(target, fragment, settleInfo) { + const firstChild = target.firstChild + insertNodesBefore(target, firstChild, fragment, settleInfo) + if (firstChild) { + while (firstChild.nextSibling) { + cleanUpElement(firstChild.nextSibling) + target.removeChild(firstChild.nextSibling) + } + cleanUpElement(firstChild) + target.removeChild(firstChild) + } + } + + /** + * @param {HtmxSwapStyle} swapStyle + * @param {Element} elt + * @param {Node} target + * @param {ParentNode} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function swapWithStyle(swapStyle, elt, target, fragment, settleInfo) { + switch (swapStyle) { + case 'none': + return + case 'outerHTML': + swapOuterHTML(target, fragment, settleInfo) + return + case 'afterbegin': + swapAfterBegin(target, fragment, settleInfo) + return + case 'beforebegin': + swapBeforeBegin(target, fragment, settleInfo) + return + case 'beforeend': + swapBeforeEnd(target, fragment, settleInfo) + return + case 'afterend': + swapAfterEnd(target, fragment, settleInfo) + return + case 'delete': + swapDelete(target) + return + default: + var extensions = getExtensions(elt) + for (let i = 0; i < extensions.length; i++) { + const ext = extensions[i] + try { + const newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo) + if (newElements) { + if (typeof newElements.length !== 'undefined') { + // if handleSwap returns an array (like) of elements, we handle them + for (let j = 0; j < newElements.length; j++) { + const child = newElements[j] + if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { + settleInfo.tasks.push(makeAjaxLoadTask(child)) + } + } + } + return + } + } catch (e) { + logError(e) + } + } + if (swapStyle === 'innerHTML') { + swapInnerHTML(target, fragment, settleInfo) + } else { + swapWithStyle(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo) } + } + } + + /** + * @param {DocumentFragment} fragment + * @param {HtmxSettleInfo} settleInfo + */ + function findAndSwapOobElements(fragment, settleInfo) { + forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function(oobElement) { + if (htmx.config.allowNestedOobSwaps || oobElement.parentElement === null) { + const oobValue = getAttributeValue(oobElement, 'hx-swap-oob') + if (oobValue != null) { + oobSwap(oobValue, oobElement, settleInfo) + } + } else { + oobElement.removeAttribute('hx-swap-oob') + oobElement.removeAttribute('data-hx-swap-oob') + } + }) + } + + /** + * Implements complete swapping pipeline, including: focus and selection preservation, + * title updates, scroll, OOB swapping, normal swapping and settling + * @param {string|Element} target + * @param {string} content + * @param {HtmxSwapSpecification} swapSpec + * @param {SwapOptions} [swapOptions] + */ + function swap(target, content, swapSpec, swapOptions) { + if (!swapOptions) { + swapOptions = {} + } - function isScrolledIntoView(el) { - var rect = el.getBoundingClientRect(); - var elemTop = rect.top; - var elemBottom = rect.bottom; - return elemTop < window.innerHeight && elemBottom >= 0; - } + target = resolveTarget(target) + + // preserve focus and selection + const activeElt = document.activeElement + let selectionInfo = {} + try { + selectionInfo = { + elt: activeElt, + // @ts-ignore + start: activeElt ? activeElt.selectionStart : null, + // @ts-ignore + end: activeElt ? activeElt.selectionEnd : null + } + } catch (e) { + // safari issue - see https://github.com/microsoft/playwright/issues/5894 + } + const settleInfo = makeSettleInfo(target) - function bodyContains(elt) { - // IE Fix - if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) { - return getDocument().body.contains(elt.getRootNode().host); - } else { - return getDocument().body.contains(elt); - } - } + // For text content swaps, don't parse the response as HTML, just insert it + if (swapSpec.swapStyle === 'textContent') { + target.textContent = content + // Otherwise, make the fragment and process it + } else { + let fragment = makeFragment(content) + + settleInfo.title = fragment.title + + // select-oob swaps + if (swapOptions.selectOOB) { + const oobSelectValues = swapOptions.selectOOB.split(',') + for (let i = 0; i < oobSelectValues.length; i++) { + const oobSelectValue = oobSelectValues[i].split(':', 2) + let id = oobSelectValue[0].trim() + if (id.indexOf('#') === 0) { + id = id.substring(1) + } + const oobValue = oobSelectValue[1] || 'true' + const oobElement = fragment.querySelector('#' + id) + if (oobElement) { + oobSwap(oobValue, oobElement, settleInfo) + } + } + } + // oob swaps + findAndSwapOobElements(fragment, settleInfo) + forEach(findAll(fragment, 'template'), /** @param {HTMLTemplateElement} template */function(template) { + findAndSwapOobElements(template.content, settleInfo) + if (template.content.childElementCount === 0) { + // Avoid polluting the DOM with empty templates that were only used to encapsulate oob swap + template.remove() + } + }) + + // normal swap + if (swapOptions.select) { + const newFragment = getDocument().createDocumentFragment() + forEach(fragment.querySelectorAll(swapOptions.select), function(node) { + newFragment.appendChild(node) + }) + fragment = newFragment + } + handlePreservedElements(fragment) + swapWithStyle(swapSpec.swapStyle, swapOptions.contextElement, target, fragment, settleInfo) + } - function splitOnWhitespace(trigger) { - return trigger.trim().split(/\s+/); - } + // apply saved focus and selection information to swapped content + if (selectionInfo.elt && + !bodyContains(selectionInfo.elt) && + getRawAttribute(selectionInfo.elt, 'id')) { + const newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, 'id')) + const focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll } + if (newActiveElt) { + // @ts-ignore + if (selectionInfo.start && newActiveElt.setSelectionRange) { + try { + // @ts-ignore + newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end) + } catch (e) { + // the setSelectionRange method is present on fields that don't support it, so just let this fail + } + } + newActiveElt.focus(focusOptions) + } + } - /** - * mergeObjects takes all of the keys from - * obj2 and duplicates them into obj1 - * @param {Object} obj1 - * @param {Object} obj2 - * @returns {Object} - */ - function mergeObjects(obj1, obj2) { - for (var key in obj2) { - if (obj2.hasOwnProperty(key)) { - obj1[key] = obj2[key]; - } - } - return obj1; - } + target.classList.remove(htmx.config.swappingClass) + forEach(settleInfo.elts, function(elt) { + if (elt.classList) { + elt.classList.add(htmx.config.settlingClass) + } + triggerEvent(elt, 'htmx:afterSwap', swapOptions.eventInfo) + }) + if (swapOptions.afterSwapCallback) { + swapOptions.afterSwapCallback() + } - function parseJSON(jString) { - try { - return JSON.parse(jString); - } catch(error) { - logError(error); - return null; - } - } + // merge in new title after swap but before settle + if (!swapSpec.ignoreTitle) { + handleTitle(settleInfo.title) + } - function canAccessLocalStorage() { - var test = 'htmx:localStorageTest'; - try { - localStorage.setItem(test, test); - localStorage.removeItem(test); - return true; - } catch(e) { - return false; - } - } + // settle + const doSettle = function() { + forEach(settleInfo.tasks, function(task) { + task.call() + }) + forEach(settleInfo.elts, function(elt) { + if (elt.classList) { + elt.classList.remove(htmx.config.settlingClass) + } + triggerEvent(elt, 'htmx:afterSettle', swapOptions.eventInfo) + }) + + if (swapOptions.anchor) { + const anchorTarget = asElement(resolveTarget('#' + swapOptions.anchor)) + if (anchorTarget) { + anchorTarget.scrollIntoView({ block: 'start', behavior: 'auto' }) + } + } + + updateScrollState(settleInfo.elts, swapSpec) + if (swapOptions.afterSettleCallback) { + swapOptions.afterSettleCallback() + } + } - function normalizePath(path) { + if (swapSpec.settleDelay > 0) { + getWindow().setTimeout(doSettle, swapSpec.settleDelay) + } else { + doSettle() + } + } + + /** + * @param {XMLHttpRequest} xhr + * @param {string} header + * @param {EventTarget} elt + */ + function handleTriggerHeader(xhr, header, elt) { + const triggerBody = xhr.getResponseHeader(header) + if (triggerBody.indexOf('{') === 0) { + const triggers = parseJSON(triggerBody) + for (const eventName in triggers) { + if (triggers.hasOwnProperty(eventName)) { + let detail = triggers[eventName] + if (!isRawObject(detail)) { + detail = { value: detail } + } + triggerEvent(elt, eventName, detail) + } + } + } else { + const eventNames = triggerBody.split(',') + for (let i = 0; i < eventNames.length; i++) { + triggerEvent(elt, eventNames[i].trim(), []) + } + } + } + + const WHITESPACE = /\s/ + const WHITESPACE_OR_COMMA = /[\s,]/ + const SYMBOL_START = /[_$a-zA-Z]/ + const SYMBOL_CONT = /[_$a-zA-Z0-9]/ + const STRINGISH_START = ['"', "'", '/'] + const NOT_WHITESPACE = /[^\s]/ + const COMBINED_SELECTOR_START = /[{(]/ + const COMBINED_SELECTOR_END = /[})]/ + + /** + * @param {string} str + * @returns {string[]} + */ + function tokenizeString(str) { + /** @type string[] */ + const tokens = [] + let position = 0 + while (position < str.length) { + if (SYMBOL_START.exec(str.charAt(position))) { + var startPosition = position + while (SYMBOL_CONT.exec(str.charAt(position + 1))) { + position++ + } + tokens.push(str.substr(startPosition, position - startPosition + 1)) + } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) { + const startChar = str.charAt(position) + var startPosition = position + position++ + while (position < str.length && str.charAt(position) !== startChar) { + if (str.charAt(position) === '\\') { + position++ + } + position++ + } + tokens.push(str.substr(startPosition, position - startPosition + 1)) + } else { + const symbol = str.charAt(position) + tokens.push(symbol) + } + position++ + } + return tokens + } + + /** + * @param {string} token + * @param {string|null} last + * @param {string} paramName + * @returns {boolean} + */ + function isPossibleRelativeReference(token, last, paramName) { + return SYMBOL_START.exec(token.charAt(0)) && + token !== 'true' && + token !== 'false' && + token !== 'this' && + token !== paramName && + last !== '.' + } + + /** + * @param {EventTarget|string} elt + * @param {string[]} tokens + * @param {string} paramName + * @returns {ConditionalFunction|null} + */ + function maybeGenerateConditional(elt, tokens, paramName) { + if (tokens[0] === '[') { + tokens.shift() + let bracketCount = 1 + let conditionalSource = ' return (function(' + paramName + '){ return (' + let last = null + while (tokens.length > 0) { + const token = tokens[0] + // @ts-ignore For some reason tsc doesn't understand the shift call, and thinks we're comparing the same value here, i.e. '[' vs ']' + if (token === ']') { + bracketCount-- + if (bracketCount === 0) { + if (last === null) { + conditionalSource = conditionalSource + 'true' + } + tokens.shift() + conditionalSource += ')})' try { - var url = new URL(path); - if (url) { - path = url.pathname + url.search; - } - // remove trailing slash, unless index page - if (!(/^\/$/.test(path))) { - path = path.replace(/\/+$/, ''); - } - return path; + const conditionFunction = maybeEval(elt, function() { + return Function(conditionalSource)() + }, + function() { return true }) + conditionFunction.source = conditionalSource + return conditionFunction } catch (e) { - // be kind to IE11, which doesn't support URL() - return path; - } - } - - //========================================================================================== - // public API - //========================================================================================== - - function internalEval(str){ - return maybeEval(getDocument().body, function () { - return eval(str); - }); - } - - function onLoadHelper(callback) { - var value = htmx.on("htmx:load", function(evt) { - callback(evt.detail.elt); - }); - return value; - } - - function logAll(){ - htmx.logger = function(elt, event, data) { - if(console) { - console.log(event, elt, data); - } - } - } - - function logNone() { - htmx.logger = null - } - - function find(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelector(selector); - } else { - return find(getDocument(), eltOrSelector); - } - } - - function findAll(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelectorAll(selector); - } else { - return findAll(getDocument(), eltOrSelector); - } - } - - function removeElement(elt, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - removeElement(elt); - elt = null; - }, delay); - } else { - elt.parentElement.removeChild(elt); - } - } - - function addClassToElement(elt, clazz, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - addClassToElement(elt, clazz); - elt = null; - }, delay); - } else { - elt.classList && elt.classList.add(clazz); - } - } - - function removeClassFromElement(elt, clazz, delay) { - elt = resolveTarget(elt); - if (delay) { - setTimeout(function(){ - removeClassFromElement(elt, clazz); - elt = null; - }, delay); - } else { - if (elt.classList) { - elt.classList.remove(clazz); - // if there are no classes left, remove the class attribute - if (elt.classList.length === 0) { - elt.removeAttribute("class"); - } - } - } - } - - function toggleClassOnElement(elt, clazz) { - elt = resolveTarget(elt); - elt.classList.toggle(clazz); - } - - function takeClassForElement(elt, clazz) { - elt = resolveTarget(elt); - forEach(elt.parentElement.children, function(child){ - removeClassFromElement(child, clazz); - }) - addClassToElement(elt, clazz); - } - - function closest(elt, selector) { - elt = resolveTarget(elt); - if (elt.closest) { - return elt.closest(selector); - } else { - // TODO remove when IE goes away - do{ - if (elt == null || matches(elt, selector)){ - return elt; - } - } - while (elt = elt && parentElt(elt)); - return null; - } - } - - function startsWith(str, prefix) { - return str.substring(0, prefix.length) === prefix - } - - function endsWith(str, suffix) { - return str.substring(str.length - suffix.length) === suffix - } - - function normalizeSelector(selector) { - var trimmedSelector = selector.trim(); - if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) { - return trimmedSelector.substring(1, trimmedSelector.length - 2); - } else { - return trimmedSelector; - } - } - - function querySelectorAllExt(elt, selector) { - if (selector.indexOf("closest ") === 0) { - return [closest(elt, normalizeSelector(selector.substr(8)))]; - } else if (selector.indexOf("find ") === 0) { - return [find(elt, normalizeSelector(selector.substr(5)))]; - } else if (selector === "next") { - return [elt.nextElementSibling] - } else if (selector.indexOf("next ") === 0) { - return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; - } else if (selector === "previous") { - return [elt.previousElementSibling] - } else if (selector.indexOf("previous ") === 0) { - return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; - } else if (selector === 'document') { - return [document]; - } else if (selector === 'window') { - return [window]; - } else if (selector === 'body') { - return [document.body]; - } else { - return getDocument().querySelectorAll(normalizeSelector(selector)); - } - } - - var scanForwardQuery = function(start, match) { - var results = getDocument().querySelectorAll(match); - for (var i = 0; i < results.length; i++) { - var elt = results[i]; - if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) { - return elt; - } - } - } - - var scanBackwardsQuery = function(start, match) { - var results = getDocument().querySelectorAll(match); - for (var i = results.length - 1; i >= 0; i--) { - var elt = results[i]; - if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) { - return elt; - } - } - } - - function querySelectorExt(eltOrSelector, selector) { - if (selector) { - return querySelectorAllExt(eltOrSelector, selector)[0]; - } else { - return querySelectorAllExt(getDocument().body, eltOrSelector)[0]; - } - } - - function resolveTarget(arg2) { - if (isType(arg2, 'String')) { - return find(arg2); - } else { - return arg2; - } - } - - function processEventArgs(arg1, arg2, arg3) { - if (isFunction(arg2)) { - return { - target: getDocument().body, - event: arg1, - listener: arg2 - } - } else { - return { - target: resolveTarget(arg1), - event: arg2, - listener: arg3 - } - } - - } - - function addEventListenerImpl(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 removeEventListenerImpl(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 - //==================================================================== - - var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors - function findAttributeTargets(elt, attrName) { - var attrTarget = getClosestAttributeValue(elt, attrName); - if (attrTarget) { - if (attrTarget === "this") { - return [findThisElement(elt, attrName)]; - } else { - var result = querySelectorAllExt(elt, attrTarget); - if (result.length === 0) { - logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!"); - return [DUMMY_ELT] - } else { - return result; - } - } - } - } - - function findThisElement(elt, attribute){ - return getClosestMatch(elt, function (elt) { - return getAttributeValue(elt, attribute) != null; - }) - } - - function getTarget(elt) { - var targetStr = getClosestAttributeValue(elt, "hx-target"); - if (targetStr) { - if (targetStr === "this") { - return findThisElement(elt,'hx-target'); - } else { - return querySelectorExt(elt, targetStr) - } - } else { - var data = getInternalData(elt); - if (data.boosted) { - return getDocument().body; - } else { - return elt; - } - } - } - - function shouldSettleAttribute(name) { - var attributesToSettle = htmx.config.attributesToSettle; - for (var i = 0; i < attributesToSettle.length; i++) { - if (name === attributesToSettle[i]) { - return true; - } - } - return false; - } - - function cloneAttributes(mergeTo, mergeFrom) { - forEach(mergeTo.attributes, function (attr) { - if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) { - mergeTo.removeAttribute(attr.name) - } - }); - forEach(mergeFrom.attributes, function (attr) { - if (shouldSettleAttribute(attr.name)) { - mergeTo.setAttribute(attr.name, attr.value); - } - }); - } - - function isInlineSwap(swapStyle, target) { - var extensions = getExtensions(target); - for (var i = 0; i < extensions.length; i++) { - var extension = extensions[i]; - try { - if (extension.isInlineSwap(swapStyle)) { - return true; - } - } catch(e) { - logError(e); - } - } - return swapStyle === "outerHTML"; - } - - /** - * - * @param {string} oobValue - * @param {HTMLElement} oobElement - * @param {*} settleInfo - * @returns - */ - function oobSwap(oobValue, oobElement, settleInfo) { - var selector = "#" + getRawAttribute(oobElement, "id"); - var swapStyle = "outerHTML"; - if (oobValue === "true") { - // do nothing - } else if (oobValue.indexOf(":") > 0) { - swapStyle = oobValue.substr(0, oobValue.indexOf(":")); - selector = oobValue.substr(oobValue.indexOf(":") + 1, oobValue.length); - } else { - swapStyle = oobValue; - } - - var targets = getDocument().querySelectorAll(selector); - if (targets) { - forEach( - targets, - function (target) { - var fragment; - var oobElementClone = oobElement.cloneNode(true); - fragment = getDocument().createDocumentFragment(); - fragment.appendChild(oobElementClone); - if (!isInlineSwap(swapStyle, target)) { - fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself - } - - var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment }; - if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return; - - target = beforeSwapDetails.target; // allow re-targeting - if (beforeSwapDetails['shouldSwap']){ - swap(swapStyle, target, target, fragment, settleInfo); - } - forEach(settleInfo.elts, function (elt) { - triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails); - }); - } - ); - oobElement.parentNode.removeChild(oobElement); - } else { - oobElement.parentNode.removeChild(oobElement); - triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement}); - } - return oobValue; - } - - function handleOutOfBandSwaps(elt, fragment, settleInfo) { - var oobSelects = getClosestAttributeValue(elt, "hx-select-oob"); - if (oobSelects) { - var oobSelectValues = oobSelects.split(","); - for (var i = 0; i < oobSelectValues.length; i++) { - var oobSelectValue = oobSelectValues[i].split(":", 2); - var id = oobSelectValue[0].trim(); - if (id.indexOf("#") === 0) { - id = id.substring(1); - } - var oobValue = oobSelectValue[1] || "true"; - var oobElement = fragment.querySelector("#" + id); - if (oobElement) { - oobSwap(oobValue, oobElement, settleInfo); - } - } - } - forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) { - var oobValue = getAttributeValue(oobElement, "hx-swap-oob"); - if (oobValue != null) { - oobSwap(oobValue, oobElement, settleInfo); - } - }); - } - - function handlePreservedElements(fragment) { - forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function (preservedElt) { - var id = getAttributeValue(preservedElt, "id"); - var oldElt = getDocument().getElementById(id); - if (oldElt != null) { - preservedElt.parentNode.replaceChild(oldElt, preservedElt); - } - }); - } - - function handleAttributes(parentNode, fragment, settleInfo) { - forEach(fragment.querySelectorAll("[id]"), function (newNode) { - var id = getRawAttribute(newNode, "id") - if (id && id.length > 0) { - var normalizedId = id.replace("'", "\\'"); - var normalizedTag = newNode.tagName.replace(':', '\\:'); - var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']"); - if (oldNode && oldNode !== parentNode) { - var newAttributes = newNode.cloneNode(); - cloneAttributes(newNode, oldNode); - settleInfo.tasks.push(function () { - cloneAttributes(newNode, newAttributes); - }); - } - } - }); - } - - function makeAjaxLoadTask(child) { - return function () { - removeClassFromElement(child, htmx.config.addedClass); - processNode(child); - processScripts(child); - processFocus(child) - triggerEvent(child, 'htmx:load'); - }; - } - - function processFocus(child) { - var autofocus = "[autofocus]"; - var autoFocusedElt = matches(child, autofocus) ? child : child.querySelector(autofocus) - if (autoFocusedElt != null) { - autoFocusedElt.focus(); - } - } - - function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) { - handleAttributes(parentNode, fragment, settleInfo); - while(fragment.childNodes.length > 0){ - var child = fragment.firstChild; - addClassToElement(child, htmx.config.addedClass); - parentNode.insertBefore(child, insertBefore); - if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { - settleInfo.tasks.push(makeAjaxLoadTask(child)); - } - } - } - - // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0, - // derived from Java's string hashcode implementation - function stringHash(string, hash) { - var char = 0; - while (char < string.length){ - hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int - } - return hash; - } - - function attributeHash(elt) { - var hash = 0; - // IE fix - if (elt.attributes) { - for (var i = 0; i < elt.attributes.length; i++) { - var attribute = elt.attributes[i]; - if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent) - hash = stringHash(attribute.name, hash); - hash = stringHash(attribute.value, hash); - } - } - } - return hash; - } - - function deInitOnHandlers(elt) { - var internalData = getInternalData(elt); - if (internalData.onHandlers) { - for (var i = 0; i < internalData.onHandlers.length; i++) { - const handlerInfo = internalData.onHandlers[i]; - elt.removeEventListener(handlerInfo.event, handlerInfo.listener); - } - delete internalData.onHandlers - } - } - - function deInitNode(element) { - var internalData = getInternalData(element); - if (internalData.timeout) { - clearTimeout(internalData.timeout); - } - if (internalData.webSocket) { - internalData.webSocket.close(); - } - if (internalData.sseEventSource) { - internalData.sseEventSource.close(); - } - if (internalData.listenerInfos) { - forEach(internalData.listenerInfos, function (info) { - if (info.on) { - info.on.removeEventListener(info.trigger, info.listener); - } - }); - } - deInitOnHandlers(element); - forEach(Object.keys(internalData), function(key) { delete internalData[key] }); - } - - function cleanUpElement(element) { - triggerEvent(element, "htmx:beforeCleanupElement") - deInitNode(element); - if (element.children) { // IE - forEach(element.children, function(child) { cleanUpElement(child) }); - } - } - - function swapOuterHTML(target, fragment, settleInfo) { - if (target.tagName === "BODY") { - return swapInnerHTML(target, fragment, settleInfo); - } else { - // @type {HTMLElement} - var newElt - var eltBeforeNewContent = target.previousSibling; - insertNodesBefore(parentElt(target), target, fragment, settleInfo); - if (eltBeforeNewContent == null) { - newElt = parentElt(target).firstChild; - } else { - newElt = eltBeforeNewContent.nextSibling; - } - settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target }); - while(newElt && newElt !== target) { - if (newElt.nodeType === Node.ELEMENT_NODE) { - settleInfo.elts.push(newElt); - } - newElt = newElt.nextElementSibling; - } - cleanUpElement(target); - parentElt(target).removeChild(target); - } - } - - function swapAfterBegin(target, fragment, settleInfo) { - return insertNodesBefore(target, target.firstChild, fragment, settleInfo); - } - - function swapBeforeBegin(target, fragment, settleInfo) { - return insertNodesBefore(parentElt(target), target, fragment, settleInfo); - } - - function swapBeforeEnd(target, fragment, settleInfo) { - return insertNodesBefore(target, null, fragment, settleInfo); - } - - function swapAfterEnd(target, fragment, settleInfo) { - return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo); - } - function swapDelete(target, fragment, settleInfo) { - cleanUpElement(target); - return parentElt(target).removeChild(target); - } - - function swapInnerHTML(target, fragment, settleInfo) { - var firstChild = target.firstChild; - insertNodesBefore(target, firstChild, fragment, settleInfo); - if (firstChild) { - while (firstChild.nextSibling) { - cleanUpElement(firstChild.nextSibling) - target.removeChild(firstChild.nextSibling); - } - cleanUpElement(firstChild) - target.removeChild(firstChild); - } - } - - function maybeSelectFromResponse(elt, fragment, selectOverride) { - var selector = selectOverride || getClosestAttributeValue(elt, "hx-select"); - if (selector) { - var newFragment = getDocument().createDocumentFragment(); - forEach(fragment.querySelectorAll(selector), function (node) { - newFragment.appendChild(node); - }); - fragment = newFragment; - } - return fragment; - } - - function swap(swapStyle, elt, target, fragment, settleInfo) { - switch (swapStyle) { - case "none": - return; - case "outerHTML": - swapOuterHTML(target, fragment, settleInfo); - return; - case "afterbegin": - swapAfterBegin(target, fragment, settleInfo); - return; - case "beforebegin": - swapBeforeBegin(target, fragment, settleInfo); - return; - case "beforeend": - swapBeforeEnd(target, fragment, settleInfo); - return; - case "afterend": - swapAfterEnd(target, fragment, settleInfo); - return; - case "delete": - swapDelete(target, fragment, settleInfo); - return; - default: - var extensions = getExtensions(elt); - for (var i = 0; i < extensions.length; i++) { - var ext = extensions[i]; - try { - var newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo); - if (newElements) { - if (typeof newElements.length !== 'undefined') { - // if handleSwap returns an array (like) of elements, we handle them - for (var j = 0; j < newElements.length; j++) { - var child = newElements[j]; - if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) { - settleInfo.tasks.push(makeAjaxLoadTask(child)); - } - } - } - return; - } - } catch (e) { - logError(e); - } - } - if (swapStyle === "innerHTML") { - swapInnerHTML(target, fragment, settleInfo); - } else { - swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo); - } - } - } - - function findTitle(content) { - if (content.indexOf('<title') > -1) { - var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, ''); - var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX); - if (result) { - return result[2]; - } - } - } - - function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) { - settleInfo.title = findTitle(responseText); - var fragment = makeFragment(responseText); - if (fragment) { - handleOutOfBandSwaps(elt, fragment, settleInfo); - fragment = maybeSelectFromResponse(elt, fragment, selectOverride); - handlePreservedElements(fragment); - return swap(swapStyle, elt, target, fragment, settleInfo); - } - } - - function handleTrigger(xhr, header, elt) { - var triggerBody = xhr.getResponseHeader(header); - if (triggerBody.indexOf("{") === 0) { - var triggers = parseJSON(triggerBody); - for (var eventName in triggers) { - if (triggers.hasOwnProperty(eventName)) { - var detail = triggers[eventName]; - if (!isRawObject(detail)) { - detail = {"value": detail} - } - triggerEvent(elt, eventName, detail); - } - } - } else { - var eventNames = triggerBody.split(",") - for (var i = 0; i < eventNames.length; i++) { - triggerEvent(elt, eventNames[i].trim(), []); - } - } - } - - var WHITESPACE = /\s/; - var WHITESPACE_OR_COMMA = /[\s,]/; - var SYMBOL_START = /[_$a-zA-Z]/; - var SYMBOL_CONT = /[_$a-zA-Z0-9]/; - var STRINGISH_START = ['"', "'", "/"]; - var NOT_WHITESPACE = /[^\s]/; - var COMBINED_SELECTOR_START = /[{(]/; - var COMBINED_SELECTOR_END = /[})]/; - function tokenizeString(str) { - var tokens = []; - var position = 0; - while (position < str.length) { - if(SYMBOL_START.exec(str.charAt(position))) { - var startPosition = position; - while (SYMBOL_CONT.exec(str.charAt(position + 1))) { - position++; - } - tokens.push(str.substr(startPosition, position - startPosition + 1)); - } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) { - var startChar = str.charAt(position); - var startPosition = position; - position++; - while (position < str.length && str.charAt(position) !== startChar ) { - if (str.charAt(position) === "\\") { - position++; - } - position++; - } - tokens.push(str.substr(startPosition, position - startPosition + 1)); - } else { - var symbol = str.charAt(position); - tokens.push(symbol); - } - position++; - } - return tokens; - } - - function isPossibleRelativeReference(token, last, paramName) { - return SYMBOL_START.exec(token.charAt(0)) && - token !== "true" && - token !== "false" && - token !== "this" && - token !== paramName && - last !== "."; - } - - function maybeGenerateConditional(elt, tokens, paramName) { - if (tokens[0] === '[') { - tokens.shift(); - var bracketCount = 1; - var conditionalSource = " return (function(" + paramName + "){ return ("; - var last = null; - while (tokens.length > 0) { - var token = tokens[0]; - if (token === "]") { - bracketCount--; - if (bracketCount === 0) { - if (last === null) { - conditionalSource = conditionalSource + "true"; - } - tokens.shift(); - conditionalSource += ")})"; - try { - var conditionFunction = maybeEval(elt,function () { - return Function(conditionalSource)(); - }, - function(){return true}) - conditionFunction.source = conditionalSource; - return conditionFunction; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:syntax:error", {error:e, source:conditionalSource}) - return null; - } - } - } else if (token === "[") { - bracketCount++; - } - if (isPossibleRelativeReference(token, last, paramName)) { - conditionalSource += "((" + paramName + "." + token + ") ? (" + paramName + "." + token + ") : (window." + token + "))"; - } else { - conditionalSource = conditionalSource + token; - } - last = tokens.shift(); - } - } - } - - function consumeUntil(tokens, match) { - var result = ""; - while (tokens.length > 0 && !match.test(tokens[0])) { - result += tokens.shift(); - } - return result; - } - - function consumeCSSSelector(tokens) { - var result; - if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { - tokens.shift(); - result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim(); - tokens.shift(); - } else { - result = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } - return result; - } - - var INPUT_SELECTOR = 'input, textarea, select'; - - /** - * @param {HTMLElement} elt - * @param {string} explicitTrigger - * @param {cache} cache for trigger specs - * @returns {import("./htmx").HtmxTriggerSpecification[]} - */ - function parseAndCacheTrigger(elt, explicitTrigger, cache) { - var triggerSpecs = []; - var tokens = tokenizeString(explicitTrigger); - do { - consumeUntil(tokens, NOT_WHITESPACE); - var initialLength = tokens.length; - var trigger = consumeUntil(tokens, /[,\[\s]/); - if (trigger !== "") { - if (trigger === "every") { - var every = {trigger: 'every'}; - consumeUntil(tokens, NOT_WHITESPACE); - every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)); - consumeUntil(tokens, NOT_WHITESPACE); - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - every.eventFilter = eventFilter; - } - triggerSpecs.push(every); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)}); - } else { - var triggerSpec = {trigger: trigger}; - var eventFilter = maybeGenerateConditional(elt, tokens, "event"); - if (eventFilter) { - triggerSpec.eventFilter = eventFilter; - } - while (tokens.length > 0 && tokens[0] !== ",") { - consumeUntil(tokens, NOT_WHITESPACE) - var token = tokens.shift(); - if (token === "changed") { - triggerSpec.changed = true; - } else if (token === "once") { - triggerSpec.once = true; - } else if (token === "consume") { - triggerSpec.consume = true; - } else if (token === "delay" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "from" && tokens[0] === ":") { - tokens.shift(); - if (COMBINED_SELECTOR_START.test(tokens[0])) { - var from_arg = consumeCSSSelector(tokens); - } else { - var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA); - if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") { - tokens.shift(); - var selector = consumeCSSSelector(tokens); - // `next` and `previous` allow a selector-less syntax - if (selector.length > 0) { - from_arg += " " + selector; - } - } - } - triggerSpec.from = from_arg; - } else if (token === "target" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.target = consumeCSSSelector(tokens); - } else if (token === "throttle" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)); - } else if (token === "queue" && tokens[0] === ":") { - tokens.shift(); - triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else if (token === "root" && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeCSSSelector(tokens); - } else if (token === "threshold" && tokens[0] === ":") { - tokens.shift(); - triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA); - } else { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - } - triggerSpecs.push(triggerSpec); - } - } - if (tokens.length === initialLength) { - triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()}); - } - consumeUntil(tokens, NOT_WHITESPACE); - } while (tokens[0] === "," && tokens.shift()) - if (cache) { - cache[explicitTrigger] = triggerSpecs - } - return triggerSpecs - } - - /** - * @param {HTMLElement} elt - * @returns {import("./htmx").HtmxTriggerSpecification[]} - */ - function getTriggerSpecs(elt) { - var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); - var triggerSpecs = []; - if (explicitTrigger) { - var cache = htmx.config.triggerSpecsCache - triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) - } - - if (triggerSpecs.length > 0) { - return triggerSpecs; - } else if (matches(elt, 'form')) { - return [{trigger: 'submit'}]; - } else if (matches(elt, 'input[type="button"], input[type="submit"]')){ - return [{trigger: 'click'}]; - } else if (matches(elt, INPUT_SELECTOR)) { - return [{trigger: 'change'}]; - } else { - return [{trigger: 'click'}]; - } - } - - function cancelPolling(elt) { - getInternalData(elt).cancelled = true; - } - - function processPolling(elt, handler, spec) { - var nodeData = getInternalData(elt); - nodeData.timeout = setTimeout(function () { - if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { - triggerSpec: spec, - target: elt - }))) { - handler(elt); - } - processPolling(elt, handler, spec); - } - }, spec.pollInterval); - } - - function isLocalLink(elt) { - return location.hostname === elt.hostname && - getRawAttribute(elt,'href') && - getRawAttribute(elt,'href').indexOf("#") !== 0; - } - - function boostElement(elt, nodeData, triggerSpecs) { - if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || 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"; - if (verb === "get") { - } - path = getRawAttribute(elt, 'action'); - } - triggerSpecs.forEach(function(triggerSpec) { - addEventListener(elt, function(elt, evt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return - } - issueAjaxRequest(verb, path, elt, evt) - }, nodeData, triggerSpec, true); - }); - } - } - - /** - * - * @param {Event} evt - * @param {HTMLElement} elt - * @returns - */ - function shouldCancel(evt, elt) { - if (evt.type === "submit" || evt.type === "click") { - if (elt.tagName === "FORM") { - return true; - } - if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { - return true; - } - if (elt.tagName === "A" && elt.href && - (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) { - return true; - } - } - return false; - } - - function ignoreBoostedAnchorCtrlClick(elt, evt) { - return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); - } - - function maybeFilterEvent(triggerSpec, elt, evt) { - var eventFilter = triggerSpec.eventFilter; - if(eventFilter){ - try { - return eventFilter.call(elt, evt) !== true; - } catch(e) { - triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); - return true; - } - } - return false; - } - - function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { - var elementData = getInternalData(elt); - var eltsToListenOn; - if (triggerSpec.from) { - eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from); - } else { - eltsToListenOn = [elt]; - } - // store the initial values of the elements, so we can tell if they change - if (triggerSpec.changed) { - eltsToListenOn.forEach(function (eltToListenOn) { - var eltToListenOnData = getInternalData(eltToListenOn); - eltToListenOnData.lastValue = eltToListenOn.value; - }) - } - forEach(eltsToListenOn, function (eltToListenOn) { - var eventListener = function (evt) { - if (!bodyContains(elt)) { - eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); - return; - } - if (ignoreBoostedAnchorCtrlClick(elt, evt)) { - return; - } - if (explicitCancel || shouldCancel(evt, elt)) { - evt.preventDefault(); - } - if (maybeFilterEvent(triggerSpec, elt, evt)) { - return; - } - var eventData = getInternalData(evt); - eventData.triggerSpec = triggerSpec; - if (eventData.handledFor == null) { - eventData.handledFor = []; - } - if (eventData.handledFor.indexOf(elt) < 0) { - eventData.handledFor.push(elt); - if (triggerSpec.consume) { - evt.stopPropagation(); - } - if (triggerSpec.target && evt.target) { - if (!matches(evt.target, triggerSpec.target)) { - return; - } - } - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } - } - if (triggerSpec.changed) { - var eltToListenOnData = getInternalData(eltToListenOn) - if (eltToListenOnData.lastValue === eltToListenOn.value) { - return; - } - eltToListenOnData.lastValue = eltToListenOn.value - } - if (elementData.delayed) { - clearTimeout(elementData.delayed); - } - if (elementData.throttle) { - return; - } - - if (triggerSpec.throttle > 0) { - if (!elementData.throttle) { - handler(elt, evt); - elementData.throttle = setTimeout(function () { - elementData.throttle = null; - }, triggerSpec.throttle); - } - } else if (triggerSpec.delay > 0) { - elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay); - } else { - triggerEvent(elt, 'htmx:trigger') - handler(elt, evt); - } - } - }; - if (nodeData.listenerInfos == null) { - nodeData.listenerInfos = []; - } - nodeData.listenerInfos.push({ - trigger: triggerSpec.trigger, - listener: eventListener, - on: eltToListenOn - }) - eltToListenOn.addEventListener(triggerSpec.trigger, eventListener); - }); - } - - var windowIsScrolling = false // used by initScrollHandler - var scrollHandler = null; - function initScrollHandler() { - if (!scrollHandler) { - scrollHandler = function() { - windowIsScrolling = true - }; - window.addEventListener("scroll", scrollHandler) - setInterval(function() { - if (windowIsScrolling) { - windowIsScrolling = false; - forEach(getDocument().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"), function (elt) { - maybeReveal(elt); - }) - } - }, 200); - } - } - - function maybeReveal(elt) { - if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) { - elt.setAttribute('data-hx-revealed', 'true'); - var nodeData = getInternalData(elt); - if (nodeData.initHash) { - triggerEvent(elt, 'revealed'); - } else { - // if the node isn't initialized, wait for it before triggering the request - elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true}); - } - } - } - - //==================================================================== - // Web Sockets - //==================================================================== - - function processWebSocketInfo(elt, nodeData, info) { - var values = splitOnWhitespace(info); - for (var i = 0; i < values.length; i++) { - var value = values[i].split(/:(.+)/); - if (value[0] === "connect") { - ensureWebSocket(elt, value[1], 0); - } - if (value[0] === "send") { - processWebSocketSend(elt); - } - } - } - - function ensureWebSocket(elt, wssSource, retryCount) { - if (!bodyContains(elt)) { - return; // stop ensuring websocket connection when socket bearing element ceases to exist - } - - if (wssSource.indexOf("/") == 0) { // complete absolute paths only - var base_part = location.hostname + (location.port ? ':'+location.port: ''); - if (location.protocol == 'https:') { - wssSource = "wss://" + base_part + wssSource; - } else if (location.protocol == 'http:') { - wssSource = "ws://" + base_part + wssSource; - } - } - var socket = htmx.createWebSocket(wssSource); - socket.onerror = function (e) { - triggerErrorEvent(elt, "htmx:wsError", {error:e, socket:socket}); - maybeCloseWebSocketSource(elt); - }; - - socket.onclose = function (e) { - if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later - var delay = getWebSocketReconnectDelay(retryCount); - setTimeout(function() { - ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout - }, delay); - } - }; - socket.onopen = function (e) { - retryCount = 0; - } - - getInternalData(elt).webSocket = socket; - socket.addEventListener('message', function (event) { - if (maybeCloseWebSocketSource(elt)) { - return; - } - - var response = event.data; - withExtensions(elt, function(extension){ - response = extension.transformResponse(response, null, elt); - }); - - var settleInfo = makeSettleInfo(elt); - var fragment = makeFragment(response); - var children = toArray(fragment.children); - for (var i = 0; i < children.length; i++) { - var child = children[i]; - oobSwap(getAttributeValue(child, "hx-swap-oob") || "true", child, settleInfo); - } - - settleImmediately(settleInfo.tasks); - }); - } - - function maybeCloseWebSocketSource(elt) { - if (!bodyContains(elt)) { - getInternalData(elt).webSocket.close(); - return true; - } - } - - function processWebSocketSend(elt) { - var webSocketSourceElt = getClosestMatch(elt, function (parent) { - return getInternalData(parent).webSocket != null; - }); - if (webSocketSourceElt) { - elt.addEventListener(getTriggerSpecs(elt)[0].trigger, function (evt) { - var webSocket = getInternalData(webSocketSourceElt).webSocket; - var headers = getHeaders(elt, webSocketSourceElt); - var results = getInputValues(elt, 'post'); - var errors = results.errors; - var rawParameters = results.values; - var expressionVars = getExpressionVars(elt); - var allParameters = mergeObjects(rawParameters, expressionVars); - var filteredParameters = filterValues(allParameters, elt); - filteredParameters['HEADERS'] = headers; - if (errors && errors.length > 0) { - triggerEvent(elt, 'htmx:validation:halted', errors); - return; - } - webSocket.send(JSON.stringify(filteredParameters)); - if(shouldCancel(evt, elt)){ - evt.preventDefault(); - } - }); - } else { - triggerErrorEvent(elt, "htmx:noWebSocketSourceError"); - } - } - - function getWebSocketReconnectDelay(retryCount) { - var delay = htmx.config.wsReconnectDelay; - if (typeof delay === 'function') { - // @ts-ignore - return delay(retryCount); - } - if (delay === 'full-jitter') { - var exp = Math.min(retryCount, 6); - var maxDelay = 1000 * Math.pow(2, exp); - return maxDelay * Math.random(); - } - logError('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"'); - } - - //==================================================================== - // Server Sent Events - //==================================================================== - - function processSSEInfo(elt, nodeData, info) { - var values = splitOnWhitespace(info); - for (var i = 0; i < values.length; i++) { - var value = values[i].split(/:(.+)/); - if (value[0] === "connect") { - processSSESource(elt, value[1]); - } - - if ((value[0] === "swap")) { - processSSESwap(elt, value[1]) - } - } - } - - function processSSESource(elt, sseSrc) { - var source = htmx.createEventSource(sseSrc); - source.onerror = function (e) { - triggerErrorEvent(elt, "htmx:sseError", {error:e, source:source}); - maybeCloseSSESource(elt); - }; - getInternalData(elt).sseEventSource = source; - } - - function processSSESwap(elt, sseEventName) { - var sseSourceElt = getClosestMatch(elt, hasEventSource); - if (sseSourceElt) { - var sseEventSource = getInternalData(sseSourceElt).sseEventSource; - var sseListener = function (event) { - if (maybeCloseSSESource(sseSourceElt)) { - return; - } - if (!bodyContains(elt)) { - sseEventSource.removeEventListener(sseEventName, sseListener); - return; - } - - /////////////////////////// - // TODO: merge this code with AJAX and WebSockets code in the future. - - var response = event.data; - withExtensions(elt, function(extension){ - response = extension.transformResponse(response, null, elt); - }); - - var swapSpec = getSwapSpecification(elt) - var target = getTarget(elt) - var settleInfo = makeSettleInfo(elt); - - selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) - settleImmediately(settleInfo.tasks) - triggerEvent(elt, "htmx:sseMessage", event) - }; - - getInternalData(elt).sseListener = sseListener; - sseEventSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "htmx:noSSESourceError"); - } - } - - function processSSETrigger(elt, handler, sseEventName) { - var sseSourceElt = getClosestMatch(elt, hasEventSource); - if (sseSourceElt) { - var sseEventSource = getInternalData(sseSourceElt).sseEventSource; - var sseListener = function () { - if (!maybeCloseSSESource(sseSourceElt)) { - if (bodyContains(elt)) { - handler(elt); - } else { - sseEventSource.removeEventListener(sseEventName, sseListener); - } - } - }; - getInternalData(elt).sseListener = sseListener; - sseEventSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "htmx:noSSESourceError"); - } - } - - function maybeCloseSSESource(elt) { - if (!bodyContains(elt)) { - getInternalData(elt).sseEventSource.close(); - return true; - } - } - - function hasEventSource(node) { - return getInternalData(node).sseEventSource != null; - } - - //==================================================================== - - function loadImmediately(elt, handler, nodeData, delay) { - var load = function(){ - if (!nodeData.loaded) { - nodeData.loaded = true; - handler(elt); - } - } - if (delay > 0) { - setTimeout(load, delay); - } else { - load(); - } - } - - function processVerbs(elt, nodeData, triggerSpecs) { - var explicitAction = false; - forEach(VERBS, function (verb) { - if (hasAttribute(elt,'hx-' + verb)) { - var path = getAttributeValue(elt, 'hx-' + verb); - explicitAction = true; - nodeData.path = path; - nodeData.verb = verb; - triggerSpecs.forEach(function(triggerSpec) { - addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return - } - issueAjaxRequest(verb, path, elt, evt) - }) - }); - } - }); - return explicitAction; - } - - function addTriggerHandler(elt, triggerSpec, nodeData, handler) { - if (triggerSpec.sseEvent) { - processSSETrigger(elt, handler, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - addEventListener(elt, handler, nodeData, triggerSpec); - maybeReveal(elt); - } else if (triggerSpec.trigger === "intersect") { - var observerOptions = {}; - if (triggerSpec.root) { - observerOptions.root = querySelectorExt(elt, triggerSpec.root) - } - if (triggerSpec.threshold) { - observerOptions.threshold = parseFloat(triggerSpec.threshold); - } - var observer = new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - if (entry.isIntersecting) { - triggerEvent(elt, "intersect"); - break; - } - } - }, observerOptions); - observer.observe(elt); - addEventListener(elt, handler, nodeData, triggerSpec); - } else if (triggerSpec.trigger === "load") { - if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { - loadImmediately(elt, handler, nodeData, triggerSpec.delay); - } - } else if (triggerSpec.pollInterval > 0) { - nodeData.polling = true; - processPolling(elt, handler, triggerSpec); - } else { - addEventListener(elt, handler, nodeData, triggerSpec); - } - } - - function evalScript(script) { - if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) { - var newScript = getDocument().createElement("script"); - forEach(script.attributes, function (attr) { - newScript.setAttribute(attr.name, attr.value); - }); - newScript.textContent = script.textContent; - newScript.async = false; - if (htmx.config.inlineScriptNonce) { - newScript.nonce = htmx.config.inlineScriptNonce; - } - var parent = script.parentElement; - - try { - parent.insertBefore(newScript, script); - } catch (e) { - logError(e); - } finally { - // remove old script element, but only if it is still in DOM - if (script.parentElement) { - script.parentElement.removeChild(script); - } - } - } - } - - function processScripts(elt) { - if (matches(elt, "script")) { - evalScript(elt); - } - forEach(findAll(elt, "script"), function (script) { - evalScript(script); - }); - } - - function shouldProcessHxOn(elt) { - var attributes = elt.attributes - for (var j = 0; j < attributes.length; j++) { - var attrName = attributes[j].name - if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") || - startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) { - return true - } - } - return false - } - - function findHxOnWildcardElements(elt) { - var node = null - var elements = [] - - if (shouldProcessHxOn(elt)) { - elements.push(elt) - } - - if (document.evaluate) { - var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + - ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt) - while (node = iter.iterateNext()) elements.push(node) - } else { - var allElements = elt.getElementsByTagName("*") - for (var i = 0; i < allElements.length; i++) { - if (shouldProcessHxOn(allElements[i])) { - elements.push(allElements[i]) - } - } - } - - return elements - } - - function findElementsToProcess(elt) { - if (elt.querySelectorAll) { - var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]"; - var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," + - " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]"); - return results; - } else { - return []; - } - } - - // Handle submit buttons/inputs that have the form attribute set - // see https://developer.mozilla.org/docs/Web/HTML/Element/button - function maybeSetLastButtonClicked(evt) { - var elt = closest(evt.target, "button, input[type='submit']"); - var internalData = getRelatedFormData(evt) - if (internalData) { - internalData.lastButtonClicked = elt; - } - }; - function maybeUnsetLastButtonClicked(evt){ - var internalData = getRelatedFormData(evt) - if (internalData) { - internalData.lastButtonClicked = null; - } - } - function getRelatedFormData(evt) { - var elt = closest(evt.target, "button, input[type='submit']"); - if (!elt) { - return; - } - var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form'); - if (!form) { - return; - } - return getInternalData(form); - } - function initButtonTracking(elt) { - // need to handle both click and focus in: - // focusin - in case someone tabs in to a button and hits the space bar - // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 - elt.addEventListener('click', maybeSetLastButtonClicked) - elt.addEventListener('focusin', maybeSetLastButtonClicked) - elt.addEventListener('focusout', maybeUnsetLastButtonClicked) - } - - function countCurlies(line) { - var tokens = tokenizeString(line); - var netCurlies = 0; - for (var i = 0; i < tokens.length; i++) { - const token = tokens[i]; - if (token === "{") { - netCurlies++; - } else if (token === "}") { - netCurlies--; - } - } - return netCurlies; - } - - function addHxOnEventHandler(elt, eventName, code) { - var nodeData = getInternalData(elt); - if (!Array.isArray(nodeData.onHandlers)) { - nodeData.onHandlers = []; - } - var func; - var listener = function (e) { - return maybeEval(elt, function() { - if (!func) { - func = new Function("event", code); - } - func.call(elt, e); - }); - }; - elt.addEventListener(eventName, listener); - nodeData.onHandlers.push({event:eventName, listener:listener}); - } - - function processHxOn(elt) { - var hxOnValue = getAttributeValue(elt, 'hx-on'); - if (hxOnValue) { - var handlers = {} - var lines = hxOnValue.split("\n"); - var currentEvent = null; - var curlyCount = 0; - while (lines.length > 0) { - var line = lines.shift(); - var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/); - if (curlyCount === 0 && match) { - line.split(":") - currentEvent = match[1].slice(0, -1); // strip last colon - handlers[currentEvent] = match[2]; - } else { - handlers[currentEvent] += line; - } - curlyCount += countCurlies(line); - } - - for (var eventName in handlers) { - addHxOnEventHandler(elt, eventName, handlers[eventName]); - } - } - } - - function processHxOnWildcard(elt) { - // wipe any previous on handlers so that this function takes precedence - deInitOnHandlers(elt) - - for (var i = 0; i < elt.attributes.length; i++) { - var name = elt.attributes[i].name - var value = elt.attributes[i].value - if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) { - var afterOnPosition = name.indexOf("-on") + 3; - var nextChar = name.slice(afterOnPosition, afterOnPosition + 1); - if (nextChar === "-" || nextChar === ":") { - var eventName = name.slice(afterOnPosition + 1); - // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support - if (startsWith(eventName, ":")) { - eventName = "htmx" + eventName - } else if (startsWith(eventName, "-")) { - eventName = "htmx:" + eventName.slice(1); - } else if (startsWith(eventName, "htmx-")) { - eventName = "htmx:" + eventName.slice(5); - } - - addHxOnEventHandler(elt, eventName, value) - } - } - } - } - - function initNode(elt) { - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return; - } - var nodeData = getInternalData(elt); - if (nodeData.initHash !== attributeHash(elt)) { - // clean up any previously processed info - deInitNode(elt); - - nodeData.initHash = attributeHash(elt); - - processHxOn(elt); - - triggerEvent(elt, "htmx:beforeProcessNode") - - if (elt.value) { - nodeData.lastValue = elt.value; - } - - var triggerSpecs = getTriggerSpecs(elt); - var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs); - - if (!hasExplicitHttpAction) { - if (getClosestAttributeValue(elt, "hx-boost") === "true") { - boostElement(elt, nodeData, triggerSpecs); - } else if (hasAttribute(elt, 'hx-trigger')) { - triggerSpecs.forEach(function (triggerSpec) { - // For "naked" triggers, don't do anything at all - addTriggerHandler(elt, triggerSpec, nodeData, function () { - }) - }) - } - } - - // Handle submit buttons/inputs that have the form attribute set - // see https://developer.mozilla.org/docs/Web/HTML/Element/button - if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) { - initButtonTracking(elt) - } - - var sseInfo = getAttributeValue(elt, 'hx-sse'); - if (sseInfo) { - processSSEInfo(elt, nodeData, sseInfo); - } - - var wsInfo = getAttributeValue(elt, 'hx-ws'); - if (wsInfo) { - processWebSocketInfo(elt, nodeData, wsInfo); - } - triggerEvent(elt, "htmx:afterProcessNode"); - } - } - - function processNode(elt) { - elt = resolveTarget(elt); - if (closest(elt, htmx.config.disableSelector)) { - cleanUpElement(elt) - return; - } - initNode(elt); - forEach(findElementsToProcess(elt), function(child) { initNode(child) }); - // Because it happens second, the new way of adding onHandlers superseeds the old one - // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored - forEach(findHxOnWildcardElements(elt), processHxOnWildcard); - } - - //==================================================================== - // Event/Log Support - //==================================================================== - - function kebabEventName(str) { - return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase(); - } - - 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({error:eventName}, detail)); - } - - function ignoreEventForLogging(eventName) { - return eventName === "htmx:afterProcessNode" - } - - /** - * `withExtensions` locates all active extensions for a provided element, then - * executes the provided function using each of the active extensions. It should - * be called internally at every extendable execution point in htmx. - * - * @param {HTMLElement} elt - * @param {(extension:import("./htmx").HtmxExtension) => void} toDo - * @returns void - */ - function withExtensions(elt, toDo) { - forEach(getExtensions(elt), function(extension){ - try { - toDo(extension); - } catch (e) { - logError(e); - } - }); - } - - function logError(msg) { - if(console.error) { - console.error(msg); - } else if (console.log) { - console.log("ERROR: ", msg); - } - } - - function triggerEvent(elt, eventName, detail) { - elt = resolveTarget(elt); - if (detail == null) { - detail = {}; - } - detail["elt"] = elt; - var event = makeEvent(eventName, detail); - if (htmx.logger && !ignoreEventForLogging(eventName)) { - htmx.logger(elt, eventName, detail); - } - if (detail.error) { - logError(detail.error); - triggerEvent(elt, "htmx:error", {errorInfo:detail}) - } - var eventResult = elt.dispatchEvent(event); - var kebabName = kebabEventName(eventName); - if (eventResult && kebabName !== eventName) { - var kebabedEvent = makeEvent(kebabName, event.detail); - eventResult = eventResult && elt.dispatchEvent(kebabedEvent) - } - withExtensions(elt, function (extension) { - eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) - }); - return eventResult; - } - - //==================================================================== - // History Support - //==================================================================== - var currentPathForHistory = location.pathname+location.search; - - function getHistoryElement() { - var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]'); - return historyElt || getDocument().body; - } - - function saveToHistoryCache(url, content, title, scroll) { - if (!canAccessLocalStorage()) { - return; - } - - if (htmx.config.historyCacheSize <= 0) { - // make sure that an eventually already existing cache is purged - localStorage.removeItem("htmx-history-cache"); - return; - } - - url = normalizePath(url); - - var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - historyCache.splice(i, 1); - break; - } - } - var newHistoryItem = {url:url, content: content, title:title, scroll:scroll}; - triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache}) - historyCache.push(newHistoryItem) - while (historyCache.length > htmx.config.historyCacheSize) { - historyCache.shift(); - } - while(historyCache.length > 0){ - try { - localStorage.setItem("htmx-history-cache", JSON.stringify(historyCache)); - break; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:historyCacheError", {cause:e, cache: historyCache}) - historyCache.shift(); // shrink the cache and retry - } - } - } - - function getCachedHistory(url) { - if (!canAccessLocalStorage()) { - return null; - } - - url = normalizePath(url); - - var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - return historyCache[i]; - } - } - return null; - } - - function cleanInnerHtmlForHistory(elt) { - var className = htmx.config.requestClass; - var clone = elt.cloneNode(true); - forEach(findAll(clone, "." + className), function(child){ - removeClassFromElement(child, className); - }); - return clone.innerHTML; - } - - function saveCurrentPageToHistory() { - var elt = getHistoryElement(); - var path = currentPathForHistory || location.pathname+location.search; - - // Allow history snapshot feature to be disabled where hx-history="false" - // is present *anywhere* in the current document we're about to save, - // so we can prevent privileged data entering the cache. - // The page will still be reachable as a history entry, but htmx will fetch it - // live from the server onpopstate rather than look in the localStorage cache - var disableHistoryCache - try { - disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') - } catch (e) { - // IE11: insensitive modifier not supported so fallback to case sensitive selector - disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') - } - if (!disableHistoryCache) { - triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt}); - saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY); - } - - if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href); - } - - function pushUrlIntoHistory(path) { - // remove the cache buster parameter, if any - if (htmx.config.getCacheBusterParam) { - path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') - if (endsWith(path, '&') || endsWith(path, "?")) { - path = path.slice(0, -1); - } - } - if(htmx.config.historyEnabled) { - history.pushState({htmx:true}, "", path); - } - currentPathForHistory = path; - } - - function replaceUrlInHistory(path) { - if(htmx.config.historyEnabled) history.replaceState({htmx:true}, "", path); - currentPathForHistory = path; - } - - function settleImmediately(tasks) { - forEach(tasks, function (task) { - task.call(); - }); - } - - function loadHistoryFromServer(path) { - var request = new XMLHttpRequest(); - var details = {path: path, xhr:request}; - triggerEvent(getDocument().body, "htmx:historyCacheMiss", details); - request.open('GET', path, true); - request.setRequestHeader("HX-Request", "true"); - request.setRequestHeader("HX-History-Restore-Request", "true"); - request.setRequestHeader("HX-Current-URL", getDocument().location.href); - request.onload = function () { - if (this.status >= 200 && this.status < 400) { - triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details); - var fragment = makeFragment(this.response); - // @ts-ignore - fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment; - var historyElement = getHistoryElement(); - var settleInfo = makeSettleInfo(historyElement); - var title = findTitle(this.response); - if (title) { - var titleElt = find("title"); - if (titleElt) { - titleElt.innerHTML = title; - } else { - window.document.title = title; - } - } - // @ts-ignore - swapInnerHTML(historyElement, fragment, settleInfo) - settleImmediately(settleInfo.tasks); - currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response}); - } else { - triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details); - } - }; - request.send(); - } - - function restoreHistory(path) { - saveCurrentPageToHistory(); - path = path || location.pathname+location.search; - var cached = getCachedHistory(path); - if (cached) { - var fragment = makeFragment(cached.content); - var historyElement = getHistoryElement(); - var settleInfo = makeSettleInfo(historyElement); - swapInnerHTML(historyElement, fragment, settleInfo) - settleImmediately(settleInfo.tasks); - document.title = cached.title; - setTimeout(function () { - window.scrollTo(0, cached.scroll); - }, 0); // next 'tick', so browser has time to render layout - currentPathForHistory = path; - triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); - } else { - if (htmx.config.refreshOnHistoryMiss) { - - // @ts-ignore: optional parameter in reload() function throws error - window.location.reload(true); - } else { - loadHistoryFromServer(path); - } - } - } - - function addRequestIndicatorClasses(elt) { - var indicators = findAttributeTargets(elt, 'hx-indicator'); - if (indicators == null) { - indicators = [elt]; - } - forEach(indicators, function (ic) { - var internalData = getInternalData(ic); - internalData.requestCount = (internalData.requestCount || 0) + 1; - ic.classList["add"].call(ic.classList, htmx.config.requestClass); - }); - return indicators; - } - - function disableElements(elt) { - var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt'); - if (disabledElts == null) { - disabledElts = []; - } - forEach(disabledElts, function (disabledElement) { - var internalData = getInternalData(disabledElement); - internalData.requestCount = (internalData.requestCount || 0) + 1; - disabledElement.setAttribute("disabled", ""); - }); - return disabledElts; - } - - function removeRequestIndicators(indicators, disabled) { - forEach(indicators, function (ic) { - var internalData = getInternalData(ic); - internalData.requestCount = (internalData.requestCount || 0) - 1; - if (internalData.requestCount === 0) { - ic.classList["remove"].call(ic.classList, htmx.config.requestClass); - } - }); - forEach(disabled, function (disabledElement) { - var internalData = getInternalData(disabledElement); - internalData.requestCount = (internalData.requestCount || 0) - 1; - if (internalData.requestCount === 0) { - disabledElement.removeAttribute('disabled'); - } - }); - } - - //==================================================================== - // 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 || closest(elt, "fieldset[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 addValueToValues(name, value, values) { - // This is a little ugly because both the current value of the named value in the form - // and the new value could be arrays, so we have to handle all four cases :/ - if (name != null && value != null) { - var current = values[name]; - if (current === undefined) { - values[name] = value; - } else if (Array.isArray(current)) { - if (Array.isArray(value)) { - values[name] = current.concat(value); - } else { - current.push(value); - } - } else { - if (Array.isArray(value)) { - values[name] = [current].concat(value); - } else { - values[name] = [current, value]; - } - } - } - } - - function processInputValue(processed, values, errors, elt, validate) { - if (elt == null || haveSeenNode(processed, elt)) { - return; - } else { - processed.push(elt); - } - if (shouldInclude(elt)) { - var name = getRawAttribute(elt,"name"); - var value = elt.value; - if (elt.multiple && elt.tagName === "SELECT") { - value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value }); - } - // include file inputs - if (elt.files) { - value = toArray(elt.files); - } - addValueToValues(name, value, values); - if (validate) { - validateElement(elt, errors); - } - } - if (matches(elt, 'form')) { - var inputs = elt.elements; - forEach(inputs, function(input) { - processInputValue(processed, values, errors, input, validate); - }); - } - } - - function validateElement(element, errors) { - if (element.willValidate) { - triggerEvent(element, "htmx:validation:validate") - if (!element.checkValidity()) { - errors.push({elt: element, message:element.validationMessage, validity:element.validity}); - triggerEvent(element, "htmx:validation:failed", {message:element.validationMessage, validity:element.validity}) - } - } - } - - /** - * @param {HTMLElement} elt - * @param {string} verb - */ - function getInputValues(elt, verb) { - var processed = []; - var values = {}; - var formValues = {}; - var errors = []; - var internalData = getInternalData(elt); - if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { - internalData.lastButtonClicked = null - } - - // only validate when form is directly submitted and novalidate or formnovalidate are not set - // or if the element has an explicit hx-validate="true" on it - var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true"; - if (internalData.lastButtonClicked) { - validate = validate && internalData.lastButtonClicked.formNoValidate !== true; - } - - // for a non-GET include the closest form - if (verb !== 'get') { - processInputValue(processed, formValues, errors, closest(elt, 'form'), validate); - } - - // include the element itself - processInputValue(processed, values, errors, elt, validate); - - // if a button or submit was clicked last, include its value - if (internalData.lastButtonClicked || elt.tagName === "BUTTON" || - (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) { - var button = internalData.lastButtonClicked || elt - var name = getRawAttribute(button, "name") - addValueToValues(name, button.value, formValues) - } - - // include any explicit includes - var includes = findAttributeTargets(elt, "hx-include"); - forEach(includes, function(node) { - processInputValue(processed, values, errors, node, validate); - // if a non-form is included, include any input values within it - if (!matches(node, 'form')) { - forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) { - processInputValue(processed, values, errors, descendant, validate); - }) - } - }); - - // form values take precedence, overriding the regular values - values = mergeObjects(values, formValues); - - return {errors:errors, values:values}; - } - - function appendParam(returnStr, name, realValue) { - if (returnStr !== "") { - returnStr += "&"; - } - if (String(realValue) === "[object Object]") { - realValue = JSON.stringify(realValue); - } - var s = encodeURIComponent(realValue); - returnStr += encodeURIComponent(name) + "=" + s; - 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; - } - - function makeFormData(values) { - var formData = new FormData(); - for (var name in values) { - if (values.hasOwnProperty(name)) { - var value = values[name]; - if (Array.isArray(value)) { - forEach(value, function(v) { - formData.append(name, v); - }); - } else { - formData.append(name, value); - } - } - } - return formData; - } - - //==================================================================== - // Ajax - //==================================================================== - - /** - * @param {HTMLElement} elt - * @param {HTMLElement} target - * @param {string} prompt - * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification - */ - function getHeaders(elt, target, prompt) { - var headers = { - "HX-Request" : "true", - "HX-Trigger" : getRawAttribute(elt, "id"), - "HX-Trigger-Name" : getRawAttribute(elt, "name"), - "HX-Target" : getAttributeValue(target, "id"), - "HX-Current-URL" : getDocument().location.href, - } - getValuesForElement(elt, "hx-headers", false, headers) - if (prompt !== undefined) { - headers["HX-Prompt"] = prompt; - } - if (getInternalData(elt).boosted) { - headers["HX-Boosted"] = "true"; - } - return headers; - } - - /** - * filterValues takes an object containing form input values - * and returns a new object that only contains keys that are - * specified by the closest "hx-params" attribute - * @param {Object} inputValues - * @param {HTMLElement} elt - * @returns {Object} - */ - function filterValues(inputValues, elt) { - var paramsValue = getClosestAttributeValue(elt, "hx-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 isAnchorLink(elt) { - return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0 - } - - /** - * - * @param {HTMLElement} elt - * @param {string} swapInfoOverride - * @returns {import("./htmx").HtmxSwapSpecification} - */ - function getSwapSpecification(elt, swapInfoOverride) { - var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap"); - var swapSpec = { - "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, - "swapDelay" : htmx.config.defaultSwapDelay, - "settleDelay" : htmx.config.defaultSettleDelay - } - if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { - swapSpec["show"] = "top" - } - if (swapInfo) { - var split = splitOnWhitespace(swapInfo); - if (split.length > 0) { - for (var i = 0; i < split.length; i++) { - var value = split[i]; - if (value.indexOf("swap:") === 0) { - swapSpec["swapDelay"] = parseInterval(value.substr(5)); - } else if (value.indexOf("settle:") === 0) { - swapSpec["settleDelay"] = parseInterval(value.substr(7)); - } else if (value.indexOf("transition:") === 0) { - swapSpec["transition"] = value.substr(11) === "true"; - } else if (value.indexOf("ignoreTitle:") === 0) { - swapSpec["ignoreTitle"] = value.substr(12) === "true"; - } else if (value.indexOf("scroll:") === 0) { - var scrollSpec = value.substr(7); - var splitSpec = scrollSpec.split(":"); - var scrollVal = splitSpec.pop(); - var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; - swapSpec["scroll"] = scrollVal; - swapSpec["scrollTarget"] = selectorVal; - } else if (value.indexOf("show:") === 0) { - var showSpec = value.substr(5); - var splitSpec = showSpec.split(":"); - var showVal = splitSpec.pop(); - var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null; - swapSpec["show"] = showVal; - swapSpec["showTarget"] = selectorVal; - } else if (value.indexOf("focus-scroll:") === 0) { - var focusScrollVal = value.substr("focus-scroll:".length); - swapSpec["focusScroll"] = focusScrollVal == "true"; - } else if (i == 0) { - swapSpec["swapStyle"] = value; - } else { - logError('Unknown modifier in hx-swap: ' + value); - } - } - } - } - return swapSpec; - } - - function usesFormData(elt) { - return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" || - (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data"); - } - - function encodeParamsForBody(xhr, elt, filteredParameters) { - var encodedParameters = null; - withExtensions(elt, function (extension) { - if (encodedParameters == null) { - encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt); - } - }); - if (encodedParameters != null) { - return encodedParameters; - } else { - if (usesFormData(elt)) { - return makeFormData(filteredParameters); - } else { - return urlEncode(filteredParameters); - } - } - } - - /** - * - * @param {Element} target - * @returns {import("./htmx").HtmxSettleInfo} - */ - function makeSettleInfo(target) { - return {tasks: [], elts: [target]}; - } - - function updateScrollState(content, swapSpec) { - var first = content[0]; - var last = content[content.length - 1]; - if (swapSpec.scroll) { - var target = null; - if (swapSpec.scrollTarget) { - target = querySelectorExt(first, swapSpec.scrollTarget); - } - if (swapSpec.scroll === "top" && (first || target)) { - target = target || first; - target.scrollTop = 0; - } - if (swapSpec.scroll === "bottom" && (last || target)) { - target = target || last; - target.scrollTop = target.scrollHeight; - } - } - if (swapSpec.show) { - var target = null; - if (swapSpec.showTarget) { - var targetStr = swapSpec.showTarget; - if (swapSpec.showTarget === "window") { - targetStr = "body"; - } - target = querySelectorExt(first, targetStr); - } - if (swapSpec.show === "top" && (first || target)) { - target = target || first; - target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior}); - } - if (swapSpec.show === "bottom" && (last || target)) { - target = target || last; - target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior}); - } - } - } - - /** - * @param {HTMLElement} elt - * @param {string} attr - * @param {boolean=} evalAsDefault - * @param {Object=} values - * @returns {Object} - */ - function getValuesForElement(elt, attr, evalAsDefault, values) { - if (values == null) { - values = {}; - } - if (elt == null) { - return values; - } - var attributeValue = getAttributeValue(elt, attr); - if (attributeValue) { - var str = attributeValue.trim(); - var evaluateValue = evalAsDefault; - if (str === "unset") { - return null; - } - if (str.indexOf("javascript:") === 0) { - str = str.substr(11); - evaluateValue = true; - } else if (str.indexOf("js:") === 0) { - str = str.substr(3); - evaluateValue = true; - } - if (str.indexOf('{') !== 0) { - str = "{" + str + "}"; - } - var varsValues; - if (evaluateValue) { - varsValues = maybeEval(elt,function () {return Function("return (" + str + ")")();}, {}); - } else { - varsValues = parseJSON(str); - } - for (var key in varsValues) { - if (varsValues.hasOwnProperty(key)) { - if (values[key] == null) { - values[key] = varsValues[key]; - } - } - } - } - return getValuesForElement(parentElt(elt), attr, evalAsDefault, values); - } - - function maybeEval(elt, toEval, defaultVal) { - if (htmx.config.allowEval) { - return toEval(); - } else { - triggerErrorEvent(elt, 'htmx:evalDisallowedError'); - return defaultVal; - } - } - - /** - * @param {HTMLElement} elt - * @param {*} expressionVars - * @returns - */ - function getHXVarsForElement(elt, expressionVars) { - return getValuesForElement(elt, "hx-vars", true, expressionVars); - } - - /** - * @param {HTMLElement} elt - * @param {*} expressionVars - * @returns - */ - function getHXValsForElement(elt, expressionVars) { - return getValuesForElement(elt, "hx-vals", false, expressionVars); - } - - /** - * @param {HTMLElement} elt - * @returns {Object} - */ - function getExpressionVars(elt) { - return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)); - } - - function safelySetHeaderValue(xhr, header, headerValue) { - if (headerValue !== null) { - try { - xhr.setRequestHeader(header, headerValue); - } catch (e) { - // On an exception, try to set the header URI encoded instead - xhr.setRequestHeader(header, encodeURIComponent(headerValue)); - xhr.setRequestHeader(header + "-URI-AutoEncoded", "true"); - } - } - } - - function getPathFromResponse(xhr) { - // NB: IE11 does not support this stuff - if (xhr.responseURL && typeof(URL) !== "undefined") { - try { - var url = new URL(xhr.responseURL); - return url.pathname + url.search; - } catch (e) { - triggerErrorEvent(getDocument().body, "htmx:badResponseUrl", {url: xhr.responseURL}); - } - } - } - - function hasHeader(xhr, regexp) { - return regexp.test(xhr.getAllResponseHeaders()) - } - - function ajaxHelper(verb, path, context) { - verb = verb.toLowerCase(); - if (context) { - if (context instanceof Element || isType(context, 'String')) { - return issueAjaxRequest(verb, path, null, null, { - targetOverride: resolveTarget(context), - returnPromise: true - }); - } else { - return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, - { - handler : context.handler, - headers : context.headers, - values : context.values, - targetOverride: resolveTarget(context.target), - swapOverride: context.swap, - select: context.select, - returnPromise: true - }); - } - } else { - return issueAjaxRequest(verb, path, null, null, { - returnPromise: true - }); - } - } - - function hierarchyForElt(elt) { - var arr = []; - while (elt) { - arr.push(elt); - elt = elt.parentElement; - } - return arr; - } - - function verifyPath(elt, path, requestConfig) { - var sameHost - var url - if (typeof URL === "function") { - url = new URL(path, document.location.href); - var origin = document.location.origin; - sameHost = origin === url.origin; - } else { - // IE11 doesn't support URL - url = path - sameHost = startsWith(path, document.location.origin) - } - - if (htmx.config.selfRequestsOnly) { - if (!sameHost) { - return false; - } - } - return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig)); - } - - function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { - var resolve = null; - var reject = null; - etc = etc != null ? etc : {}; - if(etc.returnPromise && typeof Promise !== "undefined"){ - var promise = new Promise(function (_resolve, _reject) { - resolve = _resolve; - reject = _reject; - }); - } - if(elt == null) { - elt = getDocument().body; - } - var responseHandler = etc.handler || handleAjaxResponse; - var select = etc.select || null; - - if (!bodyContains(elt)) { - // do not issue requests for elements removed from the DOM - maybeCall(resolve); - return promise; - } - var target = etc.targetOverride || getTarget(elt); - if (target == null || target == DUMMY_ELT) { - triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")}); - maybeCall(reject); - return promise; - } - - var eltData = getInternalData(elt); - var submitter = eltData.lastButtonClicked; - - if (submitter) { - var buttonPath = getRawAttribute(submitter, "formaction"); - if (buttonPath != null) { - path = buttonPath; - } - - var buttonVerb = getRawAttribute(submitter, "formmethod") - if (buttonVerb != null) { - // ignore buttons with formmethod="dialog" - if (buttonVerb.toLowerCase() !== "dialog") { - verb = buttonVerb; - } - } - } - - var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); - // allow event-based confirmation w/ a callback - if (confirmed === undefined) { - var issueRequest = function(skipConfirmation) { - return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation); - } - var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion}; - if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { - maybeCall(resolve); - return promise; - } - } - - var syncElt = elt; - var syncStrategy = getClosestAttributeValue(elt, "hx-sync"); - var queueStrategy = null; - var abortable = false; - if (syncStrategy) { - var syncStrings = syncStrategy.split(":"); - var selector = syncStrings[0].trim(); - if (selector === "this") { - syncElt = findThisElement(elt, 'hx-sync'); - } else { - syncElt = querySelectorExt(elt, selector); - } - // default to the drop strategy - syncStrategy = (syncStrings[1] || 'drop').trim(); - eltData = getInternalData(syncElt); - if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) { - maybeCall(resolve); - return promise; - } else if (syncStrategy === "abort") { - if (eltData.xhr) { - maybeCall(resolve); - return promise; - } else { - abortable = true; - } - } else if (syncStrategy === "replace") { - triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue - } else if (syncStrategy.indexOf("queue") === 0) { - var queueStrArray = syncStrategy.split(" "); - queueStrategy = (queueStrArray[1] || "last").trim(); - } - } - - if (eltData.xhr) { - if (eltData.abortable) { - triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue - } else { - if(queueStrategy == null){ - if (event) { - var eventData = getInternalData(event); - if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { - queueStrategy = eventData.triggerSpec.queue; - } - } - if (queueStrategy == null) { - queueStrategy = "last"; - } - } - if (eltData.queuedRequests == null) { - eltData.queuedRequests = []; - } - if (queueStrategy === "first" && eltData.queuedRequests.length === 0) { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } else if (queueStrategy === "all") { - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } else if (queueStrategy === "last") { - eltData.queuedRequests = []; // dump existing queue - eltData.queuedRequests.push(function () { - issueAjaxRequest(verb, path, elt, event, etc) - }); - } - maybeCall(resolve); - return promise; - } - } - - var xhr = new XMLHttpRequest(); - eltData.xhr = xhr; - eltData.abortable = abortable; - var endRequestLock = function(){ - eltData.xhr = null; - eltData.abortable = false; - if (eltData.queuedRequests != null && - eltData.queuedRequests.length > 0) { - var queuedRequest = eltData.queuedRequests.shift(); - queuedRequest(); - } - } - var promptQuestion = getClosestAttributeValue(elt, "hx-prompt"); - if (promptQuestion) { - var promptResponse = prompt(promptQuestion); - // prompt returns null if cancelled and empty string if accepted with no entry - if (promptResponse === null || - !triggerEvent(elt, 'htmx:prompt', {prompt: promptResponse, target:target})) { - maybeCall(resolve); - endRequestLock(); - return promise; - } + triggerErrorEvent(getDocument().body, 'htmx:syntax:error', { error: e, source: conditionalSource }) + return null } + } + } else if (token === '[') { + bracketCount++ + } + if (isPossibleRelativeReference(token, last, paramName)) { + conditionalSource += '((' + paramName + '.' + token + ') ? (' + paramName + '.' + token + ') : (window.' + token + '))' + } else { + conditionalSource = conditionalSource + token + } + last = tokens.shift() + } + } + } + + /** + * @param {string[]} tokens + * @param {RegExp} match + * @returns {string} + */ + function consumeUntil(tokens, match) { + let result = '' + while (tokens.length > 0 && !match.test(tokens[0])) { + result += tokens.shift() + } + return result + } + + /** + * @param {string[]} tokens + * @returns {string} + */ + function consumeCSSSelector(tokens) { + let result + if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) { + tokens.shift() + result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim() + tokens.shift() + } else { + result = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } + return result + } + + const INPUT_SELECTOR = 'input, textarea, select' + + /** + * @param {Element} elt + * @param {string} explicitTrigger + * @param {Object} cache for trigger specs + * @returns {HtmxTriggerSpecification[]} + */ + function parseAndCacheTrigger(elt, explicitTrigger, cache) { + /** @type HtmxTriggerSpecification[] */ + const triggerSpecs = [] + const tokens = tokenizeString(explicitTrigger) + do { + consumeUntil(tokens, NOT_WHITESPACE) + const initialLength = tokens.length + const trigger = consumeUntil(tokens, /[,\[\s]/) + if (trigger !== '') { + if (trigger === 'every') { + /** @type HtmxTriggerSpecification */ + const every = { trigger: 'every' } + consumeUntil(tokens, NOT_WHITESPACE) + every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/)) + consumeUntil(tokens, NOT_WHITESPACE) + var eventFilter = maybeGenerateConditional(elt, tokens, 'event') + if (eventFilter) { + every.eventFilter = eventFilter + } + triggerSpecs.push(every) + } else { + /** @type HtmxTriggerSpecification */ + const triggerSpec = { trigger } + var eventFilter = maybeGenerateConditional(elt, tokens, 'event') + if (eventFilter) { + triggerSpec.eventFilter = eventFilter + } + while (tokens.length > 0 && tokens[0] !== ',') { + consumeUntil(tokens, NOT_WHITESPACE) + const token = tokens.shift() + if (token === 'changed') { + triggerSpec.changed = true + } else if (token === 'once') { + triggerSpec.once = true + } else if (token === 'consume') { + triggerSpec.consume = true + } else if (token === 'delay' && tokens[0] === ':') { + tokens.shift() + triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)) + } else if (token === 'from' && tokens[0] === ':') { + tokens.shift() + if (COMBINED_SELECTOR_START.test(tokens[0])) { + var from_arg = consumeCSSSelector(tokens) + } else { + var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA) + if (from_arg === 'closest' || from_arg === 'find' || from_arg === 'next' || from_arg === 'previous') { + tokens.shift() + const selector = consumeCSSSelector(tokens) + // `next` and `previous` allow a selector-less syntax + if (selector.length > 0) { + from_arg += ' ' + selector + } + } + } + triggerSpec.from = from_arg + } else if (token === 'target' && tokens[0] === ':') { + tokens.shift() + triggerSpec.target = consumeCSSSelector(tokens) + } else if (token === 'throttle' && tokens[0] === ':') { + tokens.shift() + triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA)) + } else if (token === 'queue' && tokens[0] === ':') { + tokens.shift() + triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } else if (token === 'root' && tokens[0] === ':') { + tokens.shift() + triggerSpec[token] = consumeCSSSelector(tokens) + } else if (token === 'threshold' && tokens[0] === ':') { + tokens.shift() + triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA) + } else { + triggerErrorEvent(elt, 'htmx:syntax:error', { token: tokens.shift() }) + } + } + triggerSpecs.push(triggerSpec) + } + } + if (tokens.length === initialLength) { + triggerErrorEvent(elt, 'htmx:syntax:error', { token: tokens.shift() }) + } + consumeUntil(tokens, NOT_WHITESPACE) + } while (tokens[0] === ',' && tokens.shift()) + if (cache) { + cache[explicitTrigger] = triggerSpecs + } + return triggerSpecs + } + + /** + * @param {Element} elt + * @returns {HtmxTriggerSpecification[]} + */ + function getTriggerSpecs(elt) { + const explicitTrigger = getAttributeValue(elt, 'hx-trigger') + let triggerSpecs = [] + if (explicitTrigger) { + const cache = htmx.config.triggerSpecsCache + triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache) + } - if (confirmQuestion && !confirmed) { - if(!confirm(confirmQuestion)) { - maybeCall(resolve); - endRequestLock() - return promise; - } + if (triggerSpecs.length > 0) { + return triggerSpecs + } else if (matches(elt, 'form')) { + return [{ trigger: 'submit' }] + } else if (matches(elt, 'input[type="button"], input[type="submit"]')) { + return [{ trigger: 'click' }] + } else if (matches(elt, INPUT_SELECTOR)) { + return [{ trigger: 'change' }] + } else { + return [{ trigger: 'click' }] + } + } + + /** + * @param {Element} elt + */ + function cancelPolling(elt) { + getInternalData(elt).cancelled = true + } + + /** + * @param {Element} elt + * @param {TriggerHandler} handler + * @param {HtmxTriggerSpecification} spec + */ + function processPolling(elt, handler, spec) { + const nodeData = getInternalData(elt) + nodeData.timeout = getWindow().setTimeout(function() { + if (bodyContains(elt) && nodeData.cancelled !== true) { + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { + handler(elt) + } + processPolling(elt, handler, spec) + } + }, spec.pollInterval) + } + + /** + * @param {HTMLAnchorElement} elt + * @returns {boolean} + */ + function isLocalLink(elt) { + return location.hostname === elt.hostname && + getRawAttribute(elt, 'href') && + getRawAttribute(elt, 'href').indexOf('#') !== 0 + } + + /** + * @param {Element} elt + */ + function eltIsDisabled(elt) { + return closest(elt, htmx.config.disableSelector) + } + + /** + * @param {Element} elt + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification[]} triggerSpecs + */ + function boostElement(elt, nodeData, triggerSpecs) { + if ((elt instanceof HTMLAnchorElement && isLocalLink(elt) && (elt.target === '' || elt.target === '_self')) || elt.tagName === 'FORM') { + nodeData.boosted = true + let verb, path + if (elt.tagName === 'A') { + verb = 'get' + path = getRawAttribute(elt, 'href') + } else { + const rawAttribute = getRawAttribute(elt, 'method') + verb = rawAttribute ? rawAttribute.toLowerCase() : 'get' + if (verb === 'get') { + } + path = getRawAttribute(elt, 'action') + } + triggerSpecs.forEach(function(triggerSpec) { + addEventListener(elt, function(node, evt) { + const elt = asElement(node) + if (eltIsDisabled(elt)) { + cleanUpElement(elt) + return + } + issueAjaxRequest(verb, path, elt, evt) + }, nodeData, triggerSpec, true) + }) + } + } + + /** + * @param {Event} evt + * @param {Node} node + * @returns {boolean} + */ + function shouldCancel(evt, node) { + const elt = asElement(node) + if (!elt) { + return false + } + if (evt.type === 'submit' || evt.type === 'click') { + if (elt.tagName === 'FORM') { + return true + } + if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) { + return true + } + if (elt instanceof HTMLAnchorElement && elt.href && + (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf('#') !== 0)) { + return true + } + } + return false + } + + /** + * @param {Node} elt + * @param {Event|MouseEvent|KeyboardEvent|TouchEvent} evt + * @returns {boolean} + */ + function ignoreBoostedAnchorCtrlClick(elt, evt) { + return getInternalData(elt).boosted && elt instanceof HTMLAnchorElement && evt.type === 'click' && + // @ts-ignore this will resolve to undefined for events that don't define those properties, which is fine + (evt.ctrlKey || evt.metaKey) + } + + /** + * @param {HtmxTriggerSpecification} triggerSpec + * @param {Node} elt + * @param {Event} evt + * @returns {boolean} + */ + function maybeFilterEvent(triggerSpec, elt, evt) { + const eventFilter = triggerSpec.eventFilter + if (eventFilter) { + try { + return eventFilter.call(elt, evt) !== true + } catch (e) { + const source = eventFilter.source + triggerErrorEvent(getDocument().body, 'htmx:eventFilter:error', { error: e, source }) + return true + } + } + return false + } + + /** + * @param {Node} elt + * @param {TriggerHandler} handler + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification} triggerSpec + * @param {boolean} [explicitCancel] + */ + function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) { + const elementData = getInternalData(elt) + /** @type {(Node|Window)[]} */ + let eltsToListenOn + if (triggerSpec.from) { + eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from) + } else { + eltsToListenOn = [elt] + } + // store the initial values of the elements, so we can tell if they change + if (triggerSpec.changed) { + eltsToListenOn.forEach(function(eltToListenOn) { + const eltToListenOnData = getInternalData(eltToListenOn) + // @ts-ignore value will be undefined for non-input elements, which is fine + eltToListenOnData.lastValue = eltToListenOn.value + }) + } + forEach(eltsToListenOn, function(eltToListenOn) { + /** @type EventListener */ + const eventListener = function(evt) { + if (!bodyContains(elt)) { + eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener) + return + } + if (ignoreBoostedAnchorCtrlClick(elt, evt)) { + return + } + if (explicitCancel || shouldCancel(evt, elt)) { + evt.preventDefault() + } + if (maybeFilterEvent(triggerSpec, elt, evt)) { + return + } + const eventData = getInternalData(evt) + eventData.triggerSpec = triggerSpec + if (eventData.handledFor == null) { + eventData.handledFor = [] + } + if (eventData.handledFor.indexOf(elt) < 0) { + eventData.handledFor.push(elt) + if (triggerSpec.consume) { + evt.stopPropagation() + } + if (triggerSpec.target && evt.target) { + if (!matches(asElement(evt.target), triggerSpec.target)) { + return + } + } + if (triggerSpec.once) { + if (elementData.triggeredOnce) { + return + } else { + elementData.triggeredOnce = true + } + } + if (triggerSpec.changed) { + const eltToListenOnData = getInternalData(eltToListenOn) + // @ts-ignore value will be undefined for non-input elements, which is fine + const value = eltToListenOn.value + if (eltToListenOnData.lastValue === value) { + return + } + eltToListenOnData.lastValue = value + } + if (elementData.delayed) { + clearTimeout(elementData.delayed) + } + if (elementData.throttle) { + return + } + + if (triggerSpec.throttle > 0) { + if (!elementData.throttle) { + handler(elt, evt) + elementData.throttle = getWindow().setTimeout(function() { + elementData.throttle = null + }, triggerSpec.throttle) + } + } else if (triggerSpec.delay > 0) { + elementData.delayed = getWindow().setTimeout(function() { handler(elt, evt) }, triggerSpec.delay) + } else { + triggerEvent(elt, 'htmx:trigger') + handler(elt, evt) + } + } + } + if (nodeData.listenerInfos == null) { + nodeData.listenerInfos = [] + } + nodeData.listenerInfos.push({ + trigger: triggerSpec.trigger, + listener: eventListener, + on: eltToListenOn + }) + eltToListenOn.addEventListener(triggerSpec.trigger, eventListener) + }) + } + + let windowIsScrolling = false // used by initScrollHandler + let scrollHandler = null + function initScrollHandler() { + if (!scrollHandler) { + scrollHandler = function() { + windowIsScrolling = true + } + window.addEventListener('scroll', scrollHandler) + setInterval(function() { + if (windowIsScrolling) { + windowIsScrolling = false + forEach(getDocument().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"), function(elt) { + maybeReveal(elt) + }) + } + }, 200) + } + } + + /** + * @param {Element} elt + */ + function maybeReveal(elt) { + if (!hasAttribute(elt, 'data-hx-revealed') && isScrolledIntoView(elt)) { + elt.setAttribute('data-hx-revealed', 'true') + const nodeData = getInternalData(elt) + if (nodeData.initHash) { + triggerEvent(elt, 'revealed') + } else { + // if the node isn't initialized, wait for it before triggering the request + elt.addEventListener('htmx:afterProcessNode', function() { triggerEvent(elt, 'revealed') }, { once: true }) + } + } + } + + //= =================================================================== + + /** + * @param {Element} elt + * @param {TriggerHandler} handler + * @param {HtmxNodeInternalData} nodeData + * @param {number} delay + */ + function loadImmediately(elt, handler, nodeData, delay) { + const load = function() { + if (!nodeData.loaded) { + nodeData.loaded = true + handler(elt) + } + } + if (delay > 0) { + getWindow().setTimeout(load, delay) + } else { + load() + } + } + + /** + * @param {Element} elt + * @param {HtmxNodeInternalData} nodeData + * @param {HtmxTriggerSpecification[]} triggerSpecs + * @returns {boolean} + */ + function processVerbs(elt, nodeData, triggerSpecs) { + let explicitAction = false + forEach(VERBS, function(verb) { + if (hasAttribute(elt, 'hx-' + verb)) { + const path = getAttributeValue(elt, 'hx-' + verb) + explicitAction = true + nodeData.path = path + nodeData.verb = verb + triggerSpecs.forEach(function(triggerSpec) { + addTriggerHandler(elt, triggerSpec, nodeData, function(node, evt) { + const elt = asElement(node) + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return } + issueAjaxRequest(verb, path, elt, evt) + }) + }) + } + }) + return explicitAction + } + + /** + * @callback TriggerHandler + * @param {Node} elt + * @param {Event} [evt] + */ + + /** + * @param {Node} elt + * @param {HtmxTriggerSpecification} triggerSpec + * @param {HtmxNodeInternalData} nodeData + * @param {TriggerHandler} handler + */ + function addTriggerHandler(elt, triggerSpec, nodeData, handler) { + if (triggerSpec.trigger === 'revealed') { + initScrollHandler() + addEventListener(elt, handler, nodeData, triggerSpec) + maybeReveal(asElement(elt)) + } else if (triggerSpec.trigger === 'intersect') { + const observerOptions = {} + if (triggerSpec.root) { + observerOptions.root = querySelectorExt(elt, triggerSpec.root) + } + if (triggerSpec.threshold) { + observerOptions.threshold = parseFloat(triggerSpec.threshold) + } + const observer = new IntersectionObserver(function(entries) { + for (let i = 0; i < entries.length; i++) { + const entry = entries[i] + if (entry.isIntersecting) { + triggerEvent(elt, 'intersect') + break + } + } + }, observerOptions) + observer.observe(asElement(elt)) + addEventListener(asElement(elt), handler, nodeData, triggerSpec) + } else if (triggerSpec.trigger === 'load') { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent('load', { elt }))) { + loadImmediately(asElement(elt), handler, nodeData, triggerSpec.delay) + } + } else if (triggerSpec.pollInterval > 0) { + nodeData.polling = true + processPolling(asElement(elt), handler, triggerSpec) + } else { + addEventListener(elt, handler, nodeData, triggerSpec) + } + } + + /** + * @param {Node} node + * @returns {boolean} + */ + function shouldProcessHxOn(node) { + const elt = asElement(node) + if (!elt) { + return false + } + const attributes = elt.attributes + for (let j = 0; j < attributes.length; j++) { + const attrName = attributes[j].name + if (startsWith(attrName, 'hx-on:') || startsWith(attrName, 'data-hx-on:') || + startsWith(attrName, 'hx-on-') || startsWith(attrName, 'data-hx-on-')) { + return true + } + } + return false + } + + /** + * @param {Node} elt + * @returns {Element[]} + */ + const HX_ON_QUERY = new XPathEvaluator() + .createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' + + ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]') + + function processHXOnRoot(elt, elements) { + if (shouldProcessHxOn(elt)) { + elements.push(asElement(elt)) + } + const iter = HX_ON_QUERY.evaluate(elt) + let node = null + while (node = iter.iterateNext()) elements.push(asElement(node)) + } + + function findHxOnWildcardElements(elt) { + /** @type {Element[]} */ + const elements = [] + if (elt instanceof DocumentFragment) { + for (const child of elt.childNodes) { + processHXOnRoot(child, elements) + } + } else { + processHXOnRoot(elt, elements) + } + return elements + } + + /** + * @param {Element} elt + * @returns {NodeListOf<Element>|[]} + */ + function findElementsToProcess(elt) { + if (elt.querySelectorAll) { + const boostedSelector = ', [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]' + + const extensionSelectors = [] + for (const e in extensions) { + const extension = extensions[e] + if (extension.getSelectors) { + var selectors = extension.getSelectors() + if (selectors) { + extensionSelectors.push(selectors) + } + } + } + + const results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit']," + + ' [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]' + extensionSelectors.flat().map(s => ', ' + s).join('')) + + return results + } else { + return [] + } + } + + /** + * Handle submit buttons/inputs that have the form attribute set + * see https://developer.mozilla.org/docs/Web/HTML/Element/button + * @param {Event} evt + */ + function maybeSetLastButtonClicked(evt) { + const elt = /** @type {HTMLButtonElement|HTMLInputElement} */ (closest(asElement(evt.target), "button, input[type='submit']")) + const internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = elt + } + } + + /** + * @param {Event} evt + */ + function maybeUnsetLastButtonClicked(evt) { + const internalData = getRelatedFormData(evt) + if (internalData) { + internalData.lastButtonClicked = null + } + } + + /** + * @param {Event} evt + * @returns {HtmxNodeInternalData|undefined} + */ + function getRelatedFormData(evt) { + const elt = closest(asElement(evt.target), "button, input[type='submit']") + if (!elt) { + return + } + const form = resolveTarget('#' + getRawAttribute(elt, 'form'), elt.getRootNode()) || closest(elt, 'form') + if (!form) { + return + } + return getInternalData(form) + } + + /** + * @param {EventTarget} elt + */ + function initButtonTracking(elt) { + // need to handle both click and focus in: + // focusin - in case someone tabs in to a button and hits the space bar + // click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724 + elt.addEventListener('click', maybeSetLastButtonClicked) + elt.addEventListener('focusin', maybeSetLastButtonClicked) + elt.addEventListener('focusout', maybeUnsetLastButtonClicked) + } + + /** + * @param {Element} elt + * @param {string} eventName + * @param {string} code + */ + function addHxOnEventHandler(elt, eventName, code) { + const nodeData = getInternalData(elt) + if (!Array.isArray(nodeData.onHandlers)) { + nodeData.onHandlers = [] + } + let func + /** @type EventListener */ + const listener = function(e) { + maybeEval(elt, function() { + if (eltIsDisabled(elt)) { + return + } + if (!func) { + func = new Function('event', code) + } + func.call(elt, e) + }) + } + elt.addEventListener(eventName, listener) + nodeData.onHandlers.push({ event: eventName, listener }) + } + + /** + * @param {Element} elt + */ + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (let i = 0; i < elt.attributes.length; i++) { + const name = elt.attributes[i].name + const value = elt.attributes[i].value + if (startsWith(name, 'hx-on') || startsWith(name, 'data-hx-on')) { + const afterOnPosition = name.indexOf('-on') + 3 + const nextChar = name.slice(afterOnPosition, afterOnPosition + 1) + if (nextChar === '-' || nextChar === ':') { + let eventName = name.slice(afterOnPosition + 1) + // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support + if (startsWith(eventName, ':')) { + eventName = 'htmx' + eventName + } else if (startsWith(eventName, '-')) { + eventName = 'htmx:' + eventName.slice(1) + } else if (startsWith(eventName, 'htmx-')) { + eventName = 'htmx:' + eventName.slice(5) + } + + addHxOnEventHandler(elt, eventName, value) + } + } + } + } + + /** + * @param {Element|HTMLInputElement} elt + */ + function initNode(elt) { + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + const nodeData = getInternalData(elt) + if (nodeData.initHash !== attributeHash(elt)) { + // clean up any previously processed info + deInitNode(elt) + + nodeData.initHash = attributeHash(elt) + + triggerEvent(elt, 'htmx:beforeProcessNode') + + // @ts-ignore value will be undefined for non-input elements, which is fine + if (elt.value) { + // @ts-ignore + nodeData.lastValue = elt.value + } + + const triggerSpecs = getTriggerSpecs(elt) + const hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs) + + if (!hasExplicitHttpAction) { + if (getClosestAttributeValue(elt, 'hx-boost') === 'true') { + boostElement(elt, nodeData, triggerSpecs) + } else if (hasAttribute(elt, 'hx-trigger')) { + triggerSpecs.forEach(function(triggerSpec) { + // For "naked" triggers, don't do anything at all + addTriggerHandler(elt, triggerSpec, nodeData, function() { + }) + }) + } + } + // Handle submit buttons/inputs that have the form attribute set + // see https://developer.mozilla.org/docs/Web/HTML/Element/button + if (elt.tagName === 'FORM' || (getRawAttribute(elt, 'type') === 'submit' && hasAttribute(elt, 'form'))) { + initButtonTracking(elt) + } - var headers = getHeaders(elt, target, promptResponse); - - if (verb !== 'get' && !usesFormData(elt)) { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; - } + triggerEvent(elt, 'htmx:afterProcessNode') + } + } + + /** + * Processes new content, enabling htmx behavior. This can be useful if you have content that is added to the DOM outside of the normal htmx request cycle but still want htmx attributes to work. + * + * @see https://htmx.org/api/#process + * + * @param {Element|string} elt element to process + */ + function processNode(elt) { + elt = resolveTarget(elt) + if (closest(elt, htmx.config.disableSelector)) { + cleanUpElement(elt) + return + } + initNode(elt) + forEach(findElementsToProcess(elt), function(child) { initNode(child) }) + forEach(findHxOnWildcardElements(elt), processHxOnWildcard) + } + + //= =================================================================== + // Event/Log Support + //= =================================================================== + + /** + * @param {string} str + * @returns {string} + */ + function kebabEventName(str) { + return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase() + } + + /** + * @param {string} eventName + * @param {any} detail + * @returns {CustomEvent} + */ + function makeEvent(eventName, detail) { + let evt + if (window.CustomEvent && typeof window.CustomEvent === 'function') { + // TODO: `composed: true` here is a hack to make global event handlers work with events in shadow DOM + // This breaks expected encapsulation but needs to be here until decided otherwise by core devs + evt = new CustomEvent(eventName, { bubbles: true, cancelable: true, composed: true, detail }) + } else { + evt = getDocument().createEvent('CustomEvent') + evt.initCustomEvent(eventName, true, true, detail) + } + return evt + } + + /** + * @param {EventTarget|string} elt + * @param {string} eventName + * @param {any=} detail + */ + function triggerErrorEvent(elt, eventName, detail) { + triggerEvent(elt, eventName, mergeObjects({ error: eventName }, detail)) + } + + /** + * @param {string} eventName + * @returns {boolean} + */ + function ignoreEventForLogging(eventName) { + return eventName === 'htmx:afterProcessNode' + } + + /** + * `withExtensions` locates all active extensions for a provided element, then + * executes the provided function using each of the active extensions. It should + * be called internally at every extendable execution point in htmx. + * + * @param {Element} elt + * @param {(extension:HtmxExtension) => void} toDo + * @returns void + */ + function withExtensions(elt, toDo) { + forEach(getExtensions(elt), function(extension) { + try { + toDo(extension) + } catch (e) { + logError(e) + } + }) + } + + function logError(msg) { + if (console.error) { + console.error(msg) + } else if (console.log) { + console.log('ERROR: ', msg) + } + } + + /** + * Triggers a given event on an element + * + * @see https://htmx.org/api/#trigger + * + * @param {EventTarget|string} elt the element to trigger the event on + * @param {string} eventName the name of the event to trigger + * @param {any=} detail details for the event + * @returns {boolean} + */ + function triggerEvent(elt, eventName, detail) { + elt = resolveTarget(elt) + if (detail == null) { + detail = {} + } + detail.elt = elt + const event = makeEvent(eventName, detail) + if (htmx.logger && !ignoreEventForLogging(eventName)) { + htmx.logger(elt, eventName, detail) + } + if (detail.error) { + logError(detail.error) + triggerEvent(elt, 'htmx:error', { errorInfo: detail }) + } + let eventResult = elt.dispatchEvent(event) + const kebabName = kebabEventName(eventName) + if (eventResult && kebabName !== eventName) { + const kebabedEvent = makeEvent(kebabName, event.detail) + eventResult = eventResult && elt.dispatchEvent(kebabedEvent) + } + withExtensions(asElement(elt), function(extension) { + eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented) + }) + return eventResult + } + + //= =================================================================== + // History Support + //= =================================================================== + let currentPathForHistory = location.pathname + location.search + + /** + * @returns {Element} + */ + function getHistoryElement() { + const historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]') + return historyElt || getDocument().body + } + + /** + * @param {string} url + * @param {Element} rootElt + */ + function saveToHistoryCache(url, rootElt) { + if (!canAccessLocalStorage()) { + return + } - if (etc.headers) { - headers = mergeObjects(headers, etc.headers); - } - var results = getInputValues(elt, verb); - var errors = results.errors; - var rawParameters = results.values; - if (etc.values) { - rawParameters = mergeObjects(rawParameters, etc.values); - } - var expressionVars = getExpressionVars(elt); - var allParameters = mergeObjects(rawParameters, expressionVars); - var filteredParameters = filterValues(allParameters, elt); + // get state to save + const innerHTML = cleanInnerHtmlForHistory(rootElt) + const title = getDocument().title + const scroll = window.scrollY - if (htmx.config.getCacheBusterParam && verb === 'get') { - filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true"; - } + if (htmx.config.historyCacheSize <= 0) { + // make sure that an eventually already existing cache is purged + localStorage.removeItem('htmx-history-cache') + return + } - // behavior of anchors w/ empty href is to use the current URL - if (path == null || path === "") { - path = getDocument().location.href; - } + url = normalizePath(url) + const historyCache = parseJSON(localStorage.getItem('htmx-history-cache')) || [] + for (let i = 0; i < historyCache.length; i++) { + if (historyCache[i].url === url) { + historyCache.splice(i, 1) + break + } + } - var requestAttrValues = getValuesForElement(elt, 'hx-request'); + /** @type HtmxHistoryItem */ + const newHistoryItem = { url, content: innerHTML, title, scroll } - var eltIsBoosted = getInternalData(elt).boosted; + triggerEvent(getDocument().body, 'htmx:historyItemCreated', { item: newHistoryItem, cache: historyCache }) - var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + historyCache.push(newHistoryItem) + while (historyCache.length > htmx.config.historyCacheSize) { + historyCache.shift() + } - var requestConfig = { - boosted: eltIsBoosted, - useUrlParams: useUrlParams, - parameters: filteredParameters, - unfilteredParameters: allParameters, - headers:headers, - target:target, - verb:verb, - errors:errors, - withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, - timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, - path:path, - triggeringEvent:event - }; + // keep trying to save the cache until it succeeds or is empty + while (historyCache.length > 0) { + try { + localStorage.setItem('htmx-history-cache', JSON.stringify(historyCache)) + break + } catch (e) { + triggerErrorEvent(getDocument().body, 'htmx:historyCacheError', { cause: e, cache: historyCache }) + historyCache.shift() // shrink the cache and retry + } + } + } + + /** + * @typedef {Object} HtmxHistoryItem + * @property {string} url + * @property {string} content + * @property {string} title + * @property {number} scroll + */ + + /** + * @param {string} url + * @returns {HtmxHistoryItem|null} + */ + function getCachedHistory(url) { + if (!canAccessLocalStorage()) { + return null + } - if(!triggerEvent(elt, 'htmx:configRequest', requestConfig)){ - maybeCall(resolve); - endRequestLock(); - return promise; - } + url = normalizePath(url) - // copy out in case the object was overwritten - path = requestConfig.path; - verb = requestConfig.verb; - headers = requestConfig.headers; - filteredParameters = requestConfig.parameters; - errors = requestConfig.errors; - useUrlParams = requestConfig.useUrlParams; - - if(errors && errors.length > 0){ - triggerEvent(elt, 'htmx:validation:halted', requestConfig) - maybeCall(resolve); - endRequestLock(); - return promise; - } + const historyCache = parseJSON(localStorage.getItem('htmx-history-cache')) || [] + for (let i = 0; i < historyCache.length; i++) { + if (historyCache[i].url === url) { + return historyCache[i] + } + } + return null + } + + /** + * @param {Element} elt + * @returns {string} + */ + function cleanInnerHtmlForHistory(elt) { + const className = htmx.config.requestClass + const clone = /** @type Element */ (elt.cloneNode(true)) + forEach(findAll(clone, '.' + className), function(child) { + removeClassFromElement(child, className) + }) + return clone.innerHTML + } + + function saveCurrentPageToHistory() { + const elt = getHistoryElement() + const path = currentPathForHistory || location.pathname + location.search + + // Allow history snapshot feature to be disabled where hx-history="false" + // is present *anywhere* in the current document we're about to save, + // so we can prevent privileged data entering the cache. + // The page will still be reachable as a history entry, but htmx will fetch it + // live from the server onpopstate rather than look in the localStorage cache + let disableHistoryCache + try { + disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]') + } catch (e) { + // IE11: insensitive modifier not supported so fallback to case sensitive selector + disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]') + } + if (!disableHistoryCache) { + triggerEvent(getDocument().body, 'htmx:beforeHistorySave', { path, historyElt: elt }) + saveToHistoryCache(path, elt) + } - var splitPath = path.split("#"); - var pathNoAnchor = splitPath[0]; - var anchor = splitPath[1]; - - var finalPath = path - if (useUrlParams) { - finalPath = pathNoAnchor; - var values = Object.keys(filteredParameters).length !== 0; - if (values) { - if (finalPath.indexOf("?") < 0) { - finalPath += "?"; - } else { - finalPath += "&"; - } - finalPath += urlEncode(filteredParameters); - if (anchor) { - finalPath += "#" + anchor; - } - } - } + if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, getDocument().title, window.location.href) + } + + /** + * @param {string} path + */ + function pushUrlIntoHistory(path) { + // remove the cache buster parameter, if any + if (htmx.config.getCacheBusterParam) { + path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '') + if (endsWith(path, '&') || endsWith(path, '?')) { + path = path.slice(0, -1) + } + } + if (htmx.config.historyEnabled) { + history.pushState({ htmx: true }, '', path) + } + currentPathForHistory = path + } + + /** + * @param {string} path + */ + function replaceUrlInHistory(path) { + if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, '', path) + currentPathForHistory = path + } + + /** + * @param {HtmxSettleTask[]} tasks + */ + function settleImmediately(tasks) { + forEach(tasks, function(task) { + task.call(undefined) + }) + } + + /** + * @param {string} path + */ + function loadHistoryFromServer(path) { + const request = new XMLHttpRequest() + const details = { path, xhr: request } + triggerEvent(getDocument().body, 'htmx:historyCacheMiss', details) + request.open('GET', path, true) + request.setRequestHeader('HX-Request', 'true') + request.setRequestHeader('HX-History-Restore-Request', 'true') + request.setRequestHeader('HX-Current-URL', getDocument().location.href) + request.onload = function() { + if (this.status >= 200 && this.status < 400) { + triggerEvent(getDocument().body, 'htmx:historyCacheMissLoad', details) + const fragment = makeFragment(this.response) + /** @type ParentNode */ + const content = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment + const historyElement = getHistoryElement() + const settleInfo = makeSettleInfo(historyElement) + handleTitle(fragment.title) + + swapInnerHTML(historyElement, content, settleInfo) + settleImmediately(settleInfo.tasks) + currentPathForHistory = path + triggerEvent(getDocument().body, 'htmx:historyRestore', { path, cacheMiss: true, serverResponse: this.response }) + } else { + triggerErrorEvent(getDocument().body, 'htmx:historyCacheMissLoadError', details) + } + } + request.send() + } + + /** + * @param {string} [path] + */ + function restoreHistory(path) { + saveCurrentPageToHistory() + path = path || location.pathname + location.search + const cached = getCachedHistory(path) + if (cached) { + const fragment = makeFragment(cached.content) + const historyElement = getHistoryElement() + const settleInfo = makeSettleInfo(historyElement) + handleTitle(fragment.title) + swapInnerHTML(historyElement, fragment, settleInfo) + settleImmediately(settleInfo.tasks) + getWindow().setTimeout(function() { + window.scrollTo(0, cached.scroll) + }, 0) // next 'tick', so browser has time to render layout + currentPathForHistory = path + triggerEvent(getDocument().body, 'htmx:historyRestore', { path, item: cached }) + } else { + if (htmx.config.refreshOnHistoryMiss) { + // @ts-ignore: optional parameter in reload() function throws error + // noinspection JSUnresolvedReference + window.location.reload(true) + } else { + loadHistoryFromServer(path) + } + } + } + + /** + * @param {Element} elt + * @returns {Element[]} + */ + function addRequestIndicatorClasses(elt) { + let indicators = /** @type Element[] */ (findAttributeTargets(elt, 'hx-indicator')) + if (indicators == null) { + indicators = [elt] + } + forEach(indicators, function(ic) { + const internalData = getInternalData(ic) + internalData.requestCount = (internalData.requestCount || 0) + 1 + ic.classList.add.call(ic.classList, htmx.config.requestClass) + }) + return indicators + } + + /** + * @param {Element} elt + * @returns {Element[]} + */ + function disableElements(elt) { + let disabledElts = /** @type Element[] */ (findAttributeTargets(elt, 'hx-disabled-elt')) + if (disabledElts == null) { + disabledElts = [] + } + forEach(disabledElts, function(disabledElement) { + const internalData = getInternalData(disabledElement) + internalData.requestCount = (internalData.requestCount || 0) + 1 + disabledElement.setAttribute('disabled', '') + }) + return disabledElts + } + + /** + * @param {Element[]} indicators + * @param {Element[]} disabled + */ + function removeRequestIndicators(indicators, disabled) { + forEach(indicators, function(ic) { + const internalData = getInternalData(ic) + internalData.requestCount = (internalData.requestCount || 0) - 1 + if (internalData.requestCount === 0) { + ic.classList.remove.call(ic.classList, htmx.config.requestClass) + } + }) + forEach(disabled, function(disabledElement) { + const internalData = getInternalData(disabledElement) + internalData.requestCount = (internalData.requestCount || 0) - 1 + if (internalData.requestCount === 0) { + disabledElement.removeAttribute('disabled') + } + }) + } + + //= =================================================================== + // Input Value Processing + //= =================================================================== + + /** + * @param {Element[]} processed + * @param {Element} elt + * @returns {boolean} + */ + function haveSeenNode(processed, elt) { + for (let i = 0; i < processed.length; i++) { + const node = processed[i] + if (node.isSameNode(elt)) { + return true + } + } + return false + } + + /** + * @param {Element} element + * @return {boolean} + */ + function shouldInclude(element) { + // Cast to trick tsc, undefined values will work fine here + const elt = /** @type {HTMLInputElement} */ (element) + if (elt.name === '' || elt.name == null || elt.disabled || closest(elt, 'fieldset[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 + } + + /** @param {string} name + * @param {string|Array|FormDataEntryValue} value + * @param {FormData} formData */ + function addValueToFormData(name, value, formData) { + if (name != null && value != null) { + if (Array.isArray(value)) { + value.forEach(function(v) { formData.append(name, v) }) + } else { + formData.append(name, value) + } + } + } + + /** @param {string} name + * @param {string|Array} value + * @param {FormData} formData */ + function removeValueFromFormData(name, value, formData) { + if (name != null && value != null) { + let values = formData.getAll(name) + if (Array.isArray(value)) { + values = values.filter(v => value.indexOf(v) < 0) + } else { + values = values.filter(v => v !== value) + } + formData.delete(name) + forEach(values, v => formData.append(name, v)) + } + } + + /** + * @param {Element[]} processed + * @param {FormData} formData + * @param {HtmxElementValidationError[]} errors + * @param {Element|HTMLInputElement|HTMLSelectElement|HTMLFormElement} elt + * @param {boolean} validate + */ + function processInputValue(processed, formData, errors, elt, validate) { + if (elt == null || haveSeenNode(processed, elt)) { + return + } else { + processed.push(elt) + } + if (shouldInclude(elt)) { + const name = getRawAttribute(elt, 'name') + // @ts-ignore value will be undefined for non-input elements, which is fine + let value = elt.value + if (elt instanceof HTMLSelectElement && elt.multiple) { + value = toArray(elt.querySelectorAll('option:checked')).map(function(e) { return (/** @type HTMLOptionElement */(e)).value }) + } + // include file inputs + if (elt instanceof HTMLInputElement && elt.files) { + value = toArray(elt.files) + } + addValueToFormData(name, value, formData) + if (validate) { + validateElement(elt, errors) + } + } + if (elt instanceof HTMLFormElement) { + forEach(elt.elements, function(input) { + if (processed.indexOf(input) >= 0) { + // The input has already been processed and added to the values, but the FormData that will be + // constructed right after on the form, will include it once again. So remove that input's value + // now to avoid duplicates + removeValueFromFormData(input.name, input.value, formData) + } else { + processed.push(input) + } + if (validate) { + validateElement(input, errors) + } + }) + new FormData(elt).forEach(function(value, name) { + if (value instanceof File && value.name === '') { + return // ignore no-name files + } + addValueToFormData(name, value, formData) + }) + } + } + + /** + * + * @param {Element} elt + * @param {HtmxElementValidationError[]} errors + */ + function validateElement(elt, errors) { + const element = /** @type {HTMLElement & ElementInternals} */ (elt) + if (element.willValidate) { + triggerEvent(element, 'htmx:validation:validate') + if (!element.checkValidity()) { + errors.push({ elt: element, message: element.validationMessage, validity: element.validity }) + triggerEvent(element, 'htmx:validation:failed', { message: element.validationMessage, validity: element.validity }) + } + } + } + + /** + * Override values in the one FormData with those from another. + * @param {FormData} receiver the formdata that will be mutated + * @param {FormData} donor the formdata that will provide the overriding values + * @returns {FormData} the {@linkcode receiver} + */ + function overrideFormData(receiver, donor) { + for (const key of donor.keys()) { + receiver.delete(key) + donor.getAll(key).forEach(function(value) { + receiver.append(key, value) + }) + } + return receiver + } + + /** + * @param {Element|HTMLFormElement} elt + * @param {HttpVerb} verb + * @returns {{errors: HtmxElementValidationError[], formData: FormData, values: Object}} + */ + function getInputValues(elt, verb) { + /** @type Element[] */ + const processed = [] + const formData = new FormData() + const priorityFormData = new FormData() + /** @type HtmxElementValidationError[] */ + const errors = [] + const internalData = getInternalData(elt) + if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) { + internalData.lastButtonClicked = null + } - if (!verifyPath(elt, finalPath, requestConfig)) { - triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) - maybeCall(reject); - return promise; - }; + // only validate when form is directly submitted and novalidate or formnovalidate are not set + // or if the element has an explicit hx-validate="true" on it + let validate = (elt instanceof HTMLFormElement && elt.noValidate !== true) || getAttributeValue(elt, 'hx-validate') === 'true' + if (internalData.lastButtonClicked) { + validate = validate && internalData.lastButtonClicked.formNoValidate !== true + } - xhr.open(verb.toUpperCase(), finalPath, true); - xhr.overrideMimeType("text/html"); - xhr.withCredentials = requestConfig.withCredentials; - xhr.timeout = requestConfig.timeout; + // for a non-GET include the closest form + if (verb !== 'get') { + processInputValue(processed, priorityFormData, errors, closest(elt, 'form'), validate) + } - // request headers - if (requestAttrValues.noHeaders) { - // ignore all headers - } else { - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - var headerValue = headers[header]; - safelySetHeaderValue(xhr, header, headerValue); - } - } - } + // include the element itself + processInputValue(processed, formData, errors, elt, validate) - var responseInfo = { - xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select, - pathInfo: { - requestPath: path, - finalRequestPath: finalPath, - anchor: anchor - } - }; - - xhr.onload = function () { - try { - var hierarchy = hierarchyForElt(elt); - responseInfo.pathInfo.responsePath = getPathFromResponse(xhr); - responseHandler(elt, responseInfo); - removeRequestIndicators(indicators, disableElts); - triggerEvent(elt, 'htmx:afterRequest', responseInfo); - triggerEvent(elt, 'htmx:afterOnLoad', responseInfo); - // if the body no longer contains the element, trigger the event on the closest parent - // remaining in the DOM - if (!bodyContains(elt)) { - var secondaryTriggerElt = null; - while (hierarchy.length > 0 && secondaryTriggerElt == null) { - var parentEltInHierarchy = hierarchy.shift(); - if (bodyContains(parentEltInHierarchy)) { - secondaryTriggerElt = parentEltInHierarchy; - } - } - if (secondaryTriggerElt) { - triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo); - triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo); - } - } - maybeCall(resolve); - endRequestLock(); - } catch (e) { - triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({error:e}, responseInfo)); - throw e; - } - } - xhr.onerror = function () { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:sendError', responseInfo); - maybeCall(reject); - endRequestLock(); - } - xhr.onabort = function() { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo); - maybeCall(reject); - endRequestLock(); - } - xhr.ontimeout = function() { - removeRequestIndicators(indicators, disableElts); - triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo); - triggerErrorEvent(elt, 'htmx:timeout', responseInfo); - maybeCall(reject); - endRequestLock(); - } - if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){ - maybeCall(resolve); - endRequestLock() - return promise - } - var indicators = addRequestIndicatorClasses(elt); - var disableElts = disableElements(elt); - - forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { - forEach([xhr, xhr.upload], function (target) { - target.addEventListener(eventName, function(event){ - triggerEvent(elt, "htmx:xhr:" + eventName, { - lengthComputable:event.lengthComputable, - loaded:event.loaded, - total:event.total - }); - }) - }); - }); - triggerEvent(elt, 'htmx:beforeSend', responseInfo); - var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) - xhr.send(params); - return promise; - } - - function determineHistoryUpdates(elt, responseInfo) { - - var xhr = responseInfo.xhr; - - //=========================================== - // First consult response headers - //=========================================== - var pathFromHeaders = null; - var typeFromHeaders = null; - if (hasHeader(xhr,/HX-Push:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Push"); - typeFromHeaders = "push"; - } else if (hasHeader(xhr,/HX-Push-Url:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Push-Url"); - typeFromHeaders = "push"; - } else if (hasHeader(xhr,/HX-Replace-Url:/i)) { - pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url"); - typeFromHeaders = "replace"; - } + // if a button or submit was clicked last, include its value + if (internalData.lastButtonClicked || elt.tagName === 'BUTTON' || + (elt.tagName === 'INPUT' && getRawAttribute(elt, 'type') === 'submit')) { + const button = internalData.lastButtonClicked || (/** @type HTMLInputElement|HTMLButtonElement */(elt)) + const name = getRawAttribute(button, 'name') + addValueToFormData(name, button.value, priorityFormData) + } - // if there was a response header, that has priority - if (pathFromHeaders) { - if (pathFromHeaders === "false") { - return {} - } else { - return { - type: typeFromHeaders, - path : pathFromHeaders - } - } - } + // include any explicit includes + const includes = findAttributeTargets(elt, 'hx-include') + forEach(includes, function(node) { + processInputValue(processed, formData, errors, asElement(node), validate) + // if a non-form is included, include any input values within it + if (!matches(node, 'form')) { + forEach(asParentNode(node).querySelectorAll(INPUT_SELECTOR), function(descendant) { + processInputValue(processed, formData, errors, descendant, validate) + }) + } + }) + + // values from a <form> take precedence, overriding the regular values + overrideFormData(formData, priorityFormData) + + return { errors, formData, values: formDataProxy(formData) } + } + + /** + * @param {string} returnStr + * @param {string} name + * @param {any} realValue + * @returns {string} + */ + function appendParam(returnStr, name, realValue) { + if (returnStr !== '') { + returnStr += '&' + } + if (String(realValue) === '[object Object]') { + realValue = JSON.stringify(realValue) + } + const s = encodeURIComponent(realValue) + returnStr += encodeURIComponent(name) + '=' + s + return returnStr + } + + /** + * @param {FormData|Object} values + * @returns string + */ + function urlEncode(values) { + values = formDataFromObject(values) + let returnStr = '' + values.forEach(function(value, key) { + returnStr = appendParam(returnStr, key, value) + }) + return returnStr + } + + //= =================================================================== + // Ajax + //= =================================================================== + + /** + * @param {Element} elt + * @param {Element} target + * @param {string} prompt + * @returns {HtmxHeaderSpecification} + */ + function getHeaders(elt, target, prompt) { + /** @type HtmxHeaderSpecification */ + const headers = { + 'HX-Request': 'true', + 'HX-Trigger': getRawAttribute(elt, 'id'), + 'HX-Trigger-Name': getRawAttribute(elt, 'name'), + 'HX-Target': getAttributeValue(target, 'id'), + 'HX-Current-URL': getDocument().location.href + } + getValuesForElement(elt, 'hx-headers', false, headers) + if (prompt !== undefined) { + headers['HX-Prompt'] = prompt + } + if (getInternalData(elt).boosted) { + headers['HX-Boosted'] = 'true' + } + return headers + } + + /** + * filterValues takes an object containing form input values + * and returns a new object that only contains keys that are + * specified by the closest "hx-params" attribute + * @param {FormData} inputValues + * @param {Element} elt + * @returns {FormData} + */ + function filterValues(inputValues, elt) { + const paramsValue = getClosestAttributeValue(elt, 'hx-params') + if (paramsValue) { + if (paramsValue === 'none') { + return new FormData() + } else if (paramsValue === '*') { + return inputValues + } else if (paramsValue.indexOf('not ') === 0) { + forEach(paramsValue.substr(4).split(','), function(name) { + name = name.trim() + inputValues.delete(name) + }) + return inputValues + } else { + const newValues = new FormData() + forEach(paramsValue.split(','), function(name) { + name = name.trim() + if (inputValues.has(name)) { + inputValues.getAll(name).forEach(function(value) { newValues.append(name, value) }) + } + }) + return newValues + } + } else { + return inputValues + } + } + + /** + * @param {Element} elt + * @return {boolean} + */ + function isAnchorLink(elt) { + return !!getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf('#') >= 0 + } + + /** + * @param {Element} elt + * @param {HtmxSwapStyle} [swapInfoOverride] + * @returns {HtmxSwapSpecification} + */ + function getSwapSpecification(elt, swapInfoOverride) { + const swapInfo = swapInfoOverride || getClosestAttributeValue(elt, 'hx-swap') + /** @type HtmxSwapSpecification */ + const swapSpec = { + swapStyle: getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle, + swapDelay: htmx.config.defaultSwapDelay, + settleDelay: htmx.config.defaultSettleDelay + } + if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) { + swapSpec.show = 'top' + } + if (swapInfo) { + const split = splitOnWhitespace(swapInfo) + if (split.length > 0) { + for (let i = 0; i < split.length; i++) { + const value = split[i] + if (value.indexOf('swap:') === 0) { + swapSpec.swapDelay = parseInterval(value.substr(5)) + } else if (value.indexOf('settle:') === 0) { + swapSpec.settleDelay = parseInterval(value.substr(7)) + } else if (value.indexOf('transition:') === 0) { + swapSpec.transition = value.substr(11) === 'true' + } else if (value.indexOf('ignoreTitle:') === 0) { + swapSpec.ignoreTitle = value.substr(12) === 'true' + } else if (value.indexOf('scroll:') === 0) { + const scrollSpec = value.substr(7) + var splitSpec = scrollSpec.split(':') + const scrollVal = splitSpec.pop() + var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null + // @ts-ignore + swapSpec.scroll = scrollVal + swapSpec.scrollTarget = selectorVal + } else if (value.indexOf('show:') === 0) { + const showSpec = value.substr(5) + var splitSpec = showSpec.split(':') + const showVal = splitSpec.pop() + var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null + swapSpec.show = showVal + swapSpec.showTarget = selectorVal + } else if (value.indexOf('focus-scroll:') === 0) { + const focusScrollVal = value.substr('focus-scroll:'.length) + swapSpec.focusScroll = focusScrollVal == 'true' + } else if (i == 0) { + swapSpec.swapStyle = value + } else { + logError('Unknown modifier in hx-swap: ' + value) + } + } + } + } + return swapSpec + } + + /** + * @param {Element} elt + * @return {boolean} + */ + function usesFormData(elt) { + return getClosestAttributeValue(elt, 'hx-encoding') === 'multipart/form-data' || + (matches(elt, 'form') && getRawAttribute(elt, 'enctype') === 'multipart/form-data') + } + + /** + * @param {XMLHttpRequest} xhr + * @param {Element} elt + * @param {FormData} filteredParameters + * @returns {*|string|null} + */ + function encodeParamsForBody(xhr, elt, filteredParameters) { + let encodedParameters = null + withExtensions(elt, function(extension) { + if (encodedParameters == null) { + encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt) + } + }) + if (encodedParameters != null) { + return encodedParameters + } else { + if (usesFormData(elt)) { + // Force conversion to an actual FormData object in case filteredParameters is a formDataProxy + // See https://github.com/bigskysoftware/htmx/issues/2317 + return overrideFormData(new FormData(), formDataFromObject(filteredParameters)) + } else { + return urlEncode(filteredParameters) + } + } + } + + /** + * + * @param {Element} target + * @returns {HtmxSettleInfo} + */ + function makeSettleInfo(target) { + return { tasks: [], elts: [target] } + } + + /** + * @param {Element[]} content + * @param {HtmxSwapSpecification} swapSpec + */ + function updateScrollState(content, swapSpec) { + const first = content[0] + const last = content[content.length - 1] + if (swapSpec.scroll) { + var target = null + if (swapSpec.scrollTarget) { + target = asElement(querySelectorExt(first, swapSpec.scrollTarget)) + } + if (swapSpec.scroll === 'top' && (first || target)) { + target = target || first + target.scrollTop = 0 + } + if (swapSpec.scroll === 'bottom' && (last || target)) { + target = target || last + target.scrollTop = target.scrollHeight + } + } + if (swapSpec.show) { + var target = null + if (swapSpec.showTarget) { + let targetStr = swapSpec.showTarget + if (swapSpec.showTarget === 'window') { + targetStr = 'body' + } + target = asElement(querySelectorExt(first, targetStr)) + } + if (swapSpec.show === 'top' && (first || target)) { + target = target || first + // @ts-ignore For some reason tsc doesn't recognize "instant" as a valid option for now + target.scrollIntoView({ block: 'start', behavior: htmx.config.scrollBehavior }) + } + if (swapSpec.show === 'bottom' && (last || target)) { + target = target || last + // @ts-ignore For some reason tsc doesn't recognize "instant" as a valid option for now + target.scrollIntoView({ block: 'end', behavior: htmx.config.scrollBehavior }) + } + } + } + + /** + * @param {Element} elt + * @param {string} attr + * @param {boolean=} evalAsDefault + * @param {Object=} values + * @returns {Object} + */ + function getValuesForElement(elt, attr, evalAsDefault, values) { + if (values == null) { + values = {} + } + if (elt == null) { + return values + } + const attributeValue = getAttributeValue(elt, attr) + if (attributeValue) { + let str = attributeValue.trim() + let evaluateValue = evalAsDefault + if (str === 'unset') { + return null + } + if (str.indexOf('javascript:') === 0) { + str = str.substr(11) + evaluateValue = true + } else if (str.indexOf('js:') === 0) { + str = str.substr(3) + evaluateValue = true + } + if (str.indexOf('{') !== 0) { + str = '{' + str + '}' + } + let varsValues + if (evaluateValue) { + varsValues = maybeEval(elt, function() { return Function('return (' + str + ')')() }, {}) + } else { + varsValues = parseJSON(str) + } + for (const key in varsValues) { + if (varsValues.hasOwnProperty(key)) { + if (values[key] == null) { + values[key] = varsValues[key] + } + } + } + } + return getValuesForElement(asElement(parentElt(elt)), attr, evalAsDefault, values) + } + + /** + * @param {EventTarget|string} elt + * @param {() => any} toEval + * @param {any=} defaultVal + * @returns {any} + */ + function maybeEval(elt, toEval, defaultVal) { + if (htmx.config.allowEval) { + return toEval() + } else { + triggerErrorEvent(elt, 'htmx:evalDisallowedError') + return defaultVal + } + } + + /** + * @param {Element} elt + * @param {*?} expressionVars + * @returns + */ + function getHXVarsForElement(elt, expressionVars) { + return getValuesForElement(elt, 'hx-vars', true, expressionVars) + } + + /** + * @param {Element} elt + * @param {*?} expressionVars + * @returns + */ + function getHXValsForElement(elt, expressionVars) { + return getValuesForElement(elt, 'hx-vals', false, expressionVars) + } + + /** + * @param {Element} elt + * @returns {FormData} + */ + function getExpressionVars(elt) { + return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt)) + } + + /** + * @param {XMLHttpRequest} xhr + * @param {string} header + * @param {string|null} headerValue + */ + function safelySetHeaderValue(xhr, header, headerValue) { + if (headerValue !== null) { + try { + xhr.setRequestHeader(header, headerValue) + } catch (e) { + // On an exception, try to set the header URI encoded instead + xhr.setRequestHeader(header, encodeURIComponent(headerValue)) + xhr.setRequestHeader(header + '-URI-AutoEncoded', 'true') + } + } + } + + /** + * @param {XMLHttpRequest} xhr + * @return {string} + */ + function getPathFromResponse(xhr) { + // NB: IE11 does not support this stuff + if (xhr.responseURL && typeof (URL) !== 'undefined') { + try { + const url = new URL(xhr.responseURL) + return url.pathname + url.search + } catch (e) { + triggerErrorEvent(getDocument().body, 'htmx:badResponseUrl', { url: xhr.responseURL }) + } + } + } + + /** + * @param {XMLHttpRequest} xhr + * @param {RegExp} regexp + * @return {boolean} + */ + function hasHeader(xhr, regexp) { + return regexp.test(xhr.getAllResponseHeaders()) + } + + /** + * Issues an htmx-style AJAX request + * + * @see https://htmx.org/api/#ajax + * + * @param {HttpVerb} verb + * @param {string} path the URL path to make the AJAX + * @param {Element|string|HtmxAjaxHelperContext} context the element to target (defaults to the **body**) | a selector for the target | a context object that contains any of the following + * @return {Promise<void>} Promise that resolves immediately if no request is sent, or when the request is complete + */ + function ajaxHelper(verb, path, context) { + verb = (/** @type HttpVerb */(verb.toLowerCase())) + if (context) { + if (context instanceof Element || typeof context === 'string') { + return issueAjaxRequest(verb, path, null, null, { + targetOverride: resolveTarget(context), + returnPromise: true + }) + } else { + return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event, + { + handler: context.handler, + headers: context.headers, + values: context.values, + targetOverride: resolveTarget(context.target), + swapOverride: context.swap, + select: context.select, + returnPromise: true + }) + } + } else { + return issueAjaxRequest(verb, path, null, null, { + returnPromise: true + }) + } + } + + /** + * @param {Element} elt + * @return {Element[]} + */ + function hierarchyForElt(elt) { + const arr = [] + while (elt) { + arr.push(elt) + elt = elt.parentElement + } + return arr + } + + /** + * @param {Element} elt + * @param {string} path + * @param {HtmxRequestConfig} requestConfig + * @return {boolean} + */ + function verifyPath(elt, path, requestConfig) { + let sameHost + let url + if (typeof URL === 'function') { + url = new URL(path, document.location.href) + const origin = document.location.origin + sameHost = origin === url.origin + } else { + // IE11 doesn't support URL + url = path + sameHost = startsWith(path, document.location.origin) + } - //=========================================== - // Next resolve via DOM values - //=========================================== - var requestPath = responseInfo.pathInfo.finalRequestPath; - var responsePath = responseInfo.pathInfo.responsePath; - - var pushUrl = getClosestAttributeValue(elt, "hx-push-url"); - var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url"); - var elementIsBoosted = getInternalData(elt).boosted; - - var saveType = null; - var path = null; - - if (pushUrl) { - saveType = "push"; - path = pushUrl; - } else if (replaceUrl) { - saveType = "replace"; - path = replaceUrl; - } else if (elementIsBoosted) { - saveType = "push"; - path = responsePath || requestPath; // if there is no response path, go with the original request path - } + if (htmx.config.selfRequestsOnly) { + if (!sameHost) { + return false + } + } + return triggerEvent(elt, 'htmx:validateUrl', mergeObjects({ url, sameHost }, requestConfig)) + } + + /** + * @param {Object|FormData} obj + * @return {FormData} + */ + function formDataFromObject(obj) { + if (obj instanceof FormData) return obj + const formData = new FormData() + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + if (typeof obj[key].forEach === 'function') { + obj[key].forEach(function(v) { formData.append(key, v) }) + } else if (typeof obj[key] === 'object') { + formData.append(key, JSON.stringify(obj[key])) + } else { + formData.append(key, obj[key]) + } + } + } + return formData + } + + /** + * @param {FormData} formData + * @param {string} name + * @param {Array} array + * @returns {Array} + */ + function formDataArrayProxy(formData, name, array) { + // mutating the array should mutate the underlying form data + return new Proxy(array, { + get: function(target, key) { + if (typeof key === 'number') return target[key] + if (key === 'length') return target.length + if (key === 'push') { + return function(value) { + target.push(value) + formData.append(name, value) + } + } + if (typeof target[key] === 'function') { + return function() { + target[key].apply(target, arguments) + formData.delete(name) + target.forEach(function(v) { formData.append(name, v) }) + } + } + + if (target[key] && target[key].length === 1) { + return target[key][0] + } else { + return target[key] + } + }, + set: function(target, index, value) { + target[index] = value + formData.delete(name) + target.forEach(function(v) { formData.append(name, v) }) + return true + } + }) + } + + /** + * @param {FormData} formData + * @returns {Object} + */ + function formDataProxy(formData) { + return new Proxy(formData, { + get: function(target, name) { + if (typeof name === 'symbol') { + // Forward symbol calls to the FormData itself directly + return Reflect.get(target, name) + } + if (name === 'toJSON') { + // Support JSON.stringify call on proxy + return () => Object.fromEntries(formData) + } + if (name in target) { + // Wrap in function with apply to correctly bind the FormData context, as a direct call would result in an illegal invocation error + if (typeof target[name] === 'function') { + return function() { + return formData[name].apply(formData, arguments) + } + } else { + return target[name] + } + } + const array = formData.getAll(name) + // Those 2 undefined & single value returns are for retro-compatibility as we weren't using FormData before + if (array.length === 0) { + return undefined + } else if (array.length === 1) { + return array[0] + } else { + return formDataArrayProxy(target, name, array) + } + }, + set: function(target, name, value) { + if (typeof name !== 'string') { + return false + } + target.delete(name) + if (typeof value.forEach === 'function') { + value.forEach(function(v) { target.append(name, v) }) + } else { + target.append(name, value) + } + return true + }, + deleteProperty: function(target, name) { + if (typeof name === 'string') { + target.delete(name) + } + return true + }, + // Support Object.assign call from proxy + ownKeys: function(target) { + return Reflect.ownKeys(Object.fromEntries(target)) + }, + getOwnPropertyDescriptor: function(target, prop) { + return Reflect.getOwnPropertyDescriptor(Object.fromEntries(target), prop) + } + }) + } + + /** + * @param {HttpVerb} verb + * @param {string} path + * @param {Element} elt + * @param {Event} event + * @param {HtmxAjaxEtc} [etc] + * @param {boolean} [confirmed] + * @return {Promise<void>} + */ + function issueAjaxRequest(verb, path, elt, event, etc, confirmed) { + let resolve = null + let reject = null + etc = etc != null ? etc : {} + if (etc.returnPromise && typeof Promise !== 'undefined') { + var promise = new Promise(function(_resolve, _reject) { + resolve = _resolve + reject = _reject + }) + } + if (elt == null) { + elt = getDocument().body + } + const responseHandler = etc.handler || handleAjaxResponse + const select = etc.select || null - if (path) { - // false indicates no push, return empty object - if (path === "false") { - return {}; - } + if (!bodyContains(elt)) { + // do not issue requests for elements removed from the DOM + maybeCall(resolve) + return promise + } + const target = etc.targetOverride || asElement(getTarget(elt)) + if (target == null || target == DUMMY_ELT) { + triggerErrorEvent(elt, 'htmx:targetError', { target: getAttributeValue(elt, 'hx-target') }) + maybeCall(reject) + return promise + } - // true indicates we want to follow wherever the server ended up sending us - if (path === "true") { - path = responsePath || requestPath; // if there is no response path, go with the original request path - } + let eltData = getInternalData(elt) + const submitter = eltData.lastButtonClicked - // restore any anchor associated with the request - if (responseInfo.pathInfo.anchor && - path.indexOf("#") === -1) { - path = path + "#" + responseInfo.pathInfo.anchor; - } + if (submitter) { + const buttonPath = getRawAttribute(submitter, 'formaction') + if (buttonPath != null) { + path = buttonPath + } - return { - type:saveType, - path: path - } - } else { - return {}; - } + const buttonVerb = getRawAttribute(submitter, 'formmethod') + if (buttonVerb != null) { + // ignore buttons with formmethod="dialog" + if (buttonVerb.toLowerCase() !== 'dialog') { + verb = (/** @type HttpVerb */(buttonVerb)) } + } + } - function handleAjaxResponse(elt, responseInfo) { - var xhr = responseInfo.xhr; - var target = responseInfo.target; - var etc = responseInfo.etc; - var requestConfig = responseInfo.requestConfig; - var select = responseInfo.select; + const confirmQuestion = getClosestAttributeValue(elt, 'hx-confirm') + // allow event-based confirmation w/ a callback + if (confirmed === undefined) { + const issueRequest = function(skipConfirmation) { + return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation) + } + const confirmDetails = { target, elt, path, verb, triggeringEvent: event, etc, issueRequest, question: confirmQuestion } + if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) { + maybeCall(resolve) + return promise + } + } - if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return; + let syncElt = elt + let syncStrategy = getClosestAttributeValue(elt, 'hx-sync') + let queueStrategy = null + let abortable = false + if (syncStrategy) { + const syncStrings = syncStrategy.split(':') + const selector = syncStrings[0].trim() + if (selector === 'this') { + syncElt = findThisElement(elt, 'hx-sync') + } else { + syncElt = asElement(querySelectorExt(elt, selector)) + } + // default to the drop strategy + syncStrategy = (syncStrings[1] || 'drop').trim() + eltData = getInternalData(syncElt) + if (syncStrategy === 'drop' && eltData.xhr && eltData.abortable !== true) { + maybeCall(resolve) + return promise + } else if (syncStrategy === 'abort') { + if (eltData.xhr) { + maybeCall(resolve) + return promise + } else { + abortable = true + } + } else if (syncStrategy === 'replace') { + triggerEvent(syncElt, 'htmx:abort') // abort the current request and continue + } else if (syncStrategy.indexOf('queue') === 0) { + const queueStrArray = syncStrategy.split(' ') + queueStrategy = (queueStrArray[1] || 'last').trim() + } + } - if (hasHeader(xhr, /HX-Trigger:/i)) { - handleTrigger(xhr, "HX-Trigger", elt); - } + if (eltData.xhr) { + if (eltData.abortable) { + triggerEvent(syncElt, 'htmx:abort') // abort the current request and continue + } else { + if (queueStrategy == null) { + if (event) { + const eventData = getInternalData(event) + if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) { + queueStrategy = eventData.triggerSpec.queue + } + } + if (queueStrategy == null) { + queueStrategy = 'last' + } + } + if (eltData.queuedRequests == null) { + eltData.queuedRequests = [] + } + if (queueStrategy === 'first' && eltData.queuedRequests.length === 0) { + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } else if (queueStrategy === 'all') { + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } else if (queueStrategy === 'last') { + eltData.queuedRequests = [] // dump existing queue + eltData.queuedRequests.push(function() { + issueAjaxRequest(verb, path, elt, event, etc) + }) + } + maybeCall(resolve) + return promise + } + } - if (hasHeader(xhr, /HX-Location:/i)) { - saveCurrentPageToHistory(); - var redirectPath = xhr.getResponseHeader("HX-Location"); - var swapSpec; - if (redirectPath.indexOf("{") === 0) { - swapSpec = parseJSON(redirectPath); - // what's the best way to throw an error if the user didn't include this - redirectPath = swapSpec['path']; - delete swapSpec['path']; - } - ajaxHelper('GET', redirectPath, swapSpec).then(function(){ - pushUrlIntoHistory(redirectPath); - }); - return; - } + const xhr = new XMLHttpRequest() + eltData.xhr = xhr + eltData.abortable = abortable + const endRequestLock = function() { + eltData.xhr = null + eltData.abortable = false + if (eltData.queuedRequests != null && + eltData.queuedRequests.length > 0) { + const queuedRequest = eltData.queuedRequests.shift() + queuedRequest() + } + } + const promptQuestion = getClosestAttributeValue(elt, 'hx-prompt') + if (promptQuestion) { + var promptResponse = prompt(promptQuestion) + // prompt returns null if cancelled and empty string if accepted with no entry + if (promptResponse === null || + !triggerEvent(elt, 'htmx:prompt', { prompt: promptResponse, target })) { + maybeCall(resolve) + endRequestLock() + return promise + } + } - var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh"); + if (confirmQuestion && !confirmed) { + if (!confirm(confirmQuestion)) { + maybeCall(resolve) + endRequestLock() + return promise + } + } - if (hasHeader(xhr, /HX-Redirect:/i)) { - location.href = xhr.getResponseHeader("HX-Redirect"); - shouldRefresh && location.reload(); - return; - } + let headers = getHeaders(elt, target, promptResponse) - if (shouldRefresh) { - location.reload(); - return; - } + if (verb !== 'get' && !usesFormData(elt)) { + headers['Content-Type'] = 'application/x-www-form-urlencoded' + } - if (hasHeader(xhr,/HX-Retarget:/i)) { - if (xhr.getResponseHeader("HX-Retarget") === "this") { - responseInfo.target = elt; - } else { - responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget")); - } - } + if (etc.headers) { + headers = mergeObjects(headers, etc.headers) + } + const results = getInputValues(elt, verb) + let errors = results.errors + const rawFormData = results.formData + if (etc.values) { + overrideFormData(rawFormData, formDataFromObject(etc.values)) + } + const expressionVars = formDataFromObject(getExpressionVars(elt)) + const allFormData = overrideFormData(rawFormData, expressionVars) + let filteredFormData = filterValues(allFormData, elt) - var historyUpdate = determineHistoryUpdates(elt, responseInfo); - - // by default htmx only swaps on 200 return codes and does not swap - // on 204 'No Content' - // this can be ovverriden by responding to the htmx:beforeSwap event and - // overriding the detail.shouldSwap property - var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204; - var serverResponse = xhr.response; - var isError = xhr.status >= 400; - var ignoreTitle = htmx.config.ignoreTitle - var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo); - if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return; - - target = beforeSwapDetails.target; // allow re-targeting - serverResponse = beforeSwapDetails.serverResponse; // allow updating content - isError = beforeSwapDetails.isError; // allow updating error - ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title - - responseInfo.target = target; // Make updated target available to response events - responseInfo.failed = isError; // Make failed property available to response events - responseInfo.successful = !isError; // Make successful property available to response events - - if (beforeSwapDetails.shouldSwap) { - if (xhr.status === 286) { - cancelPolling(elt); - } + if (htmx.config.getCacheBusterParam && verb === 'get') { + filteredFormData.set('org.htmx.cache-buster', getRawAttribute(target, 'id') || 'true') + } - withExtensions(elt, function (extension) { - serverResponse = extension.transformResponse(serverResponse, xhr, elt); - }); + // behavior of anchors w/ empty href is to use the current URL + if (path == null || path === '') { + path = getDocument().location.href + } - // Save current page if there will be a history update - if (historyUpdate.type) { - saveCurrentPageToHistory(); - } + /** + * @type {Object} + * @property {boolean} [credentials] + * @property {number} [timeout] + * @property {boolean} [noHeaders] + */ + const requestAttrValues = getValuesForElement(elt, 'hx-request') + + const eltIsBoosted = getInternalData(elt).boosted + + let useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + + /** @type HtmxRequestConfig */ + const requestConfig = { + boosted: eltIsBoosted, + useUrlParams, + formData: filteredFormData, + parameters: formDataProxy(filteredFormData), + unfilteredFormData: allFormData, + unfilteredParameters: formDataProxy(allFormData), + headers, + target, + verb, + errors, + withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials, + timeout: etc.timeout || requestAttrValues.timeout || htmx.config.timeout, + path, + triggeringEvent: event + } - var swapOverride = etc.swapOverride; - if (hasHeader(xhr,/HX-Reswap:/i)) { - swapOverride = xhr.getResponseHeader("HX-Reswap"); - } - var swapSpec = getSwapSpecification(elt, swapOverride); + if (!triggerEvent(elt, 'htmx:configRequest', requestConfig)) { + maybeCall(resolve) + endRequestLock() + return promise + } - if (swapSpec.hasOwnProperty('ignoreTitle')) { - ignoreTitle = swapSpec.ignoreTitle; - } + // copy out in case the object was overwritten + path = requestConfig.path + verb = requestConfig.verb + headers = requestConfig.headers + filteredFormData = formDataFromObject(requestConfig.parameters) + errors = requestConfig.errors + useUrlParams = requestConfig.useUrlParams + + if (errors && errors.length > 0) { + triggerEvent(elt, 'htmx:validation:halted', requestConfig) + maybeCall(resolve) + endRequestLock() + return promise + } - target.classList.add(htmx.config.swappingClass); - - // optional transition API promise callbacks - var settleResolve = null; - var settleReject = null; - - var doSwap = function () { - try { - var activeElt = document.activeElement; - var selectionInfo = {}; - try { - selectionInfo = { - elt: activeElt, - // @ts-ignore - start: activeElt ? activeElt.selectionStart : null, - // @ts-ignore - end: activeElt ? activeElt.selectionEnd : null - }; - } catch (e) { - // safari issue - see https://github.com/microsoft/playwright/issues/5894 - } - - var selectOverride; - if (select) { - selectOverride = select; - } - - if (hasHeader(xhr, /HX-Reselect:/i)) { - selectOverride = xhr.getResponseHeader("HX-Reselect"); - } - - // if we need to save history, do so, before swapping so that relative resources have the correct base URL - if (historyUpdate.type) { - triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)); - if (historyUpdate.type === "push") { - pushUrlIntoHistory(historyUpdate.path); - triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path}); - } else { - replaceUrlInHistory(historyUpdate.path); - triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path}); - } - } - - var settleInfo = makeSettleInfo(target); - selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride); - - if (selectionInfo.elt && - !bodyContains(selectionInfo.elt) && - getRawAttribute(selectionInfo.elt, "id")) { - var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id")); - var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }; - if (newActiveElt) { - // @ts-ignore - if (selectionInfo.start && newActiveElt.setSelectionRange) { - // @ts-ignore - try { - newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end); - } catch (e) { - // the setSelectionRange method is present on fields that don't support it, so just let this fail - } - } - newActiveElt.focus(focusOptions); - } - } - - target.classList.remove(htmx.config.swappingClass); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.add(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSwap', responseInfo); - }); - - if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt); - } - - var doSettle = function () { - forEach(settleInfo.tasks, function (task) { - task.call(); - }); - forEach(settleInfo.elts, function (elt) { - if (elt.classList) { - elt.classList.remove(htmx.config.settlingClass); - } - triggerEvent(elt, 'htmx:afterSettle', responseInfo); - }); - - if (responseInfo.pathInfo.anchor) { - var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor); - if(anchorTarget) { - anchorTarget.scrollIntoView({block:'start', behavior: "auto"}); - } - } - - if(settleInfo.title && !ignoreTitle) { - var titleElt = find("title"); - if(titleElt) { - titleElt.innerHTML = settleInfo.title; - } else { - window.document.title = settleInfo.title; - } - } - - updateScrollState(settleInfo.elts, swapSpec); - - if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { - var finalElt = elt; - if (!bodyContains(elt)) { - finalElt = getDocument().body; - } - handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt); - } - maybeCall(settleResolve); - } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'htmx:swapError', responseInfo); - maybeCall(settleReject); - throw e; - } - }; - - var shouldTransition = htmx.config.globalViewTransitions - if(swapSpec.hasOwnProperty('transition')){ - shouldTransition = swapSpec.transition; - } + const splitPath = path.split('#') + const pathNoAnchor = splitPath[0] + const anchor = splitPath[1] + + let finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor + const hasValues = !filteredFormData.keys().next().done + if (hasValues) { + if (finalPath.indexOf('?') < 0) { + finalPath += '?' + } else { + finalPath += '&' + } + finalPath += urlEncode(filteredFormData) + if (anchor) { + finalPath += '#' + anchor + } + } + } - if(shouldTransition && - triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && - typeof Promise !== "undefined" && document.startViewTransition){ - var settlePromise = new Promise(function (_resolve, _reject) { - settleResolve = _resolve; - settleReject = _reject; - }); - // wrap the original doSwap() in a call to startViewTransition() - var innerDoSwap = doSwap; - doSwap = function() { - document.startViewTransition(function () { - innerDoSwap(); - return settlePromise; - }); - } - } + if (!verifyPath(elt, finalPath, requestConfig)) { + triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig) + maybeCall(reject) + return promise + } + xhr.open(verb.toUpperCase(), finalPath, true) + xhr.overrideMimeType('text/html') + xhr.withCredentials = requestConfig.withCredentials + xhr.timeout = requestConfig.timeout - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); - } - } - if (isError) { - triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo)); - } + // request headers + if (requestAttrValues.noHeaders) { + // ignore all headers + } else { + for (const header in headers) { + if (headers.hasOwnProperty(header)) { + const headerValue = headers[header] + safelySetHeaderValue(xhr, header, headerValue) } + } + } - //==================================================================== - // Extensions API - //==================================================================== - - /** @type {Object<string, import("./htmx").HtmxExtension>} */ - var extensions = {}; - - /** - * extensionBase defines the default functions for all extensions. - * @returns {import("./htmx").HtmxExtension} - */ - function extensionBase() { - return { - init: function(api) {return null;}, - onEvent : function(name, evt) {return true;}, - transformResponse : function(text, xhr, elt) {return text;}, - isInlineSwap : function(swapStyle) {return false;}, - handleSwap : function(swapStyle, target, fragment, settleInfo) {return false;}, - encodeParameters : function(xhr, parameters, elt) {return null;} - } - } + /** @type {HtmxResponseInfo} */ + const responseInfo = { + xhr, + target, + requestConfig, + etc, + boosted: eltIsBoosted, + select, + pathInfo: { + requestPath: path, + finalRequestPath: finalPath, + responsePath: null, + anchor + } + } - /** - * defineExtension initializes the extension and adds it to the htmx registry - * - * @param {string} name - * @param {import("./htmx").HtmxExtension} extension - */ - function defineExtension(name, extension) { - if(extension.init) { - extension.init(internalAPI) - } - extensions[name] = mergeObjects(extensionBase(), extension); - } + xhr.onload = function() { + try { + const hierarchy = hierarchyForElt(elt) + responseInfo.pathInfo.responsePath = getPathFromResponse(xhr) + responseHandler(elt, responseInfo) + removeRequestIndicators(indicators, disableElts) + triggerEvent(elt, 'htmx:afterRequest', responseInfo) + triggerEvent(elt, 'htmx:afterOnLoad', responseInfo) + // if the body no longer contains the element, trigger the event on the closest parent + // remaining in the DOM + if (!bodyContains(elt)) { + let secondaryTriggerElt = null + while (hierarchy.length > 0 && secondaryTriggerElt == null) { + const parentEltInHierarchy = hierarchy.shift() + if (bodyContains(parentEltInHierarchy)) { + secondaryTriggerElt = parentEltInHierarchy + } + } + if (secondaryTriggerElt) { + triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo) + triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo) + } + } + maybeCall(resolve) + endRequestLock() + } catch (e) { + triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({ error: e }, responseInfo)) + throw e + } + } + xhr.onerror = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:sendError', responseInfo) + maybeCall(reject) + endRequestLock() + } + xhr.onabort = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo) + maybeCall(reject) + endRequestLock() + } + xhr.ontimeout = function() { + removeRequestIndicators(indicators, disableElts) + triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo) + triggerErrorEvent(elt, 'htmx:timeout', responseInfo) + maybeCall(reject) + endRequestLock() + } + if (!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)) { + maybeCall(resolve) + endRequestLock() + return promise + } + var indicators = addRequestIndicatorClasses(elt) + var disableElts = disableElements(elt) + + forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) { + forEach([xhr, xhr.upload], function(target) { + target.addEventListener(eventName, function(event) { + triggerEvent(elt, 'htmx:xhr:' + eventName, { + lengthComputable: event.lengthComputable, + loaded: event.loaded, + total: event.total + }) + }) + }) + }) + triggerEvent(elt, 'htmx:beforeSend', responseInfo) + const params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredFormData) + xhr.send(params) + return promise + } + + /** + * @typedef {Object} HtmxHistoryUpdate + * @property {string|null} [type] + * @property {string|null} [path] + */ + + /** + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + * @return {HtmxHistoryUpdate} + */ + function determineHistoryUpdates(elt, responseInfo) { + const xhr = responseInfo.xhr + + //= ========================================== + // First consult response headers + //= ========================================== + let pathFromHeaders = null + let typeFromHeaders = null + if (hasHeader(xhr, /HX-Push:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Push') + typeFromHeaders = 'push' + } else if (hasHeader(xhr, /HX-Push-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Push-Url') + typeFromHeaders = 'push' + } else if (hasHeader(xhr, /HX-Replace-Url:/i)) { + pathFromHeaders = xhr.getResponseHeader('HX-Replace-Url') + typeFromHeaders = 'replace' + } - /** - * removeExtension removes an extension from the htmx registry - * - * @param {string} name - */ - function removeExtension(name) { - delete extensions[name]; + // if there was a response header, that has priority + if (pathFromHeaders) { + if (pathFromHeaders === 'false') { + return {} + } else { + return { + type: typeFromHeaders, + path: pathFromHeaders } + } + } - /** - * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element - * - * @param {HTMLElement} elt - * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn - * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore - */ - function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + //= ========================================== + // Next resolve via DOM values + //= ========================================== + const requestPath = responseInfo.pathInfo.finalRequestPath + const responsePath = responseInfo.pathInfo.responsePath + + const pushUrl = getClosestAttributeValue(elt, 'hx-push-url') + const replaceUrl = getClosestAttributeValue(elt, 'hx-replace-url') + const elementIsBoosted = getInternalData(elt).boosted + + let saveType = null + let path = null + + if (pushUrl) { + saveType = 'push' + path = pushUrl + } else if (replaceUrl) { + saveType = 'replace' + path = replaceUrl + } else if (elementIsBoosted) { + saveType = 'push' + path = responsePath || requestPath // if there is no response path, go with the original request path + } - if (elt == undefined) { - return extensionsToReturn; - } - if (extensionsToReturn == undefined) { - extensionsToReturn = []; - } - if (extensionsToIgnore == undefined) { - extensionsToIgnore = []; - } - var extensionsForElement = getAttributeValue(elt, "hx-ext"); - if (extensionsForElement) { - forEach(extensionsForElement.split(","), function(extensionName){ - extensionName = extensionName.replace(/ /g, ''); - if (extensionName.slice(0, 7) == "ignore:") { - extensionsToIgnore.push(extensionName.slice(7)); - return; - } - if (extensionsToIgnore.indexOf(extensionName) < 0) { - var extension = extensions[extensionName]; - if (extension && extensionsToReturn.indexOf(extension) < 0) { - extensionsToReturn.push(extension); - } - } - }); - } - return getExtensions(parentElt(elt), extensionsToReturn, extensionsToIgnore); - } + if (path) { + // false indicates no push, return empty object + if (path === 'false') { + return {} + } + + // true indicates we want to follow wherever the server ended up sending us + if (path === 'true') { + path = responsePath || requestPath // if there is no response path, go with the original request path + } + + // restore any anchor associated with the request + if (responseInfo.pathInfo.anchor && path.indexOf('#') === -1) { + path = path + '#' + responseInfo.pathInfo.anchor + } + + return { + type: saveType, + path + } + } else { + return {} + } + } + + /** + * @param {HtmxResponseHandlingConfig} responseHandlingConfig + * @param {number} status + * @return {boolean} + */ + function codeMatches(responseHandlingConfig, status) { + var regExp = new RegExp(responseHandlingConfig.code) + return regExp.test(status.toString(10)) + } + + /** + * @param {XMLHttpRequest} xhr + * @return {HtmxResponseHandlingConfig} + */ + function resolveResponseHandling(xhr) { + for (var i = 0; i < htmx.config.responseHandling.length; i++) { + /** @type HtmxResponseHandlingConfig */ + var responseHandlingElement = htmx.config.responseHandling[i] + if (codeMatches(responseHandlingElement, xhr.status)) { + return responseHandlingElement + } + } + // no matches, return no swap + return { + swap: false + } + } + + /** + * @param {string} title + */ + function handleTitle(title) { + if (title) { + const titleElt = find('title') + if (titleElt) { + titleElt.innerHTML = title + } else { + window.document.title = title + } + } + } + + /** + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + */ + function handleAjaxResponse(elt, responseInfo) { + const xhr = responseInfo.xhr + let target = responseInfo.target + const etc = responseInfo.etc + const responseInfoSelect = responseInfo.select + + if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return + + if (hasHeader(xhr, /HX-Trigger:/i)) { + handleTriggerHeader(xhr, 'HX-Trigger', elt) + } - //==================================================================== - // Initialization - //==================================================================== - var isReady = false - getDocument().addEventListener('DOMContentLoaded', function() { - isReady = true - }) + if (hasHeader(xhr, /HX-Location:/i)) { + saveCurrentPageToHistory() + let redirectPath = xhr.getResponseHeader('HX-Location') + /** @type {HtmxAjaxHelperContext&{path:string}} */ + var redirectSwapSpec + if (redirectPath.indexOf('{') === 0) { + redirectSwapSpec = parseJSON(redirectPath) + // what's the best way to throw an error if the user didn't include this + redirectPath = redirectSwapSpec.path + delete redirectSwapSpec.path + } + ajaxHelper('get', redirectPath, redirectSwapSpec).then(function() { + pushUrlIntoHistory(redirectPath) + }) + return + } - /** - * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. - * - * This function uses isReady because there is no realiable way to ask the browswer whether - * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded - * firing and readystate=complete. - */ - function ready(fn) { - // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by - // some means other than the initial page load. - if (isReady || getDocument().readyState === 'complete') { - fn(); - } else { - getDocument().addEventListener('DOMContentLoaded', fn); - } - } + const shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && xhr.getResponseHeader('HX-Refresh') === 'true' - function insertIndicatorStyles() { - if (htmx.config.includeIndicatorStyles !== false) { - getDocument().head.insertAdjacentHTML("beforeend", - "<style>\ - ." + htmx.config.indicatorClass + "{opacity:0}\ - ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ - ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\ - </style>"); - } - } + if (hasHeader(xhr, /HX-Redirect:/i)) { + location.href = xhr.getResponseHeader('HX-Redirect') + shouldRefresh && location.reload() + return + } - function getMetaConfig() { - var element = getDocument().querySelector('meta[name="htmx-config"]'); - if (element) { - // @ts-ignore - return parseJSON(element.content); - } else { - return null; - } - } + if (shouldRefresh) { + location.reload() + return + } - function mergeMetaConfig() { - var metaConfig = getMetaConfig(); - if (metaConfig) { - htmx.config = mergeObjects(htmx.config , metaConfig) - } - } + if (hasHeader(xhr, /HX-Retarget:/i)) { + if (xhr.getResponseHeader('HX-Retarget') === 'this') { + responseInfo.target = elt + } else { + responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget'))) + } + } - // initialize the document - ready(function () { - mergeMetaConfig(); - insertIndicatorStyles(); - var body = getDocument().body; - processNode(body); - var restoredElts = getDocument().querySelectorAll( - "[hx-trigger='restored'],[data-hx-trigger='restored']" - ); - body.addEventListener("htmx:abort", function (evt) { - var target = evt.target; - var internalData = getInternalData(target); - if (internalData && internalData.xhr) { - internalData.xhr.abort(); - } - }); - /** @type {(ev: PopStateEvent) => any} */ - const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null; - /** @type {(ev: PopStateEvent) => any} */ - window.onpopstate = function (event) { - if (event.state && event.state.htmx) { - restoreHistory(); - forEach(restoredElts, function(elt){ - triggerEvent(elt, 'htmx:restored', { - 'document': getDocument(), - 'triggerEvent': triggerEvent - }); - }); - } else { - if (originalPopstate) { - originalPopstate(event); - } - } - }; - setTimeout(function () { - triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event - body = null; // kill reference for gc - }, 0); + const historyUpdate = determineHistoryUpdates(elt, responseInfo) + + const responseHandling = resolveResponseHandling(xhr) + const shouldSwap = responseHandling.swap + let isError = !!responseHandling.error + let ignoreTitle = htmx.config.ignoreTitle || responseHandling.ignoreTitle + let selectOverride = responseHandling.select + if (responseHandling.target) { + responseInfo.target = asElement(querySelectorExt(elt, responseHandling.target)) + } + var swapOverride = etc.swapOverride + if (swapOverride == null && responseHandling.swapOverride) { + swapOverride = responseHandling.swapOverride + } + + // response headers override response handling config + if (hasHeader(xhr, /HX-Retarget:/i)) { + if (xhr.getResponseHeader('HX-Retarget') === 'this') { + responseInfo.target = elt + } else { + responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget'))) + } + } + if (hasHeader(xhr, /HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader('HX-Reswap') + } + + var serverResponse = xhr.response + /** @type HtmxBeforeSwapDetails */ + var beforeSwapDetails = mergeObjects({ + shouldSwap, + serverResponse, + isError, + ignoreTitle, + selectOverride + }, responseInfo) + + if (responseHandling.event && !triggerEvent(target, responseHandling.event, beforeSwapDetails)) return + + if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return + + target = beforeSwapDetails.target // allow re-targeting + serverResponse = beforeSwapDetails.serverResponse // allow updating content + isError = beforeSwapDetails.isError // allow updating error + ignoreTitle = beforeSwapDetails.ignoreTitle // allow updating ignoring title + selectOverride = beforeSwapDetails.selectOverride // allow updating select override + + responseInfo.target = target // Make updated target available to response events + responseInfo.failed = isError // Make failed property available to response events + responseInfo.successful = !isError // Make successful property available to response events + + if (beforeSwapDetails.shouldSwap) { + if (xhr.status === 286) { + cancelPolling(elt) + } + + withExtensions(elt, function(extension) { + serverResponse = extension.transformResponse(serverResponse, xhr, elt) + }) + + // Save current page if there will be a history update + if (historyUpdate.type) { + saveCurrentPageToHistory() + } + + if (hasHeader(xhr, /HX-Reswap:/i)) { + swapOverride = xhr.getResponseHeader('HX-Reswap') + } + var swapSpec = getSwapSpecification(elt, swapOverride) + + if (!swapSpec.hasOwnProperty('ignoreTitle')) { + swapSpec.ignoreTitle = ignoreTitle + } + + target.classList.add(htmx.config.swappingClass) + + // optional transition API promise callbacks + let settleResolve = null + let settleReject = null + + if (responseInfoSelect) { + selectOverride = responseInfoSelect + } + + if (hasHeader(xhr, /HX-Reselect:/i)) { + selectOverride = xhr.getResponseHeader('HX-Reselect') + } + + const selectOOB = getClosestAttributeValue(elt, 'hx-select-oob') + const select = getClosestAttributeValue(elt, 'hx-select') + + let doSwap = function() { + try { + // if we need to save history, do so, before swapping so that relative resources have the correct base URL + if (historyUpdate.type) { + triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo)) + if (historyUpdate.type === 'push') { + pushUrlIntoHistory(historyUpdate.path) + triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', { path: historyUpdate.path }) + } else { + replaceUrlInHistory(historyUpdate.path) + triggerEvent(getDocument().body, 'htmx:replacedInHistory', { path: historyUpdate.path }) + } + } + + swap(target, serverResponse, swapSpec, { + select: selectOverride || select, + selectOOB, + eventInfo: responseInfo, + anchor: responseInfo.pathInfo.anchor, + contextElement: elt, + afterSwapCallback: function() { + if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) { + let finalElt = elt + if (!bodyContains(elt)) { + finalElt = getDocument().body + } + handleTriggerHeader(xhr, 'HX-Trigger-After-Swap', finalElt) + } + }, + afterSettleCallback: function() { + if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) { + let finalElt = elt + if (!bodyContains(elt)) { + finalElt = getDocument().body + } + handleTriggerHeader(xhr, 'HX-Trigger-After-Settle', finalElt) + } + maybeCall(settleResolve) + } + }) + } catch (e) { + triggerErrorEvent(elt, 'htmx:swapError', responseInfo) + maybeCall(settleReject) + throw e + } + } + + let shouldTransition = htmx.config.globalViewTransitions + if (swapSpec.hasOwnProperty('transition')) { + shouldTransition = swapSpec.transition + } + + if (shouldTransition && + triggerEvent(elt, 'htmx:beforeTransition', responseInfo) && + typeof Promise !== 'undefined' && + // @ts-ignore experimental feature atm + document.startViewTransition) { + const settlePromise = new Promise(function(_resolve, _reject) { + settleResolve = _resolve + settleReject = _reject }) + // wrap the original doSwap() in a call to startViewTransition() + const innerDoSwap = doSwap + doSwap = function() { + // @ts-ignore experimental feature atm + document.startViewTransition(function() { + innerDoSwap() + return settlePromise + }) + } + } + + if (swapSpec.swapDelay > 0) { + getWindow().setTimeout(doSwap, swapSpec.swapDelay) + } else { + doSwap() + } + } + if (isError) { + triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({ error: 'Response Status Error Code ' + xhr.status + ' from ' + responseInfo.pathInfo.requestPath }, responseInfo)) + } + } + + //= =================================================================== + // Extensions API + //= =================================================================== + + /** @type {Object<string, HtmxExtension>} */ + const extensions = {} + + /** + * extensionBase defines the default functions for all extensions. + * @returns {HtmxExtension} + */ + function extensionBase() { + return { + init: function(api) { return null }, + getSelectors: function() { return null }, + onEvent: function(name, evt) { return true }, + transformResponse: function(text, xhr, elt) { return text }, + isInlineSwap: function(swapStyle) { return false }, + handleSwap: function(swapStyle, target, fragment, settleInfo) { return false }, + encodeParameters: function(xhr, parameters, elt) { return null } + } + } + + /** + * defineExtension initializes the extension and adds it to the htmx registry + * + * @see https://htmx.org/api/#defineExtension + * + * @param {string} name the extension name + * @param {HtmxExtension} extension the extension definition + */ + function defineExtension(name, extension) { + if (extension.init) { + extension.init(internalAPI) + } + extensions[name] = mergeObjects(extensionBase(), extension) + } + + /** + * removeExtension removes an extension from the htmx registry + * + * @see https://htmx.org/api/#removeExtension + * + * @param {string} name + */ + function removeExtension(name) { + delete extensions[name] + } + + /** + * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element + * + * @param {Element} elt + * @param {HtmxExtension[]=} extensionsToReturn + * @param {string[]=} extensionsToIgnore + * @returns {HtmxExtension[]} + */ + function getExtensions(elt, extensionsToReturn, extensionsToIgnore) { + if (extensionsToReturn == undefined) { + extensionsToReturn = [] + } + if (elt == undefined) { + return extensionsToReturn + } + if (extensionsToIgnore == undefined) { + extensionsToIgnore = [] + } + const extensionsForElement = getAttributeValue(elt, 'hx-ext') + if (extensionsForElement) { + forEach(extensionsForElement.split(','), function(extensionName) { + extensionName = extensionName.replace(/ /g, '') + if (extensionName.slice(0, 7) == 'ignore:') { + extensionsToIgnore.push(extensionName.slice(7)) + return + } + if (extensionsToIgnore.indexOf(extensionName) < 0) { + const extension = extensions[extensionName] + if (extension && extensionsToReturn.indexOf(extension) < 0) { + extensionsToReturn.push(extension) + } + } + }) + } + return getExtensions(asElement(parentElt(elt)), extensionsToReturn, extensionsToIgnore) + } + + //= =================================================================== + // Initialization + //= =================================================================== + var isReady = false + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true + }) + + /** + * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. + * + * This function uses isReady because there is no reliable way to ask the browser whether + * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded + * firing and readystate=complete. + */ + function ready(fn) { + // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by + // some means other than the initial page load. + if (isReady || getDocument().readyState === 'complete') { + fn() + } else { + getDocument().addEventListener('DOMContentLoaded', fn) + } + } + + function insertIndicatorStyles() { + if (htmx.config.includeIndicatorStyles !== false) { + const nonceAttribute = htmx.config.inlineStyleNonce ? ` nonce="${htmx.config.inlineStyleNonce}"` : '' + getDocument().head.insertAdjacentHTML('beforeend', + '<style' + nonceAttribute + '>\ + .' + htmx.config.indicatorClass + '{opacity:0}\ + .' + htmx.config.requestClass + ' .' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\ + .' + htmx.config.requestClass + '.' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\ + </style>') + } + } + + function getMetaConfig() { + /** @type HTMLMetaElement */ + const element = getDocument().querySelector('meta[name="htmx-config"]') + if (element) { + return parseJSON(element.content) + } else { + return null + } + } - return htmx; + function mergeMetaConfig() { + const metaConfig = getMetaConfig() + if (metaConfig) { + htmx.config = mergeObjects(htmx.config, metaConfig) + } + } + + // initialize the document + ready(function() { + mergeMetaConfig() + insertIndicatorStyles() + let body = getDocument().body + processNode(body) + const restoredElts = getDocument().querySelectorAll( + "[hx-trigger='restored'],[data-hx-trigger='restored']" + ) + body.addEventListener('htmx:abort', function(evt) { + const target = evt.target + const internalData = getInternalData(target) + if (internalData && internalData.xhr) { + internalData.xhr.abort() + } + }) + /** @type {(ev: PopStateEvent) => any} */ + const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null + /** @type {(ev: PopStateEvent) => any} */ + window.onpopstate = function(event) { + if (event.state && event.state.htmx) { + restoreHistory() + forEach(restoredElts, function(elt) { + triggerEvent(elt, 'htmx:restored', { + document: getDocument(), + triggerEvent + }) + }) + } else { + if (originalPopstate) { + originalPopstate(event) + } + } } -)() -})); + getWindow().setTimeout(function() { + triggerEvent(body, 'htmx:load', {}) // give ready handlers a chance to load up before firing this event + body = null // kill reference for gc + }, 0) + }) + + return htmx +})() + +/** @typedef {'get'|'head'|'post'|'put'|'delete'|'connect'|'options'|'trace'|'patch'} HttpVerb */ + +/** + * @typedef {Object} SwapOptions + * @property {string} [select] + * @property {string} [selectOOB] + * @property {*} [eventInfo] + * @property {string} [anchor] + * @property {Element} [contextElement] + * @property {swapCallback} [afterSwapCallback] + * @property {swapCallback} [afterSettleCallback] + */ + +/** + * @callback swapCallback + */ + +/** + * @typedef {'innerHTML' | 'outerHTML' | 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' | 'delete' | 'none' | string} HtmxSwapStyle + */ + +/** + * @typedef HtmxSwapSpecification + * @property {HtmxSwapStyle} swapStyle + * @property {number} swapDelay + * @property {number} settleDelay + * @property {boolean} [transition] + * @property {boolean} [ignoreTitle] + * @property {string} [head] + * @property {'top' | 'bottom'} [scroll] + * @property {string} [scrollTarget] + * @property {string} [show] + * @property {string} [showTarget] + * @property {boolean} [focusScroll] + */ + +/** + * @typedef {((this:Node, evt:Event) => boolean) & {source: string}} ConditionalFunction + */ + +/** + * @typedef {Object} HtmxTriggerSpecification + * @property {string} trigger + * @property {number} [pollInterval] + * @property {ConditionalFunction} [eventFilter] + * @property {boolean} [changed] + * @property {boolean} [once] + * @property {boolean} [consume] + * @property {number} [delay] + * @property {string} [from] + * @property {string} [target] + * @property {number} [throttle] + * @property {string} [queue] + * @property {string} [root] + * @property {string} [threshold] + */ + +/** + * @typedef {{elt: Element, message: string, validity: ValidityState}} HtmxElementValidationError + */ + +/** + * @typedef {Record<string, string>} HtmxHeaderSpecification + * @property {'true'} HX-Request + * @property {string|null} HX-Trigger + * @property {string|null} HX-Trigger-Name + * @property {string|null} HX-Target + * @property {string} HX-Current-URL + * @property {string} [HX-Prompt] + * @property {'true'} [HX-Boosted] + * @property {string} [Content-Type] + * @property {'true'} [HX-History-Restore-Request] + */ + +/** @typedef HtmxAjaxHelperContext + * @property {Element|string} [source] + * @property {Event} [event] + * @property {HtmxAjaxHandler} [handler] + * @property {Element|string} target + * @property {HtmxSwapStyle} [swap] + * @property {Object|FormData} [values] + * @property {Record<string,string>} [headers] + * @property {string} [select] + */ + +/** + * @typedef {Object} HtmxRequestConfig + * @property {boolean} boosted + * @property {boolean} useUrlParams + * @property {FormData} formData + * @property {Object} parameters formData proxy + * @property {FormData} unfilteredFormData + * @property {Object} unfilteredParameters unfilteredFormData proxy + * @property {HtmxHeaderSpecification} headers + * @property {Element} target + * @property {HttpVerb} verb + * @property {HtmxElementValidationError[]} errors + * @property {boolean} withCredentials + * @property {number} timeout + * @property {string} path + * @property {Event} triggeringEvent + */ + +/** + * @typedef {Object} HtmxResponseInfo + * @property {XMLHttpRequest} xhr + * @property {Element} target + * @property {HtmxRequestConfig} requestConfig + * @property {HtmxAjaxEtc} etc + * @property {boolean} boosted + * @property {string} select + * @property {{requestPath: string, finalRequestPath: string, responsePath: string|null, anchor: string}} pathInfo + * @property {boolean} [failed] + * @property {boolean} [successful] + */ + +/** + * @typedef {Object} HtmxAjaxEtc + * @property {boolean} [returnPromise] + * @property {HtmxAjaxHandler} [handler] + * @property {string} [select] + * @property {Element} [targetOverride] + * @property {HtmxSwapStyle} [swapOverride] + * @property {Record<string,string>} [headers] + * @property {Object|FormData} [values] + * @property {boolean} [credentials] + * @property {number} [timeout] + */ + +/** + * @typedef {Object} HtmxResponseHandlingConfig + * @property {string} [code] + * @property {boolean} swap + * @property {boolean} [error] + * @property {boolean} [ignoreTitle] + * @property {string} [select] + * @property {string} [target] + * @property {string} [swapOverride] + * @property {string} [event] + */ + +/** + * @typedef {HtmxResponseInfo & {shouldSwap: boolean, serverResponse: any, isError: boolean, ignoreTitle: boolean, selectOverride:string}} HtmxBeforeSwapDetails + */ + +/** + * @callback HtmxAjaxHandler + * @param {Element} elt + * @param {HtmxResponseInfo} responseInfo + */ + +/** + * @typedef {(() => void)} HtmxSettleTask + */ + +/** + * @typedef {Object} HtmxSettleInfo + * @property {HtmxSettleTask[]} tasks + * @property {Element[]} elts + * @property {string} [title] + */ + +/** + * @typedef {Object} HtmxExtension + * @see https://htmx.org/extensions/#defining + * @property {(api: any) => void} init + * @property {(name: string, event: Event|CustomEvent) => boolean} onEvent + * @property {(text: string, xhr: XMLHttpRequest, elt: Element) => string} transformResponse + * @property {(swapStyle: HtmxSwapStyle) => boolean} isInlineSwap + * @property {(swapStyle: HtmxSwapStyle, target: Element, fragment: Node, settleInfo: HtmxSettleInfo) => boolean} handleSwap + * @property {(xhr: XMLHttpRequest, parameters: FormData, elt: Element) => *|string|null} encodeParameters + */ diff --git a/code/starter_video_collector/static/js/htmx.min.js b/code/starter_video_collector/static/js/htmx.min.js index 53bbdf6..d66acce 100644 --- a/code/starter_video_collector/static/js/htmx.min.js +++ b/code/starter_video_collector/static/js/htmx.min.js @@ -1,4 +1,2 @@ -// /////////////////////////////////////////////////////////////////// -// HTMX v1.9.10 from https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js -// -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(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 a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/<body/.test(e)}function l(e){var t=!N(e);var r=A(e);var n=e;if(r==="head"){n=n.replace(S,"")}if(Q.config.useTemplateFragments&&t){var i=a("<body><template>"+n+"</template></body>",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a("<table>"+n+"</table>",1);case"col":return a("<table><colgroup>"+n+"</colgroup></table>",2);case"tr":return a("<table><tbody>"+n+"</tbody></table>",2);case"td":case"th":return a("<table><tbody><tr>"+n+"</tr></tbody></table>",3);case"script":case"style":return a("<div>"+n+"</div>",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function oe(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function X(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n<r.length;n++){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING){return i}}};var Y=function(e,t){var r=re().querySelectorAll(t);for(var n=r.length-1;n>=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r<t.length;r++){if(e===t[r]){return true}}return false}function we(t,r){oe(t.attributes,function(e){if(!r.hasAttribute(e.name)&&be(e.name)){t.removeAttribute(e.name)}});oe(r.attributes,function(e){if(be(e.name)){t.setAttribute(e.name,e.value)}})}function Se(e,t){var r=Fr(t);for(var n=0;n<r.length;n++){var i=r[n];try{if(i.isInlineSwap(e)){return true}}catch(e){b(e)}}return e==="outerHTML"}function Ee(e,i,a){var t="#"+ee(i,"id");var o="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a<i.length;a++){var o=i[a].split(":",2);var s=o[0].trim();if(s.indexOf("#")===0){s=s.substring(1)}var l=o[1]||"true";var u=t.querySelector("#"+s);if(u){Ee(l,u,r)}}}oe(f(t,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){var t=te(e,"hx-swap-oob");if(t!=null){Ee(t,e,r)}})}function Re(e){oe(f(e,"[hx-preserve], [data-hx-preserve]"),function(e){var t=te(e,"id");var r=re().getElementById(t);if(r!=null){e.parentNode.replaceChild(r,e)}})}function Te(o,e,s){oe(e.querySelectorAll("[id]"),function(e){var t=ee(e,"id");if(t&&t.length>0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r<e.length){t=(t<<5)-t+e.charCodeAt(r++)|0}return t}function Le(e){var t=0;if(e.attributes){for(var r=0;r<e.attributes.length;r++){var n=e.attributes[r];if(n.value){t=He(n.name,t);t=He(n.value,t)}}}return t}function Ae(e){var t=ae(e);if(t.onHandlers){for(var r=0;r<t.onHandlers.length;r++){const n=t.onHandlers[r];e.removeEventListener(n.event,n.listener)}delete t.onHandlers}}function Ne(e){var t=ae(e);if(t.timeout){clearTimeout(t.timeout)}if(t.webSocket){t.webSocket.close()}if(t.sseEventSource){t.sseEventSource.close()}if(t.listenerInfos){oe(t.listenerInfos,function(e){if(e.on){e.on.removeEventListener(e.trigger,e.listener)}})}Ae(e);oe(Object.keys(t),function(e){delete t[e]})}function p(e){ce(e,"htmx:beforeCleanupElement");Ne(e);if(e.children){oe(e.children,function(e){p(e)})}}function Ie(t,e,r){if(t.tagName==="BODY"){return Ue(t,e,r)}else{var n;var i=t.previousSibling;m(u(t),t,e,r);if(i==null){n=u(t).firstChild}else{n=i.nextSibling}r.elts=r.elts.filter(function(e){return e!=t});while(n&&n!==t){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}p(t);u(t).removeChild(t)}}function ke(e,t,r){return m(e,e.firstChild,t,r)}function Pe(e,t,r){return m(u(e),e,t,r)}function Me(e,t,r){return m(e,null,t,r)}function Xe(e,t,r){return m(u(e),e.nextSibling,t,r)}function De(e,t,r){p(e);return u(e).removeChild(e)}function Ue(e,t,r){var n=e.firstChild;m(e,n,t,r);if(n){while(n.nextSibling){p(n.nextSibling);e.removeChild(n.nextSibling)}p(n);e.removeChild(n)}}function Be(e,t,r){var n=r||ne(e,"hx-select");if(n){var i=re().createDocumentFragment();oe(t.querySelectorAll(n),function(e){i.appendChild(e)});t=i}return t}function Fe(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":Ie(r,n,i);return;case"afterbegin":ke(r,n,i);return;case"beforebegin":Pe(r,n,i);return;case"beforeend":Me(r,n,i);return;case"afterend":Xe(r,n,i);return;case"delete":De(r,n,i);return;default:var a=Fr(t);for(var o=0;o<a.length;o++){var s=a[o];try{var l=s.handleSwap(e,r,n,i);if(l){if(typeof l.length!=="undefined"){for(var u=0;u<l.length;u++){var f=l[u];if(f.nodeType!==Node.TEXT_NODE&&f.nodeType!==Node.COMMENT_NODE){i.tasks.push(Oe(f))}}}return}}catch(e){b(e)}}if(e==="innerHTML"){Ue(r,n,i)}else{Fe(Q.config.defaultSwapStyle,t,r,n,i)}}}function Ve(e){if(e.indexOf("<title")>-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l<s.length;l++){ce(r,s[l].trim(),[])}}}var ze=/\s/;var x=/[\s,]/;var $e=/[_$a-zA-Z]/;var We=/[_$a-zA-Z0-9]/;var Ge=['"',"'","/"];var Je=/[^\s]/;var Ze=/[{(]/;var Ke=/[})]/;function Ye(e){var t=[];var r=0;while(r<e.length){if($e.exec(e.charAt(r))){var n=r;while(We.exec(e.charAt(r+1))){r++}t.push(e.substr(n,r-n+1))}else if(Ge.indexOf(e.charAt(r))!==-1){var i=e.charAt(r);var n=r;r++;while(r<e.length&&e.charAt(r)!==i){if(e.charAt(r)==="\\"){r++}r++}t.push(e.substr(n,r-n+1))}else{var a=e.charAt(r);t.push(a)}r++}return t}function Qe(e,t,r){return $e.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==r&&t!=="."}function et(e,t,r){if(t[0]==="["){t.shift();var n=1;var i=" return (function("+r+"){ return (";var a=null;while(t.length>0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){xt(e,a[1],0)}if(a[0]==="send"){bt(e)}}}function xt(s,r,n){if(!se(s)){return}if(r.indexOf("/")==0){var e=location.hostname+(location.port?":"+location.port:"");if(location.protocol=="https:"){r="wss://"+e+r}else if(location.protocol=="http:"){r="ws://"+e+r}}var t=Q.createWebSocket(r);t.onerror=function(e){fe(s,"htmx:wsError",{error:e,socket:t});yt(s)};t.onclose=function(e){if([1006,1012,1013].indexOf(e.code)>=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a<i.length;a++){var o=i[a];Ee(te(o,"hx-swap-oob")||"true",o,r)}nr(r.tasks)})}function yt(e){if(!se(e)){ae(e).webSocket.close();return true}}function bt(u){var f=c(u,function(e){return ae(e).webSocket!=null});if(f){u.addEventListener(it(u)[0].trigger,function(e){var t=ae(f).webSocket;var r=xr(u,f);var n=dr(u,"post");var i=n.errors;var a=n.values;var o=Hr(u);var s=le(a,o);var l=yr(s,u);l["HEADERS"]=r;if(i&&i.length>0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i<n.length;i++){var a=n[i].split(/:(.+)/);if(a[0]==="connect"){Et(e,a[1])}if(a[0]==="swap"){Ct(e,a[1])}}}function Et(t,e){var r=Q.createEventSource(e);r.onerror=function(e){fe(t,"htmx:sseError",{error:e,source:r});Tt(t)};ae(t).sseEventSource=r}function Ct(a,o){var s=c(a,Ot);if(s){var l=ae(s).sseEventSource;var u=function(e){if(Tt(s)){return}if(!se(a)){l.removeEventListener(o,u);return}var t=e.data;R(a,function(e){t=e.transformResponse(t,null,a)});var r=wr(a);var n=ye(a);var i=T(a);je(r.swapStyle,n,a,t,i);nr(i.tasks);ce(a,"htmx:sseMessage",e)};ae(a).sseListener=u;l.addEventListener(o,u)}else{fe(a,"htmx:noSSESourceError")}}function Rt(e,t,r){var n=c(e,Ot);if(n){var i=ae(n).sseEventSource;var a=function(){if(!Tt(n)){if(se(e)){t(e)}else{i.removeEventListener(r,a)}}};ae(e).sseListener=a;i.addEventListener(r,a)}else{fe(e,"htmx:noSSESourceError")}}function Tt(e){if(!se(e)){ae(e).sseEventSource.close();return true}}function Ot(e){return ae(e).sseEventSource!=null}function qt(e,t,r,n){var i=function(){if(!r.loaded){r.loaded=true;t(e)}};if(n>0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t<e.length;t++){var r=e[t];if(r.isIntersecting){ce(n,"intersect");break}}},i);a.observe(n);ht(n,r,t,e)}else if(e.trigger==="load"){if(!ct(e,n,Wt("load",{elt:n}))){qt(n,r,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r<t.length;r++){var n=t[r].name;if(s(n,"hx-on:")||s(n,"data-hx-on:")||s(n,"hx-on-")||s(n,"data-hx-on-")){return true}}return false}function kt(e){var t=null;var r=[];if(It(e)){r.push(e)}if(document.evaluate){var n=document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]',e);while(t=n.iterateNext())r.push(t)}else{var i=e.getElementsByTagName("*");for(var a=0;a<i.length;a++){if(It(i[a])){r.push(i[a])}}}return r}function Pt(e){if(e.querySelectorAll){var t=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";var r=e.querySelectorAll(i+t+", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws],"+" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");return r}else{return[]}}function Mt(e){var t=v(e.target,"button, input[type='submit']");var r=Dt(e);if(r){r.lastButtonClicked=t}}function Xt(e){var t=Dt(e);if(t){t.lastButtonClicked=null}}function Dt(e){var t=v(e.target,"button, input[type='submit']");if(!t){return}var r=g("#"+ee(t,"form"))||v(t,"form");if(!r){return}return ae(r)}function Ut(e){e.addEventListener("click",Mt);e.addEventListener("focusin",Mt);e.addEventListener("focusout",Xt)}function Bt(e){var t=Ye(e);var r=0;for(var n=0;n<t.length;n++){const i=t[n];if(i==="{"){r++}else if(i==="}"){r--}}return r}function Ft(t,e,r){var n=ae(t);if(!Array.isArray(n.onHandlers)){n.onHandlers=[]}var i;var a=function(e){return Tr(t,function(){if(!i){i=new Function("event",r)}i.call(t,e)})};t.addEventListener(e,a);n.onHandlers.push({event:e,listener:a})}function Vt(e){var t=te(e,"hx-on");if(t){var r={};var n=t.split("\n");var i=null;var a=0;while(n.length>0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;t<e.attributes.length;t++){var r=e.attributes[t].name;var n=e.attributes[t].value;if(s(r,"hx-on")||s(r,"data-hx-on")){var i=r.indexOf("-on")+3;var a=r.slice(i,i+1);if(a==="-"||a===":"){var o=r.slice(i+1);if(s(o,":")){o="htmx"+o}else if(s(o,"-")){o="htmx:"+o.slice(1)}else if(s(o,"htmx-")){o="htmx:"+o.slice(5)}Ft(e,o,n)}}}}function _t(t){if(v(t,Q.config.disableSelector)){p(t);return}var r=ae(t);if(r.initHash!==Le(t)){Ne(t);r.initHash=Le(t);Vt(t);ce(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=it(t);var n=Ht(t,r,e);if(!n){if(ne(t,"hx-boost")==="true"){lt(t,r,e)}else if(o(t,"hx-trigger")){e.forEach(function(e){Lt(t,e,r,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&o(t,"form")){Ut(t)}var i=te(t,"hx-sse");if(i){St(t,r,i)}var a=te(t,"hx-ws");if(a){pt(t,r,a)}ce(t,"htmx:afterProcessNode")}}function zt(e){e=g(e);if(v(e,Q.config.disableSelector)){p(e);return}_t(e);oe(Pt(e),function(e){_t(e)});oe(kt(e),jt)}function $t(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=re().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function fe(e,t,r){ce(e,t,le({error:t},r))}function Gt(e){return e==="htmx:afterProcessNode"}function R(e,t){oe(Fr(e),function(e){try{t(e)}catch(e){b(e)}})}function b(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ce(e,t,r){e=g(e);if(r==null){r={}}r["elt"]=e;var n=Wt(t,r);if(Q.logger&&!Gt(t)){Q.logger(e,t,r)}if(r.error){b(r.error);ce(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=$t(t);if(i&&a!==t){var o=Wt(a,n.detail);i=i&&e.dispatchEvent(o)}R(e,function(e){i=i&&(e.onEvent(t,n)!==false&&!n.defaultPrevented)});return i}var Jt=location.pathname+location.search;function Zt(){var e=re().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||re().body}function Kt(e,t,r,n){if(!U()){return}if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}e=B(e);var i=E(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i.splice(a,1);break}}var o={url:e,content:t,title:r,scroll:n};ce(re().body,"htmx:historyItemCreated",{item:o,cache:i});i.push(o);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function Qt(e){var t=Q.config.requestClass;var r=e.cloneNode(true);oe(f(r,"."+t),function(e){n(e,t)});return r.innerHTML}function er(){var e=Zt();var t=Jt||location.pathname+location.search;var r;try{r=re().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){r=re().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!r){ce(re().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Kt(t,Qt(e),re().title,window.scrollY)}if(Q.config.historyEnabled)history.replaceState({htmx:true},re().title,window.location.href)}function tr(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(G(e,"&")||G(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Jt=e}function rr(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Jt=e}function nr(e){oe(e,function(e){e.call()})}function ir(a){var e=new XMLHttpRequest;var o={path:a,xhr:e};ce(re().body,"htmx:historyCacheMiss",o);e.open("GET",a,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",re().location.href);e.onload=function(){if(this.status>=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function fr(e){if(e.name===""||e.name==null||e.disabled||v(e,"fieldset[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 cr(e,t,r){if(e!=null&&t!=null){var n=r[e];if(n===undefined){r[e]=t}else if(Array.isArray(n)){if(Array.isArray(t)){r[e]=n.concat(t)}else{n.push(t)}}else{if(Array.isArray(t)){r[e]=[n].concat(t)}else{r[e]=[n,t]}}}}function hr(t,r,n,e,i){if(e==null||ur(t,e)){return}else{t.push(e)}if(fr(e)){var a=ee(e,"name");var o=e.value;if(e.multiple&&e.tagName==="SELECT"){o=M(e.querySelectorAll("option:checked")).map(function(e){return e.value})}if(e.files){o=M(e.files)}cr(a,o,r);if(i){vr(e,n)}}if(h(e,"form")){var s=e.elements;oe(s,function(e){hr(t,r,n,e,i)})}}function vr(e,t){if(e.willValidate){ce(e,"htmx:validation:validate");if(!e.checkValidity()){t.push({elt:e,message:e.validationMessage,validity:e.validity});ce(e,"htmx:validation:failed",{message:e.validationMessage,validity:e.validity})}}}function dr(e,t){var r=[];var n={};var i={};var a=[];var o=ae(e);if(o.lastButtonClicked&&!se(o.lastButtonClicked)){o.lastButtonClicked=null}var s=h(e,"form")&&e.noValidate!==true||te(e,"hx-validate")==="true";if(o.lastButtonClicked){s=s&&o.lastButtonClicked.formNoValidate!==true}if(t!=="get"){hr(r,i,a,v(e,"form"),s)}hr(r,n,a,e,s);if(o.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){var l=o.lastButtonClicked||e;var u=ee(l,"name");cr(u,l.value,i)}var f=pe(e,"hx-include");oe(f,function(e){hr(r,n,a,e,s);if(!h(e,"form")){oe(e.querySelectorAll(rt),function(e){hr(r,n,a,e,s)})}});n=le(n,i);return{errors:a,values:n}}function gr(e,t,r){if(e!==""){e+="&"}if(String(r)==="[object Object]"){r=JSON.stringify(r)}var n=encodeURIComponent(r);e+=encodeURIComponent(t)+"="+n;return e}function mr(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t=gr(t,r,e)})}else{t=gr(t,r,n)}}}return t}function pr(e){var t=new FormData;for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){oe(n,function(e){t.append(r,e)})}else{t.append(r,n)}}}return t}function xr(e,t,r){var n={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":re().location.href};Rr(e,"hx-headers",false,n);if(r!==undefined){n["HX-Prompt"]=r}if(ae(e).boosted){n["HX-Boosted"]="true"}return n}function yr(t,e){var r=ne(e,"hx-params");if(r){if(r==="none"){return{}}else if(r==="*"){return t}else if(r.indexOf("not ")===0){oe(r.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var n={};oe(r.split(","),function(e){e=e.trim();n[e]=t[e]});return n}}else{return t}}function br(e){return ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a<i.length;a++){var o=i[a];if(o.indexOf("swap:")===0){n["swapDelay"]=d(o.substr(5))}else if(o.indexOf("settle:")===0){n["settleDelay"]=d(o.substr(7))}else if(o.indexOf("transition:")===0){n["transition"]=o.substr(11)==="true"}else if(o.indexOf("ignoreTitle:")===0){n["ignoreTitle"]=o.substr(12)==="true"}else if(o.indexOf("scroll:")===0){var s=o.substr(7);var l=s.split(":");var u=l.pop();var f=l.length>0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","<style> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file +// v2.0.0 from https://github.com/bigskysoftware/htmx/releases +var htmx=function(){"use strict";const Q={onLoad:null,process:null,on:null,off:null,trigger:null,ajax:null,find:null,findAll:null,closest:null,values:function(e,t){const n=cn(e,t||"post");return n.values},remove:null,addClass:null,removeClass:null,toggleClass:null,takeClass:null,swap:null,defineExtension:null,removeExtension:null,logAll:null,logNone:null,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",inlineStyleNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",scrollBehavior:"instant",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get","delete"],selfRequestsOnly:true,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null,disableInheritance:false,responseHandling:[{code:"204",swap:false},{code:"[23]..",swap:true},{code:"[45]..",swap:false,error:true}],allowNestedOobSwaps:true},parseInterval:null,_:null,version:"2.0.0"};Q.onLoad=$;Q.process=Dt;Q.on=be;Q.off=we;Q.trigger=he;Q.ajax=Hn;Q.find=r;Q.findAll=p;Q.closest=g;Q.remove=K;Q.addClass=W;Q.removeClass=o;Q.toggleClass=Y;Q.takeClass=ge;Q.swap=ze;Q.defineExtension=Un;Q.removeExtension=Bn;Q.logAll=z;Q.logNone=J;Q.parseInterval=d;Q._=_;const n={addTriggerHandler:Et,bodyContains:le,canAccessLocalStorage:j,findThisElement:Ee,filterValues:dn,swap:ze,hasAttribute:s,getAttributeValue:te,getClosestAttributeValue:re,getClosestMatch:T,getExpressionVars:Cn,getHeaders:hn,getInputValues:cn,getInternalData:ie,getSwapSpecification:pn,getTriggerSpecs:lt,getTarget:Ce,makeFragment:D,mergeObjects:ue,makeSettleInfo:xn,oobSwap:Te,querySelectorExt:fe,settleImmediately:Gt,shouldCancel:dt,triggerEvent:he,triggerErrorEvent:ae,withExtensions:Ut};const v=["get","post","put","delete","patch"];const R=v.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");const O=e("head");function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e instanceof Element&&e.getAttribute(t)}function s(e,t){return!!e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){const t=e.parentElement;if(!t&&e.parentNode instanceof ShadowRoot)return e.parentNode;return t}function ne(){return document}function H(e,t){return e.getRootNode?e.getRootNode({composed:t}):ne()}function T(e,t){while(e&&!t(e)){e=u(e)}return e||null}function q(e,t,n){const r=te(t,n);const o=te(t,"hx-disinherit");var i=te(t,"hx-inherit");if(e!==t){if(Q.config.disableInheritance){if(i&&(i==="*"||i.split(" ").indexOf(n)>=0)){return r}else{return null}}if(o&&(o==="*"||o.split(" ").indexOf(n)>=0)){return"unset"}}return r}function re(t,n){let r=null;T(t,function(e){return!!(r=q(t,ce(e),n))});if(r!=="unset"){return r}}function a(e,t){const n=e instanceof Element&&(e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector);return!!n&&n.call(e,t)}function L(e){const t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;const n=t.exec(e);if(n){return n[1].toLowerCase()}else{return""}}function N(e){const t=new DOMParser;return t.parseFromString(e,"text/html")}function A(e,t){while(t.childNodes.length>0){e.append(t.childNodes[0])}}function I(e){const t=ne().createElement("script");se(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}return t}function P(e){return e.matches("script")&&(e.type==="text/javascript"||e.type==="module"||e.type==="")}function k(e){Array.from(e.querySelectorAll("script")).forEach(e=>{if(P(e)){const t=I(e);const n=e.parentNode;try{n.insertBefore(t,e)}catch(e){w(e)}finally{e.remove()}}})}function D(e){const t=e.replace(O,"");const n=L(t);let r;if(n==="html"){r=new DocumentFragment;const i=N(e);A(r,i.body);r.title=i.title}else if(n==="body"){r=new DocumentFragment;const i=N(t);A(r,i.body);r.title=i.title}else{const i=N('<body><template class="internal-htmx-wrapper">'+t+"</template></body>");r=i.querySelector("template").content;r.title=i.title;var o=r.querySelector("title");if(o&&o.parentNode===r){o.remove();r.title=o.innerText}}if(r){if(Q.config.allowScriptTags){k(r)}else{r.querySelectorAll("script").forEach(e=>e.remove())}}return r}function oe(e){if(e){e()}}function t(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function M(e){return typeof e==="function"}function X(e){return t(e,"Object")}function ie(e){const t="htmx-internal-data";let n=e[t];if(!n){n=e[t]={}}return n}function F(t){const n=[];if(t){for(let e=0;e<t.length;e++){n.push(t[e])}}return n}function se(t,n){if(t){for(let e=0;e<t.length;e++){n(t[e])}}}function U(e){const t=e.getBoundingClientRect();const n=t.top;const r=t.bottom;return n<window.innerHeight&&r>=0}function le(e){const t=e.getRootNode&&e.getRootNode();if(t&&t instanceof window.ShadowRoot){return ne().body.contains(t.host)}else{return ne().body.contains(e)}}function B(e){return e.trim().split(/\s+/)}function ue(e,t){for(const n in t){if(t.hasOwnProperty(n)){e[n]=t[n]}}return e}function S(e){try{return JSON.parse(e)}catch(e){w(e);return null}}function j(){const e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function V(t){try{const e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function _(e){return vn(ne().body,function(){return eval(e)})}function $(t){const e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function z(){Q.logger=function(e,t,n){if(console){console.log(t,e,n)}}}function J(){Q.logger=null}function r(e,t){if(typeof e!=="string"){return e.querySelector(t)}else{return r(ne(),e)}}function p(e,t){if(typeof e!=="string"){return e.querySelectorAll(t)}else{return p(ne(),e)}}function E(){return window}function K(e,t){e=y(e);if(t){E().setTimeout(function(){K(e);e=null},t)}else{u(e).removeChild(e)}}function ce(e){return e instanceof Element?e:null}function G(e){return e instanceof HTMLElement?e:null}function Z(e){return typeof e==="string"?e:null}function h(e){return e instanceof Element||e instanceof Document||e instanceof DocumentFragment?e:null}function W(e,t,n){e=ce(y(e));if(!e){return}if(n){E().setTimeout(function(){W(e,t);e=null},n)}else{e.classList&&e.classList.add(t)}}function o(e,t,n){let r=ce(y(e));if(!r){return}if(n){E().setTimeout(function(){o(r,t);r=null},n)}else{if(r.classList){r.classList.remove(t);if(r.classList.length===0){r.removeAttribute("class")}}}}function Y(e,t){e=y(e);e.classList.toggle(t)}function ge(e,t){e=y(e);se(e.parentElement.children,function(e){o(e,t)});W(ce(e),t)}function g(e,t){e=ce(y(e));if(e&&e.closest){return e.closest(t)}else{do{if(e==null||a(e,t)){return e}}while(e=e&&ce(u(e)));return null}}function l(e,t){return e.substring(0,t.length)===t}function pe(e,t){return e.substring(e.length-t.length)===t}function i(e){const t=e.trim();if(l(t,"<")&&pe(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function m(e,t,n){e=y(e);if(t.indexOf("closest ")===0){return[g(ce(e),i(t.substr(8)))]}else if(t.indexOf("find ")===0){return[r(h(e),i(t.substr(5)))]}else if(t==="next"){return[ce(e).nextElementSibling]}else if(t.indexOf("next ")===0){return[me(e,i(t.substr(5)),!!n)]}else if(t==="previous"){return[ce(e).previousElementSibling]}else if(t.indexOf("previous ")===0){return[ye(e,i(t.substr(9)),!!n)]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else if(t==="root"){return[H(e,!!n)]}else if(t.indexOf("global ")===0){return m(e,t.slice(7),true)}else{return F(h(H(e,!!n)).querySelectorAll(i(t)))}}var me=function(t,e,n){const r=h(H(t,n)).querySelectorAll(e);for(let e=0;e<r.length;e++){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_PRECEDING){return o}}};var ye=function(t,e,n){const r=h(H(t,n)).querySelectorAll(e);for(let e=r.length-1;e>=0;e--){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_FOLLOWING){return o}}};function fe(e,t){if(typeof e!=="string"){return m(e,t)[0]}else{return m(ne().body,e)[0]}}function y(e,t){if(typeof e==="string"){return r(h(t)||document,e)}else{return e}}function xe(e,t,n){if(M(t)){return{target:ne().body,event:Z(e),listener:t}}else{return{target:y(e),event:Z(t),listener:n}}}function be(t,n,r){_n(function(){const e=xe(t,n,r);e.target.addEventListener(e.event,e.listener)});const e=M(n);return e?n:r}function we(t,n,r){_n(function(){const e=xe(t,n,r);e.target.removeEventListener(e.event,e.listener)});return M(n)?n:r}const ve=ne().createElement("output");function Se(e,t){const n=re(e,t);if(n){if(n==="this"){return[Ee(e,t)]}else{const r=m(e,n);if(r.length===0){w('The selector "'+n+'" on '+t+" returned no matches!");return[ve]}else{return r}}}}function Ee(e,t){return ce(T(e,function(e){return te(ce(e),t)!=null}))}function Ce(e){const t=re(e,"hx-target");if(t){if(t==="this"){return Ee(e,"hx-target")}else{return fe(e,t)}}else{const n=ie(e);if(n.boosted){return ne().body}else{return e}}}function Re(t){const n=Q.config.attributesToSettle;for(let e=0;e<n.length;e++){if(t===n[e]){return true}}return false}function Oe(t,n){se(t.attributes,function(e){if(!n.hasAttribute(e.name)&&Re(e.name)){t.removeAttribute(e.name)}});se(n.attributes,function(e){if(Re(e.name)){t.setAttribute(e.name,e.value)}})}function He(t,e){const n=jn(e);for(let e=0;e<n.length;e++){const r=n[e];try{if(r.isInlineSwap(t)){return true}}catch(e){w(e)}}return t==="outerHTML"}function Te(e,o,i){let t="#"+ee(o,"id");let s="outerHTML";if(e==="true"){}else if(e.indexOf(":")>0){s=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{s=e}const n=ne().querySelectorAll(t);if(n){se(n,function(e){let t;const n=o.cloneNode(true);t=ne().createDocumentFragment();t.appendChild(n);if(!He(s,e)){t=h(n)}const r={shouldSwap:true,target:e,fragment:t};if(!he(e,"htmx:oobBeforeSwap",r))return;e=r.target;if(r.shouldSwap){_e(s,e,e,t,i)}se(i.elts,function(e){he(e,"htmx:oobAfterSwap",r)})});o.parentNode.removeChild(o)}else{o.parentNode.removeChild(o);ae(ne().body,"htmx:oobErrorNoTarget",{content:o})}return e}function qe(e){se(p(e,"[hx-preserve], [data-hx-preserve]"),function(e){const t=te(e,"id");const n=ne().getElementById(t);if(n!=null){e.parentNode.replaceChild(n,e)}})}function Le(l,e,u){se(e.querySelectorAll("[id]"),function(t){const n=ee(t,"id");if(n&&n.length>0){const r=n.replace("'","\\'");const o=t.tagName.replace(":","\\:");const e=h(l);const i=e&&e.querySelector(o+"[id='"+r+"']");if(i&&i!==e){const s=t.cloneNode();Oe(t,i);u.tasks.push(function(){Oe(t,s)})}}})}function Ne(e){return function(){o(e,Q.config.addedClass);Dt(ce(e));Ae(h(e));he(e,"htmx:load")}}function Ae(e){const t="[autofocus]";const n=G(a(e,t)?e:e.querySelector(t));if(n!=null){n.focus()}}function c(e,t,n,r){Le(e,n,r);while(n.childNodes.length>0){const o=n.firstChild;W(ce(o),Q.config.addedClass);e.insertBefore(o,t);if(o.nodeType!==Node.TEXT_NODE&&o.nodeType!==Node.COMMENT_NODE){r.tasks.push(Ne(o))}}}function Ie(e,t){let n=0;while(n<e.length){t=(t<<5)-t+e.charCodeAt(n++)|0}return t}function Pe(t){let n=0;if(t.attributes){for(let e=0;e<t.attributes.length;e++){const r=t.attributes[e];if(r.value){n=Ie(r.name,n);n=Ie(r.value,n)}}}return n}function ke(t){const n=ie(t);if(n.onHandlers){for(let e=0;e<n.onHandlers.length;e++){const r=n.onHandlers[e];we(t,r.event,r.listener)}delete n.onHandlers}}function De(e){const t=ie(e);if(t.timeout){clearTimeout(t.timeout)}if(t.listenerInfos){se(t.listenerInfos,function(e){if(e.on){we(e.on,e.trigger,e.listener)}})}ke(e);se(Object.keys(t),function(e){delete t[e]})}function f(e){he(e,"htmx:beforeCleanupElement");De(e);if(e.children){se(e.children,function(e){f(e)})}}function Me(t,e,n){let r;const o=t.previousSibling;c(u(t),t,e,n);if(o==null){r=u(t).firstChild}else{r=o.nextSibling}n.elts=n.elts.filter(function(e){return e!==t});while(r&&r!==t){if(r instanceof Element){n.elts.push(r);r=r.nextElementSibling}else{r=null}}f(t);if(t instanceof Element){t.remove()}else{t.parentNode.removeChild(t)}}function Xe(e,t,n){return c(e,e.firstChild,t,n)}function Fe(e,t,n){return c(u(e),e,t,n)}function Ue(e,t,n){return c(e,null,t,n)}function Be(e,t,n){return c(u(e),e.nextSibling,t,n)}function je(e){f(e);return u(e).removeChild(e)}function Ve(e,t,n){const r=e.firstChild;c(e,r,t,n);if(r){while(r.nextSibling){f(r.nextSibling);e.removeChild(r.nextSibling)}f(r);e.removeChild(r)}}function _e(t,e,n,r,o){switch(t){case"none":return;case"outerHTML":Me(n,r,o);return;case"afterbegin":Xe(n,r,o);return;case"beforebegin":Fe(n,r,o);return;case"beforeend":Ue(n,r,o);return;case"afterend":Be(n,r,o);return;case"delete":je(n);return;default:var i=jn(e);for(let e=0;e<i.length;e++){const s=i[e];try{const l=s.handleSwap(t,n,r,o);if(l){if(typeof l.length!=="undefined"){for(let e=0;e<l.length;e++){const u=l[e];if(u.nodeType!==Node.TEXT_NODE&&u.nodeType!==Node.COMMENT_NODE){o.tasks.push(Ne(u))}}}return}}catch(e){w(e)}}if(t==="innerHTML"){Ve(n,r,o)}else{_e(Q.config.defaultSwapStyle,e,n,r,o)}}}function $e(e,n){se(p(e,"[hx-swap-oob], [data-hx-swap-oob]"),function(e){if(Q.config.allowNestedOobSwaps||e.parentElement===null){const t=te(e,"hx-swap-oob");if(t!=null){Te(t,e,n)}}else{e.removeAttribute("hx-swap-oob");e.removeAttribute("data-hx-swap-oob")}})}function ze(e,t,r,o){if(!o){o={}}e=y(e);const n=document.activeElement;let i={};try{i={elt:n,start:n?n.selectionStart:null,end:n?n.selectionEnd:null}}catch(e){}const s=xn(e);if(r.swapStyle==="textContent"){e.textContent=t}else{let n=D(t);s.title=n.title;if(o.selectOOB){const u=o.selectOOB.split(",");for(let t=0;t<u.length;t++){const c=u[t].split(":",2);let e=c[0].trim();if(e.indexOf("#")===0){e=e.substring(1)}const f=c[1]||"true";const a=n.querySelector("#"+e);if(a){Te(f,a,s)}}}$e(n,s);se(p(n,"template"),function(e){$e(e.content,s);if(e.content.childElementCount===0){e.remove()}});if(o.select){const h=ne().createDocumentFragment();se(n.querySelectorAll(o.select),function(e){h.appendChild(e)});n=h}qe(n);_e(r.swapStyle,o.contextElement,e,n,s)}if(i.elt&&!le(i.elt)&&ee(i.elt,"id")){const d=document.getElementById(ee(i.elt,"id"));const g={preventScroll:r.focusScroll!==undefined?!r.focusScroll:!Q.config.defaultFocusScroll};if(d){if(i.start&&d.setSelectionRange){try{d.setSelectionRange(i.start,i.end)}catch(e){}}d.focus(g)}}e.classList.remove(Q.config.swappingClass);se(s.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}he(e,"htmx:afterSwap",o.eventInfo)});if(o.afterSwapCallback){o.afterSwapCallback()}if(!r.ignoreTitle){Dn(s.title)}const l=function(){se(s.tasks,function(e){e.call()});se(s.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}he(e,"htmx:afterSettle",o.eventInfo)});if(o.anchor){const e=ce(y("#"+o.anchor));if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}bn(s.elts,r);if(o.afterSettleCallback){o.afterSettleCallback()}};if(r.settleDelay>0){E().setTimeout(l,r.settleDelay)}else{l()}}function Je(e,t,n){const r=e.getResponseHeader(t);if(r.indexOf("{")===0){const o=S(r);for(const i in o){if(o.hasOwnProperty(i)){let e=o[i];if(!X(e)){e={value:e}}he(n,i,e)}}}else{const s=r.split(",");for(let e=0;e<s.length;e++){he(n,s[e].trim(),[])}}}const Ke=/\s/;const x=/[\s,]/;const Ge=/[_$a-zA-Z]/;const Ze=/[_$a-zA-Z0-9]/;const We=['"',"'","/"];const Ye=/[^\s]/;const Qe=/[{(]/;const et=/[})]/;function tt(e){const t=[];let n=0;while(n<e.length){if(Ge.exec(e.charAt(n))){var r=n;while(Ze.exec(e.charAt(n+1))){n++}t.push(e.substr(r,n-r+1))}else if(We.indexOf(e.charAt(n))!==-1){const o=e.charAt(n);var r=n;n++;while(n<e.length&&e.charAt(n)!==o){if(e.charAt(n)==="\\"){n++}n++}t.push(e.substr(r,n-r+1))}else{const i=e.charAt(n);t.push(i)}n++}return t}function nt(e,t,n){return Ge.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==n&&t!=="."}function rt(r,o,i){if(o[0]==="["){o.shift();let e=1;let t=" return (function("+i+"){ return (";let n=null;while(o.length>0){const s=o[0];if(s==="]"){e--;if(e===0){if(n===null){t=t+"true"}o.shift();t+=")})";try{const l=vn(r,function(){return Function(t)()},function(){return true});l.source=t;return l}catch(e){ae(ne().body,"htmx:syntax:error",{error:e,source:t});return null}}}else if(s==="["){e++}if(nt(s,n,i)){t+="(("+i+"."+s+") ? ("+i+"."+s+") : (window."+s+"))"}else{t=t+s}n=o.shift()}}}function b(e,t){let n="";while(e.length>0&&!t.test(e[0])){n+=e.shift()}return n}function ot(e){let t;if(e.length>0&&Qe.test(e[0])){e.shift();t=b(e,et).trim();e.shift()}else{t=b(e,x)}return t}const it="input, textarea, select";function st(e,t,n){const r=[];const o=tt(t);do{b(o,Ye);const l=o.length;const u=b(o,/[,\[\s]/);if(u!==""){if(u==="every"){const c={trigger:"every"};b(o,Ye);c.pollInterval=d(b(o,/[,\[\s]/));b(o,Ye);var i=rt(e,o,"event");if(i){c.eventFilter=i}r.push(c)}else{const f={trigger:u};var i=rt(e,o,"event");if(i){f.eventFilter=i}while(o.length>0&&o[0]!==","){b(o,Ye);const a=o.shift();if(a==="changed"){f.changed=true}else if(a==="once"){f.once=true}else if(a==="consume"){f.consume=true}else if(a==="delay"&&o[0]===":"){o.shift();f.delay=d(b(o,x))}else if(a==="from"&&o[0]===":"){o.shift();if(Qe.test(o[0])){var s=ot(o)}else{var s=b(o,x);if(s==="closest"||s==="find"||s==="next"||s==="previous"){o.shift();const h=ot(o);if(h.length>0){s+=" "+h}}}f.from=s}else if(a==="target"&&o[0]===":"){o.shift();f.target=ot(o)}else if(a==="throttle"&&o[0]===":"){o.shift();f.throttle=d(b(o,x))}else if(a==="queue"&&o[0]===":"){o.shift();f.queue=b(o,x)}else if(a==="root"&&o[0]===":"){o.shift();f[a]=ot(o)}else if(a==="threshold"&&o[0]===":"){o.shift();f[a]=b(o,x)}else{ae(e,"htmx:syntax:error",{token:o.shift()})}}r.push(f)}}if(o.length===l){ae(e,"htmx:syntax:error",{token:o.shift()})}b(o,Ye)}while(o[0]===","&&o.shift());if(n){n[t]=r}return r}function lt(e){const t=te(e,"hx-trigger");let n=[];if(t){const r=Q.config.triggerSpecsCache;n=r&&r[t]||st(e,t,r)}if(n.length>0){return n}else if(a(e,"form")){return[{trigger:"submit"}]}else if(a(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(a(e,it)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function ut(e){ie(e).cancelled=true}function ct(e,t,n){const r=ie(e);r.timeout=E().setTimeout(function(){if(le(e)&&r.cancelled!==true){if(!pt(n,e,Xt("hx:poll:trigger",{triggerSpec:n,target:e}))){t(e)}ct(e,t,n)}},n.pollInterval)}function ft(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function at(e){return g(e,Q.config.disableSelector)}function ht(t,n,e){if(t instanceof HTMLAnchorElement&&ft(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){n.boosted=true;let r,o;if(t.tagName==="A"){r="get";o=ee(t,"href")}else{const i=ee(t,"method");r=i?i.toLowerCase():"get";if(r==="get"){}o=ee(t,"action")}e.forEach(function(e){mt(t,function(e,t){const n=ce(e);if(at(n)){f(n);return}de(r,o,n,t)},n,e,true)})}}function dt(e,t){const n=ce(t);if(!n){return false}if(e.type==="submit"||e.type==="click"){if(n.tagName==="FORM"){return true}if(a(n,'input[type="submit"], button')&&g(n,"form")!==null){return true}if(n instanceof HTMLAnchorElement&&n.href&&(n.getAttribute("href")==="#"||n.getAttribute("href").indexOf("#")!==0)){return true}}return false}function gt(e,t){return ie(e).boosted&&e instanceof HTMLAnchorElement&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function pt(e,t,n){const r=e.eventFilter;if(r){try{return r.call(t,n)!==true}catch(e){const o=r.source;ae(ne().body,"htmx:eventFilter:error",{error:e,source:o});return true}}return false}function mt(s,l,e,u,c){const f=ie(s);let t;if(u.from){t=m(s,u.from)}else{t=[s]}if(u.changed){t.forEach(function(e){const t=ie(e);t.lastValue=e.value})}se(t,function(o){const i=function(e){if(!le(s)){o.removeEventListener(u.trigger,i);return}if(gt(s,e)){return}if(c||dt(e,s)){e.preventDefault()}if(pt(u,s,e)){return}const t=ie(e);t.triggerSpec=u;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(s)<0){t.handledFor.push(s);if(u.consume){e.stopPropagation()}if(u.target&&e.target){if(!a(ce(e.target),u.target)){return}}if(u.once){if(f.triggeredOnce){return}else{f.triggeredOnce=true}}if(u.changed){const n=ie(o);const r=o.value;if(n.lastValue===r){return}n.lastValue=r}if(f.delayed){clearTimeout(f.delayed)}if(f.throttle){return}if(u.throttle>0){if(!f.throttle){l(s,e);f.throttle=E().setTimeout(function(){f.throttle=null},u.throttle)}}else if(u.delay>0){f.delayed=E().setTimeout(function(){l(s,e)},u.delay)}else{he(s,"htmx:trigger");l(s,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:u.trigger,listener:i,on:o});o.addEventListener(u.trigger,i)})}let yt=false;let xt=null;function bt(){if(!xt){xt=function(){yt=true};window.addEventListener("scroll",xt);setInterval(function(){if(yt){yt=false;se(ne().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"),function(e){wt(e)})}},200)}}function wt(e){if(!s(e,"data-hx-revealed")&&U(e)){e.setAttribute("data-hx-revealed","true");const t=ie(e);if(t.initHash){he(e,"revealed")}else{e.addEventListener("htmx:afterProcessNode",function(){he(e,"revealed")},{once:true})}}}function vt(e,t,n,r){const o=function(){if(!n.loaded){n.loaded=true;t(e)}};if(r>0){E().setTimeout(o,r)}else{o()}}function St(t,n,e){let i=false;se(v,function(r){if(s(t,"hx-"+r)){const o=te(t,"hx-"+r);i=true;n.path=o;n.verb=r;e.forEach(function(e){Et(t,e,n,function(e,t){const n=ce(e);if(g(n,Q.config.disableSelector)){f(n);return}de(r,o,n,t)})})}});return i}function Et(r,e,t,n){if(e.trigger==="revealed"){bt();mt(r,n,t,e);wt(ce(r))}else if(e.trigger==="intersect"){const o={};if(e.root){o.root=fe(r,e.root)}if(e.threshold){o.threshold=parseFloat(e.threshold)}const i=new IntersectionObserver(function(t){for(let e=0;e<t.length;e++){const n=t[e];if(n.isIntersecting){he(r,"intersect");break}}},o);i.observe(ce(r));mt(ce(r),n,t,e)}else if(e.trigger==="load"){if(!pt(e,r,Xt("load",{elt:r}))){vt(ce(r),n,t,e.delay)}}else if(e.pollInterval>0){t.polling=true;ct(ce(r),n,e)}else{mt(r,n,t,e)}}function Ct(e){const t=ce(e);if(!t){return false}const n=t.attributes;for(let e=0;e<n.length;e++){const r=n[e].name;if(l(r,"hx-on:")||l(r,"data-hx-on:")||l(r,"hx-on-")||l(r,"data-hx-on-")){return true}}return false}const Rt=(new XPathEvaluator).createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or'+' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]');function Ot(e,t){if(Ct(e)){t.push(ce(e))}const n=Rt.evaluate(e);let r=null;while(r=n.iterateNext())t.push(ce(r))}function Ht(e){const t=[];if(e instanceof DocumentFragment){for(const n of e.childNodes){Ot(n,t)}}else{Ot(e,t)}return t}function Tt(e){if(e.querySelectorAll){const n=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";const r=[];for(const i in Xn){const s=Xn[i];if(s.getSelectors){var t=s.getSelectors();if(t){r.push(t)}}}const o=e.querySelectorAll(R+n+", form, [type='submit'],"+" [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]"+r.flat().map(e=>", "+e).join(""));return o}else{return[]}}function qt(e){const t=g(ce(e.target),"button, input[type='submit']");const n=Nt(e);if(n){n.lastButtonClicked=t}}function Lt(e){const t=Nt(e);if(t){t.lastButtonClicked=null}}function Nt(e){const t=g(ce(e.target),"button, input[type='submit']");if(!t){return}const n=y("#"+ee(t,"form"),t.getRootNode())||g(t,"form");if(!n){return}return ie(n)}function At(e){e.addEventListener("click",qt);e.addEventListener("focusin",qt);e.addEventListener("focusout",Lt)}function It(t,e,n){const r=ie(t);if(!Array.isArray(r.onHandlers)){r.onHandlers=[]}let o;const i=function(e){vn(t,function(){if(at(t)){return}if(!o){o=new Function("event",n)}o.call(t,e)})};t.addEventListener(e,i);r.onHandlers.push({event:e,listener:i})}function Pt(t){ke(t);for(let e=0;e<t.attributes.length;e++){const n=t.attributes[e].name;const r=t.attributes[e].value;if(l(n,"hx-on")||l(n,"data-hx-on")){const o=n.indexOf("-on")+3;const i=n.slice(o,o+1);if(i==="-"||i===":"){let e=n.slice(o+1);if(l(e,":")){e="htmx"+e}else if(l(e,"-")){e="htmx:"+e.slice(1)}else if(l(e,"htmx-")){e="htmx:"+e.slice(5)}It(t,e,r)}}}}function kt(t){if(g(t,Q.config.disableSelector)){f(t);return}const n=ie(t);if(n.initHash!==Pe(t)){De(t);n.initHash=Pe(t);he(t,"htmx:beforeProcessNode");if(t.value){n.lastValue=t.value}const e=lt(t);const r=St(t,n,e);if(!r){if(re(t,"hx-boost")==="true"){ht(t,n,e)}else if(s(t,"hx-trigger")){e.forEach(function(e){Et(t,e,n,function(){})})}}if(t.tagName==="FORM"||ee(t,"type")==="submit"&&s(t,"form")){At(t)}he(t,"htmx:afterProcessNode")}}function Dt(e){e=y(e);if(g(e,Q.config.disableSelector)){f(e);return}kt(e);se(Tt(e),function(e){kt(e)});se(Ht(e),Pt)}function Mt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Xt(e,t){let n;if(window.CustomEvent&&typeof window.CustomEvent==="function"){n=new CustomEvent(e,{bubbles:true,cancelable:true,composed:true,detail:t})}else{n=ne().createEvent("CustomEvent");n.initCustomEvent(e,true,true,t)}return n}function ae(e,t,n){he(e,t,ue({error:t},n))}function Ft(e){return e==="htmx:afterProcessNode"}function Ut(e,t){se(jn(e),function(e){try{t(e)}catch(e){w(e)}})}function w(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function he(e,t,n){e=y(e);if(n==null){n={}}n.elt=e;const r=Xt(t,n);if(Q.logger&&!Ft(t)){Q.logger(e,t,n)}if(n.error){w(n.error);he(e,"htmx:error",{errorInfo:n})}let o=e.dispatchEvent(r);const i=Mt(t);if(o&&i!==t){const s=Xt(i,r.detail);o=o&&e.dispatchEvent(s)}Ut(ce(e),function(e){o=o&&(e.onEvent(t,r)!==false&&!r.defaultPrevented)});return o}let Bt=location.pathname+location.search;function jt(){const e=ne().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||ne().body}function Vt(t,e){if(!j()){return}const n=$t(e);const r=ne().title;const o=window.scrollY;if(Q.config.historyCacheSize<=0){localStorage.removeItem("htmx-history-cache");return}t=V(t);const i=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e<i.length;e++){if(i[e].url===t){i.splice(e,1);break}}const s={url:t,content:n,title:r,scroll:o};he(ne().body,"htmx:historyItemCreated",{item:s,cache:i});i.push(s);while(i.length>Q.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ae(ne().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function _t(t){if(!j()){return null}t=V(t);const n=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e<n.length;e++){if(n[e].url===t){return n[e]}}return null}function $t(e){const t=Q.config.requestClass;const n=e.cloneNode(true);se(p(n,"."+t),function(e){o(e,t)});return n.innerHTML}function zt(){const e=jt();const t=Bt||location.pathname+location.search;let n;try{n=ne().querySelector('[hx-history="false" i],[data-hx-history="false" i]')}catch(e){n=ne().querySelector('[hx-history="false"],[data-hx-history="false"]')}if(!n){he(ne().body,"htmx:beforeHistorySave",{path:t,historyElt:e});Vt(t,e)}if(Q.config.historyEnabled)history.replaceState({htmx:true},ne().title,window.location.href)}function Jt(e){if(Q.config.getCacheBusterParam){e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,"");if(pe(e,"&")||pe(e,"?")){e=e.slice(0,-1)}}if(Q.config.historyEnabled){history.pushState({htmx:true},"",e)}Bt=e}function Kt(e){if(Q.config.historyEnabled)history.replaceState({htmx:true},"",e);Bt=e}function Gt(e){se(e,function(e){e.call(undefined)})}function Zt(o){const e=new XMLHttpRequest;const i={path:o,xhr:e};he(ne().body,"htmx:historyCacheMiss",i);e.open("GET",o,true);e.setRequestHeader("HX-Request","true");e.setRequestHeader("HX-History-Restore-Request","true");e.setRequestHeader("HX-Current-URL",ne().location.href);e.onload=function(){if(this.status>=200&&this.status<400){he(ne().body,"htmx:historyCacheMissLoad",i);const e=D(this.response);const t=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;const n=jt();const r=xn(n);Dn(e.title);Ve(n,t,r);Gt(r.tasks);Bt=o;he(ne().body,"htmx:historyRestore",{path:o,cacheMiss:true,serverResponse:this.response})}else{ae(ne().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Wt(e){zt();e=e||location.pathname+location.search;const t=_t(e);if(t){const n=D(t.content);const r=jt();const o=xn(r);Dn(n.title);Ve(r,n,o);Gt(o.tasks);E().setTimeout(function(){window.scrollTo(0,t.scroll)},0);Bt=e;he(ne().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{Zt(e)}}}function Yt(e){let t=Se(e,"hx-indicator");if(t==null){t=[e]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.classList.add.call(e.classList,Q.config.requestClass)});return t}function Qt(e){let t=Se(e,"hx-disabled-elt");if(t==null){t=[]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function en(e,t){se(e,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList.remove.call(e.classList,Q.config.requestClass)}});se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function tn(t,n){for(let e=0;e<t.length;e++){const r=t[e];if(r.isSameNode(n)){return true}}return false}function nn(e){const t=e;if(t.name===""||t.name==null||t.disabled||g(t,"fieldset[disabled]")){return false}if(t.type==="button"||t.type==="submit"||t.tagName==="image"||t.tagName==="reset"||t.tagName==="file"){return false}if(t.type==="checkbox"||t.type==="radio"){return t.checked}return true}function rn(t,e,n){if(t!=null&&e!=null){if(Array.isArray(e)){e.forEach(function(e){n.append(t,e)})}else{n.append(t,e)}}}function on(t,n,r){if(t!=null&&n!=null){let e=r.getAll(t);if(Array.isArray(n)){e=e.filter(e=>n.indexOf(e)<0)}else{e=e.filter(e=>e!==n)}r.delete(t);se(e,e=>r.append(t,e))}}function sn(t,n,r,o,i){if(o==null||tn(t,o)){return}else{t.push(o)}if(nn(o)){const s=ee(o,"name");let e=o.value;if(o instanceof HTMLSelectElement&&o.multiple){e=F(o.querySelectorAll("option:checked")).map(function(e){return e.value})}if(o instanceof HTMLInputElement&&o.files){e=F(o.files)}rn(s,e,n);if(i){ln(o,r)}}if(o instanceof HTMLFormElement){se(o.elements,function(e){if(t.indexOf(e)>=0){on(e.name,e.value,n)}else{t.push(e)}if(i){ln(e,r)}});new FormData(o).forEach(function(e,t){if(e instanceof File&&e.name===""){return}rn(t,e,n)})}}function ln(e,t){const n=e;if(n.willValidate){he(n,"htmx:validation:validate");if(!n.checkValidity()){t.push({elt:n,message:n.validationMessage,validity:n.validity});he(n,"htmx:validation:failed",{message:n.validationMessage,validity:n.validity})}}}function un(t,e){for(const n of e.keys()){t.delete(n);e.getAll(n).forEach(function(e){t.append(n,e)})}return t}function cn(e,t){const n=[];const r=new FormData;const o=new FormData;const i=[];const s=ie(e);if(s.lastButtonClicked&&!le(s.lastButtonClicked)){s.lastButtonClicked=null}let l=e instanceof HTMLFormElement&&e.noValidate!==true||te(e,"hx-validate")==="true";if(s.lastButtonClicked){l=l&&s.lastButtonClicked.formNoValidate!==true}if(t!=="get"){sn(n,o,i,g(e,"form"),l)}sn(n,r,i,e,l);if(s.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){const c=s.lastButtonClicked||e;const f=ee(c,"name");rn(f,c.value,o)}const u=Se(e,"hx-include");se(u,function(e){sn(n,r,i,ce(e),l);if(!a(e,"form")){se(h(e).querySelectorAll(it),function(e){sn(n,r,i,e,l)})}});un(r,o);return{errors:i,formData:r,values:An(r)}}function fn(e,t,n){if(e!==""){e+="&"}if(String(n)==="[object Object]"){n=JSON.stringify(n)}const r=encodeURIComponent(n);e+=encodeURIComponent(t)+"="+r;return e}function an(e){e=Ln(e);let n="";e.forEach(function(e,t){n=fn(n,t,e)});return n}function hn(e,t,n){const r={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":ne().location.href};wn(e,"hx-headers",false,r);if(n!==undefined){r["HX-Prompt"]=n}if(ie(e).boosted){r["HX-Boosted"]="true"}return r}function dn(n,e){const t=re(e,"hx-params");if(t){if(t==="none"){return new FormData}else if(t==="*"){return n}else if(t.indexOf("not ")===0){se(t.substr(4).split(","),function(e){e=e.trim();n.delete(e)});return n}else{const r=new FormData;se(t.split(","),function(t){t=t.trim();if(n.has(t)){n.getAll(t).forEach(function(e){r.append(t,e)})}});return r}}else{return n}}function gn(e){return!!ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function pn(e,t){const n=t||re(e,"hx-swap");const r={swapStyle:ie(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ie(e).boosted&&!gn(e)){r.show="top"}if(n){const s=B(n);if(s.length>0){for(let e=0;e<s.length;e++){const l=s[e];if(l.indexOf("swap:")===0){r.swapDelay=d(l.substr(5))}else if(l.indexOf("settle:")===0){r.settleDelay=d(l.substr(7))}else if(l.indexOf("transition:")===0){r.transition=l.substr(11)==="true"}else if(l.indexOf("ignoreTitle:")===0){r.ignoreTitle=l.substr(12)==="true"}else if(l.indexOf("scroll:")===0){const u=l.substr(7);var o=u.split(":");const c=o.pop();var i=o.length>0?o.join(":"):null;r.scroll=c;r.scrollTarget=i}else if(l.indexOf("show:")===0){const f=l.substr(5);var o=f.split(":");const a=o.pop();var i=o.length>0?o.join(":"):null;r.show=a;r.showTarget=i}else if(l.indexOf("focus-scroll:")===0){const h=l.substr("focus-scroll:".length);r.focusScroll=h=="true"}else if(e==0){r.swapStyle=l}else{w("Unknown modifier in hx-swap: "+l)}}}}return r}function mn(e){return re(e,"hx-encoding")==="multipart/form-data"||a(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function yn(t,n,r){let o=null;Ut(n,function(e){if(o==null){o=e.encodeParameters(t,r,n)}});if(o!=null){return o}else{if(mn(n)){return un(new FormData,Ln(r))}else{return an(r)}}}function xn(e){return{tasks:[],elts:[e]}}function bn(e,t){const n=e[0];const r=e[e.length-1];if(t.scroll){var o=null;if(t.scrollTarget){o=ce(fe(n,t.scrollTarget))}if(t.scroll==="top"&&(n||o)){o=o||n;o.scrollTop=0}if(t.scroll==="bottom"&&(r||o)){o=o||r;o.scrollTop=o.scrollHeight}}if(t.show){var o=null;if(t.showTarget){let e=t.showTarget;if(t.showTarget==="window"){e="body"}o=ce(fe(n,e))}if(t.show==="top"&&(n||o)){o=o||n;o.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(r||o)){o=o||r;o.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function wn(r,e,o,i){if(i==null){i={}}if(r==null){return i}const s=te(r,e);if(s){let e=s.trim();let t=o;if(e==="unset"){return null}if(e.indexOf("javascript:")===0){e=e.substr(11);t=true}else if(e.indexOf("js:")===0){e=e.substr(3);t=true}if(e.indexOf("{")!==0){e="{"+e+"}"}let n;if(t){n=vn(r,function(){return Function("return ("+e+")")()},{})}else{n=S(e)}for(const l in n){if(n.hasOwnProperty(l)){if(i[l]==null){i[l]=n[l]}}}}return wn(ce(u(r)),e,o,i)}function vn(e,t,n){if(Q.config.allowEval){return t()}else{ae(e,"htmx:evalDisallowedError");return n}}function Sn(e,t){return wn(e,"hx-vars",true,t)}function En(e,t){return wn(e,"hx-vals",false,t)}function Cn(e){return ue(Sn(e),En(e))}function Rn(t,n,r){if(r!==null){try{t.setRequestHeader(n,r)}catch(e){t.setRequestHeader(n,encodeURIComponent(r));t.setRequestHeader(n+"-URI-AutoEncoded","true")}}}function On(t){if(t.responseURL&&typeof URL!=="undefined"){try{const e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ae(ne().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function C(e,t){return t.test(e.getAllResponseHeaders())}function Hn(e,t,n){e=e.toLowerCase();if(n){if(n instanceof Element||typeof n==="string"){return de(e,t,null,null,{targetOverride:y(n),returnPromise:true})}else{return de(e,t,y(n.source),n.event,{handler:n.handler,headers:n.headers,values:n.values,targetOverride:y(n.target),swapOverride:n.swap,select:n.select,returnPromise:true})}}else{return de(e,t,null,null,{returnPromise:true})}}function Tn(e){const t=[];while(e){t.push(e);e=e.parentElement}return t}function qn(e,t,n){let r;let o;if(typeof URL==="function"){o=new URL(t,document.location.href);const i=document.location.origin;r=i===o.origin}else{o=t;r=l(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!r){return false}}return he(e,"htmx:validateUrl",ue({url:o,sameHost:r},n))}function Ln(e){if(e instanceof FormData)return e;const t=new FormData;for(const n in e){if(e.hasOwnProperty(n)){if(typeof e[n].forEach==="function"){e[n].forEach(function(e){t.append(n,e)})}else if(typeof e[n]==="object"){t.append(n,JSON.stringify(e[n]))}else{t.append(n,e[n])}}}return t}function Nn(r,o,e){return new Proxy(e,{get:function(t,e){if(typeof e==="number")return t[e];if(e==="length")return t.length;if(e==="push"){return function(e){t.push(e);r.append(o,e)}}if(typeof t[e]==="function"){return function(){t[e].apply(t,arguments);r.delete(o);t.forEach(function(e){r.append(o,e)})}}if(t[e]&&t[e].length===1){return t[e][0]}else{return t[e]}},set:function(e,t,n){e[t]=n;r.delete(o);e.forEach(function(e){r.append(o,e)});return true}})}function An(r){return new Proxy(r,{get:function(e,t){if(typeof t==="symbol"){return Reflect.get(e,t)}if(t==="toJSON"){return()=>Object.fromEntries(r)}if(t in e){if(typeof e[t]==="function"){return function(){return r[t].apply(r,arguments)}}else{return e[t]}}const n=r.getAll(t);if(n.length===0){return undefined}else if(n.length===1){return n[0]}else{return Nn(e,t,n)}},set:function(t,n,e){if(typeof n!=="string"){return false}t.delete(n);if(typeof e.forEach==="function"){e.forEach(function(e){t.append(n,e)})}else{t.append(n,e)}return true},deleteProperty:function(e,t){if(typeof t==="string"){e.delete(t)}return true},ownKeys:function(e){return Reflect.ownKeys(Object.fromEntries(e))},getOwnPropertyDescriptor:function(e,t){return Reflect.getOwnPropertyDescriptor(Object.fromEntries(e),t)}})}function de(t,n,r,o,i,D){let s=null;let l=null;i=i!=null?i:{};if(i.returnPromise&&typeof Promise!=="undefined"){var e=new Promise(function(e,t){s=e;l=t})}if(r==null){r=ne().body}const M=i.handler||Mn;const X=i.select||null;if(!le(r)){oe(s);return e}const u=i.targetOverride||ce(Ce(r));if(u==null||u==ve){ae(r,"htmx:targetError",{target:te(r,"hx-target")});oe(l);return e}let c=ie(r);const f=c.lastButtonClicked;if(f){const L=ee(f,"formaction");if(L!=null){n=L}const N=ee(f,"formmethod");if(N!=null){if(N.toLowerCase()!=="dialog"){t=N}}}const a=re(r,"hx-confirm");if(D===undefined){const K=function(e){return de(t,n,r,o,i,!!e)};const G={target:u,elt:r,path:n,verb:t,triggeringEvent:o,etc:i,issueRequest:K,question:a};if(he(r,"htmx:confirm",G)===false){oe(s);return e}}let h=r;let d=re(r,"hx-sync");let g=null;let F=false;if(d){const A=d.split(":");const I=A[0].trim();if(I==="this"){h=Ee(r,"hx-sync")}else{h=ce(fe(r,I))}d=(A[1]||"drop").trim();c=ie(h);if(d==="drop"&&c.xhr&&c.abortable!==true){oe(s);return e}else if(d==="abort"){if(c.xhr){oe(s);return e}else{F=true}}else if(d==="replace"){he(h,"htmx:abort")}else if(d.indexOf("queue")===0){const Z=d.split(" ");g=(Z[1]||"last").trim()}}if(c.xhr){if(c.abortable){he(h,"htmx:abort")}else{if(g==null){if(o){const P=ie(o);if(P&&P.triggerSpec&&P.triggerSpec.queue){g=P.triggerSpec.queue}}if(g==null){g="last"}}if(c.queuedRequests==null){c.queuedRequests=[]}if(g==="first"&&c.queuedRequests.length===0){c.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="all"){c.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="last"){c.queuedRequests=[];c.queuedRequests.push(function(){de(t,n,r,o,i)})}oe(s);return e}}const p=new XMLHttpRequest;c.xhr=p;c.abortable=F;const m=function(){c.xhr=null;c.abortable=false;if(c.queuedRequests!=null&&c.queuedRequests.length>0){const e=c.queuedRequests.shift();e()}};const U=re(r,"hx-prompt");if(U){var y=prompt(U);if(y===null||!he(r,"htmx:prompt",{prompt:y,target:u})){oe(s);m();return e}}if(a&&!D){if(!confirm(a)){oe(s);m();return e}}let x=hn(r,u,y);if(t!=="get"&&!mn(r)){x["Content-Type"]="application/x-www-form-urlencoded"}if(i.headers){x=ue(x,i.headers)}const B=cn(r,t);let b=B.errors;const j=B.formData;if(i.values){un(j,Ln(i.values))}const V=Ln(Cn(r));const w=un(j,V);let v=dn(w,r);if(Q.config.getCacheBusterParam&&t==="get"){v.set("org.htmx.cache-buster",ee(u,"id")||"true")}if(n==null||n===""){n=ne().location.href}const S=wn(r,"hx-request");const _=ie(r).boosted;let E=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;const C={boosted:_,useUrlParams:E,formData:v,parameters:An(v),unfilteredFormData:w,unfilteredParameters:An(w),headers:x,target:u,verb:t,errors:b,withCredentials:i.credentials||S.credentials||Q.config.withCredentials,timeout:i.timeout||S.timeout||Q.config.timeout,path:n,triggeringEvent:o};if(!he(r,"htmx:configRequest",C)){oe(s);m();return e}n=C.path;t=C.verb;x=C.headers;v=Ln(C.parameters);b=C.errors;E=C.useUrlParams;if(b&&b.length>0){he(r,"htmx:validation:halted",C);oe(s);m();return e}const $=n.split("#");const z=$[0];const R=$[1];let O=n;if(E){O=z;const W=!v.keys().next().done;if(W){if(O.indexOf("?")<0){O+="?"}else{O+="&"}O+=an(v);if(R){O+="#"+R}}}if(!qn(r,O,C)){ae(r,"htmx:invalidPath",C);oe(l);return e}p.open(t.toUpperCase(),O,true);p.overrideMimeType("text/html");p.withCredentials=C.withCredentials;p.timeout=C.timeout;if(S.noHeaders){}else{for(const k in x){if(x.hasOwnProperty(k)){const Y=x[k];Rn(p,k,Y)}}}const H={xhr:p,target:u,requestConfig:C,etc:i,boosted:_,select:X,pathInfo:{requestPath:n,finalRequestPath:O,responsePath:null,anchor:R}};p.onload=function(){try{const t=Tn(r);H.pathInfo.responsePath=On(p);M(r,H);en(T,q);he(r,"htmx:afterRequest",H);he(r,"htmx:afterOnLoad",H);if(!le(r)){let e=null;while(t.length>0&&e==null){const n=t.shift();if(le(n)){e=n}}if(e){he(e,"htmx:afterRequest",H);he(e,"htmx:afterOnLoad",H)}}oe(s);m()}catch(e){ae(r,"htmx:onLoadError",ue({error:e},H));throw e}};p.onerror=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:sendError",H);oe(l);m()};p.onabort=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:sendAbort",H);oe(l);m()};p.ontimeout=function(){en(T,q);ae(r,"htmx:afterRequest",H);ae(r,"htmx:timeout",H);oe(l);m()};if(!he(r,"htmx:beforeRequest",H)){oe(s);m();return e}var T=Yt(r);var q=Qt(r);se(["loadstart","loadend","progress","abort"],function(t){se([p,p.upload],function(e){e.addEventListener(t,function(e){he(r,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});he(r,"htmx:beforeSend",H);const J=E?null:yn(p,r,v);p.send(J);return e}function In(e,t){const n=t.xhr;let r=null;let o=null;if(C(n,/HX-Push:/i)){r=n.getResponseHeader("HX-Push");o="push"}else if(C(n,/HX-Push-Url:/i)){r=n.getResponseHeader("HX-Push-Url");o="push"}else if(C(n,/HX-Replace-Url:/i)){r=n.getResponseHeader("HX-Replace-Url");o="replace"}if(r){if(r==="false"){return{}}else{return{type:o,path:r}}}const i=t.pathInfo.finalRequestPath;const s=t.pathInfo.responsePath;const l=re(e,"hx-push-url");const u=re(e,"hx-replace-url");const c=ie(e).boosted;let f=null;let a=null;if(l){f="push";a=l}else if(u){f="replace";a=u}else if(c){f="push";a=s||i}if(a){if(a==="false"){return{}}if(a==="true"){a=s||i}if(t.pathInfo.anchor&&a.indexOf("#")===-1){a=a+"#"+t.pathInfo.anchor}return{type:f,path:a}}else{return{}}}function Pn(e,t){var n=new RegExp(e.code);return n.test(t.toString(10))}function kn(e){for(var t=0;t<Q.config.responseHandling.length;t++){var n=Q.config.responseHandling[t];if(Pn(n,e.status)){return n}}return{swap:false}}function Dn(e){if(e){const t=r("title");if(t){t.innerHTML=e}else{window.document.title=e}}}function Mn(o,i){const s=i.xhr;let l=i.target;const e=i.etc;const u=i.select;if(!he(o,"htmx:beforeOnLoad",i))return;if(C(s,/HX-Trigger:/i)){Je(s,"HX-Trigger",o)}if(C(s,/HX-Location:/i)){zt();let e=s.getResponseHeader("HX-Location");var t;if(e.indexOf("{")===0){t=S(e);e=t.path;delete t.path}Hn("get",e,t).then(function(){Jt(e)});return}const n=C(s,/HX-Refresh:/i)&&s.getResponseHeader("HX-Refresh")==="true";if(C(s,/HX-Redirect:/i)){location.href=s.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(C(s,/HX-Retarget:/i)){if(s.getResponseHeader("HX-Retarget")==="this"){i.target=o}else{i.target=ce(fe(o,s.getResponseHeader("HX-Retarget")))}}const c=In(o,i);const r=kn(s);const f=r.swap;let a=!!r.error;let h=Q.config.ignoreTitle||r.ignoreTitle;let d=r.select;if(r.target){i.target=ce(fe(o,r.target))}var g=e.swapOverride;if(g==null&&r.swapOverride){g=r.swapOverride}if(C(s,/HX-Retarget:/i)){if(s.getResponseHeader("HX-Retarget")==="this"){i.target=o}else{i.target=ce(fe(o,s.getResponseHeader("HX-Retarget")))}}if(C(s,/HX-Reswap:/i)){g=s.getResponseHeader("HX-Reswap")}var p=s.response;var m=ue({shouldSwap:f,serverResponse:p,isError:a,ignoreTitle:h,selectOverride:d},i);if(r.event&&!he(l,r.event,m))return;if(!he(l,"htmx:beforeSwap",m))return;l=m.target;p=m.serverResponse;a=m.isError;h=m.ignoreTitle;d=m.selectOverride;i.target=l;i.failed=a;i.successful=!a;if(m.shouldSwap){if(s.status===286){ut(o)}Ut(o,function(e){p=e.transformResponse(p,s,o)});if(c.type){zt()}if(C(s,/HX-Reswap:/i)){g=s.getResponseHeader("HX-Reswap")}var y=pn(o,g);if(!y.hasOwnProperty("ignoreTitle")){y.ignoreTitle=h}l.classList.add(Q.config.swappingClass);let n=null;let r=null;if(u){d=u}if(C(s,/HX-Reselect:/i)){d=s.getResponseHeader("HX-Reselect")}const x=re(o,"hx-select-oob");const b=re(o,"hx-select");let e=function(){try{if(c.type){he(ne().body,"htmx:beforeHistoryUpdate",ue({history:c},i));if(c.type==="push"){Jt(c.path);he(ne().body,"htmx:pushedIntoHistory",{path:c.path})}else{Kt(c.path);he(ne().body,"htmx:replacedInHistory",{path:c.path})}}ze(l,p,y,{select:d||b,selectOOB:x,eventInfo:i,anchor:i.pathInfo.anchor,contextElement:o,afterSwapCallback:function(){if(C(s,/HX-Trigger-After-Swap:/i)){let e=o;if(!le(o)){e=ne().body}Je(s,"HX-Trigger-After-Swap",e)}},afterSettleCallback:function(){if(C(s,/HX-Trigger-After-Settle:/i)){let e=o;if(!le(o)){e=ne().body}Je(s,"HX-Trigger-After-Settle",e)}oe(n)}})}catch(e){ae(o,"htmx:swapError",i);oe(r);throw e}};let t=Q.config.globalViewTransitions;if(y.hasOwnProperty("transition")){t=y.transition}if(t&&he(o,"htmx:beforeTransition",i)&&typeof Promise!=="undefined"&&document.startViewTransition){const w=new Promise(function(e,t){n=e;r=t});const v=e;e=function(){document.startViewTransition(function(){v();return w})}}if(y.swapDelay>0){E().setTimeout(e,y.swapDelay)}else{e()}}if(a){ae(o,"htmx:responseError",ue({error:"Response Status Error Code "+s.status+" from "+i.pathInfo.requestPath},i))}}const Xn={};function Fn(){return{init:function(e){return null},getSelectors:function(){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,n){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,n,r){return false},encodeParameters:function(e,t,n){return null}}}function Un(e,t){if(t.init){t.init(n)}Xn[e]=ue(Fn(),t)}function Bn(e){delete Xn[e]}function jn(e,n,r){if(n==undefined){n=[]}if(e==undefined){return n}if(r==undefined){r=[]}const t=te(e,"hx-ext");if(t){se(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){r.push(e.slice(7));return}if(r.indexOf(e)<0){const t=Xn[e];if(t&&n.indexOf(t)<0){n.push(t)}}})}return jn(ce(u(e)),n,r)}var Vn=false;ne().addEventListener("DOMContentLoaded",function(){Vn=true});function _n(e){if(Vn||ne().readyState==="complete"){e()}else{ne().addEventListener("DOMContentLoaded",e)}}function $n(){if(Q.config.includeIndicatorStyles!==false){const e=Q.config.inlineStyleNonce?` nonce="${Q.config.inlineStyleNonce}"`:"";ne().head.insertAdjacentHTML("beforeend","<style"+e+"> ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} </style>")}}function zn(){const e=ne().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function Jn(){const e=zn();if(e){Q.config=ue(Q.config,e)}}_n(function(){Jn();$n();let e=ne().body;Dt(e);const t=ne().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){const t=e.target;const n=ie(t);if(n&&n.xhr){n.xhr.abort()}});const n=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){Wt();se(t,function(e){he(e,"htmx:restored",{document:ne(),triggerEvent:he})})}else{if(n){n(e)}}};E().setTimeout(function(){he(e,"htmx:load",{});e=null},0)});return Q}(); \ No newline at end of file From cc98bb936648d6ac33b89b241b9d86f16fbb4021 Mon Sep 17 00:00:00 2001 From: Michael Kennedy <mikeckennedy@gmail.com> Date: Mon, 2 Dec 2024 12:53:01 -0800 Subject: [PATCH 20/21] Upgrade to recent dependencies (needed for some platforms). --- .../requirements.txt | 34 ++++++++++++------- .../requirements.txt | 34 ++++++++++++------- .../requirements.txt | 34 ++++++++++++------- .../requirements.txt | 34 ++++++++++++------- .../requirements.txt | 34 ++++++++++++------- .../requirements.txt | 34 ++++++++++++------- .../requirements.txt | 34 ++++++++++++------- .../requirements.txt | 34 ++++++++++++------- code/starter_video_collector/requirements.txt | 34 ++++++++++++------- requirements.txt | 14 ++++---- 10 files changed, 196 insertions(+), 124 deletions(-) diff --git a/code/ch4_app/ch4_final_video_collector/requirements.txt b/code/ch4_app/ch4_final_video_collector/requirements.txt index 19fcb66..556ab29 100644 --- a/code/ch4_app/ch4_final_video_collector/requirements.txt +++ b/code/ch4_app/ch4_final_video_collector/requirements.txt @@ -1,27 +1,35 @@ # This file was autogenerated by uv via the following command: # uv pip compile requirements.piptools --output-file requirements.txt -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -blinker==1.7.0 +blinker==1.9.0 # via flask click==8.1.7 # via flask -flask==3.0.2 -itsdangerous==2.1.2 +flask==3.1.0 + # via -r requirements.piptools +itsdangerous==2.2.0 # via flask -jinja2==3.1.3 - # via flask -markupsafe==2.1.5 +jinja2==3.1.4 + # via + # -r requirements.piptools + # flask +markupsafe==3.0.2 # via + # -r requirements.piptools # jinja2 # werkzeug -more-itertools==10.2.0 -pydantic==2.6.3 -pydantic-core==2.16.3 +more-itertools==10.5.0 + # via -r requirements.piptools +pydantic==2.10.2 + # via -r requirements.piptools +pydantic-core==2.27.1 # via pydantic -typing-extensions==4.10.0 +typing-extensions==4.12.2 # via # pydantic # pydantic-core -werkzeug==3.0.1 - # via flask +werkzeug==3.1.3 + # via + # -r requirements.piptools + # flask diff --git a/code/ch4_app/ch4_starter_video_collector/requirements.txt b/code/ch4_app/ch4_starter_video_collector/requirements.txt index 19fcb66..556ab29 100644 --- a/code/ch4_app/ch4_starter_video_collector/requirements.txt +++ b/code/ch4_app/ch4_starter_video_collector/requirements.txt @@ -1,27 +1,35 @@ # This file was autogenerated by uv via the following command: # uv pip compile requirements.piptools --output-file requirements.txt -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -blinker==1.7.0 +blinker==1.9.0 # via flask click==8.1.7 # via flask -flask==3.0.2 -itsdangerous==2.1.2 +flask==3.1.0 + # via -r requirements.piptools +itsdangerous==2.2.0 # via flask -jinja2==3.1.3 - # via flask -markupsafe==2.1.5 +jinja2==3.1.4 + # via + # -r requirements.piptools + # flask +markupsafe==3.0.2 # via + # -r requirements.piptools # jinja2 # werkzeug -more-itertools==10.2.0 -pydantic==2.6.3 -pydantic-core==2.16.3 +more-itertools==10.5.0 + # via -r requirements.piptools +pydantic==2.10.2 + # via -r requirements.piptools +pydantic-core==2.27.1 # via pydantic -typing-extensions==4.10.0 +typing-extensions==4.12.2 # via # pydantic # pydantic-core -werkzeug==3.0.1 - # via flask +werkzeug==3.1.3 + # via + # -r requirements.piptools + # flask diff --git a/code/ch5_partials/ch5_final_video_collector/requirements.txt b/code/ch5_partials/ch5_final_video_collector/requirements.txt index 959604b..0995500 100644 --- a/code/ch5_partials/ch5_final_video_collector/requirements.txt +++ b/code/ch5_partials/ch5_final_video_collector/requirements.txt @@ -1,30 +1,38 @@ # This file was autogenerated by uv via the following command: # uv pip compile requirements.piptools --output-file requirements.txt -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -blinker==1.7.0 +blinker==1.9.0 # via flask click==8.1.7 # via flask -flask==3.0.2 -itsdangerous==2.1.2 +flask==3.1.0 + # via -r requirements.piptools +itsdangerous==2.2.0 # via flask -jinja-partials==0.2.0 -jinja2==3.1.3 +jinja-partials==0.2.1 + # via -r requirements.piptools +jinja2==3.1.4 # via + # -r requirements.piptools # flask # jinja-partials -markupsafe==2.1.5 +markupsafe==3.0.2 # via + # -r requirements.piptools # jinja2 # werkzeug -more-itertools==10.2.0 -pydantic==2.6.3 -pydantic-core==2.16.3 +more-itertools==10.5.0 + # via -r requirements.piptools +pydantic==2.10.2 + # via -r requirements.piptools +pydantic-core==2.27.1 # via pydantic -typing-extensions==4.10.0 +typing-extensions==4.12.2 # via # pydantic # pydantic-core -werkzeug==3.0.1 - # via flask +werkzeug==3.1.3 + # via + # -r requirements.piptools + # flask diff --git a/code/ch5_partials/ch5_starter_video_collector/requirements.txt b/code/ch5_partials/ch5_starter_video_collector/requirements.txt index 19fcb66..556ab29 100644 --- a/code/ch5_partials/ch5_starter_video_collector/requirements.txt +++ b/code/ch5_partials/ch5_starter_video_collector/requirements.txt @@ -1,27 +1,35 @@ # This file was autogenerated by uv via the following command: # uv pip compile requirements.piptools --output-file requirements.txt -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -blinker==1.7.0 +blinker==1.9.0 # via flask click==8.1.7 # via flask -flask==3.0.2 -itsdangerous==2.1.2 +flask==3.1.0 + # via -r requirements.piptools +itsdangerous==2.2.0 # via flask -jinja2==3.1.3 - # via flask -markupsafe==2.1.5 +jinja2==3.1.4 + # via + # -r requirements.piptools + # flask +markupsafe==3.0.2 # via + # -r requirements.piptools # jinja2 # werkzeug -more-itertools==10.2.0 -pydantic==2.6.3 -pydantic-core==2.16.3 +more-itertools==10.5.0 + # via -r requirements.piptools +pydantic==2.10.2 + # via -r requirements.piptools +pydantic-core==2.27.1 # via pydantic -typing-extensions==4.10.0 +typing-extensions==4.12.2 # via # pydantic # pydantic-core -werkzeug==3.0.1 - # via flask +werkzeug==3.1.3 + # via + # -r requirements.piptools + # flask diff --git a/code/ch6_active_search/ch6_final_video_collector/requirements.txt b/code/ch6_active_search/ch6_final_video_collector/requirements.txt index 959604b..0995500 100644 --- a/code/ch6_active_search/ch6_final_video_collector/requirements.txt +++ b/code/ch6_active_search/ch6_final_video_collector/requirements.txt @@ -1,30 +1,38 @@ # This file was autogenerated by uv via the following command: # uv pip compile requirements.piptools --output-file requirements.txt -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -blinker==1.7.0 +blinker==1.9.0 # via flask click==8.1.7 # via flask -flask==3.0.2 -itsdangerous==2.1.2 +flask==3.1.0 + # via -r requirements.piptools +itsdangerous==2.2.0 # via flask -jinja-partials==0.2.0 -jinja2==3.1.3 +jinja-partials==0.2.1 + # via -r requirements.piptools +jinja2==3.1.4 # via + # -r requirements.piptools # flask # jinja-partials -markupsafe==2.1.5 +markupsafe==3.0.2 # via + # -r requirements.piptools # jinja2 # werkzeug -more-itertools==10.2.0 -pydantic==2.6.3 -pydantic-core==2.16.3 +more-itertools==10.5.0 + # via -r requirements.piptools +pydantic==2.10.2 + # via -r requirements.piptools +pydantic-core==2.27.1 # via pydantic -typing-extensions==4.10.0 +typing-extensions==4.12.2 # via # pydantic # pydantic-core -werkzeug==3.0.1 - # via flask +werkzeug==3.1.3 + # via + # -r requirements.piptools + # flask diff --git a/code/ch6_active_search/ch6_starter_video_collector/requirements.txt b/code/ch6_active_search/ch6_starter_video_collector/requirements.txt index 959604b..0995500 100644 --- a/code/ch6_active_search/ch6_starter_video_collector/requirements.txt +++ b/code/ch6_active_search/ch6_starter_video_collector/requirements.txt @@ -1,30 +1,38 @@ # This file was autogenerated by uv via the following command: # uv pip compile requirements.piptools --output-file requirements.txt -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -blinker==1.7.0 +blinker==1.9.0 # via flask click==8.1.7 # via flask -flask==3.0.2 -itsdangerous==2.1.2 +flask==3.1.0 + # via -r requirements.piptools +itsdangerous==2.2.0 # via flask -jinja-partials==0.2.0 -jinja2==3.1.3 +jinja-partials==0.2.1 + # via -r requirements.piptools +jinja2==3.1.4 # via + # -r requirements.piptools # flask # jinja-partials -markupsafe==2.1.5 +markupsafe==3.0.2 # via + # -r requirements.piptools # jinja2 # werkzeug -more-itertools==10.2.0 -pydantic==2.6.3 -pydantic-core==2.16.3 +more-itertools==10.5.0 + # via -r requirements.piptools +pydantic==2.10.2 + # via -r requirements.piptools +pydantic-core==2.27.1 # via pydantic -typing-extensions==4.10.0 +typing-extensions==4.12.2 # via # pydantic # pydantic-core -werkzeug==3.0.1 - # via flask +werkzeug==3.1.3 + # via + # -r requirements.piptools + # flask diff --git a/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt b/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt index 959604b..0995500 100644 --- a/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt +++ b/code/ch7_infinite_scroll/ch7_final_video_collector/requirements.txt @@ -1,30 +1,38 @@ # This file was autogenerated by uv via the following command: # uv pip compile requirements.piptools --output-file requirements.txt -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -blinker==1.7.0 +blinker==1.9.0 # via flask click==8.1.7 # via flask -flask==3.0.2 -itsdangerous==2.1.2 +flask==3.1.0 + # via -r requirements.piptools +itsdangerous==2.2.0 # via flask -jinja-partials==0.2.0 -jinja2==3.1.3 +jinja-partials==0.2.1 + # via -r requirements.piptools +jinja2==3.1.4 # via + # -r requirements.piptools # flask # jinja-partials -markupsafe==2.1.5 +markupsafe==3.0.2 # via + # -r requirements.piptools # jinja2 # werkzeug -more-itertools==10.2.0 -pydantic==2.6.3 -pydantic-core==2.16.3 +more-itertools==10.5.0 + # via -r requirements.piptools +pydantic==2.10.2 + # via -r requirements.piptools +pydantic-core==2.27.1 # via pydantic -typing-extensions==4.10.0 +typing-extensions==4.12.2 # via # pydantic # pydantic-core -werkzeug==3.0.1 - # via flask +werkzeug==3.1.3 + # via + # -r requirements.piptools + # flask diff --git a/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt b/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt index 959604b..0995500 100644 --- a/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt +++ b/code/ch7_infinite_scroll/ch7_starter_video_collector/requirements.txt @@ -1,30 +1,38 @@ # This file was autogenerated by uv via the following command: # uv pip compile requirements.piptools --output-file requirements.txt -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -blinker==1.7.0 +blinker==1.9.0 # via flask click==8.1.7 # via flask -flask==3.0.2 -itsdangerous==2.1.2 +flask==3.1.0 + # via -r requirements.piptools +itsdangerous==2.2.0 # via flask -jinja-partials==0.2.0 -jinja2==3.1.3 +jinja-partials==0.2.1 + # via -r requirements.piptools +jinja2==3.1.4 # via + # -r requirements.piptools # flask # jinja-partials -markupsafe==2.1.5 +markupsafe==3.0.2 # via + # -r requirements.piptools # jinja2 # werkzeug -more-itertools==10.2.0 -pydantic==2.6.3 -pydantic-core==2.16.3 +more-itertools==10.5.0 + # via -r requirements.piptools +pydantic==2.10.2 + # via -r requirements.piptools +pydantic-core==2.27.1 # via pydantic -typing-extensions==4.10.0 +typing-extensions==4.12.2 # via # pydantic # pydantic-core -werkzeug==3.0.1 - # via flask +werkzeug==3.1.3 + # via + # -r requirements.piptools + # flask diff --git a/code/starter_video_collector/requirements.txt b/code/starter_video_collector/requirements.txt index 19fcb66..556ab29 100644 --- a/code/starter_video_collector/requirements.txt +++ b/code/starter_video_collector/requirements.txt @@ -1,27 +1,35 @@ # This file was autogenerated by uv via the following command: # uv pip compile requirements.piptools --output-file requirements.txt -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -blinker==1.7.0 +blinker==1.9.0 # via flask click==8.1.7 # via flask -flask==3.0.2 -itsdangerous==2.1.2 +flask==3.1.0 + # via -r requirements.piptools +itsdangerous==2.2.0 # via flask -jinja2==3.1.3 - # via flask -markupsafe==2.1.5 +jinja2==3.1.4 + # via + # -r requirements.piptools + # flask +markupsafe==3.0.2 # via + # -r requirements.piptools # jinja2 # werkzeug -more-itertools==10.2.0 -pydantic==2.6.3 -pydantic-core==2.16.3 +more-itertools==10.5.0 + # via -r requirements.piptools +pydantic==2.10.2 + # via -r requirements.piptools +pydantic-core==2.27.1 # via pydantic -typing-extensions==4.10.0 +typing-extensions==4.12.2 # via # pydantic # pydantic-core -werkzeug==3.0.1 - # via flask +werkzeug==3.1.3 + # via + # -r requirements.piptools + # flask diff --git a/requirements.txt b/requirements.txt index 7c7d2f7..0995500 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,11 +2,11 @@ # uv pip compile requirements.piptools --output-file requirements.txt annotated-types==0.7.0 # via pydantic -blinker==1.8.2 +blinker==1.9.0 # via flask click==8.1.7 # via flask -flask==3.0.3 +flask==3.1.0 # via -r requirements.piptools itsdangerous==2.2.0 # via flask @@ -17,22 +17,22 @@ jinja2==3.1.4 # -r requirements.piptools # flask # jinja-partials -markupsafe==2.1.5 +markupsafe==3.0.2 # via # -r requirements.piptools # jinja2 # werkzeug -more-itertools==10.3.0 +more-itertools==10.5.0 # via -r requirements.piptools -pydantic==2.8.0 +pydantic==2.10.2 # via -r requirements.piptools -pydantic-core==2.20.0 +pydantic-core==2.27.1 # via pydantic typing-extensions==4.12.2 # via # pydantic # pydantic-core -werkzeug==3.0.3 +werkzeug==3.1.3 # via # -r requirements.piptools # flask From a5fefba524060528a12f353ee0f99d53091df6d9 Mon Sep 17 00:00:00 2001 From: Michael Kennedy <mikeckennedy@gmail.com> Date: Sat, 7 Dec 2024 09:14:58 -0800 Subject: [PATCH 21/21] Update to latest pydantic. --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 0995500..672ed8b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,7 +24,7 @@ markupsafe==3.0.2 # werkzeug more-itertools==10.5.0 # via -r requirements.piptools -pydantic==2.10.2 +pydantic==2.10.3 # via -r requirements.piptools pydantic-core==2.27.1 # via pydantic