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. 16
      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 // Activate Bootstrap tooltips
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]') web.tooltips = function() {
const tooltipList = [...tooltipTriggerList].map(element => new bootstrap.Tooltip(element)) const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
const tooltipList = [...tooltipTriggerList].map(element => new bootstrap.Tooltip(element))
}
// ----------------------------------------- // -----------------------------------------
// HTMX events // HTMX events
function runOnceAfterSettle(func) { web.afterLoad = function(func) {
// https://htmx.org/docs/#request-operations // https://htmx.org/docs/#request-operations
document.addEventListener("htmx:afterSettle", function handler(event) { document.addEventListener("htmx:afterSettle", function handler(event) {
func(); 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") { MainLayout(title: "Todos") {
TodosTableComponent(name: "todos", todos: todos) TodosTableComponent(name: "todos", todos: todos)
TodosFormComponent(name: "todos-form", target: "todos") TodosFormComponent(name: "todos-form", target: "todos")
button(.class("btn btn-primary"), .type(.button), .hx.get("/test/toast")) { "Toast" }
} }
} }
} }

16
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 // The header "HX-Trigger" will make the part refresh and show the toast message
struct ToastView: HTML { struct ToastComponent: HTML {
var state: ToastState = ToastState() var state: ToastState = ToastState()
@ -33,16 +33,14 @@ struct ToastView: HTML {
div(.class("toast-body")) { state.message } div(.class("toast-body")) { state.message }
} }
if !state.message.isEmpty { if !state.message.isEmpty {
script { ScriptAfterLoad(initial: false) {
""" """
runOnceAfterSettle(function () { const element = document.getElementById("toast");
const element = document.getElementById("toast"); const toast = new bootstrap.Toast(element, { autohide: true, delay: 5000 });
const toast = new bootstrap.Toast(element, { autohide: true, delay: 5000 }); toast.show();
toast.show();
element.addEventListener("hidden.bs.toast", function () { element.addEventListener("hidden.bs.toast", function () {
element.remove(); 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 // 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) app.get("toast", use: toast)
try app.register(collection: TodoController()) try app.register(collection: TodoController())
try app.register(collection: TestController())
try app.group("api") { api in try app.group("api") { api in
try api.register(collection: TodoAPIController()) try api.register(collection: TodoAPIController())
@ -32,7 +33,7 @@ func toast(req: Request) throws -> HTMLResponse {
let state = try getState(request: req) let state = try getState(request: req)
return HTMLResponse { return HTMLResponse {
ToastView(state: state.toast) ToastComponent(state: state.toast)
} }
} }

Loading…
Cancel
Save