Browse Source

Controllers+Views+Routes: Add ScriptAfterLoad functionality

master
Riyyi 4 weeks ago
parent
commit
f0cb958ea2
  1. 12
      Public/js/site.js
  2. 30
      Sources/App/Controllers/TestController.swift
  3. 2
      Sources/App/Controllers/TodoController.swift
  4. 6
      Sources/App/Views/Components/ToastComponent.swift
  5. 2
      Sources/App/Views/Components/TodosTableComponent.swift
  6. 2
      Sources/App/Views/Shared/MainLayout.swift
  7. 35
      Sources/App/Views/Shared/ScriptAfterLoad.swift
  8. 3
      Sources/App/routes.swift

12
Public/js/site.js

@ -1,11 +1,17 @@
window.web = {};
// -----------------------------------------
// Activate Bootstrap tooltips
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
const tooltipList = [...tooltipTriggerList].map(element => new bootstrap.Tooltip(element))
web.tooltips = function() {
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
const tooltipList = [...tooltipTriggerList].map(element => new bootstrap.Tooltip(element))
}
// -----------------------------------------
// HTMX events
function runOnceAfterSettle(func) {
web.afterLoad = function(func) {
// https://htmx.org/docs/#request-operations
document.addEventListener("htmx:afterSettle", function handler(event) {
func();

30
Sources/App/Controllers/TestController.swift

@ -0,0 +1,30 @@
import Elementary
import ElementaryHTMX
import ElementaryHTMXSSE
import ElementaryHTMXWS
import Fluent
import Vapor
import VaporElementary
struct TestController: RouteCollection {
func boot(routes: RoutesBuilder) throws {
routes.group("test") { test in
test.get("toast", use: toast)
}
}
@Sendable
func toast(req: Request) async throws -> HTMLResponse {
let state = try getState(request: req)
state.toast = ToastState(message: "Wow!",
title: "This is my title",
level: ToastState.Level.success)
throw Abort(.badRequest, headers: ["HX-Trigger": "toast"])
// return HTMLResponse { }
}
}

2
Sources/App/Controllers/TodoController.swift

@ -27,6 +27,8 @@ struct TodoController: RouteCollection {
MainLayout(title: "Todos") {
TodosTableComponent(name: "todos", todos: todos)
TodosFormComponent(name: "todos-form", target: "todos")
button(.class("btn btn-primary"), .type(.button), .hx.get("/test/toast")) { "Toast" }
}
}
}

6
Sources/App/Views/Shared/ToastView.swift → Sources/App/Views/Components/ToastComponent.swift

@ -9,7 +9,7 @@ import ElementaryHTMX
//
// The header "HX-Trigger" will make the part refresh and show the toast message
struct ToastView: HTML {
struct ToastComponent: HTML {
var state: ToastState = ToastState()
@ -33,9 +33,8 @@ struct ToastView: HTML {
div(.class("toast-body")) { state.message }
}
if !state.message.isEmpty {
script {
ScriptAfterLoad(initial: false) {
"""
runOnceAfterSettle(function () {
const element = document.getElementById("toast");
const toast = new bootstrap.Toast(element, { autohide: true, delay: 5000 });
toast.show();
@ -43,7 +42,6 @@ struct ToastView: HTML {
element.addEventListener("hidden.bs.toast", function () {
element.remove();
});
});
"""
}
}

2
Sources/App/Views/Components/TodosTableComponent.swift

@ -47,6 +47,8 @@ struct TodosTableComponent: HTML {
}
}
}
ScriptAfterLoad(initial: !refresh) { "web.tooltips();" };
}
}

2
Sources/App/Views/Shared/MainLayout.swift

@ -59,7 +59,7 @@ struct MainLayout<Body: HTML>: HTMLDocument {
}
// Placeholder for all toast messages
ToastView()
ToastComponent()
}
// ---------------------------------

35
Sources/App/Views/Shared/ScriptAfterLoad.swift

@ -0,0 +1,35 @@
import Elementary
struct ScriptAfterLoad: HTML {
var initial: Bool = false
var js: String = ""
init(initial: Bool = false, js: () -> String) {
self.initial = initial
self.js = js()
}
// -------------------------------------
var content: some HTML {
if initial {
script {
"""
document.addEventListener("DOMContentLoaded", function() {
\(js)
});
"""
}
} else {
script {
"""
web.afterLoad(function () {
\(js)
});
"""
}
}
}
}

3
Sources/App/routes.swift

@ -21,6 +21,7 @@ func routes(_ app: Application) throws {
app.get("toast", use: toast)
try app.register(collection: TodoController())
try app.register(collection: TestController())
try app.group("api") { api in
try api.register(collection: TodoAPIController())
@ -32,7 +33,7 @@ func toast(req: Request) throws -> HTMLResponse {
let state = try getState(request: req)
return HTMLResponse {
ToastView(state: state.toast)
ToastComponent(state: state.toast)
}
}

Loading…
Cancel
Save