@@ -11,13 +11,8 @@ export class MeshElement extends HTMLElement {
1111 root . appendChild ( ( template as any ) . content . cloneNode ( true ) ) ;
1212 }
1313 }
14- if ( window . htmx ) {
15- window . htmx . process ( this ) ;
16- if ( this . shadowRoot ) {
17- window . htmx . process ( this . shadowRoot ) ;
18- }
19- }
2014 this . bindListeners ( ) ;
15+ this . bindFormHandlers ( ) ;
2116 this . createIcons ( ) ;
2217 }
2318
@@ -58,6 +53,102 @@ export class MeshElement extends HTMLElement {
5853 } ) ;
5954 }
6055
56+ protected bindFormHandlers ( ) {
57+ // Handle forms with mesh-* HTTP attributes
58+ this . all ( 'form[mesh-get], form[mesh-post], form[mesh-put], form[mesh-patch], form[mesh-delete]' , form => {
59+ form . addEventListener ( 'submit' , this . handleFormSubmit . bind ( this ) ) ;
60+ } ) ;
61+ }
62+
63+ protected async handleFormSubmit ( event : Event ) {
64+ event . preventDefault ( ) ;
65+ const form = event . target as HTMLFormElement ;
66+
67+ // Determine HTTP method from mesh-* attributes
68+ let method = 'GET' ;
69+ let url = '' ;
70+
71+ if ( form . hasAttribute ( 'mesh-get' ) ) {
72+ method = 'GET' ;
73+ url = form . getAttribute ( 'mesh-get' ) || '' ;
74+ } else if ( form . hasAttribute ( 'mesh-post' ) ) {
75+ method = 'POST' ;
76+ url = form . getAttribute ( 'mesh-post' ) || '' ;
77+ } else if ( form . hasAttribute ( 'mesh-put' ) ) {
78+ method = 'PUT' ;
79+ url = form . getAttribute ( 'mesh-put' ) || '' ;
80+ } else if ( form . hasAttribute ( 'mesh-patch' ) ) {
81+ method = 'PATCH' ;
82+ url = form . getAttribute ( 'mesh-patch' ) || '' ;
83+ } else if ( form . hasAttribute ( 'mesh-delete' ) ) {
84+ method = 'DELETE' ;
85+ url = form . getAttribute ( 'mesh-delete' ) || '' ;
86+ }
87+
88+ if ( ! url ) {
89+ console . error ( 'No URL specified for form submission' ) ;
90+ return ;
91+ }
92+
93+ try {
94+ const formData = new FormData ( form ) ;
95+ const response = await this . makeRequest ( method , url , formData ) ;
96+
97+ if ( response . ok ) {
98+ const html = await response . text ( ) ;
99+ this . handleResponse ( html , form ) ;
100+ } else {
101+ console . error ( 'Form submission failed:' , response . status , response . statusText ) ;
102+ }
103+ } catch ( error ) {
104+ console . error ( 'Form submission error:' , error ) ;
105+ }
106+ }
107+
108+ protected async makeRequest ( method : string , url : string , formData : FormData ) : Promise < Response > {
109+ const options : RequestInit = {
110+ method,
111+ headers : {
112+ 'X-Requested-With' : 'XMLHttpRequest' ,
113+ } ,
114+ } ;
115+
116+ if ( method === 'GET' ) {
117+ const params = new URLSearchParams ( formData as any ) ;
118+ url += ( url . includes ( '?' ) ? '&' : '?' ) + params . toString ( ) ;
119+ } else {
120+ options . body = formData ;
121+ }
122+
123+ return fetch ( url , options ) ;
124+ }
125+
126+ protected handleResponse ( html : string , form : HTMLFormElement ) {
127+ // Check for mesh-target attribute to determine where to place response
128+ const target = form . getAttribute ( 'mesh-target' ) ;
129+
130+ if ( target ) {
131+ const targetElement = this . shadowRoot ?. querySelector ( target ) || document . querySelector ( target ) ;
132+ if ( targetElement ) {
133+ targetElement . innerHTML = html ;
134+ return ;
135+ }
136+ }
137+
138+ // Check for mesh-swap attribute to determine swap behavior
139+ const swapMode = form . getAttribute ( 'mesh-swap' ) || 'outerHTML' ;
140+
141+ switch ( swapMode ) {
142+ case 'innerHTML' :
143+ this . innerHTML = html ;
144+ break ;
145+ case 'outerHTML' :
146+ default :
147+ this . outerHTML = html ;
148+ break ;
149+ }
150+ }
151+
61152 one ( selector : string , cb : ( el : HTMLElement ) => void ) {
62153 const el = this . shadowRoot ! . querySelector ( selector )
63154 if ( el ) {
0 commit comments