1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: jan@swi-prolog.org 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2024, SWI-Prolog Solutions b.v. 7 All rights reserved. 8 9 Redistribution and use in source and binary forms, with or without 10 modification, are permitted provided that the following conditions 11 are met: 12 13 1. Redistributions of source code must retain the above copyright 14 notice, this list of conditions and the following disclaimer. 15 16 2. Redistributions in binary form must reproduce the above copyright 17 notice, this list of conditions and the following disclaimer in 18 the documentation and/or other materials provided with the 19 distribution. 20 21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 POSSIBILITY OF SUCH DAMAGE. 33*/ 34 35:- module(htmx, 36 [ reply_htmx/1, % +HTML 37 reply_htmx/2, % +HTML, +Request 38 htmx_oob//2 % ++Id, :HTML 39 ]). 40:- use_module(library(http/html_write)). 41 42/** <module> Support htmx.org 43 44Quoted from htmx.org: 45 46> [htmx](https://htmx.org) gives you access to AJAX, CSS Transitions, 47> WebSockets and Server Sent Events directly in HTML, using attributes, 48> so you can build modern user interfaces with the simplicity and power 49> of hypertext 50 51The idea behind htmx is to allow adding attributes to any HTML element 52that cause an HTTP request. The HTTP response is typically a (short) 53HTML fragment that extends or replaces an element on the page. This 54allows us to program a most functionality interactive seen in modern web 55applications using the powerful SWI-Prolog HTML generation framework 56rather than having to write a JSON backend and accompanying JavaScript 57frontend that runs in the browser. 58 59Below is a minimalistic, yet fully functional application that replaces 60a button after a click in two ways, using either a direct hx-swap our an 61out-of-band hx-swap command. 62 63``` 64:- use_module(library(http/http_server)). 65:- use_module(library(http/htmx)). 66:- use_module(library(main)). 67 68:- initialization(main, main). 69 70main(_Argv) :- 71 http_server([port(8080)]), 72 thread_get_message(quit). 73 74http:location(htmx, root(htmx), []). 75 76:- http_handler(root(.), home, []). 77 78home(_Request) :- 79 reply_html_page( 80 [ title('HTMX demo'), 81 script(src('https://unpkg.com/htmx.org'), []) 82 ], 83 [ button([ id(button1), 84 'hx-post'('/htmx/clicked1'), 85 'hx-swap'('outerHTML') 86 ], 87 'Click me (1)'), 88 button([ id(button2), 89 'hx-post'('/htmx/clicked2') 90 ], 91 'Click me (2)') 92 ]). 93 94:- http_handler(htmx(clicked1), reply_htmx(\clicked1), []). 95:- http_handler(htmx(clicked2), reply_htmx(\clicked2), []). 96 97clicked1 --> 98 html('Thanks for clicking me! (1)'). 99 100clicked2 --> 101 htmx_oob(button2, html('Thanks for clicking me! (2)')). 102``` 103 104HTMX requires no dedicated support from the server. This library 105provides reply_htmx/1,2 to reply with a single HTML element rather than 106an entire page. Future versions of this library may provide some 107additional utility predicates. 108*/ 109 110:- html_meta 111 reply_htmx(), 112 reply_htmx(, ), 113 htmx_oob(, , , ). 114 115%! reply_htmx(+HTML) is det. 116%! reply_htmx(+HTML, +Request) is det. 117% 118% Reply a plain HTML element as opposed to a complete HTML page as 119% created using reply_html_page/2,3. While reply_htmx/1 is to be used 120% in a normal HTTP handler (route), reply_htmx/2 may be registered 121% directly in the http_handler/3 declaration to deal with simple cases 122% where we do not need the `Request` data. 123 124reply_htmx(HTML) :- 125 phrase(html(HTML), Tokens), 126 format('Content-type: text/html~n~n', []), 127 print_html(Tokens). 128 129reply_htmx(HTML, _Request) :- 130 reply_htmx(HTML). 131 132%! htmx_oob(++Target, :HTML)// is det. 133% 134% Emit an htmx out-of-band element. HTML is used to swap the 135% content of the DOM element with id Target. 136 137htmx_oob(Target, HTML) --> 138 html(div([id(Target), 'hx-swap-oob'(true)], 139 HTML))