7
7
8
8
db = database (':memory:' )
9
9
10
+
11
+
10
12
class User : name :str ; pwd :str
11
13
12
14
class Todo :
@@ -42,7 +44,7 @@ def user_auth_before(req, sess):
42
44
user_auth_before ,
43
45
skip = [r'/favicon\.ico' , r'/static/.*' , r'.*\.css' , r'.*\.js' , '/login' ]
44
46
)
45
- app , rt = fast_app (hdrs = Theme .blue .headers (),before = beforeware )
47
+ app , rt = fast_app (hdrs = Theme .blue .headers ()+ [ SortableJS ( '.sortable' ),] ,before = beforeware )
46
48
47
49
# Authentication
48
50
login_redir = Redirect ('/login' )
@@ -68,7 +70,7 @@ def post(login:Login, sess):
68
70
sess ['auth' ] = u .name
69
71
return Redirect ('/' )
70
72
71
- @app . get ( "/logout" )
73
+ @rt
72
74
def logout (sess ):
73
75
del sess ['auth' ]
74
76
return login_redir
@@ -81,7 +83,7 @@ def index(auth):
81
83
add = Form (Group (new_inp , Button ("Add" )),
82
84
hx_post = add_todo , target_id = 'todo-list' , hx_swap = "afterbegin" )
83
85
frm = Form (* db .todos (order_by = 'priority' ),
84
- id = 'todo-list' , cls = 'sortable' , hx_post = "/ reorder" , hx_trigger = "end" )
86
+ id = 'todo-list' , cls = 'sortable' , hx_post = reorder , hx_trigger = "end" )
85
87
86
88
card = Card (Ul (frm ), header = add , footer = Div (id = 'current-todo' ))
87
89
return Titled (f"{ auth } 's Todo list" , Container (top , card ))
@@ -91,7 +93,17 @@ def add_todo(todo:Todo, auth):
91
93
new_inp = LabelInput ('Title' , id = "new-title" , name = "title" , placeholder = "New Todo" , hx_swap_oob = 'true' )
92
94
# `insert` returns the inserted todo, which is appended to the start of the list, because we used
93
95
# `hx_swap='afterbegin'` when creating the todo list form.
94
- return db .todos .insert (todo ), new_inp
96
+ return db .todos .insert (todo ), new_inp
97
+
98
+ @rt
99
+ def reorder (id :list [int ]):
100
+ for i ,id_ in enumerate (id ): db .todos .update ({'priority' :i }, id_ )
101
+ # HTMX by default replaces the inner HTML of the calling element, which in this case is the todo list form.
102
+ # Therefore, we return the list of todos, now in the correct order, which will be auto-converted to FT for us.
103
+ # In this case, it's not strictly necessary, because sortable.js has already reorder the DOM elements.
104
+ # However, by returning the updated data, we can be assured that there aren't sync issues between the DOM
105
+ # and the server.
106
+ return tuple (db .todos (order_by = 'priority' ))
95
107
96
108
97
109
serve ()
0 commit comments