From c27f6857deeb4c4623db294172a8ec572790a9be Mon Sep 17 00:00:00 2001 From: Dave Verwer Date: Tue, 1 Jun 2021 16:56:34 +0100 Subject: [PATCH] Boolean attributes (#68) * Change `required` and `autofocus` to be boolean attributes. * Added `readonly`, `disabled`, and `multiple` boolean attributes to `input` elements. * Added `readonly ` and `disabled ` attributes to the `textarea` element. * Added a `placeholder` attribute to the `textarea` element. * Changed the `allowfullscreen` attribute on the `iframe` element to be a boolean attribute. * Added an `open` boolean attribute to the `details` element. * Added the `hidden` boolean attribute as a global attribute. * Added `checked` boolean attribute to the `input` element. * Added a `name` to the `file` input element in the form test. --- Sources/Plot/API/HTMLAttributes.swift | 70 ++++++++++++++++++++++-- Tests/PlotTests/HTMLComponentTests.swift | 4 +- Tests/PlotTests/HTMLTests.swift | 44 +++++++++++---- 3 files changed, 100 insertions(+), 18 deletions(-) diff --git a/Sources/Plot/API/HTMLAttributes.swift b/Sources/Plot/API/HTMLAttributes.swift index db87b87..9fa1c3d 100644 --- a/Sources/Plot/API/HTMLAttributes.swift +++ b/Sources/Plot/API/HTMLAttributes.swift @@ -74,6 +74,12 @@ public extension Node where Context: HTMLContext { static func title(_ title: String) -> Node { .attribute(named: "title", value: title) } + + /// Assign whether the element should be hidden. + /// - parameter isHidden: Whether the element should be hidden or not. + static func hidden(_ isHidden: Bool) -> Node { + isHidden ? .attribute(named: "hidden") : .empty + } } public extension Attribute where Context: HTMLNamableContext { @@ -185,6 +191,16 @@ public extension Node where Context == HTML.AnchorContext { } } +// MARK: - Interactive elements + +public extension Node where Context == HTML.DetailsContext { + /// Assign whether the details element is opened/expanded. + /// - parameter isOpen: Whether the element should be displayed as open. + static func open(_ isOpen: Bool) -> Node { + isOpen ? .attribute(named: "open") : .empty + } +} + // MARK: - Sources and media public extension Attribute where Context: HTMLSourceContext { @@ -286,7 +302,7 @@ public extension Attribute where Context == HTML.InputContext { Attribute(name: "type", value: type.rawValue) } - /// Assigns a placeholder to the input field. + /// Assign a placeholder to the input field. /// - parameter placeholder: The placeholder to assign. static func placeholder(_ placeholder: String) -> Attribute { Attribute(name: "placeholder", value: placeholder) @@ -301,13 +317,37 @@ public extension Attribute where Context == HTML.InputContext { /// Assign whether the element is required before submitting the form. /// - parameter isRequired: Whether the element is required. static func required(_ isRequired: Bool) -> Attribute { - isRequired ? Attribute(name: "required", value: "true") : .empty + isRequired ? Attribute(name: "required", value: nil, ignoreIfValueIsEmpty: false) : .empty } /// Assign whether the element should be autofocused when the page loads. /// - parameter isOn: Whether autofocus should be turned on. static func autofocus(_ isOn: Bool) -> Attribute { - isOn ? Attribute(name: "autofocus", value: "true") : .empty + isOn ? Attribute(name: "autofocus", value: nil, ignoreIfValueIsEmpty: false) : .empty + } + + /// Assign whether the element should be read-only. + /// - parameter isReadonly: Whether the input is read-only. + static func readonly(_ isReadonly: Bool) -> Attribute { + isReadonly ? Attribute(name: "readonly", value: nil, ignoreIfValueIsEmpty: false) : .empty + } + + /// Assign whether the element should be disabled. + /// - parameter isDisabled: Whether the input is disabled. + static func disabled(_ isDisabled: Bool) -> Attribute { + isDisabled ? Attribute(name: "disabled", value: nil, ignoreIfValueIsEmpty: false) : .empty + } + + /// Assign whether the element should allow the selection of multiple values. + /// - parameter isMultiple: Whether multiple values are allowed. + static func multiple(_ isEnabled: Bool) -> Attribute { + isEnabled ? Attribute(name: "multiple", value: nil, ignoreIfValueIsEmpty: false) : .empty + } + + /// Assign whether a checkbox or radio input element has an active state. + /// - parameter isChecked: Whether the element has an active state. + static func checked(_ isChecked: Bool) -> Attribute { + isChecked ? Attribute(name: "checked", value: nil, ignoreIfValueIsEmpty: false) : .empty } } @@ -332,16 +372,34 @@ public extension Node where Context == HTML.TextAreaContext { .attribute(named: "rows", value: String(rows)) } + /// Assign a placeholder to the text area. + /// - parameter placeholder: The placeholder to assign. + static func placeholder(_ placeholder: String) -> Node { + .attribute(named: "placeholder", value: placeholder) + } + /// Assign whether the element is required before submitting the form. /// - parameter isRequired: Whether the element is required. static func required(_ isRequired: Bool) -> Node { - isRequired ? .attribute(named: "required", value: "true") : .empty + isRequired ? .attribute(named: "required") : .empty } /// Assign whether the element should be autofocused when the page loads. /// - parameter isOn: Whether autofocus should be turned on. static func autofocus(_ isOn: Bool) -> Node { - isOn ? .attribute(named: "autofocus", value: "true") : .empty + isOn ? .attribute(named: "autofocus") : .empty + } + + /// Assign whether the element should be read-only. + /// - parameter isReadonly: Whether the input is read-only. + static func readonly(_ isReadonly: Bool) -> Node { + isReadonly ? .attribute(named: "readonly") : .empty + } + + /// Assign whether the element should be disabled. + /// - parameter isDisabled: Whether the input is disabled. + static func disabled(_ isDisabled: Bool) -> Node { + isDisabled ? .attribute(named: "disabled") : .empty } } @@ -423,7 +481,7 @@ public extension Attribute where Context == HTML.IFrameContext { /// Assign whether to grant the iframe full screen capabilities. /// - parameter allow: Whether the iframe should be allowed to go full screen. static func allowfullscreen(_ allow: Bool) -> Attribute { - Attribute(name: "allowfullscreen", value: String(allow)) + allow ? Attribute(name: "allowfullscreen", value: nil, ignoreIfValueIsEmpty: false) : .empty } } diff --git a/Tests/PlotTests/HTMLComponentTests.swift b/Tests/PlotTests/HTMLComponentTests.swift index 1c6d3d2..42dd660 100644 --- a/Tests/PlotTests/HTMLComponentTests.swift +++ b/Tests/PlotTests/HTMLComponentTests.swift @@ -364,7 +364,7 @@ final class HTMLComponentTests: XCTestCase {
\
\ \
\ - \ + \ \ - \ - \ - \ + \ + \ + \ + \ + \ + \ + \ \
""") @@ -577,13 +593,17 @@ final class HTMLTests: XCTestCase { .src("url.com"), .frameborder(false), .allow("gyroscope"), + .allowfullscreen(false) + ), + .iframe( .allowfullscreen(true) ) )) assertEqualHTMLContent(html, """ \ - \ + \ + \ """) } @@ -657,11 +677,15 @@ final class HTMLTests: XCTestCase { func testDetails() { let html = HTML(.body( - .details(.summary("Summary"), .p("Text")) + .details(.open(true), .summary("Open Summary"), .p("Text")), + .details(.open(false), .summary("Closed Summary"), .p("Text")) )) assertEqualHTMLContent(html, """ -
Summary

Text

+ \ +
Open Summary

Text

\ +
Closed Summary

Text

\ + """) }