From 8ef92b13bdcfe8409966ad1fceb0beaf781e3d37 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Sat, 18 Dec 2021 21:36:25 +0100 Subject: [PATCH] Quick fix (#54) * Fix issues * Update the instructions --- Instructions/Essential/Context.md | 7 +- Instructions/Essential/Elements.md | 45 +++- Instructions/Essential/Layouts.md | 17 +- .../Example/Page/Contexts/CreateContext.swift | 2 +- .../Example/Page/Contexts/IndexContext.swift | 2 +- .../Page/Controllers/SimpleController.swift | 16 +- .../Example/Page/Views/SimpleTemplate.swift | 7 +- Instructions/Installation.md | 4 +- Instructions/Overview.md | 17 +- README.md | 2 +- .../External/Attributes/BasicAttributes.swift | 2 +- .../External/Elements/BodyElements.swift | 213 ------------------ .../External/Elements/HeadElements.swift | 213 ++++++++++++++++++ Sources/HTMLKit/External/Statements.swift | 4 +- 14 files changed, 301 insertions(+), 250 deletions(-) diff --git a/Instructions/Essential/Context.md b/Instructions/Essential/Context.md index 154024b7..f54a07f9 100644 --- a/Instructions/Essential/Context.md +++ b/Instructions/Essential/Context.md @@ -7,9 +7,9 @@ The context is ### Definition ```swift -/// [IndexContext.swift] +/// [SimpleContext.swift] -struct IndexContext { +struct SimpleContext: Codable { var headline: String var categories: [Category] @@ -21,7 +21,8 @@ struct IndexContext { struct SimpleView: View { - var context: TemplateValue + @TemplateValue(SimpleContext.self) + var context var body: AnyContent { Heading1 { diff --git a/Instructions/Essential/Elements.md b/Instructions/Essential/Elements.md index 9ffba8c4..845a0ee3 100644 --- a/Instructions/Essential/Elements.md +++ b/Instructions/Essential/Elements.md @@ -1,34 +1,34 @@ # Elements -The elements represents the HTML tags. Every element has function handlers, wich are representing the attribute of a tag. +The elements in HTMLKit represent the official HTML elements. Elements with content use the curly brackets, while elements without content use the round brackets. To add attributes to the element use the offered functions. ## Essential ### Definition ```swift -/// Element with content +/// element with content Body { ... } -/// Element without content +/// element without content Input() ``` ### Attributes ```swift -/// Attribute with value +/// attribute with value .class("value") -/// Attribute as toggle +/// attribute as toggle .required() ``` ### Modifier ```swift -/// Modifies if the condition is true +/// modifies if the condition is true Body { ... } @@ -36,7 +36,7 @@ Body { $0.hidden() } -/// Modifies if the value is set +/// modifies if the value is set Body { ... } @@ -45,4 +45,33 @@ Body { } ``` -## Variation +## Limitation + +To prevent invalid code, each element owns a element definition. For example the element `Heading1` is a type of `BodyElement`, so it is only allowed to be placed in the `Body` element. See the [wiki](https://github.com/vapor-community/HTMLKit/wiki) for more element definitions. + +```swift +/// [BodyElements.swift] + +public struct Heading1: ContentNode, BodyElement { + ... +} +``` + +```html + + +

headline

+ + +

headline

+ + +``` + +If you need to break the limitation, extend the element with the element definition of your choice or define it as `GlobalElement`. + +```swift +extension FormContainer: GlobalElement { + ... +} +``` diff --git a/Instructions/Essential/Layouts.md b/Instructions/Essential/Layouts.md index 9eff9ed6..0ad82d70 100644 --- a/Instructions/Essential/Layouts.md +++ b/Instructions/Essential/Layouts.md @@ -15,12 +15,14 @@ struct SimplePage: Page { var body: AnyContent { Document(type: .html5) - Head { - Title { - "SimplePage" + Html { + Head { + Title { + "SimplePage" + } + } + Body { } - } - Body { } } } @@ -37,7 +39,8 @@ The view is a partial view of the page. It should be used to display data using struct SimpleView: View { - var context: TemplateValue = "" + @TemplateValue(SimpleContext.self) + var context var body: AnyContent { Heading1 { @@ -49,6 +52,8 @@ struct SimpleView: View { ### Context +The context as an object holds the information for the view. ... See [Context](https://github.com/vapor-community/HTMLKit/blob/master/Instructions/Essential/Context.md) to learn more about it. + ## Component The component is a reusable portion of a page. It should be used to break up large files into smaller components. diff --git a/Instructions/Example/Page/Contexts/CreateContext.swift b/Instructions/Example/Page/Contexts/CreateContext.swift index cf649e2d..2c812f17 100644 --- a/Instructions/Example/Page/Contexts/CreateContext.swift +++ b/Instructions/Example/Page/Contexts/CreateContext.swift @@ -1,4 +1,4 @@ -struct CreateContext { +struct CreateContext: Codable { var title: String } diff --git a/Instructions/Example/Page/Contexts/IndexContext.swift b/Instructions/Example/Page/Contexts/IndexContext.swift index cf9fcaba..cfda0ab0 100644 --- a/Instructions/Example/Page/Contexts/IndexContext.swift +++ b/Instructions/Example/Page/Contexts/IndexContext.swift @@ -1,4 +1,4 @@ -struct IndexContext { +struct IndexContext: Codable { var title: String } diff --git a/Instructions/Example/Page/Controllers/SimpleController.swift b/Instructions/Example/Page/Controllers/SimpleController.swift index cf012ea9..757539f0 100644 --- a/Instructions/Example/Page/Controllers/SimpleController.swift +++ b/Instructions/Example/Page/Controllers/SimpleController.swift @@ -1,5 +1,4 @@ import Vapor -import HTMLKit // [/simple] final class SimpleController { @@ -7,8 +6,19 @@ final class SimpleController { // [/index] func getIndex(_ request: Request) throws -> EventLoopFuture { - let context = IndexContext(title: "Index") + return SimpleTemplate.IndexView() + .render(with: IndexContext(title: "Index"), for: request) + } + + // [/create] + func getCreate(_ request: Request) throws -> EventLoopFuture { - return IndexView().render(with: context, for: request) + return SimpleTemplate.CreateView() + .render(with: CreateContext(title: "Create"), for: request) + } + + // [/create/:model] + func postCreate(_ request: Request) throws -> EventLoopFuture { + return request.redirect(to: "/simple/index") } } diff --git a/Instructions/Example/Page/Views/SimpleTemplate.swift b/Instructions/Example/Page/Views/SimpleTemplate.swift index 6450545d..3b2a192f 100644 --- a/Instructions/Example/Page/Views/SimpleTemplate.swift +++ b/Instructions/Example/Page/Views/SimpleTemplate.swift @@ -1,10 +1,12 @@ import HTMLKit +import HTMLKitVaporProvider public enum SimpleTemplate { public struct IndexView: View { - public var context: TemplateValue + @TemplateValue(IndexContext.self) + public var context public var body: AnyContent { SimplePage { @@ -17,7 +19,8 @@ public enum SimpleTemplate { public struct CreateView: View { - public var context: TemplateValue + @TemplateValue(CreateContext.self) + public var context public var body: AnyContent { SimplePage { diff --git a/Instructions/Installation.md b/Instructions/Installation.md index 7ad60a4c..942af3d1 100644 --- a/Instructions/Installation.md +++ b/Instructions/Installation.md @@ -13,7 +13,7 @@ Add the packages as dependecies to your package. dependencies: [ ... .package(name: "HTMLKit", url: "https://github.com/vapor-community/HTMLKit.git", from: "2.4.0"), - .package(name: "HTMLKitVaporProvider", url: "https://github.com/vapor-community/htmlkit-vapor-provider.git", from: "1.2.0") + .package(name: "HTMLKitVaporProvider", url: "https://github.com/vapor-community/htmlkit-vapor-provider.git", from: "1.2.1") ], targets: [ .target( @@ -29,4 +29,4 @@ targets: [ ## Vapor 3 -Check the provider to learn more about supporting Vapor 3. +Check the [provider](https://github.com/vapor-community/htmlkit-vapor-provider) to learn more about supporting Vapor 3. diff --git a/Instructions/Overview.md b/Instructions/Overview.md index 21125e00..a8a5fac1 100644 --- a/Instructions/Overview.md +++ b/Instructions/Overview.md @@ -5,15 +5,18 @@ By using Swift's powerful language features and a pre-rendering algorithm, HTMLK ## Index 1. Installation + 2. Essential - 2.1 Elements - 2.2 Layouts - 2.3 Context - 2.4 Statements +2.1 Elements +2.2 Layouts +2.3 Context +2.4 Statements + 3. Features - 3.1 Localization - 3.2 Conversion - 3.3 Templating +3.1 Localization +3.2 Conversion +3.3 Templating + 4. Example ## References diff --git a/README.md b/README.md index 4d37b74b..05239dda 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ dependencies: [ ... ///1. Add the packages .package(name: "HTMLKit", url: "https://github.com/vapor-community/HTMLKit.git", from: "2.4.0"), - .package(name: "HTMLKitVaporProvider", url: "https://github.com/MatsMoll/htmlkit-vapor-provider.git", from: "1.2.0") + .package(name: "HTMLKitVaporProvider", url: "https://github.com/MatsMoll/htmlkit-vapor-provider.git", from: "1.2.1") ], targets: [ .target( diff --git a/Sources/HTMLKit/External/Attributes/BasicAttributes.swift b/Sources/HTMLKit/External/Attributes/BasicAttributes.swift index 88652f92..3868521a 100644 --- a/Sources/HTMLKit/External/Attributes/BasicAttributes.swift +++ b/Sources/HTMLKit/External/Attributes/BasicAttributes.swift @@ -163,7 +163,7 @@ public protocol AlternateAttribute: AnyAttribute { extension AlternateAttribute { - internal var key: String { "alternate" } + internal var key: String { "alt" } } extension AlternateAttribute where Self: ContentNode { diff --git a/Sources/HTMLKit/External/Elements/BodyElements.swift b/Sources/HTMLKit/External/Elements/BodyElements.swift index 59abe7e7..5c4e77dd 100644 --- a/Sources/HTMLKit/External/Elements/BodyElements.swift +++ b/Sources/HTMLKit/External/Elements/BodyElements.swift @@ -191,219 +191,6 @@ public typealias Iframe = InlineFrame /// public typealias Param = Parameter -/// # Description: -/// The element represents a comment output. -/// -/// # References: -/// https://html.spec.whatwg.org/#the-link-element -/// -public struct Link: EmptyNode, BodyElement { - - internal var name: String { "link" } - - internal var attributes: OrderedDictionary? - - public init() {} - - internal init(attributes: OrderedDictionary?) { - self.attributes = attributes - } -} - -extension Link: GlobalAttributes, ReferenceAttribute, ReferenceLanguageAttribute, MediaAttribute, ReferrerPolicyAttribute, RelationshipAttribute, SizesAttribute, TypeAttribute, ErrorEventAttribute, LoadEventAttribute { - - public func onError(_ value: String) -> Link { - return mutate(onerror: value) - } - - public func onLoad(_ value: String) -> Link { - return mutate(onload: value) - } - - public func accessKey(_ value: String) -> Link { - return mutate(accesskey: value) - } - - public func autocapitalize(_ type: Capitalization) -> Link { - return mutate(autocapitalize: type.rawValue) - } - - public func autofocus() -> Link { - return mutate(autofocus: "autofocus") - } - - public func `class`(_ value: String) -> Link { - return mutate(class: value) - } - - public func isEditable(_ condition: Bool) -> Link { - return mutate(contenteditable: condition) - } - - public func direction(_ type: Direction) -> Link { - return mutate(dir: type.rawValue) - } - - public func isDraggable(_ condition: Bool) -> Link { - return mutate(draggable: condition) - } - - public func enterKeyHint(_ type: Hint) -> Link { - return mutate(enterkeyhint: type.rawValue) - } - - public func hidden() -> Link { - return mutate(hidden: "hidden") - } - - public func inputMode(_ value: String) -> Link { - return mutate(inputmode: value) - } - - public func `is`(_ value: String) -> Link { - return mutate(is: value) - } - - public func itemId(_ value: String) -> Link { - return mutate(itemid: value) - } - - public func itemProperty(_ value: String) -> Link { - return mutate(itemprop: value) - } - - public func itemReference(_ value: String) -> Link { - return mutate(itemref: value) - } - - public func itemScope(_ value: String) -> Link { - return mutate(itemscope: value) - } - - public func itemType(_ value: String) -> Link { - return mutate(itemtype: value) - } - - public func id(_ value: String) -> Link { - return mutate(id: value) - } - - public func id(_ value: TemplateValue) -> Link { - return mutate(id: value.rawValue) - } - - public func language(_ type: Language) -> Link { - return mutate(lang: type.rawValue) - } - - public func nonce(_ value: String) -> Link { - return mutate(nonce: value) - } - - public func role(_ value: String) -> Link { - return mutate(role: value) - } - - public func hasSpellCheck(_ condition: Bool) -> Link { - return mutate(spellcheck: condition) - } - - public func style(_ value: String) -> Link { - return mutate(style: value) - } - - public func tabIndex(_ value: String) -> Link { - return mutate(tabindex: value) - } - - public func title(_ value: String) -> Link { - return mutate(title: value) - } - - public func translate(_ value: String) -> Link { - return mutate(translate: value) - } - - public func reference(_ value: String) -> Link { - return mutate(href: value) - } - - public func reference(_ value: TemplateValue) -> Link { - return mutate(href: value.rawValue) - } - - public func referenceLanguage(_ type: Language) -> Link { - return mutate(hreflang: type.rawValue) - } - - public func media(_ value: String) -> Link { - return mutate(media: value) - } - - public func referrerPolicy(_ type: Policy) -> Link { - return mutate(referrerpolicy: type.rawValue) - } - - public func relationship(_ type: Relation) -> Link { - return mutate(rel: type.rawValue) - } - - public func sizes(_ size: Int) -> Link { - return mutate(sizes: size) - } - - public func type(_ value: MediaType) -> Link { - return mutate(type: value.rawValue) - } -} - -extension Link: AnyContent { - - public func prerender(_ formula: Renderer.Formula) throws { - try self.build(formula) - } - - public func render(with manager: Renderer.ContextManager) throws -> String { - try self.build(with: manager) - } -} - -extension Link: Modifiable { - - public func modify(if condition: Bool, element: (Self) -> Self) -> Self { - - if condition { - return modify(element(self)) - } - - return self - } - - public func modify(unwrap value: TemplateValue, element: (Self, TemplateValue) -> Self) -> Self { - - switch value { - case .constant(let optional): - - guard let value = optional else { - return self - } - - return modify(element(self, .constant(value))) - - case .dynamic(let context): - - if context.isMascadingOptional { - - return modify(element(self, .dynamic(context.unsafeCast(to: T.self)))) - - } else { - - return modify(element(self, .dynamic(context.unsafelyUnwrapped))) - } - } - } -} - /// # Description: /// The element represents a self-contained content. /// diff --git a/Sources/HTMLKit/External/Elements/HeadElements.swift b/Sources/HTMLKit/External/Elements/HeadElements.swift index 3432ed7e..6fafc8b4 100644 --- a/Sources/HTMLKit/External/Elements/HeadElements.swift +++ b/Sources/HTMLKit/External/Elements/HeadElements.swift @@ -763,3 +763,216 @@ extension Style: Modifiable { } } } + +/// # Description: +/// The element represents a comment output. +/// +/// # References: +/// https://html.spec.whatwg.org/#the-link-element +/// +public struct Link: EmptyNode, HeadElement { + + internal var name: String { "link" } + + internal var attributes: OrderedDictionary? + + public init() {} + + internal init(attributes: OrderedDictionary?) { + self.attributes = attributes + } +} + +extension Link: GlobalAttributes, ReferenceAttribute, ReferenceLanguageAttribute, MediaAttribute, ReferrerPolicyAttribute, RelationshipAttribute, SizesAttribute, TypeAttribute, ErrorEventAttribute, LoadEventAttribute { + + public func onError(_ value: String) -> Link { + return mutate(onerror: value) + } + + public func onLoad(_ value: String) -> Link { + return mutate(onload: value) + } + + public func accessKey(_ value: String) -> Link { + return mutate(accesskey: value) + } + + public func autocapitalize(_ type: Capitalization) -> Link { + return mutate(autocapitalize: type.rawValue) + } + + public func autofocus() -> Link { + return mutate(autofocus: "autofocus") + } + + public func `class`(_ value: String) -> Link { + return mutate(class: value) + } + + public func isEditable(_ condition: Bool) -> Link { + return mutate(contenteditable: condition) + } + + public func direction(_ type: Direction) -> Link { + return mutate(dir: type.rawValue) + } + + public func isDraggable(_ condition: Bool) -> Link { + return mutate(draggable: condition) + } + + public func enterKeyHint(_ type: Hint) -> Link { + return mutate(enterkeyhint: type.rawValue) + } + + public func hidden() -> Link { + return mutate(hidden: "hidden") + } + + public func inputMode(_ value: String) -> Link { + return mutate(inputmode: value) + } + + public func `is`(_ value: String) -> Link { + return mutate(is: value) + } + + public func itemId(_ value: String) -> Link { + return mutate(itemid: value) + } + + public func itemProperty(_ value: String) -> Link { + return mutate(itemprop: value) + } + + public func itemReference(_ value: String) -> Link { + return mutate(itemref: value) + } + + public func itemScope(_ value: String) -> Link { + return mutate(itemscope: value) + } + + public func itemType(_ value: String) -> Link { + return mutate(itemtype: value) + } + + public func id(_ value: String) -> Link { + return mutate(id: value) + } + + public func id(_ value: TemplateValue) -> Link { + return mutate(id: value.rawValue) + } + + public func language(_ type: Language) -> Link { + return mutate(lang: type.rawValue) + } + + public func nonce(_ value: String) -> Link { + return mutate(nonce: value) + } + + public func role(_ value: String) -> Link { + return mutate(role: value) + } + + public func hasSpellCheck(_ condition: Bool) -> Link { + return mutate(spellcheck: condition) + } + + public func style(_ value: String) -> Link { + return mutate(style: value) + } + + public func tabIndex(_ value: String) -> Link { + return mutate(tabindex: value) + } + + public func title(_ value: String) -> Link { + return mutate(title: value) + } + + public func translate(_ value: String) -> Link { + return mutate(translate: value) + } + + public func reference(_ value: String) -> Link { + return mutate(href: value) + } + + public func reference(_ value: TemplateValue) -> Link { + return mutate(href: value.rawValue) + } + + public func referenceLanguage(_ type: Language) -> Link { + return mutate(hreflang: type.rawValue) + } + + public func media(_ value: String) -> Link { + return mutate(media: value) + } + + public func referrerPolicy(_ type: Policy) -> Link { + return mutate(referrerpolicy: type.rawValue) + } + + public func relationship(_ type: Relation) -> Link { + return mutate(rel: type.rawValue) + } + + public func sizes(_ size: Int) -> Link { + return mutate(sizes: size) + } + + public func type(_ value: MediaType) -> Link { + return mutate(type: value.rawValue) + } +} + +extension Link: AnyContent { + + public func prerender(_ formula: Renderer.Formula) throws { + try self.build(formula) + } + + public func render(with manager: Renderer.ContextManager) throws -> String { + try self.build(with: manager) + } +} + +extension Link: Modifiable { + + public func modify(if condition: Bool, element: (Self) -> Self) -> Self { + + if condition { + return modify(element(self)) + } + + return self + } + + public func modify(unwrap value: TemplateValue, element: (Self, TemplateValue) -> Self) -> Self { + + switch value { + case .constant(let optional): + + guard let value = optional else { + return self + } + + return modify(element(self, .constant(value))) + + case .dynamic(let context): + + if context.isMascadingOptional { + + return modify(element(self, .dynamic(context.unsafeCast(to: T.self)))) + + } else { + + return modify(element(self, .dynamic(context.unsafelyUnwrapped))) + } + } + } +} diff --git a/Sources/HTMLKit/External/Statements.swift b/Sources/HTMLKit/External/Statements.swift index 9641586d..0a8d55e3 100644 --- a/Sources/HTMLKit/External/Statements.swift +++ b/Sources/HTMLKit/External/Statements.swift @@ -13,7 +13,7 @@ /// /// # References: /// -public struct IF { +public struct IF: GlobalElement { public class Condition { @@ -159,7 +159,7 @@ extension IF: AnyContent { /// /// # References: /// -public struct ForEach where Values: Sequence { +public struct ForEach: GlobalElement where Values: Sequence { public let context: TemplateValue