diff --git a/cli/runner.go b/cli/runner.go
index 3e226b2..05c408e 100644
--- a/cli/runner.go
+++ b/cli/runner.go
@@ -5,6 +5,7 @@ import (
"flag"
"fmt"
"github.com/maddalax/htmgo/cli/tasks/astgen"
+ "github.com/maddalax/htmgo/cli/tasks/copyassets"
"github.com/maddalax/htmgo/cli/tasks/css"
"github.com/maddalax/htmgo/cli/tasks/downloadtemplate"
"github.com/maddalax/htmgo/cli/tasks/process"
@@ -56,6 +57,7 @@ func main() {
if taskName == "watch" {
os.Setenv("ENV", "development")
os.Setenv("WATCH_MODE", "true")
+ copyassets.CopyAssets()
astgen.GenAst(true)
css.GenerateCss(true)
run.EntGenerate()
diff --git a/cli/tasks/astgen/entry.go b/cli/tasks/astgen/entry.go
index 5e4e7c4..0653d9b 100644
--- a/cli/tasks/astgen/entry.go
+++ b/cli/tasks/astgen/entry.go
@@ -210,7 +210,7 @@ func buildGetPartialFromContext(builder *CodeBuilder, partials []Partial) {
f := Function{
Name: fName,
Parameters: []NameType{
- {Name: "ctx", Type: "*fiber.Ctx"},
+ {Name: "ctx", Type: "echo.Context"},
},
Return: []ReturnType{
{Type: "*h.Partial"},
@@ -221,11 +221,11 @@ func buildGetPartialFromContext(builder *CodeBuilder, partials []Partial) {
builder.Append(builder.BuildFunction(f))
registerFunction := fmt.Sprintf(`
- func RegisterPartials(f *fiber.App) {
- f.All("%s/partials*", func(ctx *fiber.Ctx) error {
+ func RegisterPartials(f *echo.Echo) {
+ f.Any("%s/partials*", func(ctx echo.Context) error {
partial := GetPartialFromContext(ctx)
if partial == nil {
- return ctx.SendStatus(404)
+ return ctx.NoContent(404)
}
return h.PartialView(ctx, partial)
})
@@ -252,7 +252,7 @@ func writePartialsFile() {
builder.AppendLine(`// Package partials THIS FILE IS GENERATED. DO NOT EDIT.`)
builder.AppendLine("package load")
builder.AddImport("github.com/maddalax/htmgo/framework/h")
- builder.AddImport("github.com/gofiber/fiber/v2")
+ builder.AddImport("github.com/labstack/echo/v4")
moduleName := GetModuleName()
for _, partial := range partials {
@@ -293,7 +293,7 @@ func writePagesFile() {
builder := NewCodeBuilder(nil)
builder.AppendLine(`// Package pages THIS FILE IS GENERATED. DO NOT EDIT.`)
builder.AppendLine("package pages")
- builder.AddImport("github.com/gofiber/fiber/v2")
+ builder.AddImport("github.com/labstack/echo/v4")
builder.AddImport("github.com/maddalax/htmgo/framework/h")
pages, _ := findPublicFuncsReturningHPage("pages")
@@ -319,7 +319,7 @@ func writePagesFile() {
}
body += fmt.Sprintf(`
- f.Get("%s", func(ctx *fiber.Ctx) error {
+ f.GET("%s", func(ctx echo.Context) error {
return h.HtmlView(ctx, %s(ctx))
})
`, formatRoute(page.Path), call)
@@ -328,7 +328,7 @@ func writePagesFile() {
f := Function{
Name: fName,
Parameters: []NameType{
- {Name: "f", Type: "*fiber.App"},
+ {Name: "f", Type: "*echo.Echo"},
},
Body: body,
}
diff --git a/cli/tasks/copyassets/bundle.go b/cli/tasks/copyassets/bundle.go
index f1ff820..bb91a81 100644
--- a/cli/tasks/copyassets/bundle.go
+++ b/cli/tasks/copyassets/bundle.go
@@ -2,12 +2,14 @@ package copyassets
import (
"fmt"
+ "github.com/maddalax/htmgo/cli/tasks/module"
"github.com/maddalax/htmgo/cli/tasks/process"
"golang.org/x/mod/modfile"
"io"
"log"
"os"
"path/filepath"
+ "strings"
)
func getModuleVersion(modulePath string) (string, error) {
@@ -85,17 +87,25 @@ func copyDir(srcDir, dstDir string) error {
}
func CopyAssets() {
- modulePath := "github.com/maddalax/htmgo/framework"
- version, err := getModuleVersion(modulePath)
- if err != nil {
- log.Fatalf("Error: %v", err)
- }
- dirname, err := os.UserHomeDir()
- if err != nil {
- log.Fatal(err)
+ moduleName := "github.com/maddalax/htmgo/framework"
+ modulePath := module.GetDependencyPath(moduleName)
+
+ assetDir := ""
+ // Is hosted version and not local version from .work file
+ if strings.HasPrefix(modulePath, "github.com/") {
+ version, err := getModuleVersion(modulePath)
+ if err != nil {
+ log.Fatalf("Error: %v", err)
+ }
+ dirname, err := os.UserHomeDir()
+ if err != nil {
+ log.Fatal(err)
+ }
+ assetDir = fmt.Sprintf("%s/go/pkg/mod/%s@%s/assets", dirname, modulePath, version)
+ } else {
+ assetDir = fmt.Sprintf("%s/assets", modulePath)
}
- assetDir := fmt.Sprintf("%s/go/pkg/mod/%s@%s/assets", dirname, modulePath, version)
assetDistDir := fmt.Sprintf("%s/dist", assetDir)
assetCssDir := fmt.Sprintf("%s/css", assetDir)
@@ -105,7 +115,7 @@ func CopyAssets() {
destDirDist := fmt.Sprintf("%s/dist", destDir)
destDirCss := fmt.Sprintf("%s/css", destDir)
- err = copyDir(assetDistDir, destDirDist)
+ err := copyDir(assetDistDir, destDirDist)
err = copyDir(assetCssDir, destDirCss)
if err != nil {
diff --git a/cli/tasks/module/module.go b/cli/tasks/module/module.go
new file mode 100644
index 0000000..5476cf5
--- /dev/null
+++ b/cli/tasks/module/module.go
@@ -0,0 +1,23 @@
+package module
+
+import (
+ "fmt"
+ "os/exec"
+ "strings"
+)
+
+func GetDependencyPath(dep string) string {
+ cmd := exec.Command("go", "list", "-m", "-f", "{{.Dir}}", dep)
+ // Run the command and capture the output
+ output, err := cmd.CombinedOutput() // Use CombinedOutput to capture both stdout and stderr
+ if err != nil {
+ fmt.Printf("Command execution failed: %v\n", err)
+ }
+
+ // Convert output to string
+ dir := strings.TrimSuffix(string(output), "\n")
+ if strings.Contains(dir, "not a known dependency") {
+ return dep
+ }
+ return dir
+}
diff --git a/cli/tasks/process/process.go b/cli/tasks/process/process.go
index 1f2f2f5..8a0dbdd 100644
--- a/cli/tasks/process/process.go
+++ b/cli/tasks/process/process.go
@@ -161,13 +161,14 @@ func Run(command string, exitOnError bool) error {
return nil
}
+ if strings.Contains(err.Error(), "signal: killed") {
+ return nil
+ }
+
if exitOnError {
log.Println(fmt.Sprintf("error: %v", err))
os.Exit(1)
}
- if strings.Contains(err.Error(), "signal: killed") {
- return nil
- }
return err
}
diff --git a/framework-ui/go.mod b/framework-ui/go.mod
index 7bfc2d7..85c0e93 100644
--- a/framework-ui/go.mod
+++ b/framework-ui/go.mod
@@ -4,7 +4,6 @@ go 1.23.0
require (
github.com/andybalholm/brotli v1.0.5 // indirect
- github.com/gofiber/fiber/v2 v2.52.5 // indirect
github.com/google/uuid v1.5.0 // indirect
github.com/klauspost/compress v1.17.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
diff --git a/framework/assets/dist/htmgo.js b/framework/assets/dist/htmgo.js
index cae5083..129b9ec 100644
--- a/framework/assets/dist/htmgo.js
+++ b/framework/assets/dist/htmgo.js
@@ -1 +1 @@
-var $=function(){let htmx={onLoad:null,process:null,on:null,off:null,trigger:null,ajax:null,find:null,findAll:null,closest:null,values:function(e,t){return getInputValues(e,t||"post").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:!0,historyCacheSize:10,refreshOnHistoryMiss:!1,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:!0,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:!0,allowScriptTags:!0,inlineScriptNonce:"",inlineStyleNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:!1,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",scrollBehavior:"instant",defaultFocusScroll:!1,getCacheBusterParam:!1,globalViewTransitions:!1,methodsThatUseUrlParams:["get","delete"],selfRequestsOnly:!0,ignoreTitle:!1,scrollIntoViewOnBoost:!0,triggerSpecsCache:null,disableInheritance:!1,responseHandling:[{code:"204",swap:!1},{code:"[23]..",swap:!0},{code:"[45]..",swap:!1,error:!0}],allowNestedOobSwaps:!0},parseInterval:null,_:null,version:"2.0.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;let 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},VERBS=["get","post","put","delete","patch"],VERB_SELECTOR=VERBS.map(function(e){return "[hx-"+e+"], [data-hx-"+e+"]"}).join(", "),HEAD_TAG_REGEX=makeTagRegEx("head");function makeTagRegEx(e,t=!1){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function parseInterval(e){if(e==null)return;let t=NaN;return e.slice(-2)=="ms"?t=parseFloat(e.slice(0,-2)):e.slice(-1)=="s"?t=parseFloat(e.slice(0,-1))*1e3:e.slice(-1)=="m"?t=parseFloat(e.slice(0,-1))*1e3*60:t=parseFloat(e),isNaN(t)?void 0:t}function getRawAttribute(e,t){return e instanceof Element&&e.getAttribute(t)}function hasAttribute(e,t){return !!e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function getAttributeValue(e,t){return getRawAttribute(e,t)||getRawAttribute(e,"data-"+t)}function parentElt(e){let t=e.parentElement;return !t&&e.parentNode instanceof ShadowRoot?e.parentNode:t}function getDocument(){return document}function getRootNode(e,t){return e.getRootNode?e.getRootNode({composed:t}):getDocument()}function getClosestMatch(e,t){for(;e&&!t(e);)e=parentElt(e);return e||null}function getAttributeValueWithDisinheritance(e,t,n){let r=getAttributeValue(t,n),o=getAttributeValue(t,"hx-disinherit");var i=getAttributeValue(t,"hx-inherit");if(e!==t){if(htmx.config.disableInheritance)return i&&(i==="*"||i.split(" ").indexOf(n)>=0)?r:null;if(o&&(o==="*"||o.split(" ").indexOf(n)>=0))return "unset"}return r}function getClosestAttributeValue(e,t){let n=null;if(getClosestMatch(e,function(r){return !!(n=getAttributeValueWithDisinheritance(e,asElement(r),t))}),n!=="unset")return n}function matches(e,t){let n=e instanceof Element&&(e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector);return !!n&&n.call(e,t)}function getStartTag(e){let n=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i.exec(e);return n?n[1].toLowerCase():""}function parseHTML(e){return new DOMParser().parseFromString(e,"text/html")}function takeChildrenFor(e,t){for(;t.childNodes.length>0;)e.append(t.childNodes[0]);}function duplicateScript(e){let t=getDocument().createElement("script");return forEach(e.attributes,function(n){t.setAttribute(n.name,n.value);}),t.textContent=e.textContent,t.async=!1,htmx.config.inlineScriptNonce&&(t.nonce=htmx.config.inlineScriptNonce),t}function isJavaScriptScriptNode(e){return e.matches("script")&&(e.type==="text/javascript"||e.type==="module"||e.type==="")}function normalizeScriptTags(e){Array.from(e.querySelectorAll("script")).forEach(t=>{if(isJavaScriptScriptNode(t)){let n=duplicateScript(t),r=t.parentNode;try{r.insertBefore(n,t);}catch(o){logError(o);}finally{t.remove();}}});}function makeFragment(e){let t=e.replace(HEAD_TAG_REGEX,""),n=getStartTag(t),r;if(n==="html"){r=new DocumentFragment;let i=parseHTML(e);takeChildrenFor(r,i.body),r.title=i.title;}else if(n==="body"){r=new DocumentFragment;let i=parseHTML(t);takeChildrenFor(r,i.body),r.title=i.title;}else {let i=parseHTML('
'+t+"");r=i.querySelector("template").content,r.title=i.title;var o=r.querySelector("title");o&&o.parentNode===r&&(o.remove(),r.title=o.innerText);}return r&&(htmx.config.allowScriptTags?normalizeScriptTags(r):r.querySelectorAll("script").forEach(i=>i.remove())),r}function maybeCall(e){e&&e();}function isType(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function isFunction(e){return typeof e=="function"}function isRawObject(e){return isType(e,"Object")}function getInternalData(e){let t="htmx-internal-data",n=e[t];return n||(n=e[t]={}),n}function toArray(e){let t=[];if(e)for(let n=0;n=0}function bodyContains(e){let t=e.getRootNode&&e.getRootNode();return t&&t instanceof window.ShadowRoot?getDocument().body.contains(t.host):getDocument().body.contains(e)}function splitOnWhitespace(e){return e.trim().split(/\s+/)}function mergeObjects(e,t){for(let n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e}function parseJSON(e){try{return JSON.parse(e)}catch(t){return logError(t),null}}function canAccessLocalStorage(){let e="htmx:localStorageTest";try{return localStorage.setItem(e,e),localStorage.removeItem(e),!0}catch{return !1}}function normalizePath(e){try{let t=new URL(e);return t&&(e=t.pathname+t.search),/^\/$/.test(e)||(e=e.replace(/\/+$/,"")),e}catch{return e}}function internalEval(str){return maybeEval(getDocument().body,function(){return eval(str)})}function onLoadHelper(e){return htmx.on("htmx:load",function(n){e(n.detail.elt);})}function logAll(){htmx.logger=function(e,t,n){console&&console.log(t,e,n);};}function logNone(){htmx.logger=null;}function find(e,t){return typeof e!="string"?e.querySelector(t):find(getDocument(),e)}function findAll(e,t){return typeof e!="string"?e.querySelectorAll(t):findAll(getDocument(),e)}function getWindow(){return window}function removeElement(e,t){e=resolveTarget(e),t?getWindow().setTimeout(function(){removeElement(e),e=null;},t):parentElt(e).removeChild(e);}function asElement(e){return e instanceof Element?e:null}function asHtmlElement(e){return e instanceof HTMLElement?e:null}function asString(e){return typeof e=="string"?e:null}function asParentNode(e){return e instanceof Element||e instanceof Document||e instanceof DocumentFragment?e:null}function addClassToElement(e,t,n){e=asElement(resolveTarget(e)),e&&(n?getWindow().setTimeout(function(){addClassToElement(e,t),e=null;},n):e.classList&&e.classList.add(t));}function removeClassFromElement(e,t,n){let r=asElement(resolveTarget(e));r&&(n?getWindow().setTimeout(function(){removeClassFromElement(r,t),r=null;},n):r.classList&&(r.classList.remove(t),r.classList.length===0&&r.removeAttribute("class")));}function toggleClassOnElement(e,t){e=resolveTarget(e),e.classList.toggle(t);}function takeClassForElement(e,t){e=resolveTarget(e),forEach(e.parentElement.children,function(n){removeClassFromElement(n,t);}),addClassToElement(asElement(e),t);}function closest(e,t){if(e=asElement(resolveTarget(e)),e&&e.closest)return e.closest(t);do if(e==null||matches(e,t))return e;while(e=e&&asElement(parentElt(e)));return null}function startsWith(e,t){return e.substring(0,t.length)===t}function endsWith(e,t){return e.substring(e.length-t.length)===t}function normalizeSelector(e){let t=e.trim();return startsWith(t,"<")&&endsWith(t,"/>")?t.substring(1,t.length-2):t}function querySelectorAllExt(e,t,n){return e=resolveTarget(e),t.indexOf("closest ")===0?[closest(asElement(e),normalizeSelector(t.substr(8)))]:t.indexOf("find ")===0?[find(asParentNode(e),normalizeSelector(t.substr(5)))]:t==="next"?[asElement(e).nextElementSibling]:t.indexOf("next ")===0?[scanForwardQuery(e,normalizeSelector(t.substr(5)),!!n)]:t==="previous"?[asElement(e).previousElementSibling]:t.indexOf("previous ")===0?[scanBackwardsQuery(e,normalizeSelector(t.substr(9)),!!n)]:t==="document"?[document]:t==="window"?[window]:t==="body"?[document.body]:t==="root"?[getRootNode(e,!!n)]:t.indexOf("global ")===0?querySelectorAllExt(e,t.slice(7),!0):toArray(asParentNode(getRootNode(e,!!n)).querySelectorAll(normalizeSelector(t)))}var scanForwardQuery=function(e,t,n){let r=asParentNode(getRootNode(e,n)).querySelectorAll(t);for(let o=0;o=0;o--){let i=r[o];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING)return i}};function querySelectorExt(e,t){return typeof e!="string"?querySelectorAllExt(e,t)[0]:querySelectorAllExt(getDocument().body,e)[0]}function resolveTarget(e,t){return typeof e=="string"?find(asParentNode(t)||document,e):e}function processEventArgs(e,t,n){return isFunction(t)?{target:getDocument().body,event:asString(e),listener:t}:{target:resolveTarget(e),event:asString(t),listener:n}}function addEventListenerImpl(e,t,n){return ready(function(){let o=processEventArgs(e,t,n);o.target.addEventListener(o.event,o.listener);}),isFunction(t)?t:n}function removeEventListenerImpl(e,t,n){return ready(function(){let r=processEventArgs(e,t,n);r.target.removeEventListener(r.event,r.listener);}),isFunction(t)?t:n}let DUMMY_ELT=getDocument().createElement("output");function findAttributeTargets(e,t){let n=getClosestAttributeValue(e,t);if(n){if(n==="this")return [findThisElement(e,t)];{let r=querySelectorAllExt(e,n);return r.length===0?(logError('The selector "'+n+'" on '+t+" returned no matches!"),[DUMMY_ELT]):r}}}function findThisElement(e,t){return asElement(getClosestMatch(e,function(n){return getAttributeValue(asElement(n),t)!=null}))}function getTarget(e){let t=getClosestAttributeValue(e,"hx-target");return t?t==="this"?findThisElement(e,"hx-target"):querySelectorExt(e,t):getInternalData(e).boosted?getDocument().body:e}function shouldSettleAttribute(e){let t=htmx.config.attributesToSettle;for(let n=0;n0?(o=e.substr(0,e.indexOf(":")),r=e.substr(e.indexOf(":")+1,e.length)):o=e);let i=getDocument().querySelectorAll(r);return i?(forEach(i,function(s){let l,a=t.cloneNode(!0);l=getDocument().createDocumentFragment(),l.appendChild(a),isInlineSwap(o,s)||(l=asParentNode(a));let u={shouldSwap:!0,target:s,fragment:l};triggerEvent(s,"htmx:oobBeforeSwap",u)&&(s=u.target,u.shouldSwap&&swapWithStyle(o,s,s,l,n),forEach(n.elts,function(f){triggerEvent(f,"htmx:oobAfterSwap",u);}));}),t.parentNode.removeChild(t)):(t.parentNode.removeChild(t),triggerErrorEvent(getDocument().body,"htmx:oobErrorNoTarget",{content:t})),e}function handlePreservedElements(e){forEach(findAll(e,"[hx-preserve], [data-hx-preserve]"),function(t){let n=getAttributeValue(t,"id"),r=getDocument().getElementById(n);r!=null&&t.parentNode.replaceChild(r,t);});}function handleAttributes(e,t,n){forEach(t.querySelectorAll("[id]"),function(r){let o=getRawAttribute(r,"id");if(o&&o.length>0){let i=o.replace("'","\\'"),s=r.tagName.replace(":","\\:"),l=asParentNode(e),a=l&&l.querySelector(s+"[id='"+i+"']");if(a&&a!==l){let u=r.cloneNode();cloneAttributes(r,a),n.tasks.push(function(){cloneAttributes(r,u);});}}});}function makeAjaxLoadTask(e){return function(){removeClassFromElement(e,htmx.config.addedClass),processNode(asElement(e)),processFocus(asParentNode(e)),triggerEvent(e,"htmx:load");}}function processFocus(e){let t="[autofocus]",n=asHtmlElement(matches(e,t)?e:e.querySelector(t));n?.focus();}function insertNodesBefore(e,t,n,r){for(handleAttributes(e,n,r);n.childNodes.length>0;){let o=n.firstChild;addClassToElement(asElement(o),htmx.config.addedClass),e.insertBefore(o,t),o.nodeType!==Node.TEXT_NODE&&o.nodeType!==Node.COMMENT_NODE&&r.tasks.push(makeAjaxLoadTask(o));}}function stringHash(e,t){let n=0;for(;n0}function swap(e,t,n,r){r||(r={}),e=resolveTarget(e);let o=document.activeElement,i={};try{i={elt:o,start:o?o.selectionStart:null,end:o?o.selectionEnd:null};}catch{}let s=makeSettleInfo(e);if(n.swapStyle==="textContent")e.textContent=t;else {let a=makeFragment(t);if(s.title=a.title,r.selectOOB){let u=r.selectOOB.split(",");for(let f=0;f0?getWindow().setTimeout(l,n.settleDelay):l();}function handleTriggerHeader(e,t,n){let r=e.getResponseHeader(t);if(r.indexOf("{")===0){let o=parseJSON(r);for(let i in o)if(o.hasOwnProperty(i)){let s=o[i];isRawObject(s)?n=s.target!==void 0?s.target:n:s={value:s},triggerEvent(n,i,s);}}else {let o=r.split(",");for(let i=0;i0;){let s=t[0];if(s==="]"){if(r--,r===0){i===null&&(o=o+"true"),t.shift(),o+=")})";try{let l=maybeEval(e,function(){return Function(o)()},function(){return !0});return l.source=o,l}catch(l){return triggerErrorEvent(getDocument().body,"htmx:syntax:error",{error:l,source:o}),null}}}else s==="["&&r++;isPossibleRelativeReference(s,i,n)?o+="(("+n+"."+s+") ? ("+n+"."+s+") : (window."+s+"))":o=o+s,i=t.shift();}}}function consumeUntil(e,t){let n="";for(;e.length>0&&!t.test(e[0]);)n+=e.shift();return n}function consumeCSSSelector(e){let t;return e.length>0&&COMBINED_SELECTOR_START.test(e[0])?(e.shift(),t=consumeUntil(e,COMBINED_SELECTOR_END).trim(),e.shift()):t=consumeUntil(e,WHITESPACE_OR_COMMA),t}let INPUT_SELECTOR="input, textarea, select";function parseAndCacheTrigger(e,t,n){let r=[],o=tokenizeString(t);do{consumeUntil(o,NOT_WHITESPACE);let l=o.length,a=consumeUntil(o,/[,\[\s]/);if(a!=="")if(a==="every"){let u={trigger:"every"};consumeUntil(o,NOT_WHITESPACE),u.pollInterval=parseInterval(consumeUntil(o,/[,\[\s]/)),consumeUntil(o,NOT_WHITESPACE);var i=maybeGenerateConditional(e,o,"event");i&&(u.eventFilter=i),r.push(u);}else {let u={trigger:a};var i=maybeGenerateConditional(e,o,"event");for(i&&(u.eventFilter=i);o.length>0&&o[0]!==",";){consumeUntil(o,NOT_WHITESPACE);let c=o.shift();if(c==="changed")u.changed=!0;else if(c==="once")u.once=!0;else if(c==="consume")u.consume=!0;else if(c==="delay"&&o[0]===":")o.shift(),u.delay=parseInterval(consumeUntil(o,WHITESPACE_OR_COMMA));else if(c==="from"&&o[0]===":"){if(o.shift(),COMBINED_SELECTOR_START.test(o[0]))var s=consumeCSSSelector(o);else {var s=consumeUntil(o,WHITESPACE_OR_COMMA);if(s==="closest"||s==="find"||s==="next"||s==="previous"){o.shift();let b=consumeCSSSelector(o);b.length>0&&(s+=" "+b);}}u.from=s;}else c==="target"&&o[0]===":"?(o.shift(),u.target=consumeCSSSelector(o)):c==="throttle"&&o[0]===":"?(o.shift(),u.throttle=parseInterval(consumeUntil(o,WHITESPACE_OR_COMMA))):c==="queue"&&o[0]===":"?(o.shift(),u.queue=consumeUntil(o,WHITESPACE_OR_COMMA)):c==="root"&&o[0]===":"?(o.shift(),u[c]=consumeCSSSelector(o)):c==="threshold"&&o[0]===":"?(o.shift(),u[c]=consumeUntil(o,WHITESPACE_OR_COMMA)):triggerErrorEvent(e,"htmx:syntax:error",{token:o.shift()});}r.push(u);}o.length===l&&triggerErrorEvent(e,"htmx:syntax:error",{token:o.shift()}),consumeUntil(o,NOT_WHITESPACE);}while(o[0]===","&&o.shift());return n&&(n[t]=r),r}function getTriggerSpecs(e){let t=getAttributeValue(e,"hx-trigger"),n=[];if(t){let r=htmx.config.triggerSpecsCache;n=r&&r[t]||parseAndCacheTrigger(e,t,r);}return n.length>0?n:matches(e,"form")?[{trigger:"submit"}]:matches(e,'input[type="button"], input[type="submit"]')?[{trigger:"click"}]:matches(e,INPUT_SELECTOR)?[{trigger:"change"}]:[{trigger:"click"}]}function cancelPolling(e){getInternalData(e).cancelled=!0;}function processPolling(e,t,n){let r=getInternalData(e);r.timeout=getWindow().setTimeout(function(){bodyContains(e)&&r.cancelled!==!0&&(maybeFilterEvent(n,e,makeEvent("hx:poll:trigger",{triggerSpec:n,target:e}))||t(e),processPolling(e,t,n));},n.pollInterval);}function isLocalLink(e){return location.hostname===e.hostname&&getRawAttribute(e,"href")&&getRawAttribute(e,"href").indexOf("#")!==0}function eltIsDisabled(e){return closest(e,htmx.config.disableSelector)}function boostElement(e,t,n){if(e instanceof HTMLAnchorElement&&isLocalLink(e)&&(e.target===""||e.target==="_self")||e.tagName==="FORM"&&String(getRawAttribute(e,"method")).toLowerCase()!=="dialog"){t.boosted=!0;let r,o;if(e.tagName==="A")r="get",o=getRawAttribute(e,"href");else {let i=getRawAttribute(e,"method");r=i?i.toLowerCase():"get",o=getRawAttribute(e,"action");}n.forEach(function(i){addEventListener(e,function(s,l){let a=asElement(s);if(eltIsDisabled(a)){cleanUpElement(a);return}issueAjaxRequest(r,o,a,l);},t,i,!0);});}}function shouldCancel(e,t){let n=asElement(t);return n?!!((e.type==="submit"||e.type==="click")&&(n.tagName==="FORM"||matches(n,'input[type="submit"], button')&&closest(n,"form")!==null||n instanceof HTMLAnchorElement&&n.href&&(n.getAttribute("href")==="#"||n.getAttribute("href").indexOf("#")!==0))):!1}function ignoreBoostedAnchorCtrlClick(e,t){return getInternalData(e).boosted&&e instanceof HTMLAnchorElement&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function maybeFilterEvent(e,t,n){let r=e.eventFilter;if(r)try{return r.call(t,n)!==!0}catch(o){let i=r.source;return triggerErrorEvent(getDocument().body,"htmx:eventFilter:error",{error:o,source:i}),!0}return !1}function addEventListener(e,t,n,r,o){let i=getInternalData(e),s;r.from?s=querySelectorAllExt(e,r.from):s=[e],r.changed&&s.forEach(function(l){let a=getInternalData(l);a.lastValue=l.value;}),forEach(s,function(l){let a=function(u){if(!bodyContains(e)){l.removeEventListener(r.trigger,a);return}if(ignoreBoostedAnchorCtrlClick(e,u)||((o||shouldCancel(u,e))&&u.preventDefault(),maybeFilterEvent(r,e,u)))return;let f=getInternalData(u);if(f.triggerSpec=r,f.handledFor==null&&(f.handledFor=[]),f.handledFor.indexOf(e)<0){if(f.handledFor.push(e),r.consume&&u.stopPropagation(),r.target&&u.target&&!matches(asElement(u.target),r.target))return;if(r.once){if(i.triggeredOnce)return;i.triggeredOnce=!0;}if(r.changed){let c=getInternalData(l),d=l.value;if(c.lastValue===d)return;c.lastValue=d;}if(i.delayed&&clearTimeout(i.delayed),i.throttle)return;r.throttle>0?i.throttle||(triggerEvent(e,"htmx:trigger"),t(e,u),i.throttle=getWindow().setTimeout(function(){i.throttle=null;},r.throttle)):r.delay>0?i.delayed=getWindow().setTimeout(function(){triggerEvent(e,"htmx:trigger"),t(e,u);},r.delay):(triggerEvent(e,"htmx:trigger"),t(e,u));}};n.listenerInfos==null&&(n.listenerInfos=[]),n.listenerInfos.push({trigger:r.trigger,listener:a,on:l}),l.addEventListener(r.trigger,a);});}let windowIsScrolling=!1,scrollHandler=null;function initScrollHandler(){scrollHandler||(scrollHandler=function(){windowIsScrolling=!0;},window.addEventListener("scroll",scrollHandler),setInterval(function(){windowIsScrolling&&(windowIsScrolling=!1,forEach(getDocument().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"),function(e){maybeReveal(e);}));},200));}function maybeReveal(e){!hasAttribute(e,"data-hx-revealed")&&isScrolledIntoView(e)&&(e.setAttribute("data-hx-revealed","true"),getInternalData(e).initHash?triggerEvent(e,"revealed"):e.addEventListener("htmx:afterProcessNode",function(){triggerEvent(e,"revealed");},{once:!0}));}function loadImmediately(e,t,n,r){let o=function(){n.loaded||(n.loaded=!0,t(e));};r>0?getWindow().setTimeout(o,r):o();}function processVerbs(e,t,n){let r=!1;return forEach(VERBS,function(o){if(hasAttribute(e,"hx-"+o)){let i=getAttributeValue(e,"hx-"+o);r=!0,t.path=i,t.verb=o,n.forEach(function(s){addTriggerHandler(e,s,t,function(l,a){let u=asElement(l);if(closest(u,htmx.config.disableSelector)){cleanUpElement(u);return}issueAjaxRequest(o,i,u,a);});});}}),r}function addTriggerHandler(e,t,n,r){if(t.trigger==="revealed")initScrollHandler(),addEventListener(e,r,n,t),maybeReveal(asElement(e));else if(t.trigger==="intersect"){let o={};t.root&&(o.root=querySelectorExt(e,t.root)),t.threshold&&(o.threshold=parseFloat(t.threshold)),new IntersectionObserver(function(s){for(let l=0;l0?(n.polling=!0,processPolling(asElement(e),r,t)):addEventListener(e,r,n,t);}function shouldProcessHxOn(e){let t=asElement(e);if(!t)return !1;let n=t.attributes;for(let r=0;r", "+i).join(""))}else return []}function maybeSetLastButtonClicked(e){let t=closest(asElement(e.target),"button, input[type='submit']"),n=getRelatedFormData(e);n&&(n.lastButtonClicked=t);}function maybeUnsetLastButtonClicked(e){let t=getRelatedFormData(e);t&&(t.lastButtonClicked=null);}function getRelatedFormData(e){let t=closest(asElement(e.target),"button, input[type='submit']");if(!t)return;let n=resolveTarget("#"+getRawAttribute(t,"form"),t.getRootNode())||closest(t,"form");if(n)return getInternalData(n)}function initButtonTracking(e){e.addEventListener("click",maybeSetLastButtonClicked),e.addEventListener("focusin",maybeSetLastButtonClicked),e.addEventListener("focusout",maybeUnsetLastButtonClicked);}function addHxOnEventHandler(e,t,n){let r=getInternalData(e);Array.isArray(r.onHandlers)||(r.onHandlers=[]);let o,i=function(s){maybeEval(e,function(){eltIsDisabled(e)||(o||(o=new Function("event",n)),o.call(e,s));});};e.addEventListener(t,i),r.onHandlers.push({event:t,listener:i});}function processHxOnWildcard(e){deInitOnHandlers(e);for(let t=0;thtmx.config.historyCacheSize;)i.shift();for(;i.length>0;)try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(l){triggerErrorEvent(getDocument().body,"htmx:historyCacheError",{cause:l,cache:i}),i.shift();}}function getCachedHistory(e){if(!canAccessLocalStorage())return null;e=normalizePath(e);let t=parseJSON(localStorage.getItem("htmx-history-cache"))||[];for(let n=0;n=200&&this.status<400){triggerEvent(getDocument().body,"htmx:historyCacheMissLoad",n);let r=makeFragment(this.response),o=r.querySelector("[hx-history-elt],[data-hx-history-elt]")||r,i=getHistoryElement(),s=makeSettleInfo(i);handleTitle(r.title),swapInnerHTML(i,o,s),settleImmediately(s.tasks),currentPathForHistory=e,triggerEvent(getDocument().body,"htmx:historyRestore",{path:e,cacheMiss:!0,serverResponse:this.response});}else triggerErrorEvent(getDocument().body,"htmx:historyCacheMissLoadError",n);},t.send();}function restoreHistory(e){saveCurrentPageToHistory(),e=e||location.pathname+location.search;let t=getCachedHistory(e);if(t){let n=makeFragment(t.content),r=getHistoryElement(),o=makeSettleInfo(r);handleTitle(n.title),swapInnerHTML(r,n,o),settleImmediately(o.tasks),getWindow().setTimeout(function(){window.scrollTo(0,t.scroll);},0),currentPathForHistory=e,triggerEvent(getDocument().body,"htmx:historyRestore",{path:e,item:t});}else htmx.config.refreshOnHistoryMiss?window.location.reload(!0):loadHistoryFromServer(e);}function addRequestIndicatorClasses(e){let t=findAttributeTargets(e,"hx-indicator");return t==null&&(t=[e]),forEach(t,function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||0)+1,n.classList.add.call(n.classList,htmx.config.requestClass);}),t}function disableElements(e){let t=findAttributeTargets(e,"hx-disabled-elt");return t==null&&(t=[]),forEach(t,function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||0)+1,n.setAttribute("disabled",""),n.setAttribute("data-disabled-by-htmx","");}),t}function removeRequestIndicators(e,t){forEach(e,function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||0)-1,r.requestCount===0&&n.classList.remove.call(n.classList,htmx.config.requestClass);}),forEach(t,function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||0)-1,r.requestCount===0&&(n.removeAttribute("disabled"),n.removeAttribute("data-disabled-by-htmx"));});}function haveSeenNode(e,t){for(let n=0;nt.indexOf(o)<0):r=r.filter(o=>o!==t),n.delete(e),forEach(r,o=>n.append(e,o));}}function processInputValue(e,t,n,r,o){if(!(r==null||haveSeenNode(e,r))){if(e.push(r),shouldInclude(r)){let i=getRawAttribute(r,"name"),s=r.value;r instanceof HTMLSelectElement&&r.multiple&&(s=toArray(r.querySelectorAll("option:checked")).map(function(l){return l.value})),r instanceof HTMLInputElement&&r.files&&(s=toArray(r.files)),addValueToFormData(i,s,t),o&&validateElement(r,n);}r instanceof HTMLFormElement&&(forEach(r.elements,function(i){e.indexOf(i)>=0?removeValueFromFormData(i.name,i.value,t):e.push(i),o&&validateElement(i,n);}),new FormData(r).forEach(function(i,s){i instanceof File&&i.name===""||addValueToFormData(s,i,t);}));}}function validateElement(e,t){let n=e;n.willValidate&&(triggerEvent(n,"htmx:validation:validate"),n.checkValidity()||(t.push({elt:n,message:n.validationMessage,validity:n.validity}),triggerEvent(n,"htmx:validation:failed",{message:n.validationMessage,validity:n.validity})));}function overrideFormData(e,t){for(let n of t.keys())e.delete(n);return t.forEach(function(n,r){e.append(r,n);}),e}function getInputValues(e,t){let n=[],r=new FormData,o=new FormData,i=[],s=getInternalData(e);s.lastButtonClicked&&!bodyContains(s.lastButtonClicked)&&(s.lastButtonClicked=null);let l=e instanceof HTMLFormElement&&e.noValidate!==!0||getAttributeValue(e,"hx-validate")==="true";if(s.lastButtonClicked&&(l=l&&s.lastButtonClicked.formNoValidate!==!0),t!=="get"&&processInputValue(n,o,i,closest(e,"form"),l),processInputValue(n,r,i,e,l),s.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&getRawAttribute(e,"type")==="submit"){let u=s.lastButtonClicked||e,f=getRawAttribute(u,"name");addValueToFormData(f,u.value,o);}let a=findAttributeTargets(e,"hx-include");return forEach(a,function(u){processInputValue(n,r,i,asElement(u),l),matches(u,"form")||forEach(asParentNode(u).querySelectorAll(INPUT_SELECTOR),function(f){processInputValue(n,r,i,f,l);});}),overrideFormData(r,o),{errors:i,formData:r,values:formDataProxy(r)}}function appendParam(e,t,n){e!==""&&(e+="&"),String(n)==="[object Object]"&&(n=JSON.stringify(n));let r=encodeURIComponent(n);return e+=encodeURIComponent(t)+"="+r,e}function urlEncode(e){e=formDataFromObject(e);let t="";return e.forEach(function(n,r){t=appendParam(t,r,n);}),t}function getHeaders(e,t,n){let r={"HX-Request":"true","HX-Trigger":getRawAttribute(e,"id"),"HX-Trigger-Name":getRawAttribute(e,"name"),"HX-Target":getAttributeValue(t,"id"),"HX-Current-URL":getDocument().location.href};return getValuesForElement(e,"hx-headers",!1,r),n!==void 0&&(r["HX-Prompt"]=n),getInternalData(e).boosted&&(r["HX-Boosted"]="true"),r}function filterValues(e,t){let n=getClosestAttributeValue(t,"hx-params");if(n){if(n==="none")return new FormData;if(n==="*")return e;if(n.indexOf("not ")===0)return forEach(n.substr(4).split(","),function(r){r=r.trim(),e.delete(r);}),e;{let r=new FormData;return forEach(n.split(","),function(o){o=o.trim(),e.has(o)&&e.getAll(o).forEach(function(i){r.append(o,i);});}),r}}else return e}function isAnchorLink(e){return !!getRawAttribute(e,"href")&&getRawAttribute(e,"href").indexOf("#")>=0}function getSwapSpecification(e,t){let n=t||getClosestAttributeValue(e,"hx-swap"),r={swapStyle:getInternalData(e).boosted?"innerHTML":htmx.config.defaultSwapStyle,swapDelay:htmx.config.defaultSwapDelay,settleDelay:htmx.config.defaultSettleDelay};if(htmx.config.scrollIntoViewOnBoost&&getInternalData(e).boosted&&!isAnchorLink(e)&&(r.show="top"),n){let s=splitOnWhitespace(n);if(s.length>0)for(let l=0;l0?o.join(":"):null;r.scroll=f,r.scrollTarget=i;}else if(a.indexOf("show:")===0){var o=a.substr(5).split(":");let c=o.pop();var i=o.length>0?o.join(":"):null;r.show=c,r.showTarget=i;}else if(a.indexOf("focus-scroll:")===0){let u=a.substr(13);r.focusScroll=u=="true";}else l==0?r.swapStyle=a:logError("Unknown modifier in hx-swap: "+a);}}return r}function usesFormData(e){return getClosestAttributeValue(e,"hx-encoding")==="multipart/form-data"||matches(e,"form")&&getRawAttribute(e,"enctype")==="multipart/form-data"}function encodeParamsForBody(e,t,n){let r=null;return withExtensions(t,function(o){r==null&&(r=o.encodeParameters(e,n,t));}),r??(usesFormData(t)?overrideFormData(new FormData,formDataFromObject(n)):urlEncode(n))}function makeSettleInfo(e){return {tasks:[],elts:[e]}}function updateScrollState(e,t){let n=e[0],r=e[e.length-1];if(t.scroll){var o=null;t.scrollTarget&&(o=asElement(querySelectorExt(n,t.scrollTarget))),t.scroll==="top"&&(n||o)&&(o=o||n,o.scrollTop=0),t.scroll==="bottom"&&(r||o)&&(o=o||r,o.scrollTop=o.scrollHeight);}if(t.show){var o=null;if(t.showTarget){let s=t.showTarget;t.showTarget==="window"&&(s="body"),o=asElement(querySelectorExt(n,s));}t.show==="top"&&(n||o)&&(o=o||n,o.scrollIntoView({block:"start",behavior:htmx.config.scrollBehavior})),t.show==="bottom"&&(r||o)&&(o=o||r,o.scrollIntoView({block:"end",behavior:htmx.config.scrollBehavior}));}}function getValuesForElement(e,t,n,r){if(r==null&&(r={}),e==null)return r;let o=getAttributeValue(e,t);if(o){let i=o.trim(),s=n;if(i==="unset")return null;i.indexOf("javascript:")===0?(i=i.substr(11),s=!0):i.indexOf("js:")===0&&(i=i.substr(3),s=!0),i.indexOf("{")!==0&&(i="{"+i+"}");let l;s?l=maybeEval(e,function(){return Function("return ("+i+")")()},{}):l=parseJSON(i);for(let a in l)l.hasOwnProperty(a)&&r[a]==null&&(r[a]=l[a]);}return getValuesForElement(asElement(parentElt(e)),t,n,r)}function maybeEval(e,t,n){return htmx.config.allowEval?t():(triggerErrorEvent(e,"htmx:evalDisallowedError"),n)}function getHXVarsForElement(e,t){return getValuesForElement(e,"hx-vars",!0,t)}function getHXValsForElement(e,t){return getValuesForElement(e,"hx-vals",!1,t)}function getExpressionVars(e){return mergeObjects(getHXVarsForElement(e),getHXValsForElement(e))}function safelySetHeaderValue(e,t,n){if(n!==null)try{e.setRequestHeader(t,n);}catch{e.setRequestHeader(t,encodeURIComponent(n)),e.setRequestHeader(t+"-URI-AutoEncoded","true");}}function getPathFromResponse(e){if(e.responseURL&&typeof URL<"u")try{let t=new URL(e.responseURL);return t.pathname+t.search}catch{triggerErrorEvent(getDocument().body,"htmx:badResponseUrl",{url:e.responseURL});}}function hasHeader(e,t){return t.test(e.getAllResponseHeaders())}function ajaxHelper(e,t,n){return e=e.toLowerCase(),n?n instanceof Element||typeof n=="string"?issueAjaxRequest(e,t,null,null,{targetOverride:resolveTarget(n),returnPromise:!0}):issueAjaxRequest(e,t,resolveTarget(n.source),n.event,{handler:n.handler,headers:n.headers,values:n.values,targetOverride:resolveTarget(n.target),swapOverride:n.swap,select:n.select,returnPromise:!0}):issueAjaxRequest(e,t,null,null,{returnPromise:!0})}function hierarchyForElt(e){let t=[];for(;e;)t.push(e),e=e.parentElement;return t}function verifyPath(e,t,n){let r,o;return typeof URL=="function"?(o=new URL(t,document.location.href),r=document.location.origin===o.origin):(o=t,r=startsWith(t,document.location.origin)),htmx.config.selfRequestsOnly&&!r?!1:triggerEvent(e,"htmx:validateUrl",mergeObjects({url:o,sameHost:r},n))}function formDataFromObject(e){if(e instanceof FormData)return e;let t=new FormData;for(let n in e)e.hasOwnProperty(n)&&(typeof e[n].forEach=="function"?e[n].forEach(function(r){t.append(n,r);}):typeof e[n]=="object"&&!(e[n]instanceof Blob)?t.append(n,JSON.stringify(e[n])):t.append(n,e[n]));return t}function formDataArrayProxy(e,t,n){return new Proxy(n,{get:function(r,o){return typeof o=="number"?r[o]:o==="length"?r.length:o==="push"?function(i){r.push(i),e.append(t,i);}:typeof r[o]=="function"?function(){r[o].apply(r,arguments),e.delete(t),r.forEach(function(i){e.append(t,i);});}:r[o]&&r[o].length===1?r[o][0]:r[o]},set:function(r,o,i){return r[o]=i,e.delete(t),r.forEach(function(s){e.append(t,s);}),!0}})}function formDataProxy(e){return new Proxy(e,{get:function(t,n){if(typeof n=="symbol")return Reflect.get(t,n);if(n==="toJSON")return ()=>Object.fromEntries(e);if(n in t)return typeof t[n]=="function"?function(){return e[n].apply(e,arguments)}:t[n];let r=e.getAll(n);if(r.length!==0)return r.length===1?r[0]:formDataArrayProxy(t,n,r)},set:function(t,n,r){return typeof n!="string"?!1:(t.delete(n),typeof r.forEach=="function"?r.forEach(function(o){t.append(n,o);}):typeof r=="object"&&!(r instanceof Blob)?t.append(n,JSON.stringify(r)):t.append(n,r),!0)},deleteProperty:function(t,n){return typeof n=="string"&&t.delete(n),!0},ownKeys:function(t){return Reflect.ownKeys(Object.fromEntries(t))},getOwnPropertyDescriptor:function(t,n){return Reflect.getOwnPropertyDescriptor(Object.fromEntries(t),n)}})}function issueAjaxRequest(e,t,n,r,o,i){let s=null,l=null;if(o=o??{},o.returnPromise&&typeof Promise<"u")var a=new Promise(function(h,E){s=h,l=E;});n==null&&(n=getDocument().body);let u=o.handler||handleAjaxResponse,f=o.select||null;if(!bodyContains(n))return maybeCall(s),a;let c=o.targetOverride||asElement(getTarget(n));if(c==null||c==DUMMY_ELT)return triggerErrorEvent(n,"htmx:targetError",{target:getAttributeValue(n,"hx-target")}),maybeCall(l),a;let d=getInternalData(n),b=d.lastButtonClicked;if(b){let h=getRawAttribute(b,"formaction");h!=null&&(t=h);let E=getRawAttribute(b,"formmethod");E!=null&&E.toLowerCase()!=="dialog"&&(e=E);}let S=getClosestAttributeValue(n,"hx-confirm");if(i===void 0&&triggerEvent(n,"htmx:confirm",{target:c,elt:n,path:t,verb:e,triggeringEvent:r,etc:o,issueRequest:function(O){return issueAjaxRequest(e,t,n,r,o,!!O)},question:S})===!1)return maybeCall(s),a;let A=n,p=getClosestAttributeValue(n,"hx-sync"),x=null,H=!1;if(p){let h=p.split(":"),E=h[0].trim();if(E==="this"?A=findThisElement(n,"hx-sync"):A=asElement(querySelectorExt(n,E)),p=(h[1]||"drop").trim(),d=getInternalData(A),p==="drop"&&d.xhr&&d.abortable!==!0)return maybeCall(s),a;if(p==="abort"){if(d.xhr)return maybeCall(s),a;H=!0;}else p==="replace"?triggerEvent(A,"htmx:abort"):p.indexOf("queue")===0&&(x=(p.split(" ")[1]||"last").trim());}if(d.xhr)if(d.abortable)triggerEvent(A,"htmx:abort");else {if(x==null){if(r){let h=getInternalData(r);h&&h.triggerSpec&&h.triggerSpec.queue&&(x=h.triggerSpec.queue);}x==null&&(x="last");}return d.queuedRequests==null&&(d.queuedRequests=[]),x==="first"&&d.queuedRequests.length===0?d.queuedRequests.push(function(){issueAjaxRequest(e,t,n,r,o);}):x==="all"?d.queuedRequests.push(function(){issueAjaxRequest(e,t,n,r,o);}):x==="last"&&(d.queuedRequests=[],d.queuedRequests.push(function(){issueAjaxRequest(e,t,n,r,o);})),maybeCall(s),a}let m=new XMLHttpRequest;d.xhr=m,d.abortable=H;let T=function(){d.xhr=null,d.abortable=!1,d.queuedRequests!=null&&d.queuedRequests.length>0&&d.queuedRequests.shift()();},P=getClosestAttributeValue(n,"hx-prompt");if(P){var I=prompt(P);if(I===null||!triggerEvent(n,"htmx:prompt",{prompt:I,target:c}))return maybeCall(s),T(),a}if(S&&!i&&!confirm(S))return maybeCall(s),T(),a;let R=getHeaders(n,c,I);e!=="get"&&!usesFormData(n)&&(R["Content-Type"]="application/x-www-form-urlencoded"),o.headers&&(R=mergeObjects(R,o.headers));let v=getInputValues(n,e),L=v.errors,N=v.formData;o.values&&overrideFormData(N,formDataFromObject(o.values));let k=formDataFromObject(getExpressionVars(n)),B=overrideFormData(N,k),q=filterValues(B,n);htmx.config.getCacheBusterParam&&e==="get"&&q.set("org.htmx.cache-buster",getRawAttribute(c,"id")||"true"),(t==null||t==="")&&(t=getDocument().location.href);let _=getValuesForElement(n,"hx-request"),j=getInternalData(n).boosted,F=htmx.config.methodsThatUseUrlParams.indexOf(e)>=0,w={boosted:j,useUrlParams:F,formData:q,parameters:formDataProxy(q),unfilteredFormData:B,unfilteredParameters:formDataProxy(B),headers:R,target:c,verb:e,errors:L,withCredentials:o.credentials||_.credentials||htmx.config.withCredentials,timeout:o.timeout||_.timeout||htmx.config.timeout,path:t,triggeringEvent:r};if(!triggerEvent(n,"htmx:configRequest",w))return maybeCall(s),T(),a;if(t=w.path,e=w.verb,R=w.headers,q=formDataFromObject(w.parameters),L=w.errors,F=w.useUrlParams,L&&L.length>0)return triggerEvent(n,"htmx:validation:halted",w),maybeCall(s),T(),a;let z=t.split("#"),G=z[0],W=z[1],D=t;if(F&&(D=G,!q.keys().next().done&&(D.indexOf("?")<0?D+="?":D+="&",D+=urlEncode(q),W&&(D+="#"+W))),!verifyPath(n,D,w))return triggerErrorEvent(n,"htmx:invalidPath",w),maybeCall(l),a;if(m.open(e.toUpperCase(),D,!0),m.overrideMimeType("text/html"),m.withCredentials=w.withCredentials,m.timeout=w.timeout,!_.noHeaders){for(let h in R)if(R.hasOwnProperty(h)){let E=R[h];safelySetHeaderValue(m,h,E);}}let y={xhr:m,target:c,requestConfig:w,etc:o,boosted:j,select:f,pathInfo:{requestPath:t,finalRequestPath:D,responsePath:null,anchor:W}};if(m.onload=function(){try{let h=hierarchyForElt(n);if(y.pathInfo.responsePath=getPathFromResponse(m),u(n,y),y.keepIndicators!==!0&&removeRequestIndicators(M,V),triggerEvent(n,"htmx:afterRequest",y),triggerEvent(n,"htmx:afterOnLoad",y),!bodyContains(n)){let E=null;for(;h.length>0&&E==null;){let O=h.shift();bodyContains(O)&&(E=O);}E&&(triggerEvent(E,"htmx:afterRequest",y),triggerEvent(E,"htmx:afterOnLoad",y));}maybeCall(s),T();}catch(h){throw triggerErrorEvent(n,"htmx:onLoadError",mergeObjects({error:h},y)),h}},m.onerror=function(){removeRequestIndicators(M,V),triggerErrorEvent(n,"htmx:afterRequest",y),triggerErrorEvent(n,"htmx:sendError",y),maybeCall(l),T();},m.onabort=function(){removeRequestIndicators(M,V),triggerErrorEvent(n,"htmx:afterRequest",y),triggerErrorEvent(n,"htmx:sendAbort",y),maybeCall(l),T();},m.ontimeout=function(){removeRequestIndicators(M,V),triggerErrorEvent(n,"htmx:afterRequest",y),triggerErrorEvent(n,"htmx:timeout",y),maybeCall(l),T();},!triggerEvent(n,"htmx:beforeRequest",y))return maybeCall(s),T(),a;var M=addRequestIndicatorClasses(n),V=disableElements(n);forEach(["loadstart","loadend","progress","abort"],function(h){forEach([m,m.upload],function(E){E.addEventListener(h,function(O){triggerEvent(n,"htmx:xhr:"+h,{lengthComputable:O.lengthComputable,loaded:O.loaded,total:O.total});});});}),triggerEvent(n,"htmx:beforeSend",y);let Y=F?null:encodeParamsForBody(m,n,q);return m.send(Y),a}function determineHistoryUpdates(e,t){let n=t.xhr,r=null,o=null;if(hasHeader(n,/HX-Push:/i)?(r=n.getResponseHeader("HX-Push"),o="push"):hasHeader(n,/HX-Push-Url:/i)?(r=n.getResponseHeader("HX-Push-Url"),o="push"):hasHeader(n,/HX-Replace-Url:/i)&&(r=n.getResponseHeader("HX-Replace-Url"),o="replace"),r)return r==="false"?{}:{type:o,path:r};let i=t.pathInfo.finalRequestPath,s=t.pathInfo.responsePath,l=getClosestAttributeValue(e,"hx-push-url"),a=getClosestAttributeValue(e,"hx-replace-url"),u=getInternalData(e).boosted,f=null,c=null;return l?(f="push",c=l):a?(f="replace",c=a):u&&(f="push",c=s||i),c?c==="false"?{}:(c==="true"&&(c=s||i),t.pathInfo.anchor&&c.indexOf("#")===-1&&(c=c+"#"+t.pathInfo.anchor),{type:f,path:c}):{}}function codeMatches(e,t){var n=new RegExp(e.code);return n.test(t.toString(10))}function resolveResponseHandling(e){for(var t=0;t0?getWindow().setTimeout(I,x.swapDelay):I();}c&&triggerErrorEvent(e,"htmx:responseError",mergeObjects({error:"Response Status Error Code "+n.status+" from "+t.pathInfo.requestPath},t));}}let extensions={};function extensionBase(){return {init:function(e){return null},getSelectors:function(){return null},onEvent:function(e,t){return !0},transformResponse:function(e,t,n){return e},isInlineSwap:function(e){return !1},handleSwap:function(e,t,n,r){return !1},encodeParameters:function(e,t,n){return null}}}function defineExtension(e,t){t.init&&t.init(internalAPI),extensions[e]=mergeObjects(extensionBase(),t);}function removeExtension(e){delete extensions[e];}function getExtensions(e,t,n){if(t==null&&(t=[]),e==null)return t;n==null&&(n=[]);let r=getAttributeValue(e,"hx-ext");return r&&forEach(r.split(","),function(o){if(o=o.replace(/ /g,""),o.slice(0,7)=="ignore:"){n.push(o.slice(7));return}if(n.indexOf(o)<0){let i=extensions[o];i&&t.indexOf(i)<0&&t.push(i);}}),getExtensions(asElement(parentElt(e)),t,n)}var isReady=!1;getDocument().addEventListener("DOMContentLoaded",function(){isReady=!0;});function ready(e){isReady||getDocument().readyState==="complete"?e():getDocument().addEventListener("DOMContentLoaded",e);}function insertIndicatorStyles(){if(htmx.config.includeIndicatorStyles!==!1){let e=htmx.config.inlineStyleNonce?` nonce="${htmx.config.inlineStyleNonce}"`:"";getDocument().head.insertAdjacentHTML("beforeend","");}}function getMetaConfig(){let e=getDocument().querySelector('meta[name="htmx-config"]');return e?parseJSON(e.content):null}function mergeMetaConfig(){let e=getMetaConfig();e&&(htmx.config=mergeObjects(htmx.config,e));}return ready(function(){mergeMetaConfig(),insertIndicatorStyles();let e=getDocument().body;processNode(e);let t=getDocument().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(r){let o=r.target,i=getInternalData(o);i&&i.xhr&&i.xhr.abort();});let n=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(r){r.state&&r.state.htmx?(restoreHistory(),forEach(t,function(o){triggerEvent(o,"htmx:restored",{document:getDocument(),triggerEvent});})):n&&n(r);},getWindow().setTimeout(function(){triggerEvent(e,"htmx:load",{}),e=null;},0);}),htmx}(),g=$;function Q(e,t){if(e==="ignore")return !1;let n=e.split("/"),r=t.split("/");for(let o=0;o{if(!(t instanceof CustomEvent))return !1;let n=t.detail.target;return n&&n.children&&Array.from(n.children).forEach(r=>{g.trigger(r,e,null);}),!0},init:function(e){},transformResponse:function(e,t,n){return e},isInlineSwap:function(e){return !1},handleSwap:function(e,t,n,r){return !1},encodeParameters:function(e,t,n){},getSelectors:function(){return null}});g.defineExtension("debug",{onEvent:function(e,t){console.debug?console.debug(e):console&&console.log("DEBUG:",e);}});var C=g.config,U,Z="hx-target-";function J(e,t){return e.substring(0,t.length)===t}function ee(e,t){if(!e||!t)return null;let n=t.toString(),r=[n,n.substr(0,2)+"*",n.substr(0,2)+"x",n.substr(0,1)+"*",n.substr(0,1)+"x",n.substr(0,1)+"**",n.substr(0,1)+"xx","*","x","***","xxx"];(J(n,"4")||J(n,"5"))&&r.push("error");for(let o=0;o{U=e,C.responseTargetUnsetsError===void 0&&(C.responseTargetUnsetsError=!0),C.responseTargetSetsError===void 0&&(C.responseTargetSetsError=!1),C.responseTargetPrefersExisting===void 0&&(C.responseTargetPrefersExisting=!1),C.responseTargetPrefersRetargetHeader===void 0&&(C.responseTargetPrefersRetargetHeader=!0);},onEvent:(e,t)=>{if(!(t instanceof CustomEvent))return !1;if(e==="htmx:beforeSwap"&&t.detail.xhr&&t.detail.xhr.status!==200){if(t.detail.target&&(C.responseTargetPrefersExisting||C.responseTargetPrefersRetargetHeader&&t.detail.xhr.getAllResponseHeaders().match(/HX-Retarget:/i)))return t.detail.shouldSwap=!0,X(t),!0;if(!t.detail.requestConfig)return !0;let n=ee(t.detail.requestConfig.elt,t.detail.xhr.status);return n&&(X(t),t.detail.shouldSwap=!0,t.detail.target=n),!0}}});g.defineExtension("mutation-error",{onEvent:(e,t)=>{if(!(t instanceof CustomEvent))return !1;if(e==="htmx:afterRequest"){if(!t.detail||!t.detail.xhr)return;let n=t.detail.xhr.status;n>=400&&g.findAll("[hx-on\\:\\:mutation-error]").forEach(r=>{g.trigger(r,"htmx:mutation-error",{status:n});});}}});function te(e){let t=window.location.href;setInterval(()=>{window.location.href!==t&&(e(t,window.location.href),t=window.location.href);},100);}te((e,t)=>{ne(t);});function ne(e){let t=new URL(e);document.querySelectorAll("[hx-trigger]").forEach(function(n){let r=n.getAttribute("hx-trigger");if(!r)return;if(r.split(", ").find(i=>i==="url"))g.swap(n,"url",{swapStyle:"outerHTML",swapDelay:0,settleDelay:0});else for(let[i,s]of t.searchParams){let l="qs:"+i;if(r.includes(l)){console.log("triggering",l),g.trigger(n,l,null);break}}}),document.querySelectorAll("[hx-match-qp]").forEach(n=>{let r=!1;for(let o of n.getAttributeNames())if(o.startsWith("hx-match-qp-mapping:")){let i=o.replace("hx-match-qp-mapping:","");if(t.searchParams.get(i)){g.swap(n,n.getAttribute(o)??"",{swapStyle:"innerHTML",swapDelay:0,settleDelay:0}),r=!0;break}}if(!r){let o=n.getAttribute("hx-match-qp-default");o&&g.swap(n,n.getAttribute("hx-match-qp-mapping:"+o)??"",{swapStyle:"innerHTML",swapDelay:0,settleDelay:0});}});}
+var K=function(){let htmx={onLoad:null,process:null,on:null,off:null,trigger:null,ajax:null,find:null,findAll:null,closest:null,values:function(e,t){return getInputValues(e,t||"post").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:!0,historyCacheSize:10,refreshOnHistoryMiss:!1,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:!0,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:!0,allowScriptTags:!0,inlineScriptNonce:"",inlineStyleNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:!1,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",scrollBehavior:"instant",defaultFocusScroll:!1,getCacheBusterParam:!1,globalViewTransitions:!1,methodsThatUseUrlParams:["get","delete"],selfRequestsOnly:!0,ignoreTitle:!1,scrollIntoViewOnBoost:!0,triggerSpecsCache:null,disableInheritance:!1,responseHandling:[{code:"204",swap:!1},{code:"[23]..",swap:!0},{code:"[45]..",swap:!1,error:!0}],allowNestedOobSwaps:!0},parseInterval:null,_:null,version:"2.0.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;let 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},VERBS=["get","post","put","delete","patch"],VERB_SELECTOR=VERBS.map(function(e){return "[hx-"+e+"], [data-hx-"+e+"]"}).join(", "),HEAD_TAG_REGEX=makeTagRegEx("head");function makeTagRegEx(e,t=!1){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function parseInterval(e){if(e==null)return;let t=NaN;return e.slice(-2)=="ms"?t=parseFloat(e.slice(0,-2)):e.slice(-1)=="s"?t=parseFloat(e.slice(0,-1))*1e3:e.slice(-1)=="m"?t=parseFloat(e.slice(0,-1))*1e3*60:t=parseFloat(e),isNaN(t)?void 0:t}function getRawAttribute(e,t){return e instanceof Element&&e.getAttribute(t)}function hasAttribute(e,t){return !!e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function getAttributeValue(e,t){return getRawAttribute(e,t)||getRawAttribute(e,"data-"+t)}function parentElt(e){let t=e.parentElement;return !t&&e.parentNode instanceof ShadowRoot?e.parentNode:t}function getDocument(){return document}function getRootNode(e,t){return e.getRootNode?e.getRootNode({composed:t}):getDocument()}function getClosestMatch(e,t){for(;e&&!t(e);)e=parentElt(e);return e||null}function getAttributeValueWithDisinheritance(e,t,n){let r=getAttributeValue(t,n),o=getAttributeValue(t,"hx-disinherit");var i=getAttributeValue(t,"hx-inherit");if(e!==t){if(htmx.config.disableInheritance)return i&&(i==="*"||i.split(" ").indexOf(n)>=0)?r:null;if(o&&(o==="*"||o.split(" ").indexOf(n)>=0))return "unset"}return r}function getClosestAttributeValue(e,t){let n=null;if(getClosestMatch(e,function(r){return !!(n=getAttributeValueWithDisinheritance(e,asElement(r),t))}),n!=="unset")return n}function matches(e,t){let n=e instanceof Element&&(e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector);return !!n&&n.call(e,t)}function getStartTag(e){let n=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i.exec(e);return n?n[1].toLowerCase():""}function parseHTML(e){return new DOMParser().parseFromString(e,"text/html")}function takeChildrenFor(e,t){for(;t.childNodes.length>0;)e.append(t.childNodes[0]);}function duplicateScript(e){let t=getDocument().createElement("script");return forEach(e.attributes,function(n){t.setAttribute(n.name,n.value);}),t.textContent=e.textContent,t.async=!1,htmx.config.inlineScriptNonce&&(t.nonce=htmx.config.inlineScriptNonce),t}function isJavaScriptScriptNode(e){return e.matches("script")&&(e.type==="text/javascript"||e.type==="module"||e.type==="")}function normalizeScriptTags(e){Array.from(e.querySelectorAll("script")).forEach(t=>{if(isJavaScriptScriptNode(t)){let n=duplicateScript(t),r=t.parentNode;try{r.insertBefore(n,t);}catch(o){logError(o);}finally{t.remove();}}});}function makeFragment(e){let t=e.replace(HEAD_TAG_REGEX,""),n=getStartTag(t),r;if(n==="html"){r=new DocumentFragment;let i=parseHTML(e);takeChildrenFor(r,i.body),r.title=i.title;}else if(n==="body"){r=new DocumentFragment;let i=parseHTML(t);takeChildrenFor(r,i.body),r.title=i.title;}else {let i=parseHTML(''+t+"");r=i.querySelector("template").content,r.title=i.title;var o=r.querySelector("title");o&&o.parentNode===r&&(o.remove(),r.title=o.innerText);}return r&&(htmx.config.allowScriptTags?normalizeScriptTags(r):r.querySelectorAll("script").forEach(i=>i.remove())),r}function maybeCall(e){e&&e();}function isType(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function isFunction(e){return typeof e=="function"}function isRawObject(e){return isType(e,"Object")}function getInternalData(e){let t="htmx-internal-data",n=e[t];return n||(n=e[t]={}),n}function toArray(e){let t=[];if(e)for(let n=0;n=0}function bodyContains(e){let t=e.getRootNode&&e.getRootNode();return t&&t instanceof window.ShadowRoot?getDocument().body.contains(t.host):getDocument().body.contains(e)}function splitOnWhitespace(e){return e.trim().split(/\s+/)}function mergeObjects(e,t){for(let n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e}function parseJSON(e){try{return JSON.parse(e)}catch(t){return logError(t),null}}function canAccessLocalStorage(){let e="htmx:localStorageTest";try{return localStorage.setItem(e,e),localStorage.removeItem(e),!0}catch{return !1}}function normalizePath(e){try{let t=new URL(e);return t&&(e=t.pathname+t.search),/^\/$/.test(e)||(e=e.replace(/\/+$/,"")),e}catch{return e}}function internalEval(str){return maybeEval(getDocument().body,function(){return eval(str)})}function onLoadHelper(e){return htmx.on("htmx:load",function(n){e(n.detail.elt);})}function logAll(){htmx.logger=function(e,t,n){console&&console.log(t,e,n);};}function logNone(){htmx.logger=null;}function find(e,t){return typeof e!="string"?e.querySelector(t):find(getDocument(),e)}function findAll(e,t){return typeof e!="string"?e.querySelectorAll(t):findAll(getDocument(),e)}function getWindow(){return window}function removeElement(e,t){e=resolveTarget(e),t?getWindow().setTimeout(function(){removeElement(e),e=null;},t):parentElt(e).removeChild(e);}function asElement(e){return e instanceof Element?e:null}function asHtmlElement(e){return e instanceof HTMLElement?e:null}function asString(e){return typeof e=="string"?e:null}function asParentNode(e){return e instanceof Element||e instanceof Document||e instanceof DocumentFragment?e:null}function addClassToElement(e,t,n){e=asElement(resolveTarget(e)),e&&(n?getWindow().setTimeout(function(){addClassToElement(e,t),e=null;},n):e.classList&&e.classList.add(t));}function removeClassFromElement(e,t,n){let r=asElement(resolveTarget(e));r&&(n?getWindow().setTimeout(function(){removeClassFromElement(r,t),r=null;},n):r.classList&&(r.classList.remove(t),r.classList.length===0&&r.removeAttribute("class")));}function toggleClassOnElement(e,t){e=resolveTarget(e),e.classList.toggle(t);}function takeClassForElement(e,t){e=resolveTarget(e),forEach(e.parentElement.children,function(n){removeClassFromElement(n,t);}),addClassToElement(asElement(e),t);}function closest(e,t){if(e=asElement(resolveTarget(e)),e&&e.closest)return e.closest(t);do if(e==null||matches(e,t))return e;while(e=e&&asElement(parentElt(e)));return null}function startsWith(e,t){return e.substring(0,t.length)===t}function endsWith(e,t){return e.substring(e.length-t.length)===t}function normalizeSelector(e){let t=e.trim();return startsWith(t,"<")&&endsWith(t,"/>")?t.substring(1,t.length-2):t}function querySelectorAllExt(e,t,n){return e=resolveTarget(e),t.indexOf("closest ")===0?[closest(asElement(e),normalizeSelector(t.substr(8)))]:t.indexOf("find ")===0?[find(asParentNode(e),normalizeSelector(t.substr(5)))]:t==="next"?[asElement(e).nextElementSibling]:t.indexOf("next ")===0?[scanForwardQuery(e,normalizeSelector(t.substr(5)),!!n)]:t==="previous"?[asElement(e).previousElementSibling]:t.indexOf("previous ")===0?[scanBackwardsQuery(e,normalizeSelector(t.substr(9)),!!n)]:t==="document"?[document]:t==="window"?[window]:t==="body"?[document.body]:t==="root"?[getRootNode(e,!!n)]:t.indexOf("global ")===0?querySelectorAllExt(e,t.slice(7),!0):toArray(asParentNode(getRootNode(e,!!n)).querySelectorAll(normalizeSelector(t)))}var scanForwardQuery=function(e,t,n){let r=asParentNode(getRootNode(e,n)).querySelectorAll(t);for(let o=0;o=0;o--){let i=r[o];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING)return i}};function querySelectorExt(e,t){return typeof e!="string"?querySelectorAllExt(e,t)[0]:querySelectorAllExt(getDocument().body,e)[0]}function resolveTarget(e,t){return typeof e=="string"?find(asParentNode(t)||document,e):e}function processEventArgs(e,t,n){return isFunction(t)?{target:getDocument().body,event:asString(e),listener:t}:{target:resolveTarget(e),event:asString(t),listener:n}}function addEventListenerImpl(e,t,n){return ready(function(){let o=processEventArgs(e,t,n);o.target.addEventListener(o.event,o.listener);}),isFunction(t)?t:n}function removeEventListenerImpl(e,t,n){return ready(function(){let r=processEventArgs(e,t,n);r.target.removeEventListener(r.event,r.listener);}),isFunction(t)?t:n}let DUMMY_ELT=getDocument().createElement("output");function findAttributeTargets(e,t){let n=getClosestAttributeValue(e,t);if(n){if(n==="this")return [findThisElement(e,t)];{let r=querySelectorAllExt(e,n);return r.length===0?(logError('The selector "'+n+'" on '+t+" returned no matches!"),[DUMMY_ELT]):r}}}function findThisElement(e,t){return asElement(getClosestMatch(e,function(n){return getAttributeValue(asElement(n),t)!=null}))}function getTarget(e){let t=getClosestAttributeValue(e,"hx-target");return t?t==="this"?findThisElement(e,"hx-target"):querySelectorExt(e,t):getInternalData(e).boosted?getDocument().body:e}function shouldSettleAttribute(e){let t=htmx.config.attributesToSettle;for(let n=0;n0?(o=e.substr(0,e.indexOf(":")),r=e.substr(e.indexOf(":")+1,e.length)):o=e);let i=getDocument().querySelectorAll(r);return i?(forEach(i,function(s){let l,a=t.cloneNode(!0);l=getDocument().createDocumentFragment(),l.appendChild(a),isInlineSwap(o,s)||(l=asParentNode(a));let u={shouldSwap:!0,target:s,fragment:l};triggerEvent(s,"htmx:oobBeforeSwap",u)&&(s=u.target,u.shouldSwap&&swapWithStyle(o,s,s,l,n),forEach(n.elts,function(f){triggerEvent(f,"htmx:oobAfterSwap",u);}));}),t.parentNode.removeChild(t)):(t.parentNode.removeChild(t),triggerErrorEvent(getDocument().body,"htmx:oobErrorNoTarget",{content:t})),e}function handlePreservedElements(e){forEach(findAll(e,"[hx-preserve], [data-hx-preserve]"),function(t){let n=getAttributeValue(t,"id"),r=getDocument().getElementById(n);r!=null&&t.parentNode.replaceChild(r,t);});}function handleAttributes(e,t,n){forEach(t.querySelectorAll("[id]"),function(r){let o=getRawAttribute(r,"id");if(o&&o.length>0){let i=o.replace("'","\\'"),s=r.tagName.replace(":","\\:"),l=asParentNode(e),a=l&&l.querySelector(s+"[id='"+i+"']");if(a&&a!==l){let u=r.cloneNode();cloneAttributes(r,a),n.tasks.push(function(){cloneAttributes(r,u);});}}});}function makeAjaxLoadTask(e){return function(){removeClassFromElement(e,htmx.config.addedClass),processNode(asElement(e)),processFocus(asParentNode(e)),triggerEvent(e,"htmx:load");}}function processFocus(e){let t="[autofocus]",n=asHtmlElement(matches(e,t)?e:e.querySelector(t));n?.focus();}function insertNodesBefore(e,t,n,r){for(handleAttributes(e,n,r);n.childNodes.length>0;){let o=n.firstChild;addClassToElement(asElement(o),htmx.config.addedClass),e.insertBefore(o,t),o.nodeType!==Node.TEXT_NODE&&o.nodeType!==Node.COMMENT_NODE&&r.tasks.push(makeAjaxLoadTask(o));}}function stringHash(e,t){let n=0;for(;n0}function swap(e,t,n,r){r||(r={}),e=resolveTarget(e);let o=document.activeElement,i={};try{i={elt:o,start:o?o.selectionStart:null,end:o?o.selectionEnd:null};}catch{}let s=makeSettleInfo(e);if(n.swapStyle==="textContent")e.textContent=t;else {let a=makeFragment(t);if(s.title=a.title,r.selectOOB){let u=r.selectOOB.split(",");for(let f=0;f0?getWindow().setTimeout(l,n.settleDelay):l();}function handleTriggerHeader(e,t,n){let r=e.getResponseHeader(t);if(r.indexOf("{")===0){let o=parseJSON(r);for(let i in o)if(o.hasOwnProperty(i)){let s=o[i];isRawObject(s)?n=s.target!==void 0?s.target:n:s={value:s},triggerEvent(n,i,s);}}else {let o=r.split(",");for(let i=0;i0;){let s=t[0];if(s==="]"){if(r--,r===0){i===null&&(o=o+"true"),t.shift(),o+=")})";try{let l=maybeEval(e,function(){return Function(o)()},function(){return !0});return l.source=o,l}catch(l){return triggerErrorEvent(getDocument().body,"htmx:syntax:error",{error:l,source:o}),null}}}else s==="["&&r++;isPossibleRelativeReference(s,i,n)?o+="(("+n+"."+s+") ? ("+n+"."+s+") : (window."+s+"))":o=o+s,i=t.shift();}}}function consumeUntil(e,t){let n="";for(;e.length>0&&!t.test(e[0]);)n+=e.shift();return n}function consumeCSSSelector(e){let t;return e.length>0&&COMBINED_SELECTOR_START.test(e[0])?(e.shift(),t=consumeUntil(e,COMBINED_SELECTOR_END).trim(),e.shift()):t=consumeUntil(e,WHITESPACE_OR_COMMA),t}let INPUT_SELECTOR="input, textarea, select";function parseAndCacheTrigger(e,t,n){let r=[],o=tokenizeString(t);do{consumeUntil(o,NOT_WHITESPACE);let l=o.length,a=consumeUntil(o,/[,\[\s]/);if(a!=="")if(a==="every"){let u={trigger:"every"};consumeUntil(o,NOT_WHITESPACE),u.pollInterval=parseInterval(consumeUntil(o,/[,\[\s]/)),consumeUntil(o,NOT_WHITESPACE);var i=maybeGenerateConditional(e,o,"event");i&&(u.eventFilter=i),r.push(u);}else {let u={trigger:a};var i=maybeGenerateConditional(e,o,"event");for(i&&(u.eventFilter=i);o.length>0&&o[0]!==",";){consumeUntil(o,NOT_WHITESPACE);let c=o.shift();if(c==="changed")u.changed=!0;else if(c==="once")u.once=!0;else if(c==="consume")u.consume=!0;else if(c==="delay"&&o[0]===":")o.shift(),u.delay=parseInterval(consumeUntil(o,WHITESPACE_OR_COMMA));else if(c==="from"&&o[0]===":"){if(o.shift(),COMBINED_SELECTOR_START.test(o[0]))var s=consumeCSSSelector(o);else {var s=consumeUntil(o,WHITESPACE_OR_COMMA);if(s==="closest"||s==="find"||s==="next"||s==="previous"){o.shift();let b=consumeCSSSelector(o);b.length>0&&(s+=" "+b);}}u.from=s;}else c==="target"&&o[0]===":"?(o.shift(),u.target=consumeCSSSelector(o)):c==="throttle"&&o[0]===":"?(o.shift(),u.throttle=parseInterval(consumeUntil(o,WHITESPACE_OR_COMMA))):c==="queue"&&o[0]===":"?(o.shift(),u.queue=consumeUntil(o,WHITESPACE_OR_COMMA)):c==="root"&&o[0]===":"?(o.shift(),u[c]=consumeCSSSelector(o)):c==="threshold"&&o[0]===":"?(o.shift(),u[c]=consumeUntil(o,WHITESPACE_OR_COMMA)):triggerErrorEvent(e,"htmx:syntax:error",{token:o.shift()});}r.push(u);}o.length===l&&triggerErrorEvent(e,"htmx:syntax:error",{token:o.shift()}),consumeUntil(o,NOT_WHITESPACE);}while(o[0]===","&&o.shift());return n&&(n[t]=r),r}function getTriggerSpecs(e){let t=getAttributeValue(e,"hx-trigger"),n=[];if(t){let r=htmx.config.triggerSpecsCache;n=r&&r[t]||parseAndCacheTrigger(e,t,r);}return n.length>0?n:matches(e,"form")?[{trigger:"submit"}]:matches(e,'input[type="button"], input[type="submit"]')?[{trigger:"click"}]:matches(e,INPUT_SELECTOR)?[{trigger:"change"}]:[{trigger:"click"}]}function cancelPolling(e){getInternalData(e).cancelled=!0;}function processPolling(e,t,n){let r=getInternalData(e);r.timeout=getWindow().setTimeout(function(){bodyContains(e)&&r.cancelled!==!0&&(maybeFilterEvent(n,e,makeEvent("hx:poll:trigger",{triggerSpec:n,target:e}))||t(e),processPolling(e,t,n));},n.pollInterval);}function isLocalLink(e){return location.hostname===e.hostname&&getRawAttribute(e,"href")&&getRawAttribute(e,"href").indexOf("#")!==0}function eltIsDisabled(e){return closest(e,htmx.config.disableSelector)}function boostElement(e,t,n){if(e instanceof HTMLAnchorElement&&isLocalLink(e)&&(e.target===""||e.target==="_self")||e.tagName==="FORM"&&String(getRawAttribute(e,"method")).toLowerCase()!=="dialog"){t.boosted=!0;let r,o;if(e.tagName==="A")r="get",o=getRawAttribute(e,"href");else {let i=getRawAttribute(e,"method");r=i?i.toLowerCase():"get",o=getRawAttribute(e,"action");}n.forEach(function(i){addEventListener(e,function(s,l){let a=asElement(s);if(eltIsDisabled(a)){cleanUpElement(a);return}issueAjaxRequest(r,o,a,l);},t,i,!0);});}}function shouldCancel(e,t){let n=asElement(t);return n?!!((e.type==="submit"||e.type==="click")&&(n.tagName==="FORM"||matches(n,'input[type="submit"], button')&&closest(n,"form")!==null||n instanceof HTMLAnchorElement&&n.href&&(n.getAttribute("href")==="#"||n.getAttribute("href").indexOf("#")!==0))):!1}function ignoreBoostedAnchorCtrlClick(e,t){return getInternalData(e).boosted&&e instanceof HTMLAnchorElement&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function maybeFilterEvent(e,t,n){let r=e.eventFilter;if(r)try{return r.call(t,n)!==!0}catch(o){let i=r.source;return triggerErrorEvent(getDocument().body,"htmx:eventFilter:error",{error:o,source:i}),!0}return !1}function addEventListener(e,t,n,r,o){let i=getInternalData(e),s;r.from?s=querySelectorAllExt(e,r.from):s=[e],r.changed&&s.forEach(function(l){let a=getInternalData(l);a.lastValue=l.value;}),forEach(s,function(l){let a=function(u){if(!bodyContains(e)){l.removeEventListener(r.trigger,a);return}if(ignoreBoostedAnchorCtrlClick(e,u)||((o||shouldCancel(u,e))&&u.preventDefault(),maybeFilterEvent(r,e,u)))return;let f=getInternalData(u);if(f.triggerSpec=r,f.handledFor==null&&(f.handledFor=[]),f.handledFor.indexOf(e)<0){if(f.handledFor.push(e),r.consume&&u.stopPropagation(),r.target&&u.target&&!matches(asElement(u.target),r.target))return;if(r.once){if(i.triggeredOnce)return;i.triggeredOnce=!0;}if(r.changed){let c=getInternalData(l),d=l.value;if(c.lastValue===d)return;c.lastValue=d;}if(i.delayed&&clearTimeout(i.delayed),i.throttle)return;r.throttle>0?i.throttle||(triggerEvent(e,"htmx:trigger"),t(e,u),i.throttle=getWindow().setTimeout(function(){i.throttle=null;},r.throttle)):r.delay>0?i.delayed=getWindow().setTimeout(function(){triggerEvent(e,"htmx:trigger"),t(e,u);},r.delay):(triggerEvent(e,"htmx:trigger"),t(e,u));}};n.listenerInfos==null&&(n.listenerInfos=[]),n.listenerInfos.push({trigger:r.trigger,listener:a,on:l}),l.addEventListener(r.trigger,a);});}let windowIsScrolling=!1,scrollHandler=null;function initScrollHandler(){scrollHandler||(scrollHandler=function(){windowIsScrolling=!0;},window.addEventListener("scroll",scrollHandler),setInterval(function(){windowIsScrolling&&(windowIsScrolling=!1,forEach(getDocument().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"),function(e){maybeReveal(e);}));},200));}function maybeReveal(e){!hasAttribute(e,"data-hx-revealed")&&isScrolledIntoView(e)&&(e.setAttribute("data-hx-revealed","true"),getInternalData(e).initHash?triggerEvent(e,"revealed"):e.addEventListener("htmx:afterProcessNode",function(){triggerEvent(e,"revealed");},{once:!0}));}function loadImmediately(e,t,n,r){let o=function(){n.loaded||(n.loaded=!0,t(e));};r>0?getWindow().setTimeout(o,r):o();}function processVerbs(e,t,n){let r=!1;return forEach(VERBS,function(o){if(hasAttribute(e,"hx-"+o)){let i=getAttributeValue(e,"hx-"+o);r=!0,t.path=i,t.verb=o,n.forEach(function(s){addTriggerHandler(e,s,t,function(l,a){let u=asElement(l);if(closest(u,htmx.config.disableSelector)){cleanUpElement(u);return}issueAjaxRequest(o,i,u,a);});});}}),r}function addTriggerHandler(e,t,n,r){if(t.trigger==="revealed")initScrollHandler(),addEventListener(e,r,n,t),maybeReveal(asElement(e));else if(t.trigger==="intersect"){let o={};t.root&&(o.root=querySelectorExt(e,t.root)),t.threshold&&(o.threshold=parseFloat(t.threshold)),new IntersectionObserver(function(s){for(let l=0;l0?(n.polling=!0,processPolling(asElement(e),r,t)):addEventListener(e,r,n,t);}function shouldProcessHxOn(e){let t=asElement(e);if(!t)return !1;let n=t.attributes;for(let r=0;r", "+i).join(""))}else return []}function maybeSetLastButtonClicked(e){let t=closest(asElement(e.target),"button, input[type='submit']"),n=getRelatedFormData(e);n&&(n.lastButtonClicked=t);}function maybeUnsetLastButtonClicked(e){let t=getRelatedFormData(e);t&&(t.lastButtonClicked=null);}function getRelatedFormData(e){let t=closest(asElement(e.target),"button, input[type='submit']");if(!t)return;let n=resolveTarget("#"+getRawAttribute(t,"form"),t.getRootNode())||closest(t,"form");if(n)return getInternalData(n)}function initButtonTracking(e){e.addEventListener("click",maybeSetLastButtonClicked),e.addEventListener("focusin",maybeSetLastButtonClicked),e.addEventListener("focusout",maybeUnsetLastButtonClicked);}function addHxOnEventHandler(e,t,n){let r=getInternalData(e);Array.isArray(r.onHandlers)||(r.onHandlers=[]);let o,i=function(s){maybeEval(e,function(){eltIsDisabled(e)||(o||(o=new Function("event",n)),o.call(e,s));});};e.addEventListener(t,i),r.onHandlers.push({event:t,listener:i});}function processHxOnWildcard(e){deInitOnHandlers(e);for(let t=0;thtmx.config.historyCacheSize;)i.shift();for(;i.length>0;)try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(l){triggerErrorEvent(getDocument().body,"htmx:historyCacheError",{cause:l,cache:i}),i.shift();}}function getCachedHistory(e){if(!canAccessLocalStorage())return null;e=normalizePath(e);let t=parseJSON(localStorage.getItem("htmx-history-cache"))||[];for(let n=0;n=200&&this.status<400){triggerEvent(getDocument().body,"htmx:historyCacheMissLoad",n);let r=makeFragment(this.response),o=r.querySelector("[hx-history-elt],[data-hx-history-elt]")||r,i=getHistoryElement(),s=makeSettleInfo(i);handleTitle(r.title),swapInnerHTML(i,o,s),settleImmediately(s.tasks),currentPathForHistory=e,triggerEvent(getDocument().body,"htmx:historyRestore",{path:e,cacheMiss:!0,serverResponse:this.response});}else triggerErrorEvent(getDocument().body,"htmx:historyCacheMissLoadError",n);},t.send();}function restoreHistory(e){saveCurrentPageToHistory(),e=e||location.pathname+location.search;let t=getCachedHistory(e);if(t){let n=makeFragment(t.content),r=getHistoryElement(),o=makeSettleInfo(r);handleTitle(n.title),swapInnerHTML(r,n,o),settleImmediately(o.tasks),getWindow().setTimeout(function(){window.scrollTo(0,t.scroll);},0),currentPathForHistory=e,triggerEvent(getDocument().body,"htmx:historyRestore",{path:e,item:t});}else htmx.config.refreshOnHistoryMiss?window.location.reload(!0):loadHistoryFromServer(e);}function addRequestIndicatorClasses(e){let t=findAttributeTargets(e,"hx-indicator");return t==null&&(t=[e]),forEach(t,function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||0)+1,n.classList.add.call(n.classList,htmx.config.requestClass);}),t}function disableElements(e){let t=findAttributeTargets(e,"hx-disabled-elt");return t==null&&(t=[]),forEach(t,function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||0)+1,n.setAttribute("disabled",""),n.setAttribute("data-disabled-by-htmx","");}),t}function removeRequestIndicators(e,t){forEach(e,function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||0)-1,r.requestCount===0&&n.classList.remove.call(n.classList,htmx.config.requestClass);}),forEach(t,function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||0)-1,r.requestCount===0&&(n.removeAttribute("disabled"),n.removeAttribute("data-disabled-by-htmx"));});}function haveSeenNode(e,t){for(let n=0;nt.indexOf(o)<0):r=r.filter(o=>o!==t),n.delete(e),forEach(r,o=>n.append(e,o));}}function processInputValue(e,t,n,r,o){if(!(r==null||haveSeenNode(e,r))){if(e.push(r),shouldInclude(r)){let i=getRawAttribute(r,"name"),s=r.value;r instanceof HTMLSelectElement&&r.multiple&&(s=toArray(r.querySelectorAll("option:checked")).map(function(l){return l.value})),r instanceof HTMLInputElement&&r.files&&(s=toArray(r.files)),addValueToFormData(i,s,t),o&&validateElement(r,n);}r instanceof HTMLFormElement&&(forEach(r.elements,function(i){e.indexOf(i)>=0?removeValueFromFormData(i.name,i.value,t):e.push(i),o&&validateElement(i,n);}),new FormData(r).forEach(function(i,s){i instanceof File&&i.name===""||addValueToFormData(s,i,t);}));}}function validateElement(e,t){let n=e;n.willValidate&&(triggerEvent(n,"htmx:validation:validate"),n.checkValidity()||(t.push({elt:n,message:n.validationMessage,validity:n.validity}),triggerEvent(n,"htmx:validation:failed",{message:n.validationMessage,validity:n.validity})));}function overrideFormData(e,t){for(let n of t.keys())e.delete(n);return t.forEach(function(n,r){e.append(r,n);}),e}function getInputValues(e,t){let n=[],r=new FormData,o=new FormData,i=[],s=getInternalData(e);s.lastButtonClicked&&!bodyContains(s.lastButtonClicked)&&(s.lastButtonClicked=null);let l=e instanceof HTMLFormElement&&e.noValidate!==!0||getAttributeValue(e,"hx-validate")==="true";if(s.lastButtonClicked&&(l=l&&s.lastButtonClicked.formNoValidate!==!0),t!=="get"&&processInputValue(n,o,i,closest(e,"form"),l),processInputValue(n,r,i,e,l),s.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&getRawAttribute(e,"type")==="submit"){let u=s.lastButtonClicked||e,f=getRawAttribute(u,"name");addValueToFormData(f,u.value,o);}let a=findAttributeTargets(e,"hx-include");return forEach(a,function(u){processInputValue(n,r,i,asElement(u),l),matches(u,"form")||forEach(asParentNode(u).querySelectorAll(INPUT_SELECTOR),function(f){processInputValue(n,r,i,f,l);});}),overrideFormData(r,o),{errors:i,formData:r,values:formDataProxy(r)}}function appendParam(e,t,n){e!==""&&(e+="&"),String(n)==="[object Object]"&&(n=JSON.stringify(n));let r=encodeURIComponent(n);return e+=encodeURIComponent(t)+"="+r,e}function urlEncode(e){e=formDataFromObject(e);let t="";return e.forEach(function(n,r){t=appendParam(t,r,n);}),t}function getHeaders(e,t,n){let r={"HX-Request":"true","HX-Trigger":getRawAttribute(e,"id"),"HX-Trigger-Name":getRawAttribute(e,"name"),"HX-Target":getAttributeValue(t,"id"),"HX-Current-URL":getDocument().location.href};return getValuesForElement(e,"hx-headers",!1,r),n!==void 0&&(r["HX-Prompt"]=n),getInternalData(e).boosted&&(r["HX-Boosted"]="true"),r}function filterValues(e,t){let n=getClosestAttributeValue(t,"hx-params");if(n){if(n==="none")return new FormData;if(n==="*")return e;if(n.indexOf("not ")===0)return forEach(n.substr(4).split(","),function(r){r=r.trim(),e.delete(r);}),e;{let r=new FormData;return forEach(n.split(","),function(o){o=o.trim(),e.has(o)&&e.getAll(o).forEach(function(i){r.append(o,i);});}),r}}else return e}function isAnchorLink(e){return !!getRawAttribute(e,"href")&&getRawAttribute(e,"href").indexOf("#")>=0}function getSwapSpecification(e,t){let n=t||getClosestAttributeValue(e,"hx-swap"),r={swapStyle:getInternalData(e).boosted?"innerHTML":htmx.config.defaultSwapStyle,swapDelay:htmx.config.defaultSwapDelay,settleDelay:htmx.config.defaultSettleDelay};if(htmx.config.scrollIntoViewOnBoost&&getInternalData(e).boosted&&!isAnchorLink(e)&&(r.show="top"),n){let s=splitOnWhitespace(n);if(s.length>0)for(let l=0;l0?o.join(":"):null;r.scroll=f,r.scrollTarget=i;}else if(a.indexOf("show:")===0){var o=a.substr(5).split(":");let c=o.pop();var i=o.length>0?o.join(":"):null;r.show=c,r.showTarget=i;}else if(a.indexOf("focus-scroll:")===0){let u=a.substr(13);r.focusScroll=u=="true";}else l==0?r.swapStyle=a:logError("Unknown modifier in hx-swap: "+a);}}return r}function usesFormData(e){return getClosestAttributeValue(e,"hx-encoding")==="multipart/form-data"||matches(e,"form")&&getRawAttribute(e,"enctype")==="multipart/form-data"}function encodeParamsForBody(e,t,n){let r=null;return withExtensions(t,function(o){r==null&&(r=o.encodeParameters(e,n,t));}),r??(usesFormData(t)?overrideFormData(new FormData,formDataFromObject(n)):urlEncode(n))}function makeSettleInfo(e){return {tasks:[],elts:[e]}}function updateScrollState(e,t){let n=e[0],r=e[e.length-1];if(t.scroll){var o=null;t.scrollTarget&&(o=asElement(querySelectorExt(n,t.scrollTarget))),t.scroll==="top"&&(n||o)&&(o=o||n,o.scrollTop=0),t.scroll==="bottom"&&(r||o)&&(o=o||r,o.scrollTop=o.scrollHeight);}if(t.show){var o=null;if(t.showTarget){let s=t.showTarget;t.showTarget==="window"&&(s="body"),o=asElement(querySelectorExt(n,s));}t.show==="top"&&(n||o)&&(o=o||n,o.scrollIntoView({block:"start",behavior:htmx.config.scrollBehavior})),t.show==="bottom"&&(r||o)&&(o=o||r,o.scrollIntoView({block:"end",behavior:htmx.config.scrollBehavior}));}}function getValuesForElement(e,t,n,r){if(r==null&&(r={}),e==null)return r;let o=getAttributeValue(e,t);if(o){let i=o.trim(),s=n;if(i==="unset")return null;i.indexOf("javascript:")===0?(i=i.substr(11),s=!0):i.indexOf("js:")===0&&(i=i.substr(3),s=!0),i.indexOf("{")!==0&&(i="{"+i+"}");let l;s?l=maybeEval(e,function(){return Function("return ("+i+")")()},{}):l=parseJSON(i);for(let a in l)l.hasOwnProperty(a)&&r[a]==null&&(r[a]=l[a]);}return getValuesForElement(asElement(parentElt(e)),t,n,r)}function maybeEval(e,t,n){return htmx.config.allowEval?t():(triggerErrorEvent(e,"htmx:evalDisallowedError"),n)}function getHXVarsForElement(e,t){return getValuesForElement(e,"hx-vars",!0,t)}function getHXValsForElement(e,t){return getValuesForElement(e,"hx-vals",!1,t)}function getExpressionVars(e){return mergeObjects(getHXVarsForElement(e),getHXValsForElement(e))}function safelySetHeaderValue(e,t,n){if(n!==null)try{e.setRequestHeader(t,n);}catch{e.setRequestHeader(t,encodeURIComponent(n)),e.setRequestHeader(t+"-URI-AutoEncoded","true");}}function getPathFromResponse(e){if(e.responseURL&&typeof URL<"u")try{let t=new URL(e.responseURL);return t.pathname+t.search}catch{triggerErrorEvent(getDocument().body,"htmx:badResponseUrl",{url:e.responseURL});}}function hasHeader(e,t){return t.test(e.getAllResponseHeaders())}function ajaxHelper(e,t,n){return e=e.toLowerCase(),n?n instanceof Element||typeof n=="string"?issueAjaxRequest(e,t,null,null,{targetOverride:resolveTarget(n),returnPromise:!0}):issueAjaxRequest(e,t,resolveTarget(n.source),n.event,{handler:n.handler,headers:n.headers,values:n.values,targetOverride:resolveTarget(n.target),swapOverride:n.swap,select:n.select,returnPromise:!0}):issueAjaxRequest(e,t,null,null,{returnPromise:!0})}function hierarchyForElt(e){let t=[];for(;e;)t.push(e),e=e.parentElement;return t}function verifyPath(e,t,n){let r,o;return typeof URL=="function"?(o=new URL(t,document.location.href),r=document.location.origin===o.origin):(o=t,r=startsWith(t,document.location.origin)),htmx.config.selfRequestsOnly&&!r?!1:triggerEvent(e,"htmx:validateUrl",mergeObjects({url:o,sameHost:r},n))}function formDataFromObject(e){if(e instanceof FormData)return e;let t=new FormData;for(let n in e)e.hasOwnProperty(n)&&(typeof e[n].forEach=="function"?e[n].forEach(function(r){t.append(n,r);}):typeof e[n]=="object"&&!(e[n]instanceof Blob)?t.append(n,JSON.stringify(e[n])):t.append(n,e[n]));return t}function formDataArrayProxy(e,t,n){return new Proxy(n,{get:function(r,o){return typeof o=="number"?r[o]:o==="length"?r.length:o==="push"?function(i){r.push(i),e.append(t,i);}:typeof r[o]=="function"?function(){r[o].apply(r,arguments),e.delete(t),r.forEach(function(i){e.append(t,i);});}:r[o]&&r[o].length===1?r[o][0]:r[o]},set:function(r,o,i){return r[o]=i,e.delete(t),r.forEach(function(s){e.append(t,s);}),!0}})}function formDataProxy(e){return new Proxy(e,{get:function(t,n){if(typeof n=="symbol")return Reflect.get(t,n);if(n==="toJSON")return ()=>Object.fromEntries(e);if(n in t)return typeof t[n]=="function"?function(){return e[n].apply(e,arguments)}:t[n];let r=e.getAll(n);if(r.length!==0)return r.length===1?r[0]:formDataArrayProxy(t,n,r)},set:function(t,n,r){return typeof n!="string"?!1:(t.delete(n),typeof r.forEach=="function"?r.forEach(function(o){t.append(n,o);}):typeof r=="object"&&!(r instanceof Blob)?t.append(n,JSON.stringify(r)):t.append(n,r),!0)},deleteProperty:function(t,n){return typeof n=="string"&&t.delete(n),!0},ownKeys:function(t){return Reflect.ownKeys(Object.fromEntries(t))},getOwnPropertyDescriptor:function(t,n){return Reflect.getOwnPropertyDescriptor(Object.fromEntries(t),n)}})}function issueAjaxRequest(e,t,n,r,o,i){let s=null,l=null;if(o=o??{},o.returnPromise&&typeof Promise<"u")var a=new Promise(function(h,E){s=h,l=E;});n==null&&(n=getDocument().body);let u=o.handler||handleAjaxResponse,f=o.select||null;if(!bodyContains(n))return maybeCall(s),a;let c=o.targetOverride||asElement(getTarget(n));if(c==null||c==DUMMY_ELT)return triggerErrorEvent(n,"htmx:targetError",{target:getAttributeValue(n,"hx-target")}),maybeCall(l),a;let d=getInternalData(n),b=d.lastButtonClicked;if(b){let h=getRawAttribute(b,"formaction");h!=null&&(t=h);let E=getRawAttribute(b,"formmethod");E!=null&&E.toLowerCase()!=="dialog"&&(e=E);}let S=getClosestAttributeValue(n,"hx-confirm");if(i===void 0&&triggerEvent(n,"htmx:confirm",{target:c,elt:n,path:t,verb:e,triggeringEvent:r,etc:o,issueRequest:function(O){return issueAjaxRequest(e,t,n,r,o,!!O)},question:S})===!1)return maybeCall(s),a;let A=n,p=getClosestAttributeValue(n,"hx-sync"),x=null,H=!1;if(p){let h=p.split(":"),E=h[0].trim();if(E==="this"?A=findThisElement(n,"hx-sync"):A=asElement(querySelectorExt(n,E)),p=(h[1]||"drop").trim(),d=getInternalData(A),p==="drop"&&d.xhr&&d.abortable!==!0)return maybeCall(s),a;if(p==="abort"){if(d.xhr)return maybeCall(s),a;H=!0;}else p==="replace"?triggerEvent(A,"htmx:abort"):p.indexOf("queue")===0&&(x=(p.split(" ")[1]||"last").trim());}if(d.xhr)if(d.abortable)triggerEvent(A,"htmx:abort");else {if(x==null){if(r){let h=getInternalData(r);h&&h.triggerSpec&&h.triggerSpec.queue&&(x=h.triggerSpec.queue);}x==null&&(x="last");}return d.queuedRequests==null&&(d.queuedRequests=[]),x==="first"&&d.queuedRequests.length===0?d.queuedRequests.push(function(){issueAjaxRequest(e,t,n,r,o);}):x==="all"?d.queuedRequests.push(function(){issueAjaxRequest(e,t,n,r,o);}):x==="last"&&(d.queuedRequests=[],d.queuedRequests.push(function(){issueAjaxRequest(e,t,n,r,o);})),maybeCall(s),a}let m=new XMLHttpRequest;d.xhr=m,d.abortable=H;let T=function(){d.xhr=null,d.abortable=!1,d.queuedRequests!=null&&d.queuedRequests.length>0&&d.queuedRequests.shift()();},P=getClosestAttributeValue(n,"hx-prompt");if(P){var I=prompt(P);if(I===null||!triggerEvent(n,"htmx:prompt",{prompt:I,target:c}))return maybeCall(s),T(),a}if(S&&!i&&!confirm(S))return maybeCall(s),T(),a;let R=getHeaders(n,c,I);e!=="get"&&!usesFormData(n)&&(R["Content-Type"]="application/x-www-form-urlencoded"),o.headers&&(R=mergeObjects(R,o.headers));let v=getInputValues(n,e),L=v.errors,N=v.formData;o.values&&overrideFormData(N,formDataFromObject(o.values));let U=formDataFromObject(getExpressionVars(n)),B=overrideFormData(N,U),q=filterValues(B,n);htmx.config.getCacheBusterParam&&e==="get"&&q.set("org.htmx.cache-buster",getRawAttribute(c,"id")||"true"),(t==null||t==="")&&(t=getDocument().location.href);let _=getValuesForElement(n,"hx-request"),z=getInternalData(n).boosted,F=htmx.config.methodsThatUseUrlParams.indexOf(e)>=0,w={boosted:z,useUrlParams:F,formData:q,parameters:formDataProxy(q),unfilteredFormData:B,unfilteredParameters:formDataProxy(B),headers:R,target:c,verb:e,errors:L,withCredentials:o.credentials||_.credentials||htmx.config.withCredentials,timeout:o.timeout||_.timeout||htmx.config.timeout,path:t,triggeringEvent:r};if(!triggerEvent(n,"htmx:configRequest",w))return maybeCall(s),T(),a;if(t=w.path,e=w.verb,R=w.headers,q=formDataFromObject(w.parameters),L=w.errors,F=w.useUrlParams,L&&L.length>0)return triggerEvent(n,"htmx:validation:halted",w),maybeCall(s),T(),a;let J=t.split("#"),$=J[0],W=J[1],D=t;if(F&&(D=$,!q.keys().next().done&&(D.indexOf("?")<0?D+="?":D+="&",D+=urlEncode(q),W&&(D+="#"+W))),!verifyPath(n,D,w))return triggerErrorEvent(n,"htmx:invalidPath",w),maybeCall(l),a;if(m.open(e.toUpperCase(),D,!0),m.overrideMimeType("text/html"),m.withCredentials=w.withCredentials,m.timeout=w.timeout,!_.noHeaders){for(let h in R)if(R.hasOwnProperty(h)){let E=R[h];safelySetHeaderValue(m,h,E);}}let y={xhr:m,target:c,requestConfig:w,etc:o,boosted:z,select:f,pathInfo:{requestPath:t,finalRequestPath:D,responsePath:null,anchor:W}};if(m.onload=function(){try{let h=hierarchyForElt(n);if(y.pathInfo.responsePath=getPathFromResponse(m),u(n,y),y.keepIndicators!==!0&&removeRequestIndicators(M,V),triggerEvent(n,"htmx:afterRequest",y),triggerEvent(n,"htmx:afterOnLoad",y),!bodyContains(n)){let E=null;for(;h.length>0&&E==null;){let O=h.shift();bodyContains(O)&&(E=O);}E&&(triggerEvent(E,"htmx:afterRequest",y),triggerEvent(E,"htmx:afterOnLoad",y));}maybeCall(s),T();}catch(h){throw triggerErrorEvent(n,"htmx:onLoadError",mergeObjects({error:h},y)),h}},m.onerror=function(){removeRequestIndicators(M,V),triggerErrorEvent(n,"htmx:afterRequest",y),triggerErrorEvent(n,"htmx:sendError",y),maybeCall(l),T();},m.onabort=function(){removeRequestIndicators(M,V),triggerErrorEvent(n,"htmx:afterRequest",y),triggerErrorEvent(n,"htmx:sendAbort",y),maybeCall(l),T();},m.ontimeout=function(){removeRequestIndicators(M,V),triggerErrorEvent(n,"htmx:afterRequest",y),triggerErrorEvent(n,"htmx:timeout",y),maybeCall(l),T();},!triggerEvent(n,"htmx:beforeRequest",y))return maybeCall(s),T(),a;var M=addRequestIndicatorClasses(n),V=disableElements(n);forEach(["loadstart","loadend","progress","abort"],function(h){forEach([m,m.upload],function(E){E.addEventListener(h,function(O){triggerEvent(n,"htmx:xhr:"+h,{lengthComputable:O.lengthComputable,loaded:O.loaded,total:O.total});});});}),triggerEvent(n,"htmx:beforeSend",y);let Q=F?null:encodeParamsForBody(m,n,q);return m.send(Q),a}function determineHistoryUpdates(e,t){let n=t.xhr,r=null,o=null;if(hasHeader(n,/HX-Push:/i)?(r=n.getResponseHeader("HX-Push"),o="push"):hasHeader(n,/HX-Push-Url:/i)?(r=n.getResponseHeader("HX-Push-Url"),o="push"):hasHeader(n,/HX-Replace-Url:/i)&&(r=n.getResponseHeader("HX-Replace-Url"),o="replace"),r)return r==="false"?{}:{type:o,path:r};let i=t.pathInfo.finalRequestPath,s=t.pathInfo.responsePath,l=getClosestAttributeValue(e,"hx-push-url"),a=getClosestAttributeValue(e,"hx-replace-url"),u=getInternalData(e).boosted,f=null,c=null;return l?(f="push",c=l):a?(f="replace",c=a):u&&(f="push",c=s||i),c?c==="false"?{}:(c==="true"&&(c=s||i),t.pathInfo.anchor&&c.indexOf("#")===-1&&(c=c+"#"+t.pathInfo.anchor),{type:f,path:c}):{}}function codeMatches(e,t){var n=new RegExp(e.code);return n.test(t.toString(10))}function resolveResponseHandling(e){for(var t=0;t0?getWindow().setTimeout(I,x.swapDelay):I();}c&&triggerErrorEvent(e,"htmx:responseError",mergeObjects({error:"Response Status Error Code "+n.status+" from "+t.pathInfo.requestPath},t));}}let extensions={};function extensionBase(){return {init:function(e){return null},getSelectors:function(){return null},onEvent:function(e,t){return !0},transformResponse:function(e,t,n){return e},isInlineSwap:function(e){return !1},handleSwap:function(e,t,n,r){return !1},encodeParameters:function(e,t,n){return null}}}function defineExtension(e,t){t.init&&t.init(internalAPI),extensions[e]=mergeObjects(extensionBase(),t);}function removeExtension(e){delete extensions[e];}function getExtensions(e,t,n){if(t==null&&(t=[]),e==null)return t;n==null&&(n=[]);let r=getAttributeValue(e,"hx-ext");return r&&forEach(r.split(","),function(o){if(o=o.replace(/ /g,""),o.slice(0,7)=="ignore:"){n.push(o.slice(7));return}if(n.indexOf(o)<0){let i=extensions[o];i&&t.indexOf(i)<0&&t.push(i);}}),getExtensions(asElement(parentElt(e)),t,n)}var isReady=!1;getDocument().addEventListener("DOMContentLoaded",function(){isReady=!0;});function ready(e){isReady||getDocument().readyState==="complete"?e():getDocument().addEventListener("DOMContentLoaded",e);}function insertIndicatorStyles(){if(htmx.config.includeIndicatorStyles!==!1){let e=htmx.config.inlineStyleNonce?` nonce="${htmx.config.inlineStyleNonce}"`:"";getDocument().head.insertAdjacentHTML("beforeend","");}}function getMetaConfig(){let e=getDocument().querySelector('meta[name="htmx-config"]');return e?parseJSON(e.content):null}function mergeMetaConfig(){let e=getMetaConfig();e&&(htmx.config=mergeObjects(htmx.config,e));}return ready(function(){mergeMetaConfig(),insertIndicatorStyles();let e=getDocument().body;processNode(e);let t=getDocument().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(r){let o=r.target,i=getInternalData(o);i&&i.xhr&&i.xhr.abort();});let n=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(r){r.state&&r.state.htmx?(restoreHistory(),forEach(t,function(o){triggerEvent(o,"htmx:restored",{document:getDocument(),triggerEvent});})):n&&n(r);},getWindow().setTimeout(function(){triggerEvent(e,"htmx:load",{}),e=null;},0);}),htmx}(),g=K;function Z(e,t){if(e==="ignore")return !1;let n=e.split("/"),r=t.split("/");for(let o=0;o{if(!(t instanceof CustomEvent))return !1;let n=t.detail.target;return n&&n.children&&Array.from(n.children).forEach(r=>{g.trigger(r,e,null);}),!0},init:function(e){},transformResponse:function(e,t,n){return e},isInlineSwap:function(e){return !1},handleSwap:function(e,t,n,r){return !1},encodeParameters:function(e,t,n){},getSelectors:function(){return null}});g.defineExtension("debug",{onEvent:function(e,t){console.debug?console.debug(e):console&&console.log("DEBUG:",e);}});var C=g.config,k,te="hx-target-";function G(e,t){return e.substring(0,t.length)===t}function ne(e,t){if(!e||!t)return null;let n=t.toString(),r=[n,n.substr(0,2)+"*",n.substr(0,2)+"x",n.substr(0,1)+"*",n.substr(0,1)+"x",n.substr(0,1)+"**",n.substr(0,1)+"xx","*","x","***","xxx"];(G(n,"4")||G(n,"5"))&&r.push("error");for(let o=0;o{k=e,C.responseTargetUnsetsError===void 0&&(C.responseTargetUnsetsError=!0),C.responseTargetSetsError===void 0&&(C.responseTargetSetsError=!1),C.responseTargetPrefersExisting===void 0&&(C.responseTargetPrefersExisting=!1),C.responseTargetPrefersRetargetHeader===void 0&&(C.responseTargetPrefersRetargetHeader=!0);},onEvent:(e,t)=>{if(!(t instanceof CustomEvent))return !1;if(e==="htmx:beforeSwap"&&t.detail.xhr&&t.detail.xhr.status!==200){if(t.detail.target&&(C.responseTargetPrefersExisting||C.responseTargetPrefersRetargetHeader&&t.detail.xhr.getAllResponseHeaders().match(/HX-Retarget:/i)))return t.detail.shouldSwap=!0,X(t),!0;if(!t.detail.requestConfig)return !0;let n=ne(t.detail.requestConfig.elt,t.detail.xhr.status);return n&&(X(t),t.detail.shouldSwap=!0,t.detail.target=n),!0}}});g.defineExtension("mutation-error",{onEvent:(e,t)=>{if(!(t instanceof CustomEvent))return !1;if(e==="htmx:afterRequest"){if(!t.detail||!t.detail.xhr)return;let n=t.detail.xhr.status;n>=400&&g.findAll("[hx-on\\:\\:mutation-error]").forEach(r=>{g.trigger(r,"htmx:mutation-error",{status:n});});}}});function Y(e){let t=null,n=o=>{t=new WebSocket(e.url),t.onopen=()=>{},t.onmessage=i=>{e.onMessage(i.data);},t.onerror=i=>{},t.onclose=()=>{console.log("WebSocket connection closed. Attempting to reconnect...");let i=o*(e.reconnectInterval||50);setTimeout(()=>n(o+1),i);};};n(1);let r=o=>{t&&t.readyState===WebSocket.OPEN?t.send(o):setTimeout(()=>r(o),100);};return {sendMessage:r}}var j="";g.defineExtension("livereload",{init:function(){let e=window.location.host;console.log("livereload extension initialized."),Y({url:`ws://${e}/dev/livereload`,onOpen:()=>{console.log("LiveReload connected.");},onMessage:t=>{j===""&&(j=t),j!==t&&window.location.reload();},onError:t=>{},onClose:()=>{}});},onEvent:function(e,t){}});function re(e){let t=window.location.href;setInterval(()=>{window.location.href!==t&&(e(t,window.location.href),t=window.location.href);},100);}re((e,t)=>{oe(t);});function oe(e){let t=new URL(e);document.querySelectorAll("[hx-trigger]").forEach(function(n){let r=n.getAttribute("hx-trigger");if(!r)return;if(r.split(", ").find(i=>i==="url"))g.swap(n,"url",{swapStyle:"outerHTML",swapDelay:0,settleDelay:0});else for(let[i,s]of t.searchParams){let l="qs:"+i;if(r.includes(l)){console.log("triggering",l),g.trigger(n,l,null);break}}}),document.querySelectorAll("[hx-match-qp]").forEach(n=>{let r=!1;for(let o of n.getAttributeNames())if(o.startsWith("hx-match-qp-mapping:")){let i=o.replace("hx-match-qp-mapping:","");if(t.searchParams.get(i)){g.swap(n,n.getAttribute(o)??"",{swapStyle:"innerHTML",swapDelay:0,settleDelay:0}),r=!0;break}}if(!r){let o=n.getAttribute("hx-match-qp-default");o&&g.swap(n,n.getAttribute("hx-match-qp-mapping:"+o)??"",{swapStyle:"innerHTML",swapDelay:0,settleDelay:0});}});}
diff --git a/framework/assets/js/htmgo.ts b/framework/assets/js/htmgo.ts
index 2debef2..260772d 100644
--- a/framework/assets/js/htmgo.ts
+++ b/framework/assets/js/htmgo.ts
@@ -4,6 +4,7 @@ import "./htmxextensions/trigger-children";
import "./htmxextensions/debug";
import "./htmxextensions/response-targets";
import "./htmxextensions/mutation-error";
+import "./htmxextensions/livereload"
function watchUrl(callback: (oldUrl: string, newUrl: string) => void) {
let lastUrl = window.location.href;
diff --git a/framework/assets/js/htmxextensions/livereload.ts b/framework/assets/js/htmxextensions/livereload.ts
new file mode 100644
index 0000000..7fd6575
--- /dev/null
+++ b/framework/assets/js/htmxextensions/livereload.ts
@@ -0,0 +1,33 @@
+import htmx from "htmx.org";
+import {createWebSocketClient} from "../util/ws";
+
+let lastVersion = "";
+
+htmx.defineExtension("livereload", {
+ init: function () {
+ const host = window.location.host;
+ console.log('livereload extension initialized.');
+ createWebSocketClient({
+ url: `ws://${host}/dev/livereload`,
+ onOpen: () => {
+ console.log('LiveReload connected.');
+ },
+ onMessage: (message) => {
+ if(lastVersion === "") {
+ lastVersion = message;
+ }
+ if(lastVersion !== message) {
+ window.location.reload();
+ }
+ },
+ onError: (error) => {
+ },
+ onClose: () => {
+ }
+ })
+ },
+ // @ts-ignore
+ onEvent: function (name, evt) {
+
+ },
+});
\ No newline at end of file
diff --git a/framework/assets/js/util/ws.ts b/framework/assets/js/util/ws.ts
new file mode 100644
index 0000000..8e72f9f
--- /dev/null
+++ b/framework/assets/js/util/ws.ts
@@ -0,0 +1,40 @@
+type WsOpts = {
+ url: string;
+ reconnectInterval?: number;
+ onOpen?: () => void;
+ onMessage: (message: string) => void;
+ onError?: (error: Event) => void;
+ onClose?: () => void;
+}
+
+export function createWebSocketClient(opts: WsOpts) {
+ let socket: WebSocket | null = null;
+ const connect = (tries: number) => {
+ socket = new WebSocket(opts.url);
+ // Handle connection open
+ socket.onopen = () => {
+ };
+ // Handle incoming messages
+ socket.onmessage = (event) => {
+ opts.onMessage(event.data)
+ };
+ // Handle connection errors
+ socket.onerror = (error) => {
+ };
+ // Handle connection close and attempt reconnection
+ socket.onclose = () => {
+ console.log('WebSocket connection closed. Attempting to reconnect...');
+ let interval = tries * (opts.reconnectInterval || 50);
+ setTimeout(() => connect(tries + 1), interval);
+ };
+ };
+ connect(1);
+ const sendMessage = (message: string) => {
+ if (socket && socket.readyState === WebSocket.OPEN) {
+ socket.send(message);
+ } else {
+ setTimeout(() => sendMessage(message), 100);
+ }
+ };
+ return { sendMessage };
+}
\ No newline at end of file
diff --git a/framework/go.mod b/framework/go.mod
index 013da8c..af149c0 100644
--- a/framework/go.mod
+++ b/framework/go.mod
@@ -5,20 +5,27 @@ go 1.23.0
require (
github.com/dave/jennifer v1.7.1
github.com/fsnotify/fsnotify v1.7.0
- github.com/gofiber/fiber/v2 v2.52.5
golang.org/x/net v0.29.0
)
require (
- github.com/andybalholm/brotli v1.0.5 // indirect
- github.com/google/uuid v1.5.0 // indirect
- github.com/klauspost/compress v1.17.0 // indirect
+ github.com/andybalholm/brotli v1.1.0 // indirect
+ github.com/fasthttp/websocket v1.5.10 // indirect
+ github.com/gofiber/contrib/websocket v1.3.2 // indirect
+ github.com/google/uuid v1.6.0 // indirect
+ github.com/klauspost/compress v1.17.9 // indirect
+ github.com/labstack/echo/v4 v4.12.0 // indirect
+ github.com/labstack/gommon v0.4.2 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
- github.com/mattn/go-runewidth v0.0.15 // indirect
- github.com/rivo/uniseg v0.2.0 // indirect
+ github.com/mattn/go-runewidth v0.0.16 // indirect
+ github.com/rivo/uniseg v0.4.7 // indirect
+ github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
- github.com/valyala/fasthttp v1.51.0 // indirect
+ github.com/valyala/fasthttp v1.55.0 // indirect
+ github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
+ golang.org/x/crypto v0.27.0 // indirect
golang.org/x/sys v0.25.0 // indirect
+ golang.org/x/text v0.18.0 // indirect
)
diff --git a/framework/h/app.go b/framework/h/app.go
index 5ecc8fa..f3cb2d5 100644
--- a/framework/h/app.go
+++ b/framework/h/app.go
@@ -2,7 +2,7 @@ package h
import (
"fmt"
- "github.com/gofiber/fiber/v2"
+ "github.com/labstack/echo/v4"
"github.com/maddalax/htmgo/framework/util/process"
"log/slog"
"time"
@@ -10,7 +10,7 @@ import (
type App struct {
LiveReload bool
- Fiber *fiber.App
+ Echo *echo.Echo
}
var instance *App
@@ -22,21 +22,21 @@ func GetApp() *App {
return instance
}
-func Start(app *fiber.App, opts App) {
+func Start(app *echo.Echo, opts App) {
instance = &opts
instance.start(app)
}
-func (a App) start(app *fiber.App) {
+func (a App) start(app *echo.Echo) {
- a.Fiber = app
+ a.Echo = app
if a.LiveReload {
- AddLiveReloadHandler("/livereload", a.Fiber)
+ AddLiveReloadHandler("/dev/livereload", a.Echo)
}
port := ":3000"
- err := a.Fiber.Listen(port)
+ err := a.Echo.Start(port)
if err != nil {
// If we are in watch mode, just try to kill any processes holding that port
@@ -45,7 +45,7 @@ func (a App) start(app *fiber.App) {
slog.Info("Port already in use, trying to kill the process and start again")
process.RunOrExit(fmt.Sprintf("kill -9 $(lsof -t -i%s)", port))
time.Sleep(time.Millisecond * 50)
- err = a.Fiber.Listen(port)
+ err = a.Echo.Start(port)
if err != nil {
panic(err)
}
@@ -55,25 +55,16 @@ func (a App) start(app *fiber.App) {
}
}
-func HtmlView(c *fiber.Ctx, page *Page) error {
+func HtmlView(c echo.Context, page *Page) error {
root := page.Root.Render()
- c.Set(fiber.HeaderContentType, fiber.MIMETextHTML)
-
- if GetApp().LiveReload && root.tag == "html" {
- root.AppendChild(
- LiveReload(),
- )
- }
-
- return c.SendString(
+ return c.HTML(200,
Render(
root,
),
)
}
-func PartialViewWithHeaders(c *fiber.Ctx, headers *Headers, partial *Partial) error {
- c.Set(fiber.HeaderContentType, fiber.MIMETextHTML)
+func PartialViewWithHeaders(c echo.Context, headers *Headers, partial *Partial) error {
if partial.Headers != nil {
for s, a := range *partial.Headers {
c.Set(s, a)
@@ -86,22 +77,22 @@ func PartialViewWithHeaders(c *fiber.Ctx, headers *Headers, partial *Partial) er
}
}
- return c.SendString(
+ return c.HTML(200,
Render(
partial.Root,
),
)
}
-func PartialView(c *fiber.Ctx, partial *Partial) error {
- c.Set(fiber.HeaderContentType, fiber.MIMETextHTML)
+func PartialView(c echo.Context, partial *Partial) error {
+ c.Set(echo.HeaderContentType, echo.MIMETextHTML)
if partial.Headers != nil {
for s, a := range *partial.Headers {
c.Set(s, a)
}
}
- return c.SendString(
+ return c.HTML(200,
Render(
partial.Root,
),
diff --git a/framework/h/base.go b/framework/h/base.go
index b508102..a43602f 100644
--- a/framework/h/base.go
+++ b/framework/h/base.go
@@ -1,7 +1,7 @@
package h
import (
- "github.com/gofiber/fiber/v2"
+ "github.com/labstack/echo/v4"
"html"
"net/http"
"reflect"
@@ -51,10 +51,10 @@ func NewPartial(root Renderable) *Partial {
}
}
-func GetPartialPath(partial func(ctx *fiber.Ctx) *Partial) string {
+func GetPartialPath(partial func(ctx echo.Context) *Partial) string {
return runtime.FuncForPC(reflect.ValueOf(partial).Pointer()).Name()
}
-func GetPartialPathWithQs(partial func(ctx *fiber.Ctx) *Partial, qs string) string {
+func GetPartialPathWithQs(partial func(ctx echo.Context) *Partial, qs string) string {
return html.EscapeString(GetPartialPath(partial) + "?" + qs)
}
diff --git a/framework/h/livereload.go b/framework/h/livereload.go
index f30375b..4569d9d 100644
--- a/framework/h/livereload.go
+++ b/framework/h/livereload.go
@@ -1,33 +1,30 @@
package h
import (
- "github.com/gofiber/fiber/v2"
- "strconv"
+ "github.com/google/uuid"
+ "github.com/labstack/echo/v4"
+ "golang.org/x/net/websocket"
"time"
)
-var Version = time.Now().Nanosecond()
+var Version = uuid.NewString()
-func LiveReloadHandler(c *fiber.Ctx) error {
- v := strconv.FormatInt(int64(Version), 10)
- current := c.Cookies("version", v)
-
- if current != v {
- c.Set("HX-Refresh", "true")
- }
-
- c.Cookie(&fiber.Cookie{
- Name: "version",
- Value: v,
- })
-
- return c.SendString("")
+func handler(c echo.Context) error {
+ websocket.Handler(func(ws *websocket.Conn) {
+ defer ws.Close()
+ _ = websocket.Message.Send(ws, Version)
+ // keep ws alive
+ for {
+ err := websocket.Message.Send(ws, Version)
+ if err != nil {
+ return
+ }
+ time.Sleep(500 * time.Millisecond)
+ }
+ }).ServeHTTP(c.Response(), c.Request())
+ return nil
}
-func LiveReload() Renderable {
- return Div(Get("/livereload"), Trigger("every 200ms"))
-}
-
-func AddLiveReloadHandler(path string, app *fiber.App) {
- app.Get(path, LiveReloadHandler)
+func AddLiveReloadHandler(path string, app *echo.Echo) {
+ app.GET(path, handler)
}
diff --git a/framework/h/tag.go b/framework/h/tag.go
index 9c0696b..2128c0f 100644
--- a/framework/h/tag.go
+++ b/framework/h/tag.go
@@ -3,7 +3,7 @@ package h
import (
"encoding/json"
"fmt"
- "github.com/gofiber/fiber/v2"
+ "github.com/labstack/echo/v4"
"html"
"net/url"
"strings"
@@ -101,11 +101,11 @@ func Get(path string) Renderable {
return Attribute("hx-get", path)
}
-func GetPartial(partial func(ctx *fiber.Ctx) *Partial) Renderable {
+func GetPartial(partial func(ctx echo.Context) *Partial) Renderable {
return Get(GetPartialPath(partial))
}
-func GetPartialWithQs(partial func(ctx *fiber.Ctx) *Partial, qs string) Renderable {
+func GetPartialWithQs(partial func(ctx echo.Context) *Partial, qs string) Renderable {
return Get(GetPartialPathWithQs(partial, qs))
}
@@ -119,13 +119,13 @@ type ReloadParams struct {
Children Renderable
}
-func ViewOnLoad(partial func(ctx *fiber.Ctx) *Partial) Renderable {
+func ViewOnLoad(partial func(ctx echo.Context) *Partial) Renderable {
return View(partial, ReloadParams{
Triggers: CreateTriggers("load"),
})
}
-func View(partial func(ctx *fiber.Ctx) *Partial, params ReloadParams) Renderable {
+func View(partial func(ctx echo.Context) *Partial, params ReloadParams) Renderable {
return Div(Attributes(map[string]string{
"hx-get": GetPartialPath(partial),
"hx-trigger": strings.Join(params.Triggers, ", "),
@@ -133,7 +133,7 @@ func View(partial func(ctx *fiber.Ctx) *Partial, params ReloadParams) Renderable
}), params.Children)
}
-func PartialWithTriggers(partial func(ctx *fiber.Ctx) *Partial, triggers ...string) Renderable {
+func PartialWithTriggers(partial func(ctx echo.Context) *Partial, triggers ...string) Renderable {
return Div(Attributes(map[string]string{
"hx-get": GetPartialPath(partial),
"hx-trigger": strings.Join(triggers, ", "),
@@ -283,8 +283,8 @@ func CombineHeaders(headers ...*Headers) *Headers {
return &m
}
-func CurrentPath(ctx *fiber.Ctx) string {
- current := ctx.Get("Hx-Current-Url")
+func CurrentPath(ctx echo.Context) string {
+ current := ctx.Request().Header.Get("Hx-Current-Url")
parsed, err := url.Parse(current)
if err != nil {
return ""
@@ -292,8 +292,8 @@ func CurrentPath(ctx *fiber.Ctx) string {
return parsed.Path
}
-func PushQsHeader(ctx *fiber.Ctx, key string, value string) *Headers {
- current := ctx.Get("Hx-Current-Url")
+func PushQsHeader(ctx echo.Context, key string, value string) *Headers {
+ current := ctx.Request().Header.Get("Hx-Current-Url")
parsed, err := url.Parse(current)
if err != nil {
return NewHeaders()
@@ -512,11 +512,11 @@ func IfElseLazy(condition bool, cb1 func() Renderable, cb2 func() Renderable) Re
}
}
-func GetTriggerName(ctx *fiber.Ctx) string {
- return ctx.Get("HX-Trigger-Name")
+func GetTriggerName(ctx echo.Context) string {
+ return ctx.Request().Header.Get("HX-Trigger-Name")
}
-func IfHtmxRequest(ctx *fiber.Ctx, node Renderable) Renderable {
+func IfHtmxRequest(ctx echo.Context, node Renderable) Renderable {
if ctx.Get("HX-Request") != "" {
return node
}
@@ -535,11 +535,11 @@ func NewSwap(selector string, content *Node) SwapArg {
}
}
-func Swap(ctx *fiber.Ctx, content Renderable) Renderable {
+func Swap(ctx echo.Context, content Renderable) Renderable {
return SwapWithSelector(ctx, "", content)
}
-func SwapWithSelector(ctx *fiber.Ctx, selector string, content Renderable) Renderable {
+func SwapWithSelector(ctx echo.Context, selector string, content Renderable) Renderable {
if ctx == nil || ctx.Get("HX-Request") == "" {
return Empty()
}
@@ -547,7 +547,7 @@ func SwapWithSelector(ctx *fiber.Ctx, selector string, content Renderable) Rende
return c.AppendChild(OutOfBandSwap(selector))
}
-func SwapMany(ctx *fiber.Ctx, args ...SwapArg) Renderable {
+func SwapMany(ctx echo.Context, args ...SwapArg) Renderable {
if ctx.Get("HX-Request") == "" {
return Empty()
}
diff --git a/framework/h/util.go b/framework/h/util.go
index 38f0fe3..bba8adb 100644
--- a/framework/h/util.go
+++ b/framework/h/util.go
@@ -2,7 +2,7 @@ package h
import (
"encoding/json"
- "github.com/gofiber/fiber/v2"
+ "github.com/labstack/echo/v4"
"net/url"
)
@@ -33,10 +33,10 @@ func JsonSerialize(data any) string {
return string(serialized)
}
-func GetQueryParam(ctx *fiber.Ctx, key string) string {
- value := ctx.Query(key)
+func GetQueryParam(ctx echo.Context, key string) string {
+ value := ctx.QueryParam(key)
if value == "" {
- current := ctx.Get("Hx-Current-Url")
+ current := ctx.Request().Header.Get("Hx-Current-Url")
if current != "" {
u, err := url.Parse(current)
if err == nil {
diff --git a/sandbox/features/patient/patient-service.go b/sandbox/features/patient/patient-service.go
index 33698a8..e7ee1db 100644
--- a/sandbox/features/patient/patient-service.go
+++ b/sandbox/features/patient/patient-service.go
@@ -2,8 +2,8 @@ package patient
import (
"errors"
- "github.com/gofiber/fiber/v2"
"github.com/google/uuid"
+ "github.com/labstack/echo/v4"
"starter-template/database"
"time"
)
@@ -16,10 +16,10 @@ type Patient struct {
}
type Service struct {
- ctx *fiber.Ctx
+ ctx echo.Context
}
-func NewService(ctx *fiber.Ctx) *Service {
+func NewService(ctx echo.Context) *Service {
return &Service{}
}
diff --git a/sandbox/go.mod b/sandbox/go.mod
index b3b4319..7fff5e7 100644
--- a/sandbox/go.mod
+++ b/sandbox/go.mod
@@ -3,7 +3,6 @@ module sandbox
go 1.23.0
require (
- github.com/gofiber/fiber/v2 v2.52.5
github.com/google/uuid v1.6.0
github.com/maddalax/htmgo/framework v0.0.0-20240914010415-2397bf9fb057
github.com/maddalax/htmgo/framework-ui v0.0.0-20240914003619-c256552b2143
diff --git a/sandbox/go.sum b/sandbox/go.sum
index 3af5118..ae73e3b 100644
--- a/sandbox/go.sum
+++ b/sandbox/go.sum
@@ -2,8 +2,8 @@ github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
-github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo=
-github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
+github.com/labstack/echo/v4 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo=
+github.com/labstack/echo/v4 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
diff --git a/sandbox/main.go b/sandbox/main.go
index b0e8038..52b9cec 100644
--- a/sandbox/main.go
+++ b/sandbox/main.go
@@ -1,8 +1,8 @@
package main
import (
- "github.com/gofiber/fiber/v2"
"github.com/google/uuid"
+ "github.com/labstack/echo/v4"
"github.com/maddalax/htmgo/framework/h"
"log"
"starter-template/pages"
@@ -11,16 +11,16 @@ import (
)
func main() {
- f := fiber.New()
+ f := echo.New()
f.Static("/public", "./assets/dist")
- f.Use(func(ctx *fiber.Ctx) error {
+ f.Use(func(ctx echo.Context) error {
if ctx.Cookies("htmgo-session") != "" {
return ctx.Next()
}
id := ctx.IP() + uuid.NewString()
- ctx.Cookie(&fiber.Cookie{
+ ctx.Cookie(&echo.Cookie{
Name: "htmgo-session",
Value: id,
SessionOnly: true,
@@ -28,7 +28,7 @@ func main() {
return ctx.Next()
})
- f.Use(func(ctx *fiber.Ctx) error {
+ f.Use(func(ctx echo.Context) error {
if ctx.Path() == "/livereload" {
return ctx.Next()
}
diff --git a/sandbox/pages/generated.go b/sandbox/pages/generated.go
index 5fa743a..a98135a 100644
--- a/sandbox/pages/generated.go
+++ b/sandbox/pages/generated.go
@@ -1,20 +1,20 @@
// Package pages THIS FILE IS GENERATED. DO NOT EDIT.
package pages
-import "github.com/gofiber/fiber/v2"
+import "github.com/labstack/echo/v4"
import "github.com/maddalax/htmgo/framework/h"
-func RegisterPages(f *fiber.App) {
- f.Get("/", func(ctx *fiber.Ctx) error {
+func RegisterPages(f *echo.Echo) {
+ f.Get("/", func(ctx echo.Context) error {
return h.HtmlView(ctx, IndexPage(ctx))
})
- f.Get("/news/:id", func(ctx *fiber.Ctx) error {
+ f.Get("/news/:id", func(ctx echo.Context) error {
return h.HtmlView(ctx, Test(ctx))
})
- f.Get("/news", func(ctx *fiber.Ctx) error {
+ f.Get("/news", func(ctx echo.Context) error {
return h.HtmlView(ctx, ListPage(ctx))
})
- f.Get("/patients", func(ctx *fiber.Ctx) error {
+ f.Get("/patients", func(ctx echo.Context) error {
return h.HtmlView(ctx, PatientsIndex(ctx))
})
}
diff --git a/sandbox/pages/index.go b/sandbox/pages/index.go
index 56d01e1..5889746 100644
--- a/sandbox/pages/index.go
+++ b/sandbox/pages/index.go
@@ -2,13 +2,13 @@ package pages
import (
"fmt"
- "github.com/gofiber/fiber/v2"
+ "github.com/labstack/echo/v4"
"github.com/maddalax/htmgo/framework/h"
"os"
"time"
)
-func IndexPage(c *fiber.Ctx) *h.Page {
+func IndexPage(c echo.Context) *h.Page {
return h.NewPage(h.Html(
h.Class("bg-background flex flex-col items-center"),
h.Head(
diff --git a/sandbox/pages/news.$id.go b/sandbox/pages/news.$id.go
index c63bebb..a3a70a9 100644
--- a/sandbox/pages/news.$id.go
+++ b/sandbox/pages/news.$id.go
@@ -2,11 +2,11 @@ package pages
import (
"fmt"
- "github.com/gofiber/fiber/v2"
+ "github.com/labstack/echo/v4"
"github.com/maddalax/htmgo/framework/h"
)
-func Test(ctx *fiber.Ctx) *h.Page {
+func Test(ctx echo.Context) *h.Page {
text := fmt.Sprintf("News ID: %s", ctx.Params("id"))
return h.NewPage(
h.Div(h.Text(text)),
diff --git a/sandbox/pages/news.index.go b/sandbox/pages/news.index.go
index dd30ad5..d43b58e 100644
--- a/sandbox/pages/news.index.go
+++ b/sandbox/pages/news.index.go
@@ -1,19 +1,19 @@
package pages
import (
- "github.com/gofiber/fiber/v2"
+ "github.com/labstack/echo/v4"
"github.com/maddalax/htmgo/framework/h"
"starter-template/pages/base"
"starter-template/partials"
)
-func ListPage(ctx *fiber.Ctx) *h.Page {
+func ListPage(ctx echo.Context) *h.Page {
return h.NewPage(base.RootPage(
list(ctx),
))
}
-func list(ctx *fiber.Ctx) h.Renderable {
+func list(ctx echo.Context) h.Renderable {
return h.Fragment(
h.ViewOnLoad(partials.NewsSheet),
h.Div(
diff --git a/sandbox/pages/patients.index.go b/sandbox/pages/patients.index.go
index 52b404c..c9d511e 100644
--- a/sandbox/pages/patients.index.go
+++ b/sandbox/pages/patients.index.go
@@ -1,13 +1,13 @@
package pages
import (
- "github.com/gofiber/fiber/v2"
+ "github.com/labstack/echo/v4"
"github.com/maddalax/htmgo/framework/h"
"starter-template/pages/base"
"starter-template/partials/patient"
)
-func PatientsIndex(ctx *fiber.Ctx) *h.Page {
+func PatientsIndex(ctx echo.Context) *h.Page {
return h.NewPage(base.RootPage(
h.Div(
h.Class("flex flex-col p-4 w-full"),
diff --git a/sandbox/partials/load/generated.go b/sandbox/partials/load/generated.go
index eb982c4..5db01f4 100644
--- a/sandbox/partials/load/generated.go
+++ b/sandbox/partials/load/generated.go
@@ -2,12 +2,12 @@
package load
import "github.com/maddalax/htmgo/framework/h"
-import "github.com/gofiber/fiber/v2"
+import "github.com/labstack/echo/v4"
import "starter-template/partials"
import "starter-template/partials/patient"
import "starter-template/partials/sheet"
-func GetPartialFromContext(ctx *fiber.Ctx) *h.Partial {
+func GetPartialFromContext(ctx echo.Context) *h.Partial {
path := ctx.Path()
if path == "NewsSheet" || path == "/starter-template/partials.NewsSheet" {
return partials.NewsSheet(ctx)
@@ -33,8 +33,8 @@ func GetPartialFromContext(ctx *fiber.Ctx) *h.Partial {
return nil
}
-func RegisterPartials(f *fiber.App) {
- f.All("starter-template/partials*", func(ctx *fiber.Ctx) error {
+func RegisterPartials(f *echo.Echo) {
+ f.All("starter-template/partials*", func(ctx echo.Context) error {
partial := GetPartialFromContext(ctx)
if partial == nil {
return ctx.SendStatus(404)
diff --git a/sandbox/partials/news.go b/sandbox/partials/news.go
index de2e767..6c03d89 100644
--- a/sandbox/partials/news.go
+++ b/sandbox/partials/news.go
@@ -2,13 +2,13 @@ package partials
import (
"fmt"
- "github.com/gofiber/fiber/v2"
+ "github.com/labstack/echo/v4"
"github.com/maddalax/htmgo/framework-ui/ui"
"github.com/maddalax/htmgo/framework/h"
"starter-template/news"
)
-func NewsSheet(ctx *fiber.Ctx) *h.Partial {
+func NewsSheet(ctx echo.Context) *h.Partial {
open := h.GetQueryParam(ctx, "open") == "true"
return h.NewPartialWithHeaders(
&map[string]string{
@@ -23,7 +23,7 @@ func NewsSheet(ctx *fiber.Ctx) *h.Partial {
)
}
-func NewsSheetOpenCount(ctx *fiber.Ctx) *h.Partial {
+func NewsSheetOpenCount(ctx echo.Context) *h.Partial {
open := h.GetQueryParam(ctx, "open") == "true"
diff --git a/sandbox/partials/patient/create.go b/sandbox/partials/patient/create.go
index 18f206b..e56cf5d 100644
--- a/sandbox/partials/patient/create.go
+++ b/sandbox/partials/patient/create.go
@@ -1,13 +1,13 @@
package patient
import (
- "github.com/gofiber/fiber/v2"
+ "github.com/labstack/echo/v4"
"github.com/maddalax/htmgo/framework/h"
"starter-template/features/patient"
"starter-template/partials/sheet"
)
-func Create(ctx *fiber.Ctx) *h.Partial {
+func Create(ctx echo.Context) *h.Partial {
name := ctx.FormValue("name")
reason := ctx.FormValue("reason-for-visit")
location := ctx.FormValue("location-name")
diff --git a/sandbox/partials/patient/patient.go b/sandbox/partials/patient/patient.go
index dde50fb..5986c66 100644
--- a/sandbox/partials/patient/patient.go
+++ b/sandbox/partials/patient/patient.go
@@ -1,7 +1,7 @@
package patient
import (
- "github.com/gofiber/fiber/v2"
+ "github.com/labstack/echo/v4"
"github.com/maddalax/htmgo/framework-ui/ui"
"github.com/maddalax/htmgo/framework/h"
"starter-template/features/patient"
@@ -9,7 +9,7 @@ import (
"strings"
)
-func List(ctx *fiber.Ctx) *h.Partial {
+func List(ctx echo.Context) *h.Partial {
patients, err := patient.NewService(ctx).List()
if err != nil {
@@ -33,7 +33,7 @@ func List(ctx *fiber.Ctx) *h.Partial {
))
}
-func AddPatientSheetPartial(ctx *fiber.Ctx) *h.Partial {
+func AddPatientSheetPartial(ctx echo.Context) *h.Partial {
closePathQs := h.GetQueryParam(ctx, "onClosePath")
return h.NewPartialWithHeaders(
h.PushQsHeader(ctx, "adding", "true"),
@@ -56,7 +56,7 @@ func AddPatientSheet(onClosePath string) h.Renderable {
})
}
-func ValidateForm(ctx *fiber.Ctx) *h.Partial {
+func ValidateForm(ctx echo.Context) *h.Partial {
trigger := h.GetTriggerName(ctx)
value := ctx.FormValue(trigger)
diff --git a/sandbox/partials/sheet/sheet.go b/sandbox/partials/sheet/sheet.go
index 3ccc85b..fb69a93 100644
--- a/sandbox/partials/sheet/sheet.go
+++ b/sandbox/partials/sheet/sheet.go
@@ -2,7 +2,7 @@ package sheet
import (
"fmt"
- "github.com/gofiber/fiber/v2"
+ "github.com/labstack/echo/v4"
"github.com/maddalax/htmgo/framework/h"
)
@@ -28,7 +28,7 @@ func Closed() h.Renderable {
return h.Div(h.Id(Id))
}
-func Close(ctx *fiber.Ctx) *h.Partial {
+func Close(ctx echo.Context) *h.Partial {
return h.NewPartialWithHeaders(
h.Ternary(ctx.Query("path") != "", h.ReplaceUrlHeader(ctx.Query("path")), h.NewHeaders()),
h.Swap(ctx, Closed()),
diff --git a/starter-template/go.mod b/starter-template/go.mod
index b23a75a..e426cf1 100644
--- a/starter-template/go.mod
+++ b/starter-template/go.mod
@@ -4,7 +4,6 @@ go 1.23.0
require (
entgo.io/ent v0.14.1
- github.com/gofiber/fiber/v2 v2.52.5
github.com/maddalax/htmgo/framework v0.0.0-20240916224719-9e5d8edada65
)
diff --git a/starter-template/main.go b/starter-template/main.go
index 84971ca..cda342e 100644
--- a/starter-template/main.go
+++ b/starter-template/main.go
@@ -1,47 +1,30 @@
package main
import (
- "context"
- "github.com/gofiber/fiber/v2"
+ "github.com/labstack/echo/v4"
"github.com/maddalax/htmgo/framework/h"
_ "github.com/mattn/go-sqlite3"
- "log"
- "starter-template/ent"
"starter-template/pages"
"starter-template/partials/load"
- "time"
)
func main() {
- f := fiber.New()
+ f := echo.New()
f.Static("/public", "./assets/dist")
- f.Use(func(ctx *fiber.Ctx) error {
- if ctx.Path() == "/livereload" {
- return ctx.Next()
- }
- now := time.Now()
- err := ctx.Next()
- duration := time.Since(now)
- ctx.Set("X-Response-Times", duration.String())
- // Log or print the request method, URL, and duration
- log.Printf("Requests: %s %s took %dms", ctx.Method(), ctx.OriginalURL(), duration.Milliseconds())
- return err
- })
-
load.RegisterPartials(f)
pages.RegisterPages(f)
- client, err := ent.Open("sqlite3", "file:ent.db?cache=shared&_fk=1")
- if err != nil {
- log.Fatalf("failed opening connection to sqlite: %v", err)
- }
- defer client.Close()
- // Run the auto migration tool.
- if err := client.Schema.Create(context.Background()); err != nil {
- log.Fatalf("failed schema resources: %v", err)
- }
+ //client, err := ent.Open("sqlite3", "file:ent.db?cache=shared&_fk=1")
+ //if err != nil {
+ // log.Fatalf("failed opening connection to sqlite: %v", err)
+ //}
+ //defer client.Close()
+ //// Run the auto migration tool.
+ //if err := client.Schema.Create(context.Background()); err != nil {
+ // log.Fatalf("failed schema resources: %v", err)
+ //}
h.Start(f, h.App{
LiveReload: true,
diff --git a/starter-template/pages/base/root.go b/starter-template/pages/base/root.go
index c97875c..9a98ddb 100644
--- a/starter-template/pages/base/root.go
+++ b/starter-template/pages/base/root.go
@@ -6,7 +6,11 @@ import (
)
func Extensions() string {
- return strings.Join([]string{"path-deps", "response-targets", "mutation-error"}, ", ")
+ extensions := []string{"path-deps", "response-targets", "mutation-error"}
+ if h.IsDevelopment() {
+ extensions = append(extensions, "livereload")
+ }
+ return strings.Join(extensions, ", ")
}
func RootPage(children ...h.Renderable) h.Renderable {
diff --git a/starter-template/pages/generated.go b/starter-template/pages/generated.go
index 6500330..66c5f81 100644
--- a/starter-template/pages/generated.go
+++ b/starter-template/pages/generated.go
@@ -1,11 +1,11 @@
// Package pages THIS FILE IS GENERATED. DO NOT EDIT.
package pages
-import "github.com/gofiber/fiber/v2"
+import "github.com/labstack/echo/v4"
import "github.com/maddalax/htmgo/framework/h"
-func RegisterPages(f *fiber.App) {
- f.Get("/", func(ctx *fiber.Ctx) error {
+func RegisterPages(f *echo.Echo) {
+ f.GET("/", func(ctx echo.Context) error {
return h.HtmlView(ctx, IndexPage(ctx))
})
}
diff --git a/starter-template/pages/index.go b/starter-template/pages/index.go
index a673aa7..bde1c17 100644
--- a/starter-template/pages/index.go
+++ b/starter-template/pages/index.go
@@ -1,14 +1,16 @@
package pages
import (
- "github.com/gofiber/fiber/v2"
+ "github.com/labstack/echo/v4"
"github.com/maddalax/htmgo/framework/h"
+ "starter-template/pages/base"
"starter-template/partials"
)
-func IndexPage(c *fiber.Ctx) *h.Page {
+func IndexPage(c echo.Context) *h.Page {
return h.NewPage(h.Html(
- h.Class("bg-blue-400 flex flex-col items-center h-full w-full"),
+ h.HxExtension(base.Extensions()),
+ h.Class("bg-slate-100 flex flex-col items-center h-full w-full"),
h.Head(
h.Link("/public/main.css", "stylesheet"),
h.Script("/public/htmgo.js"),
@@ -19,7 +21,7 @@ func IndexPage(c *fiber.Ctx) *h.Page {
h.Class("flex flex-col items-center justify-center gap-6 p-12 text-center"),
h.H1(
h.Class("text-4xl sm:text-5xl font-bold max-w-3xl"),
- h.Text("Welcome to my fast!!"),
+ h.Text("test"),
),
h.P(
h.Class("text-lg sm:text-xl max-w-1xl"),
@@ -33,8 +35,8 @@ func IndexPage(c *fiber.Ctx) *h.Page {
}
func Button() h.Renderable {
- return h.Button(h.Class("btn bg-slate-500 p-4 rounded text-white"),
- h.Text("Ctest"),
+ return h.Button(h.Class("btn bg-red-500 p-4 rounded text-white"),
+ h.Text("this is my nice this works"),
h.AfterRequest(
h.SetDisabled(true),
h.RemoveClass("bg-red-600"),
diff --git a/starter-template/partials/index.go b/starter-template/partials/index.go
index 11e7107..4372ff6 100644
--- a/starter-template/partials/index.go
+++ b/starter-template/partials/index.go
@@ -1,18 +1,18 @@
package partials
import (
- "github.com/gofiber/fiber/v2"
+ "github.com/labstack/echo/v4"
"github.com/maddalax/htmgo/framework/h"
)
-func SamplePartial(ctx *fiber.Ctx) *h.Partial {
- return h.NewPartial(h.Div(h.P(h.Text(" asdas"))))
+func SamplePartial(ctx echo.Context) *h.Partial {
+ return h.NewPartial(h.Div(h.P(h.Text(" asdasasds"))))
}
-func NewPartial(ctx *fiber.Ctx) *h.Partial {
+func NewPartial(ctx echo.Context) *h.Partial {
return h.NewPartial(h.Div(h.P(h.Text("This sadsl."))))
}
-func NewPartial2(ctx *fiber.Ctx) *h.Partial {
+func NewPartial2(ctx echo.Context) *h.Partial {
return h.NewPartial(h.Div(h.P(h.Text("This sasdsadasdwl."))))
}
diff --git a/starter-template/partials/load/generated.go b/starter-template/partials/load/generated.go
index f5e3b8b..833662e 100644
--- a/starter-template/partials/load/generated.go
+++ b/starter-template/partials/load/generated.go
@@ -2,10 +2,10 @@
package load
import "github.com/maddalax/htmgo/framework/h"
-import "github.com/gofiber/fiber/v2"
+import "github.com/labstack/echo/v4"
import "starter-template/partials"
-func GetPartialFromContext(ctx *fiber.Ctx) *h.Partial {
+func GetPartialFromContext(ctx echo.Context) *h.Partial {
path := ctx.Path()
if path == "SamplePartial" || path == "/starter-template/partials.SamplePartial" {
return partials.SamplePartial(ctx)
@@ -19,11 +19,11 @@ func GetPartialFromContext(ctx *fiber.Ctx) *h.Partial {
return nil
}
-func RegisterPartials(f *fiber.App) {
- f.All("starter-template/partials*", func(ctx *fiber.Ctx) error {
+func RegisterPartials(f *echo.Echo) {
+ f.Any("starter-template/partials*", func(ctx echo.Context) error {
partial := GetPartialFromContext(ctx)
if partial == nil {
- return ctx.SendStatus(404)
+ return ctx.NoContent(404)
}
return h.PartialView(ctx, partial)
})