import Elementary import ElementaryHTMX import SharedModels extension HTMLAttribute.hx { static func get(route: SharedModels.ViewRoute) -> HTMLAttribute { get(SharedModels.ViewRoute.router.path(for: route)) } static func post(route: SharedModels.ViewRoute) -> HTMLAttribute { post(SharedModels.ViewRoute.router.path(for: route)) } static func put(route: SharedModels.ViewRoute) -> HTMLAttribute { put(SharedModels.ViewRoute.router.path(for: route)) } static func delete(route: SharedModels.ViewRoute) -> HTMLAttribute { delete(SharedModels.ViewRoute.router.path(for: route)) } } extension HTMLAttribute.hx { static func target(_ target: HXTarget) -> HTMLAttribute { Self.target(target.selector) } } extension HTMLAttribute.hx where Tag: HTMLTrait.Attributes.Global { static func on(_ event: HXOnEvent, value: String) -> HTMLAttribute { HTMLAttribute.custom(name: "hx-on::\(event.rawValue)", value: value) } static func on(_ event: HXOnEvent, _ value: HXOnValue) -> HTMLAttribute { on(event, value: value.value) } static func on(_ event: HXOnEvent, _ values: HXOnValue...) -> HTMLAttribute { on(event, value: values.value) } } enum HXOnEvent: String { case afterRequest = "after-request" } indirect enum HXOnValue { case ifSuccessful([Self]) case resetForm case setWindowLocation(String) case toggleContent(id: String) static func toggleContent(_ toggle: Toggle) -> Self { toggleContent(id: toggle.rawValue) } static func setWindowLocation(to route: ViewRoute) -> Self { setWindowLocation(ViewRoute.router.path(for: route)) } static func ifSuccessful(_ values: Self...) -> Self { .ifSuccessful(values) } fileprivate var value: String { switch self { case .resetForm: return "this.reset();" case let .toggleContent(toggle): return "toggleContent('\(toggle)');" case let .setWindowLocation(string): return "window.location.href='\(string)';" case let .ifSuccessful(values): return "if(event.detail.successful) \(values.value)" } } enum Toggle: String { case float } } extension Array where Element == HXOnValue { var value: String { return map(\.value).joined(separator: " ") } } extension HTMLAttribute where Tag: HTMLTrait.Attributes.Global { static func id(_ key: IDKey) -> Self { id(key.description) } } enum IDKey: CustomStringConvertible { case branch(Branch) case employee(Employee) case float case purchaseOrder(PurchaseOrder? = nil) case user(User) case vendor(Vendor) var description: String { switch self { case let .branch(key): return "branch-\(key)" case let .employee(key): return "employee-\(key)" case .float: return "float" case let .purchaseOrder(key): guard let key else { return "purchase-order" } return "purchase-order-\(key)" case let .user(key): return "user-\(key)" case let .vendor(key): return "vendor-\(key)" } } enum Branch: CustomStringConvertible { case list case form case row(id: VendorBranch.ID) var description: String { switch self { case .list: return "list" case .form: return "form" case let .row(id): return id.uuidString } } } enum Employee: CustomStringConvertible { case table case row(id: SharedModels.Employee.ID) var description: String { switch self { case .table: return "table" case let .row(id): return "\(id)" } } } enum PurchaseOrder: CustomStringConvertible { case content case row(id: SharedModels.PurchaseOrder.ID) case search case table var description: String { switch self { case .content: return "content" case let .row(id): return "\(id)" case .search: return "search" case .table: return "table" } } } enum User: CustomStringConvertible { case form case row(id: SharedModels.User.ID) case table var description: String { switch self { case .form: return "form" case .table: return "table" case let .row(id): return "\(id)" } } } enum Vendor: CustomStringConvertible { case form case row(id: SharedModels.Vendor.ID) var description: String { switch self { case .form: return "form" case let .row(id): return "\(id)" } } } } enum HXTarget: CustomStringConvertible { case body case id(IDKey) case this var selector: String { switch self { case .body: return "body" case let .id(key): return "#\(key)" case .this: return "this" } } var description: String { selector } }