diff --git a/.editorconfig b/.editorconfig index cd706d2..57b794d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,26 +8,6 @@ insert_final_newline = true tab_width = 2 trim_trailing_whitespace = true -[*.cs] -csharp_indent_case_contents_when_block = false -csharp_indent_labels = no_change -csharp_new_line_before_open_brace = none -csharp_prefer_braces = false -csharp_space_after_cast = true -csharp_space_before_colon_in_inheritance_clause = false -csharp_style_expression_bodied_constructors = true -csharp_style_expression_bodied_local_functions = true -csharp_style_expression_bodied_methods = true -csharp_style_expression_bodied_operators = true -csharp_style_namespace_declarations = file_scoped -csharp_style_var_elsewhere = true -csharp_style_var_for_built_in_types = true -csharp_style_var_when_type_is_apparent = true -csharp_using_directive_placement = inside_namespace -dotnet_diagnostic.CS8524.severity = silent -dotnet_sort_system_directives_first = false -dotnet_style_namespace_match_folder = false - [*.md] trim_trailing_whitespace = false diff --git a/.github/workflows/ContinuousIntegration.yaml b/.github/workflows/ContinuousIntegration.yaml index 0ef586a..4d2ae6d 100644 --- a/.github/workflows/ContinuousIntegration.yaml +++ b/.github/workflows/ContinuousIntegration.yaml @@ -11,10 +11,6 @@ jobs: steps: - name: Fetch sources uses: actions/checkout@v6 - - name: Set up .NET - uses: actions/setup-dotnet@v5 - with: - dotnet-version: 10 - name: Set up PowerShell run: | Invoke-WebRequest "https://aka.ms/install-powershell.ps1" -OutFile Install-PowerShell.ps1 diff --git a/.gitignore b/.gitignore index 0cffc73..f06f879 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,5 @@ /**/*.user /.idea/ /.vs/ -/bin/ -/*/obj/ -/src/**/*.g.cs +/src/Generated/ /var/ diff --git a/.vscode/extensions.json b/.vscode/extensions.json index e2d0e78..b408c54 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,6 +1,5 @@ { "recommendations": [ - "ms-dotnettools.csdevkit", "ms-vscode.powershell" ] } diff --git a/.vscode/launch.json b/.vscode/launch.json index ec38296..93c907c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -3,7 +3,6 @@ "configurations": [ { "name": "Script", - "preLaunchTask": "Build", "request": "launch", "type": "PowerShell", "script": "${workspaceFolder}/Debug.ps1" diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index b3a0bfc..0000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "Build", - "type": "shell", - "command": "./Invoke.ps1", - "args": ["Build"] - } - ] -} diff --git a/ChangeLog.md b/ChangeLog.md index ef0cab8..d3be8f9 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,59 +1,63 @@ # Changelog -## Version [1.2.0](https://github.com/cedx/html.net/compare/v1.1.0...v1.2.0) +## Version [2.0.0](https://github.com/cedx/html.ps1/compare/v1.2.0...v2.0.0) +- Breaking change: ported the source code to [PowerShell](https://learn.microsoft.com/en-us/powershell). +- Breaking change: renamed the `-DataSet` parameter to `-Data`. + +## Version [1.2.0](https://github.com/cedx/html.ps1/compare/v1.1.0...v1.2.0) - Added the `Use-Layout` and `Write-View` cmdlets. -## Version [1.1.0](https://github.com/cedx/html.net/compare/v1.0.1...v1.1.0) +## Version [1.1.0](https://github.com/cedx/html.ps1/compare/v1.0.1...v1.1.0) - Added support for `[switch]` parameters in attribute values. - The `New-DelElement`, `New-InsElement` and `New-TimeElement` cmdlets now use a non-terminating error. -## Version [1.0.1](https://github.com/cedx/html.net/compare/v1.0.0...v1.0.1) +## Version [1.0.1](https://github.com/cedx/html.ps1/compare/v1.0.0...v1.0.1) - Fixed a packaging issue: the generated cmdlets were not included in the release. -## Version [1.0.0](https://github.com/cedx/html.net/compare/v0.10.0...v1.0.0) +## Version [1.0.0](https://github.com/cedx/html.ps1/compare/v0.10.0...v1.0.0) - Added the `New-FormElement`, `New-IframeElement`, `New-InputElement`, `New-TemplateElement` and `New-TextareaElement` cmdlets. - Added the `form`, `iframe`, `input`, `template` and `textarea` aliases. -## Version [0.10.0](https://github.com/cedx/html.net/compare/v0.9.0...v0.10.0) +## Version [0.10.0](https://github.com/cedx/html.ps1/compare/v0.9.0...v0.10.0) - Added the `New-ButtonElement`, `New-QElement`, `New-SelectElement`, `New-SlotElement` and `New-SourceElement` cmdlets. - Added the `button`, `q`, `selectTag`, `slot` and `source` aliases. - The common parameter `-Style` is now an `OrderedHashtable`, allowing the declaration order to be preserved. -## Version [0.9.0](https://github.com/cedx/html.net/compare/v0.8.0...v0.9.0) +## Version [0.9.0](https://github.com/cedx/html.ps1/compare/v0.8.0...v0.9.0) - Added the `New-OlElement`, `New-OptgroupElement`, `New-OptionElement`, `New-OutputElement` and `New-ProgressElement` cmdlets. - Added the `ol`, `optgroup`, `option`, `output` and `progress` aliases. -## Version [0.8.0](https://github.com/cedx/html.net/compare/v0.7.0...v0.8.0) +## Version [0.8.0](https://github.com/cedx/html.ps1/compare/v0.7.0...v0.8.0) - Added the `New-LabelElement`, `New-LiElement`, `New-MapElement`, `New-MeterElement` and `New-ObjectElement` cmdlets. - Added the `label`, `li`, `map`, `meter` and `object` aliases. - Renamed the common parameter `-Data` to `-DataSet`. -## Version [0.7.0](https://github.com/cedx/html.net/compare/v0.6.0...v0.7.0) +## Version [0.7.0](https://github.com/cedx/html.ps1/compare/v0.6.0...v0.7.0) - Added the `New-DetailsElement`, `New-DialogElement`, `New-EmbedElement`, `New-FieldsetElement` and `New-InsElement` cmdlets. - Added the `details`, `dialog`, `embed`, `fieldset` and `ins` aliases. -## Version [0.6.0](https://github.com/cedx/html.net/compare/v0.5.0...v0.6.0) +## Version [0.6.0](https://github.com/cedx/html.ps1/compare/v0.5.0...v0.6.0) - Added the `Html` prefix to the nouns of all cmdlets. - Added the `New-DelElement`, `New-TdElement`, `New-ThElement`, `New-TimeElement` and `New-TrackElement` cmdlets. - Added the `delTag`, `td`, `th`, `time` and `track` aliases. -## Version [0.5.0](https://github.com/cedx/html.net/compare/v0.4.0...v0.5.0) +## Version [0.5.0](https://github.com/cedx/html.ps1/compare/v0.4.0...v0.5.0) - Added the `New-ColGroupElement`, `New-DataElement`, `New-StyleElement` and `New-VideoElement` cmdlets. - Added the `colgroup`, `dataTag`, `style` and `video` aliases. -## Version [0.4.0](https://github.com/cedx/html.net/compare/v0.3.0...v0.4.0) +## Version [0.4.0](https://github.com/cedx/html.ps1/compare/v0.3.0...v0.4.0) - Added support for the `on*` and `tabindex` attributes. - Added the `New-AudioElement`, `New-BlockquoteElement`, `New-CanvasElement` and `New-ColElement` cmdlets. - Added the `audio`, `blockquote`, `canvas` and `col` aliases. - Renamed the `New-Doctype` cmdlet to `New-DocumentType`. -## Version [0.3.0](https://github.com/cedx/html.net/compare/v0.2.0...v0.3.0) +## Version [0.3.0](https://github.com/cedx/html.ps1/compare/v0.2.0...v0.3.0) - Added support for the `data-*`, `dir`, `lang` and `title` attributes. - Added the `New-AElement`, `New-AreaElement`, `New-ImgElement` and `New-ScriptElement` cmdlets. - Added the `a`, `area`, `img` and `script` aliases. -## Version [0.2.0](https://github.com/cedx/html.net/compare/v0.1.0...v0.2.0) -- Added the `New-BaseElement`, `New-HtmlElement`, `New-LinkElement` and `New-MetaElement` cmdlets. +## Version [0.2.0](https://github.com/cedx/html.ps1/compare/v0.1.0...v0.2.0) +- Added the `New-BaseElement`, `Write-HtmlElement`, `New-LinkElement` and `New-MetaElement` cmdlets. - Added the `base`, `html`, `link` and `meta` aliases. ## Version 0.1.0 diff --git a/Html.psd1 b/Html.psd1 index d454a57..3b3a47f 100644 --- a/Html.psd1 +++ b/Html.psd1 @@ -1,7 +1,7 @@ @{ - ModuleVersion = "1.2.0" + # DefaultCommandPrefix = "Html" + ModuleVersion = "2.0.0" PowerShellVersion = "7.6" - RootModule = "bin/Belin.Html.dll" Author = "Cédric Belin " CompanyName = "Cedric-Belin.fr" @@ -9,137 +9,35 @@ Description = "PowerShell cmdlets for rendering HTML documents." GUID = "3c16800c-921e-4c31-9fc3-00052d2f30ba" - AliasesToExport = "doctype", "layout" - FunctionsToExport = "New-HtmlDocumentType", "Use-HtmlLayout", "Write-HtmlView" + CmdletsToExport = @() VariablesToExport = @() - CmdletsToExport = @( - "New-HtmlAbbrElement" - "New-HtmlAddressElement" + AliasesToExport = @( + "doctype" + "a" + "area" + "tag" + ) + + FunctionsToExport = @( "New-HtmlAElement" - "New-HtmlAreaElement" - "New-HtmlArticleElement" - "New-HtmlAsideElement" - "New-HtmlAudioElement" - "New-HtmlBaseElement" - "New-HtmlBdiElement" - "New-HtmlBdoElement" - "New-HtmlBElement" - "New-HtmlBlockquoteElement" - "New-HtmlBodyElement" - "New-HtmlBrElement" - "New-HtmlButtonElement" - "New-HtmlCanvasElement" - "New-HtmlCaptionElement" - "New-HtmlCiteElement" - "New-HtmlCodeElement" - "New-HtmlColElement" - "New-HtmlColgroupElement" + "New-HtmlDocumentType" "New-HtmlCustomElement" - "New-HtmlDataElement" - "New-HtmlDatalistElement" - "New-HtmlDdElement" - "New-HtmlDelElement" - "New-HtmlDetailsElement" - "New-HtmlDfnElement" - "New-HtmlDialogElement" - "New-HtmlDivElement" - "New-HtmlDlElement" - "New-HtmlDtElement" - "New-HtmlEmbedElement" - "New-HtmlEmElement" - "New-HtmlFieldsetElement" - "New-HtmlFigcaptionElement" - "New-HtmlFigureElement" - "New-HtmlFooterElement" - "New-HtmlFormElement" - "New-HtmlH1Element" - "New-HtmlH2Element" - "New-HtmlH3Element" - "New-HtmlH4Element" - "New-HtmlH5Element" - "New-HtmlH6Element" - "New-HtmlHeadElement" - "New-HtmlHeaderElement" - "New-HtmlHgroupElement" - "New-HtmlHrElement" - "New-HtmlHtmlElement" - "New-HtmlIElement" - "New-HtmlIframeElement" - "New-HtmlImgElement" - "New-HtmlInputElement" - "New-HtmlInsElement" - "New-HtmlKbdElement" - "New-HtmlLabelElement" - "New-HtmlLegendElement" - "New-HtmlLiElement" - "New-HtmlLinkElement" - "New-HtmlMainElement" - "New-HtmlMapElement" - "New-HtmlMarkElement" - "New-HtmlMenuElement" - "New-HtmlMetaElement" - "New-HtmlMeterElement" - "New-HtmlNavElement" - "New-HtmlNoscriptElement" - "New-HtmlObjectElement" - "New-HtmlOlElement" - "New-HtmlOptgroupElement" - "New-HtmlOptionElement" - "New-HtmlOutputElement" - "New-HtmlPElement" - "New-HtmlPictureElement" - "New-HtmlPreElement" - "New-HtmlProgressElement" - "New-HtmlQElement" - "New-HtmlRpElement" - "New-HtmlRtElement" - "New-HtmlRubyElement" - "New-HtmlSampElement" - "New-HtmlScriptElement" - "New-HtmlSearchElement" - "New-HtmlSectionElement" - "New-HtmlSelectElement" - "New-HtmlSElement" - "New-HtmlSlotElement" - "New-HtmlSmallElement" - "New-HtmlSourceElement" - "New-HtmlSpanElement" - "New-HtmlStrongElement" - "New-HtmlStyleElement" - "New-HtmlSubElement" - "New-HtmlSummaryElement" - "New-HtmlSupElement" - "New-HtmlTableElement" - "New-HtmlTbodyElement" - "New-HtmlTdElement" - "New-HtmlTemplateElement" - "New-HtmlTextareaElement" - "New-HtmlTfootElement" - "New-HtmlTheadElement" - "New-HtmlThElement" - "New-HtmlTimeElement" - "New-HtmlTitleElement" - "New-HtmlTrackElement" - "New-HtmlTrElement" - "New-HtmlUElement" - "New-HtmlUlElement" - "New-HtmlVarElement" - "New-HtmlVideoElement" - "New-HtmlWbrElement" + "New-HtmlAreaElement" ) NestedModules = @( + "src/Elements/New-AElement.psm1" + "src/Elements/New-AreaElement.psm1" "src/New-DocumentType.psm1" - "src/Use-Layout.psm1" - "src/Write-View.psm1" + "src/New-CustomElement.psm1" ) PrivateData = @{ PSData = @{ - LicenseUri = "https://github.com/cedx/html.net/blob/main/License.md" - ProjectUri = "https://github.com/cedx/html.net" - ReleaseNotes = "https://github.com/cedx/html.net/releases" + LicenseUri = "https://github.com/cedx/html.ps1/blob/main/License.md" + ProjectUri = "https://github.com/cedx/html.ps1" + ReleaseNotes = "https://github.com/cedx/html.ps1/releases" Tags = "html", "renderer", "template", "templating", "web" } } diff --git a/Html.slnx b/Html.slnx deleted file mode 100644 index c2cf796..0000000 --- a/Html.slnx +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/ReadMe.md b/ReadMe.md index 87b3432..c1bca09 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1,13 +1,13 @@ -# HTML Renderer for PS +# HTML Renderer for PowerShell [PowerShell](https://learn.microsoft.com/en-us/powershell) cmdlets for rendering [HTML](https://developer.mozilla.org/docs/Web/HTML) documents. ## Documentation -- [User guide](https://github.com/cedx/html.net/tree/main/docs) -- [Examples](https://github.com/cedx/html.net/tree/main/example) +- [User guide](https://github.com/cedx/html.ps1/tree/main/docs) +- [Examples](https://github.com/cedx/html.ps1/tree/main/example) ## Development -- [Git repository](https://github.com/cedx/html.net) -- [Submit an issue](https://github.com/cedx/html.net/issues) +- [Git repository](https://github.com/cedx/html.ps1) +- [Submit an issue](https://github.com/cedx/html.ps1/issues) ## License -[HTML Renderer for PS](https://github.com/cedx/html.net) is distributed under the MIT License. +[HTML Renderer for PowerShell](https://github.com/cedx/html.ps1) is distributed under the MIT License. diff --git a/docs/Installation.md b/docs/Installation.md index 1774d7d..f41318c 100644 --- a/docs/Installation.md +++ b/docs/Installation.md @@ -1,7 +1,7 @@ # Installation ## Requirements -Before installing **HTML Renderer for PS**, you need to make sure you have [PowerShell](https://learn.microsoft.com/en-us/powershell) up and running. +Before installing **HTML Renderer for PowerShell**, you need to make sure you have [PowerShell](https://learn.microsoft.com/en-us/powershell) up and running. You can verify if you're already good to go with the following command: ```shell diff --git a/res/Content.ps1 b/res/Content.ps1 index 0536746..a72f016 100644 --- a/res/Content.ps1 +++ b/res/Content.ps1 @@ -1,4 +1,4 @@ param ([hashtable] $data) h1 $data.Title -div -class alert, alert-success "Welcome to my website!" +div -Class alert, alert-success "Welcome to my website!" diff --git a/res/Footer.ps1 b/res/Footer.ps1 index ba18bae..aafa71e 100644 --- a/res/Footer.ps1 +++ b/res/Footer.ps1 @@ -1,5 +1,5 @@ param ([hashtable] $data) -footer -class text-center { +footer -Class text-center { "Copyright © $($data.Year) - All rights reserved." } diff --git a/res/Header.ps1 b/res/Header.ps1 index 41cff9e..655ad44 100644 --- a/res/Header.ps1 +++ b/res/Header.ps1 @@ -1,15 +1,15 @@ param ([hashtable] $data) header { - nav -class navbar, navbar-expand-xl { - div -class container-fluid { - button -class navbar-toggler -dataset @{ BsTarget = "#menu"; BsToggle = "offcanvas" } { - span -class navbar-toggler-icon + nav -Class navbar, navbar-expand-xl { + div -Class container-fluid { + button -Class navbar-toggler -Data @{ BsTarget = "#menu"; BsToggle = "offcanvas" } { + span -Class navbar-toggler-icon } - div -class navbar-brand, d-flex, align-items-center { - a -href Index.html { img -alt "" -src Favicon.ico -width 30 -height 30 } - div -class ms-2 $data.AppName + div -Class navbar-brand, d-flex, align-items-center { + a -Href Index.html { img -Alt "" -Src Favicon.ico -Width 30 -Height 30 } + div -Class ms-2 $data.AppName } } } diff --git a/res/Layout.ps1 b/res/Layout.ps1 index 18ed2ae..34221aa 100644 --- a/res/Layout.ps1 +++ b/res/Layout.ps1 @@ -1,22 +1,22 @@ param ([string] $content, [hashtable] $data) doctype -html -lang $PSCulture { +html -Lang $PSCulture { head { - meta -charset utf-8 + meta -Charset utf-8 title $data.AppName - meta -name color-scheme -content light - meta -name viewport -content "initial-scale=1, width=device-width" + meta -Name color-scheme -Content light + meta -Name viewport -Content "initial-scale=1, width=device-width" - link -rel icon -href Favicon.ico - link -rel preload -href Assets/Font.woff2 -as font -crossorigin anonymous -type font/woff2 + link -Rel icon -Href Favicon.ico + link -Rel preload -Href Assets/Font.woff2 -As font -CrossOrigin anonymous -Type font/woff2 - link -rel stylesheet -href "https://cdn.jsdelivr.net/npm/bootstrap@5/dist/css/bootstrap.css" -integrity "sha256-2FMn2Zx6PuH5tdBQDRNwrOo60ts5wWPC9R8jK67b3t4" - link -rel stylesheet -href Assets/Styles.css + link -Rel stylesheet -Href "https://cdn.jsdelivr.net/npm/bootstrap@5/dist/css/bootstrap.css" -Integrity "sha256-2FMn2Zx6PuH5tdBQDRNwrOo60ts5wWPC9R8jK67b3t4" + link -Rel stylesheet -Href Assets/Styles.css - script -src "https://cdn.jsdelivr.net/npm/bootstrap@5/dist/js/bootstrap.js" -integrity "sha256-ew8UiV1pJH/YjpOEBInP1HxVvT/SfrCmwSoUzF9JIgc=" - script -src Assets/Scripts.js -type module + script -Src "https://cdn.jsdelivr.net/npm/bootstrap@5/dist/js/bootstrap.js" -Integrity "sha256-ew8UiV1pJH/YjpOEBInP1HxVvT/SfrCmwSoUzF9JIgc=" + script -Src Assets/Scripts.js -Type module } body { @@ -24,7 +24,7 @@ html -lang $PSCulture { main { noscript { p "This application requires $(b JavaScript) to be enabled in your browser." } - article -class container-xl { $content } + article -Class container-xl { $content } } & "$PSScriptRoot/Footer.ps1" @{ Year = $data.Year } diff --git a/share/Cmdlet.Template.cs b/share/Cmdlet.Template.cs index 494f5c7..8bdccb1 100644 --- a/share/Cmdlet.Template.cs +++ b/share/Cmdlet.Template.cs @@ -1,7 +1,6 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new {Tag} element. -/// +<# +.SYNOPSIS + Creates a new `{Tag}` element. +#> [Cmdlet(VerbsCommon.New, "Html{CapitalizedTag}Element"), Alias("{Alias}"), OutputType(typeof(string))] -public class New{CapitalizedTag}ElementCommand(): NewElementCommand("{Tag}", isVoid: {IsVoid}) {} +function New-Html{CapitalizedTag}Element: NewElementCommand("{Tag}", isVoid: {IsVoid}) {} diff --git a/share/Cmdlet.Template.psm1 b/share/Cmdlet.Template.psm1 new file mode 100644 index 0000000..97e612a --- /dev/null +++ b/share/Cmdlet.Template.psm1 @@ -0,0 +1,28 @@ +<# +.SYNOPSIS + Creates a new `{Tag}` element. +.INPUTS + The inner HTML of the `{Tag}` element. +.OUTPUTS + The newly created `{Tag}` element. +#> +function New-Html{CapitalizedTag}Element { + [Alias("{Alias}")] + [CmdletBinding()] + [OutputType([string])] + param ( + # The inner HTML of the element. + [Parameter(Position = 0, ValueFromPipeline)] + [object] $Content, + + # The custom attributes to render. + [hashtable] $Attributes = @{} + ) + + process { + # TODO handle void elements !!! they don't have content ! + $attributesToRender = $Attributes.Clone() + $MyInvocation.MyCommand.Parameters.Keys.ForEach{ $PSBoundParameters.Remove($_) | Out-Null } + Write-HtmlElement -TagName {Tag} -Attributes $attributesToRender -Content $Content -Void:{IsVoid} @PSBoundParameters + } +} diff --git a/src/Elements/New-AElement.cs b/src/Elements/New-AElement.cs deleted file mode 100644 index 4176b0e..0000000 --- a/src/Elements/New-AElement.cs +++ /dev/null @@ -1,51 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new a element. -/// -[Cmdlet(VerbsCommon.New, "HtmlAElement"), Alias("a"), OutputType(typeof(string))] -public class NewAElementCommand(): NewElementCommand("a", isVoid: false) { - - /// - /// The suggested filename when the browser treats the linked URL as a download. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Download { get; set; } - - /// - /// The URL that the hyperlink points to. - /// - [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)] - public required Uri Href { get; set; } - - /// - /// A list of URLs. When the link is followed, the browser will send POST requests with the body PING to the URLs. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public Uri[] Ping { get; set; } = []; - - /// - /// The relationship of the linked URL. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string[] Rel { get; set; } = []; - - /// - /// The browsing context to show the results of navigation. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Target { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - attributes["href"] = Href.ToString(); - if (!string.IsNullOrWhiteSpace(Download)) attributes["download"] = Download; - if (Ping.Length > 0) attributes["ping"] = string.Join(' ', Ping.Select(url => url.ToString())).Trim(); - if (Rel.Length > 0) attributes["rel"] = string.Join(' ', Rel).Trim(); - if (!string.IsNullOrWhiteSpace(Target)) attributes["target"] = Target; - } -} diff --git a/src/Elements/New-AElement.psm1 b/src/Elements/New-AElement.psm1 new file mode 100644 index 0000000..81f3730 --- /dev/null +++ b/src/Elements/New-AElement.psm1 @@ -0,0 +1,51 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `a` element. +.INPUTS + The inner HTML of the `a` element. +.OUTPUTS + The newly created `a` element. +#> +function New-HtmlAElement { + [Alias("a")] + [CmdletBinding()] + [OutputType([string])] + param ( + # The URL that the hyperlink points to. + [Parameter(Mandatory)] + [uri] $Href, + + # The inner HTML of the element. + [Parameter(Position = 0, ValueFromPipeline)] + [object] $Content, + + # The custom attributes to render. + [hashtable] $Attributes = @{}, + + # The suggested filename when the browser treats the linked URL as a download. + [string] $Download, + + # A list of URLs. When the link is followed, the browser will send `POST` requests with the body `PING` to the URLs. + [uri[]] $Ping = @(), + + # The relationship of the linked URL. + [string[]] $Rel = @(), + + # The browsing context to show the results of navigation. + [string] $Target + ) + + process { + $attributesToRender = $Attributes.Clone() + $attributesToRender.href = $Href + if ($Download) { $attributesToRender.download = $Download } + if ($Ping) { $attributesToRender.ping = ($Ping -join " ").Trim() } + if ($Rel) { $attributesToRender.rel = ($Rel -join " ").Trim() } + if ($Target) { $attributesToRender.target = $Target } + + $MyInvocation.MyCommand.Parameters.Keys.ForEach{ $PSBoundParameters.Remove($_) | Out-Null } + Write-HtmlElement -TagName a -Attributes $attributesToRender -Content $Content @PSBoundParameters + } +} diff --git a/src/Elements/New-AreaElement.cs b/src/Elements/New-AreaElement.cs deleted file mode 100644 index 1092468..0000000 --- a/src/Elements/New-AreaElement.cs +++ /dev/null @@ -1,78 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new area element. -/// -[Cmdlet(VerbsCommon.New, "HtmlAreaElement"), Alias("area"), OutputType(typeof(string))] -public class NewAreaElementCommand(): NewElementCommand("area", isVoid: true) { - - /// - /// A text to display on browsers that do not display images. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Alt { get; set; } - - /// - /// The browsing context to show the results of navigation. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateCount(3, int.MaxValue)] - public double[]? Coords { get; set; } - - /// - /// The suggested filename when the browser treats the linked URL as a download. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Download { get; set; } - - /// - /// The hyperlink target for the area. - /// - [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)] - public required Uri Href { get; set; } - - /// - /// A list of URLs. When the link is followed, the browser will send POST requests with the body PING to the URLs. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public Uri[] Ping { get; set; } = []; - - /// - /// The relationship of the linked URL. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string[] Rel { get; set; } = []; - - /// - /// The browsing context to show the results of navigation. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("circle", "default", "poly", "rect")] - public string? Shape { get; set; } - - /// - /// The browsing context to show the results of navigation. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Target { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - attributes["href"] = Href.ToString(); - - if (Shape is not null) { - attributes["shape"] = Shape; - if (Coords is not null && Shape != "default") attributes["coords"] = string.Join(',', Coords.Select(number => number.ToString(CultureInfo.InvariantCulture))); - } - - if (Alt is not null) attributes["alt"] = Alt; - if (!string.IsNullOrWhiteSpace(Download)) attributes["download"] = Download; - if (Ping.Length > 0) attributes["ping"] = string.Join(' ', Ping.Select(url => url.ToString())).Trim(); - if (Rel.Length > 0) attributes["rel"] = string.Join(' ', Rel).Trim(); - if (!string.IsNullOrWhiteSpace(Target)) attributes["target"] = Target; - } -} diff --git a/src/Elements/New-AreaElement.psm1 b/src/Elements/New-AreaElement.psm1 new file mode 100644 index 0000000..a5c8449 --- /dev/null +++ b/src/Elements/New-AreaElement.psm1 @@ -0,0 +1,68 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `area` element. +.INPUTS + The inner HTML of the `area` element. +.OUTPUTS + The newly created `area` element. +#> +function New-HtmlAreaElement { + [Alias("area")] + [CmdletBinding()] + [OutputType([string])] + param ( + # The hyperlink target for the area. + [Parameter(Mandatory)] + [uri] $Href, + + # The inner HTML of the element. + [Parameter(Position = 0, ValueFromPipeline)] + [object] $Content, + + # The custom attributes to render. + [hashtable] $Attributes = @{}, + + # A text to display on browsers that do not display images. + [string] $Alt, + + # The browsing context to show the results of navigation. + [ValidateCount(3, [int]::MaxValue)] + [double[]] $Coords, + + # The suggested filename when the browser treats the linked URL as a download. + [string] $Download, + + # A list of URLs. When the link is followed, the browser will send `POST` requests with the body `PING` to the URLs. + [uri[]] $Ping = @(), + + # The relationship of the linked URL. + [string[]] $Rel = @(), + + # The browsing context to show the results of navigation. + [ValidateSet("circle", "default", "poly", "rect")] + [string] $Shape, + + # The browsing context to show the results of navigation. + [string] $Target + ) + + process { + $attributesToRender = $Attributes.Clone() + $attributesToRender.href = $Href + if ($Alt) { $attributesToRender.alt = $Alt } + if ($Download) { $attributesToRender.download = $Download } + if ($Ping) { $attributesToRender.ping = ($Ping -join " ").Trim() } + if ($Rel) { $attributesToRender.rel = ($Rel -join " ").Trim() } + if ($Target) { $attributesToRender.target = $Target } + + if ($Shape) { + $attributesToRender.shape = $Shape + if ($Coords -and ($Shape -ne "default")) { $attributesToRender.coords = $Coords.ForEach{ [string] $_ } -join "," } + } + + $MyInvocation.MyCommand.Parameters.Keys.ForEach{ $PSBoundParameters.Remove($_) | Out-Null } + Write-HtmlElement -TagName area -Attributes $attributesToRender -Content $Content -Void @PSBoundParameters + } +} diff --git a/src/Elements/New-AudioElement.cs b/src/Elements/New-AudioElement.cs deleted file mode 100644 index cb578df..0000000 --- a/src/Elements/New-AudioElement.cs +++ /dev/null @@ -1,72 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new audio element. -/// -[Cmdlet(VerbsCommon.New, "HtmlAudioElement"), Alias("audio"), OutputType(typeof(string))] -public class NewAudioElementCommand(): NewElementCommand("audio", isVoid: false) { - - /// - /// Value indicating whether playback should start automatically as soon as the audio signal allows. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter AutoPlay { get; set; } - - /// - /// Value indicating whether to offer controls to allow the user to control audio playback. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Controls { get; set; } - - /// - /// Value indicating whether CORS must be used when fetching the resource. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("anonymous", "use-credentials")] - public string? CrossOrigin { get; set; } - - /// - /// Value indicating whether to disable the capability of remote playback in devices that are attached using wired and wireless technologies. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter DisableRemotePlayback { get; set; } - - /// - /// Value indicating whether the audio player will automatically seek back to the start upon reaching the end of the audio. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Loop { get; set; } - - /// - /// Value indicating whether the audio will be initially silenced. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Muted { get; set; } - - /// - /// Value providing a hint to the browser about what the author thinks will lead to the best user experience. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("auto", "none", "metadata")] - public string? Preload { get; set; } - - /// - /// The URL of the audio to embed. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public Uri? Src { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (AutoPlay) attributes["autoplay"] = true; - if (Controls) attributes["controls"] = true; - if (CrossOrigin is not null) attributes["crossorigin"] = CrossOrigin; - if (DisableRemotePlayback) attributes["disableremoteplayback"] = true; - if (Loop) attributes["loop"] = true; - if (Muted) attributes["muted"] = true; - if (Preload is not null) attributes["preload"] = Preload; - if (Src is not null) attributes["src"] = Src.ToString(); - } -} diff --git a/src/Elements/New-AudioElement.psm1 b/src/Elements/New-AudioElement.psm1 new file mode 100644 index 0000000..afa5c0d --- /dev/null +++ b/src/Elements/New-AudioElement.psm1 @@ -0,0 +1,76 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `audio` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlAudioElement"), Alias("audio"), OutputType(typeof(string))] +function New-HtmlAudioElement: NewElementCommand("audio", isVoid: false) { + + <# + .SYNOPSIS + Value indicating whether playback should start automatically as soon as the audio signal allows. + #> + [switch] $AutoPlay + + <# + .SYNOPSIS + Value indicating whether to offer controls to allow the user to control audio playback. + #> + [switch] $Controls + + <# + .SYNOPSIS + Value indicating whether CORS must be used when fetching the resource. + #> + [ValidateSet("anonymous", "use-credentials")] + [string] $CrossOrigin + + <# + .SYNOPSIS + Value indicating whether to disable the capability of remote playback in devices that are attached using wired and wireless technologies. + #> + [switch] $DisableRemotePlayback + + <# + .SYNOPSIS + Value indicating whether the audio player will automatically seek back to the start upon reaching the end of the audio. + #> + [switch] $Loop + + <# + .SYNOPSIS + Value indicating whether the audio will be initially silenced. + #> + [switch] $Muted + + <# + .SYNOPSIS + Value providing a hint to the browser about what the author thinks will lead to the best user experience. + #> + [ValidateSet("auto", "none", "metadata")] + [string] $Preload + + <# + .SYNOPSIS + The URL of the audio to embed. + #> + Uri? Src + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (AutoPlay) $attributesToRender.autoplay"] = true; + if (Controls) $attributesToRender.controls"] = true; + if (CrossOrigin is not null) $attributesToRender.crossorigin"] = CrossOrigin; + if (DisableRemotePlayback) $attributesToRender.disableremoteplayback"] = true; + if (Loop) $attributesToRender.loop"] = true; + if (Muted) $attributesToRender.muted"] = true; + if (Preload is not null) $attributesToRender.preload"] = Preload; + if (Src is not null) $attributesToRender.src"] = Src.ToString(); + } +} diff --git a/src/Elements/New-BaseElement.cs b/src/Elements/New-BaseElement.cs deleted file mode 100644 index 43d53bc..0000000 --- a/src/Elements/New-BaseElement.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new base element. -/// -[Cmdlet(VerbsCommon.New, "HtmlBaseElement"), Alias("base"), OutputType(typeof(string))] -public class NewBaseElementCommand(): NewElementCommand("base", isVoid: true) { - - /// - /// The base URL to be used throughout the document for relative URLs. - /// - [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)] - public required Uri Href { get; set; } - - /// - /// The default browsing context to show the results of navigation from elements without explicit target attribute. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Target { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - attributes["href"] = Href.ToString(); - if (!string.IsNullOrWhiteSpace(Target)) attributes["target"] = Target; - } -} diff --git a/src/Elements/New-BaseElement.psm1 b/src/Elements/New-BaseElement.psm1 new file mode 100644 index 0000000..44457b9 --- /dev/null +++ b/src/Elements/New-BaseElement.psm1 @@ -0,0 +1,33 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `base` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlBaseElement"), Alias("base"), OutputType(typeof(string))] +function New-HtmlBaseElement: NewElementCommand("base", isVoid: true) { + + <# + .SYNOPSIS + The base URL to be used throughout the document for relative URLs. + #> + [Parameter(Mandatory)] + [uri] $Href + + <# + .SYNOPSIS + The default browsing context to show the results of navigation from elements without explicit `target` attribute. + #> + [string] $Target + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + $attributesToRender.href"] = Href.ToString(); + if ($Target) { $attributesToRender.target"] = Target; + } +} diff --git a/src/Elements/New-BlockquoteElement.cs b/src/Elements/New-BlockquoteElement.cs deleted file mode 100644 index fc97231..0000000 --- a/src/Elements/New-BlockquoteElement.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new blockquote element. -/// -[Cmdlet(VerbsCommon.New, "HtmlBlockquoteElement"), Alias("blockquote"), OutputType(typeof(string))] -public class NewBlockquoteElementCommand(): NewElementCommand("blockquote", isVoid: false) { - - /// - /// A URL that designates a source document or message for the information quoted. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public Uri? Cite { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (Cite is not null) attributes["cite"] = Cite.ToString(); - } -} diff --git a/src/Elements/New-BlockquoteElement.psm1 b/src/Elements/New-BlockquoteElement.psm1 new file mode 100644 index 0000000..86149c6 --- /dev/null +++ b/src/Elements/New-BlockquoteElement.psm1 @@ -0,0 +1,25 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `blockquote` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlBlockquoteElement"), Alias("blockquote"), OutputType(typeof(string))] +function New-HtmlBlockquoteElement: NewElementCommand("blockquote", isVoid: false) { + + <# + .SYNOPSIS + A URL that designates a source document or message for the information quoted. + #> + Uri? Cite + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (Cite is not null) $attributesToRender.cite"] = Cite.ToString(); + } +} diff --git a/src/Elements/New-ButtonElement.cs b/src/Elements/New-ButtonElement.cs deleted file mode 100644 index c0e61c8..0000000 --- a/src/Elements/New-ButtonElement.cs +++ /dev/null @@ -1,116 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Net.Mime; - -/// -/// Creates a new button element. -/// -[Cmdlet(VerbsCommon.New, "HtmlButtonElement"), Alias("button"), OutputType(typeof(string))] -public class NewButtonElementCommand(): NewElementCommand("button", isVoid: false) { - - /// - /// The action to be performed on an element being controlled via the attribute. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Command { get; set; } - - /// - /// The identifier of an element to control. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? CommandFor { get; set; } - - /// - /// Value indicating whether to prevent the user from interacting with the element. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Disabled { get; set; } - - /// - /// The identifier of a form element to associate with the element. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Form { get; set; } - - /// - /// The URL that processes the information submitted by the button. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public Uri? FormAction { get; set; } - - /// - /// Value indicating how to encode the form data that is submitted. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet(MediaTypeNames.Application.FormUrlEncoded, MediaTypeNames.Multipart.FormData, MediaTypeNames.Text.Plain)] - public string? FormEnctype { get; set; } - - /// - /// The HTTP method used to submit the form. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("dialog", "get", "post")] - public string? FormMethod { get; set; } - - /// - /// Value indicating whether the form is not to be validated when it is submitted. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter FormNoValidate { get; set; } - - /// - /// The browsing context to show the response after submitting the form. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? FormTarget { get; set; } - - /// - /// The name of the control. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Name { get; set; } - - /// - /// The identifier of a popover element to control. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? PopoverTarget { get; set; } - - /// - /// The action to be performed on a popover element being controlled via the attribute. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("hide", "show", "toggle")] - public string? PopoverTargetAction { get; set; } - - /// - /// The default behavior of the button. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("button", "reset", "submit")] - public string? Type { get; set; } - - /// - /// The value of the control. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public object? Value { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (!string.IsNullOrWhiteSpace(Command)) attributes["command"] = Command; - if (!string.IsNullOrWhiteSpace(CommandFor)) attributes["commandfor"] = CommandFor; - if (Disabled) attributes["disabled"] = true; - if (!string.IsNullOrWhiteSpace(Form)) attributes["form"] = Form; - if (FormAction is not null) attributes["formaction"] = FormAction.ToString(); - if (FormEnctype is not null) attributes["formenctype"] = FormEnctype; - if (FormMethod is not null) attributes["formmethod"] = FormMethod; - if (FormNoValidate) attributes["formnovalidate"] = true; - if (!string.IsNullOrWhiteSpace(FormTarget)) attributes["formtarget"] = FormTarget; - if (!string.IsNullOrWhiteSpace(Name)) attributes["name"] = Name; - if (!string.IsNullOrWhiteSpace(PopoverTarget)) attributes["popovertarget"] = PopoverTarget; - if (PopoverTargetAction is not null) attributes["popovertargetaction"] = PopoverTargetAction; - if (Type is not null) attributes["type"] = Type; - if (Value is not null) attributes["value"] = Value; - } -} diff --git a/src/Elements/New-ButtonElement.psm1 b/src/Elements/New-ButtonElement.psm1 new file mode 100644 index 0000000..98edd2d --- /dev/null +++ b/src/Elements/New-ButtonElement.psm1 @@ -0,0 +1,121 @@ +using namespace System.Net.Mime +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `button` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlButtonElement"), Alias("button"), OutputType(typeof(string))] +function New-HtmlButtonElement: NewElementCommand("button", isVoid: false) { + + <# + .SYNOPSIS + The action to be performed on an element being controlled via the attribute. + #> + [string] $Command + + <# + .SYNOPSIS + The identifier of an element to control. + #> + [string] $CommandFor + + <# + .SYNOPSIS + Value indicating whether to prevent the user from interacting with the element. + #> + [switch] $Disabled + + <# + .SYNOPSIS + The identifier of a `form` element to associate with the element. + #> + [string] $Form + + <# + .SYNOPSIS + The URL that processes the information submitted by the button. + #> + Uri? FormAction + + <# + .SYNOPSIS + Value indicating how to encode the form data that is submitted. + #> + [ValidateSet(MediaTypeNames.Application.FormUrlEncoded, MediaTypeNames.Multipart.FormData, MediaTypeNames.Text.Plain)] + [string] $FormEnctype + + <# + .SYNOPSIS + The HTTP method used to submit the form. + #> + [ValidateSet("dialog", "get", "post")] + [string] $FormMethod + + <# + .SYNOPSIS + Value indicating whether the form is not to be validated when it is submitted. + #> + [switch] $FormNoValidate + + <# + .SYNOPSIS + The browsing context to show the response after submitting the form. + #> + [string] $FormTarget + + <# + .SYNOPSIS + The name of the control. + #> + [string] $Name + + <# + .SYNOPSIS + The identifier of a popover element to control. + #> + [string] $PopoverTarget + + <# + .SYNOPSIS + The action to be performed on a popover element being controlled via the attribute. + #> + [ValidateSet("hide", "show", "toggle")] + [string] $PopoverTargetAction + + <# + .SYNOPSIS + The default behavior of the button. + #> + [ValidateSet("button", "reset", "submit")] + [string] $Type + + <# + .SYNOPSIS + The value of the control. + #> + [object] $Value + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if ($Command) { $attributesToRender.command"] = Command; + if ($CommandFor) { $attributesToRender.commandfor"] = CommandFor; + if (Disabled) $attributesToRender.disabled"] = true; + if ($Form) { $attributesToRender.form"] = Form; + if (FormAction is not null) $attributesToRender.formaction"] = FormAction.ToString(); + if (FormEnctype is not null) $attributesToRender.formenctype"] = FormEnctype; + if (FormMethod is not null) $attributesToRender.formmethod"] = FormMethod; + if (FormNoValidate) $attributesToRender.formnovalidate"] = true; + if ($FormTarget) { $attributesToRender.formtarget"] = FormTarget; + if ($Name) { $attributesToRender.name"] = Name; + if ($PopoverTarget) { $attributesToRender.popovertarget"] = PopoverTarget; + if (PopoverTargetAction is not null) $attributesToRender.popovertargetaction"] = PopoverTargetAction; + if (Type is not null) $attributesToRender.type"] = Type; + if (Value is not null) $attributesToRender.value"] = Value; + } +} diff --git a/src/Elements/New-CanvasElement.cs b/src/Elements/New-CanvasElement.cs deleted file mode 100644 index 46610e2..0000000 --- a/src/Elements/New-CanvasElement.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new canvas element. -/// -[Cmdlet(VerbsCommon.New, "HtmlCanvasElement"), Alias("canvas"), OutputType(typeof(string))] -public class NewCanvasElementCommand(): NewElementCommand("canvas", isVoid: false) { - - /// - /// The height of the coordinate space in CSS pixels. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int Height { get; set; } = -1; - - /// - /// The width of the coordinate space in CSS pixels. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int Width { get; set; } = -1; - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (Height >= 0) attributes["height"] = Height.ToString(CultureInfo.InvariantCulture); - if (Width >= 0) attributes["width"] = Width.ToString(CultureInfo.InvariantCulture); - } -} diff --git a/src/Elements/New-CanvasElement.psm1 b/src/Elements/New-CanvasElement.psm1 new file mode 100644 index 0000000..fd679cc --- /dev/null +++ b/src/Elements/New-CanvasElement.psm1 @@ -0,0 +1,34 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `canvas` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlCanvasElement"), Alias("canvas"), OutputType(typeof(string))] +function New-HtmlCanvasElement: NewElementCommand("canvas", isVoid: false) { + + <# + .SYNOPSIS + The height of the coordinate space in CSS pixels. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int Height = -1; + + <# + .SYNOPSIS + The width of the coordinate space in CSS pixels. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int Width = -1; + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (Height >= 0) $attributesToRender.height"] = Height + if (Width >= 0) $attributesToRender.width"] = Width + } +} diff --git a/src/Elements/New-ColElement.cs b/src/Elements/New-ColElement.cs deleted file mode 100644 index e683cab..0000000 --- a/src/Elements/New-ColElement.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new col element. -/// -[Cmdlet(VerbsCommon.New, "HtmlColElement"), Alias("col"), OutputType(typeof(string))] -public class NewColElementCommand(): NewElementCommand("col", isVoid: true) { - - /// - /// The number of consecutive columns the element spans. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.Positive)] - public int Span { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (Span > 0) attributes["span"] = Span.ToString(CultureInfo.InvariantCulture); - } -} diff --git a/src/Elements/New-ColElement.psm1 b/src/Elements/New-ColElement.psm1 new file mode 100644 index 0000000..1657eb5 --- /dev/null +++ b/src/Elements/New-ColElement.psm1 @@ -0,0 +1,26 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `col` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlColElement"), Alias("col"), OutputType(typeof(string))] +function New-HtmlColElement: NewElementCommand("col", isVoid: true) { + + <# + .SYNOPSIS + The number of consecutive columns the element spans. + #> + [ValidateRange(ValidateRangeKind.Positive)] + int Span + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (Span > 0) $attributesToRender.span"] = Span + } +} diff --git a/src/Elements/New-ColGroupElement.cs b/src/Elements/New-ColGroupElement.cs deleted file mode 100644 index b9b4361..0000000 --- a/src/Elements/New-ColGroupElement.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new colgroup element. -/// -[Cmdlet(VerbsCommon.New, "HtmlColgroupElement"), Alias("colgroup"), OutputType(typeof(string))] -public class NewColgroupElementCommand(): NewElementCommand("colgroup", isVoid: false) { - - /// - /// The number of consecutive columns the element spans. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.Positive)] - public int Span { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (Span > 0) attributes["span"] = Span.ToString(CultureInfo.InvariantCulture); - } -} diff --git a/src/Elements/New-ColGroupElement.psm1 b/src/Elements/New-ColGroupElement.psm1 new file mode 100644 index 0000000..959e79c --- /dev/null +++ b/src/Elements/New-ColGroupElement.psm1 @@ -0,0 +1,26 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `colgroup` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlColgroupElement"), Alias("colgroup"), OutputType(typeof(string))] +function New-HtmlColgroupElement: NewElementCommand("colgroup", isVoid: false) { + + <# + .SYNOPSIS + The number of consecutive columns the element spans. + #> + [ValidateRange(ValidateRangeKind.Positive)] + int Span + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (Span > 0) $attributesToRender.span"] = Span + } +} diff --git a/src/Elements/New-DataElement.cs b/src/Elements/New-DataElement.cs deleted file mode 100644 index 16327d9..0000000 --- a/src/Elements/New-DataElement.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new data element. -/// -[Cmdlet(VerbsCommon.New, "HtmlDataElement"), Alias("dataTag"), OutputType(typeof(string))] -public class NewDataElementCommand(): NewElementCommand("data", isVoid: false) { - - /// - /// The machine-readable translation of the content of the element. - /// - [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)] - public required string Value { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - attributes["value"] = Value; - } -} diff --git a/src/Elements/New-DataElement.psm1 b/src/Elements/New-DataElement.psm1 new file mode 100644 index 0000000..d45b25d --- /dev/null +++ b/src/Elements/New-DataElement.psm1 @@ -0,0 +1,26 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `data` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlDataElement"), Alias("dataTag"), OutputType(typeof(string))] +function New-HtmlDataElement: NewElementCommand("data", isVoid: false) { + + <# + .SYNOPSIS + The machine-readable translation of the content of the element. + #> + [Parameter(Mandatory)] + required string Value + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + $attributesToRender.value"] = Value; + } +} diff --git a/src/Elements/New-DelElement.cs b/src/Elements/New-DelElement.cs deleted file mode 100644 index 4aba228..0000000 --- a/src/Elements/New-DelElement.cs +++ /dev/null @@ -1,42 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new del element. -/// -[Cmdlet(VerbsCommon.New, "HtmlDelElement"), Alias("delTag"), OutputType(typeof(string))] -public class NewDelElementCommand(): NewElementCommand("del", isVoid: false) { - - /// - /// A URI for a resource that explains the change. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public Uri? Cite { get; set; } - - /// - /// The date and time of the change. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public object? DateTime { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (Cite is not null) attributes["cite"] = Cite.ToString(); - - if (DateTime is not null) { - try { - attributes["datetime"] = (DateTime is PSObject psObject ? psObject.BaseObject : DateTime) switch { - DateOnly value => value.ToString("o"), - DateTime value => value.ToString("o"), - _ => throw new NotSupportedException("The specified date/time value is not supported.") - }; - } - catch (NotSupportedException e) { - WriteError(new ErrorRecord(e, "New-DelElement:NotSupportedException", ErrorCategory.InvalidArgument, DateTime)); - } - } - } -} diff --git a/src/Elements/New-DelElement.psm1 b/src/Elements/New-DelElement.psm1 new file mode 100644 index 0000000..9dd633b --- /dev/null +++ b/src/Elements/New-DelElement.psm1 @@ -0,0 +1,44 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `del` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlDelElement"), Alias("delTag"), OutputType(typeof(string))] +function New-HtmlDelElement: NewElementCommand("del", isVoid: false) { + + <# + .SYNOPSIS + A URI for a resource that explains the change. + #> + Uri? Cite + + <# + .SYNOPSIS + The date and time of the change. + #> + [object] $DateTime + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (Cite is not null) $attributesToRender.cite"] = Cite.ToString(); + + if (DateTime is not null) { + try { + $attributesToRender.datetime"] = (DateTime is PSObject psObject ? psObject.BaseObject : DateTime) switch { + DateOnly value => value.ToString("o"), + DateTime value => value.ToString("o"), + _ => throw new NotSupportedException("The specified date/time value is not supported.") + }; + } + catch (NotSupportedException e) { + WriteError(new ErrorRecord(e, "New-DelElement:NotSupportedException", ErrorCategory.InvalidArgument, DateTime)); + } + } + } +} diff --git a/src/Elements/New-DetailsElement.cs b/src/Elements/New-DetailsElement.cs deleted file mode 100644 index 0c37a8b..0000000 --- a/src/Elements/New-DetailsElement.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new details element. -/// -[Cmdlet(VerbsCommon.New, "HtmlDetailsElement"), Alias("details"), OutputType(typeof(string))] -public class NewDetailsElementCommand(): NewElementCommand("details", isVoid: false) { - - /// - /// The group name allowing multiple details elements to be connected, with only one open at a time. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Name { get; set; } - - /// - /// Value indicating whether the details are currently visible. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Open { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (!string.IsNullOrWhiteSpace(Name)) attributes["name"] = Name; - if (Open) attributes["open"] = true; - } -} diff --git a/src/Elements/New-DetailsElement.psm1 b/src/Elements/New-DetailsElement.psm1 new file mode 100644 index 0000000..82863c0 --- /dev/null +++ b/src/Elements/New-DetailsElement.psm1 @@ -0,0 +1,32 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `details` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlDetailsElement"), Alias("details"), OutputType(typeof(string))] +function New-HtmlDetailsElement: NewElementCommand("details", isVoid: false) { + + <# + .SYNOPSIS + The group name allowing multiple `details` elements to be connected, with only one open at a time. + #> + [string] $Name + + <# + .SYNOPSIS + Value indicating whether the details are currently visible. + #> + [switch] $Open + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if ($Name) { $attributesToRender.name"] = Name; + if (Open) $attributesToRender.open"] = true; + } +} diff --git a/src/Elements/New-DialogElement.cs b/src/Elements/New-DialogElement.cs deleted file mode 100644 index 5d774cb..0000000 --- a/src/Elements/New-DialogElement.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new dialog element. -/// -[Cmdlet(VerbsCommon.New, "HtmlDialogElement"), Alias("dialog"), OutputType(typeof(string))] -public class NewDialogElementCommand(): NewElementCommand("dialog", isVoid: false) { - - /// - /// Specifies the types of user actions that can be used to close the element. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("any", "closerequest", "none")] - public string? ClosedBy { get; set; } - - /// - /// Value indicating whether the dialog box is active and is available for interaction. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Open { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (ClosedBy is not null) attributes["closedby"] = ClosedBy; - if (Open) attributes["open"] = true; - } -} diff --git a/src/Elements/New-DialogElement.psm1 b/src/Elements/New-DialogElement.psm1 new file mode 100644 index 0000000..241bd37 --- /dev/null +++ b/src/Elements/New-DialogElement.psm1 @@ -0,0 +1,33 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `dialog` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlDialogElement"), Alias("dialog"), OutputType(typeof(string))] +function New-HtmlDialogElement: NewElementCommand("dialog", isVoid: false) { + + <# + .SYNOPSIS + Specifies the types of user actions that can be used to close the element. + #> + [ValidateSet("any", "closerequest", "none")] + [string] $ClosedBy + + <# + .SYNOPSIS + Value indicating whether the dialog box is active and is available for interaction. + #> + [switch] $Open + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (ClosedBy is not null) $attributesToRender.closedby"] = ClosedBy; + if (Open) $attributesToRender.open"] = true; + } +} diff --git a/src/Elements/New-EmbedElement.cs b/src/Elements/New-EmbedElement.cs deleted file mode 100644 index 88f4eae..0000000 --- a/src/Elements/New-EmbedElement.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new embed element. -/// -[Cmdlet(VerbsCommon.New, "HtmlEmbedElement"), Alias("embed"), OutputType(typeof(string))] -public class NewEmbedElementCommand(): NewElementCommand("embed", isVoid: true) { - - /// - /// The displayed height of the resource, in CSS pixels. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int Height { get; set; } = -1; - - /// - /// The URL of the resource being embedded. - /// - [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)] - public required Uri Src { get; set; } - - /// - /// The media type to use, optionally including a codecs parameter. - /// - [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)] - public required string Type { get; set; } - - /// - /// The displayed height of the resource, in CSS pixels. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int Width { get; set; } = -1; - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - attributes["src"] = Src.ToString(); - attributes["type"] = Type; - if (Height >= 0) attributes["height"] = Height.ToString(CultureInfo.InvariantCulture); - if (Width >= 0) attributes["width"] = Width.ToString(CultureInfo.InvariantCulture); - } -} diff --git a/src/Elements/New-EmbedElement.psm1 b/src/Elements/New-EmbedElement.psm1 new file mode 100644 index 0000000..ea13c85 --- /dev/null +++ b/src/Elements/New-EmbedElement.psm1 @@ -0,0 +1,50 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `embed` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlEmbedElement"), Alias("embed"), OutputType(typeof(string))] +function New-HtmlEmbedElement: NewElementCommand("embed", isVoid: true) { + + <# + .SYNOPSIS + The displayed height of the resource, in CSS pixels. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int Height = -1; + + <# + .SYNOPSIS + The URL of the resource being embedded. + #> + [Parameter(Mandatory)] + required Uri Src + + <# + .SYNOPSIS + The media type to use, optionally including a `codecs` parameter. + #> + [Parameter(Mandatory)] + required string Type + + <# + .SYNOPSIS + The displayed height of the resource, in CSS pixels. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int Width = -1; + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + $attributesToRender.src"] = Src.ToString(); + $attributesToRender.type"] = Type; + if (Height >= 0) $attributesToRender.height"] = Height + if (Width >= 0) $attributesToRender.width"] = Width + } +} diff --git a/src/Elements/New-FieldsetElement.cs b/src/Elements/New-FieldsetElement.cs deleted file mode 100644 index 6e54138..0000000 --- a/src/Elements/New-FieldsetElement.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new fieldset element. -/// -[Cmdlet(VerbsCommon.New, "HtmlFieldsetElement"), Alias("fieldset"), OutputType(typeof(string))] -public class NewFieldsetElementCommand(): NewElementCommand("fieldset", isVoid: false) { - - /// - /// Value indicating whether all form controls that are descendants of the element, are disabled. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Disabled { get; set; } - - /// - /// The identifier of a form element to associate with the element. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Form { get; set; } - - /// - /// The name associated with the group. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Name { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (Disabled) attributes["disabled"] = true; - if (!string.IsNullOrWhiteSpace(Form)) attributes["form"] = Form; - if (!string.IsNullOrWhiteSpace(Name)) attributes["name"] = Name; - } -} diff --git a/src/Elements/New-FieldsetElement.psm1 b/src/Elements/New-FieldsetElement.psm1 new file mode 100644 index 0000000..2eb8f0a --- /dev/null +++ b/src/Elements/New-FieldsetElement.psm1 @@ -0,0 +1,39 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `fieldset` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlFieldsetElement"), Alias("fieldset"), OutputType(typeof(string))] +function New-HtmlFieldsetElement: NewElementCommand("fieldset", isVoid: false) { + + <# + .SYNOPSIS + Value indicating whether all form controls that are descendants of the element, are disabled. + #> + [switch] $Disabled + + <# + .SYNOPSIS + The identifier of a `form` element to associate with the element. + #> + [string] $Form + + <# + .SYNOPSIS + The name associated with the group. + #> + [string] $Name + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (Disabled) $attributesToRender.disabled"] = true; + if ($Form) { $attributesToRender.form"] = Form; + if ($Name) { $attributesToRender.name"] = Name; + } +} diff --git a/src/Elements/New-FormElement.cs b/src/Elements/New-FormElement.cs deleted file mode 100644 index a229044..0000000 --- a/src/Elements/New-FormElement.cs +++ /dev/null @@ -1,74 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Net.Mime; - -/// -/// Creates a new form element. -/// -[Cmdlet(VerbsCommon.New, "HtmlFormElement"), Alias("form"), OutputType(typeof(string))] -public class NewFormElementCommand(): NewElementCommand("form", isVoid: false) { - - /// - /// The URL that processes the form submission. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public Uri? Action { get; set; } - - /// - /// Value indicating whether input elements can by default have their values automatically completed by the browser. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("off", "on")] - public string? AutoComplete { get; set; } - - /// - /// The media type of the form submission. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet(MediaTypeNames.Application.FormUrlEncoded, MediaTypeNames.Multipart.FormData, MediaTypeNames.Text.Plain)] - public string? Enctype { get; set; } - - /// - /// The HTTP method to submit the form with. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("dialog", "get", "post")] - public string? Method { get; set; } - - /// - /// The name of the form. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Name { get; set; } - - /// - /// Value indicating whether the form shouldn't be validated when submitted. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter NoValidate { get; set; } - - /// - /// The annotations and what kinds of links the form creates. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string[] Rel { get; set; } = []; - - /// - /// The browsing context to show the response after submitting the form. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Target { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (Action is not null) attributes["action"] = Action.ToString(); - if (AutoComplete is not null) attributes["autocomplete"] = AutoComplete; - if (Enctype is not null) attributes["enctype"] = Enctype; - if (Method is not null) attributes["method"] = Method; - if (!string.IsNullOrWhiteSpace(Name)) attributes["name"] = Name; - if (NoValidate) attributes["novalidate"] = true; - if (Rel.Length > 0) attributes["rel"] = string.Join(' ', Rel).Trim(); - if (!string.IsNullOrWhiteSpace(Target)) attributes["target"] = Target; - } -} diff --git a/src/Elements/New-FormElement.psm1 b/src/Elements/New-FormElement.psm1 new file mode 100644 index 0000000..d4995dd --- /dev/null +++ b/src/Elements/New-FormElement.psm1 @@ -0,0 +1,78 @@ +using namespace System.Net.Mime +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `form` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlFormElement"), Alias("form"), OutputType(typeof(string))] +function New-HtmlFormElement: NewElementCommand("form", isVoid: false) { + + <# + .SYNOPSIS + The URL that processes the form submission. + #> + Uri? Action + + <# + .SYNOPSIS + Value indicating whether input elements can by default have their values automatically completed by the browser. + #> + [ValidateSet("off", "on")] + [string] $AutoComplete + + <# + .SYNOPSIS + The media type of the form submission. + #> + [ValidateSet(MediaTypeNames.Application.FormUrlEncoded, MediaTypeNames.Multipart.FormData, MediaTypeNames.Text.Plain)] + [string] $Enctype + + <# + .SYNOPSIS + The HTTP method to submit the form with. + #> + [ValidateSet("dialog", "get", "post")] + [string] $Method + + <# + .SYNOPSIS + The name of the form. + #> + [string] $Name + + <# + .SYNOPSIS + Value indicating whether the form shouldn't be validated when submitted. + #> + [switch] $NoValidate + + <# + .SYNOPSIS + The annotations and what kinds of links the form creates. + #> + [string[]] $Rel = @(), + + <# + .SYNOPSIS + The browsing context to show the response after submitting the form. + #> + [string] $Target + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (Action is not null) $attributesToRender.action"] = Action.ToString(); + if (AutoComplete is not null) $attributesToRender.autocomplete"] = AutoComplete; + if (Enctype is not null) $attributesToRender.enctype"] = Enctype; + if (Method is not null) $attributesToRender.method"] = Method; + if ($Name) { $attributesToRender.name"] = Name; + if (NoValidate) $attributesToRender.novalidate"] = true; + if (Rel.Length > 0) $attributesToRender.rel"] = string.Join(' ', Rel).Trim(); + if ($Target) { $attributesToRender.target"] = Target; + } +} diff --git a/src/Elements/New-IframeElement.cs b/src/Elements/New-IframeElement.cs deleted file mode 100644 index 55c7491..0000000 --- a/src/Elements/New-IframeElement.cs +++ /dev/null @@ -1,77 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new iframe element. -/// -[Cmdlet(VerbsCommon.New, "HtmlIframeElement"), Alias("iframe"), OutputType(typeof(string))] -public class NewIframeElementCommand(): NewElementCommand("iframe", isVoid: false) { - - /// - /// Specifies a permissions policy thaht defines what features are available to the frame based on the origin of the request. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Allow { get; set; } - - /// - /// The height of the frame in CSS pixels. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int Height { get; set; } = -1; - - /// - /// Value indicating how the browser should load the frame. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("eager", "lazy")] - public string? Loading { get; set; } - - /// - /// A targetable name for the embedded browsing context. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Name { get; set; } - - /// - /// Value indicating which referrer to send when fetching the frame's resource. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet( - "no-referrer-when-downgrade", "no-referrer", "origin-when-cross-origin", "origin", - "same-origin", "strict-origin-when-cross-origin", "strict-origin", "unsafe-url" - )] - public string? ReferrerPolicy { get; set; } - - /// - /// The restrictions applied to the content embedded in the frame. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string[] Sandbox { get; set; } = []; - - /// - /// The URL of the page to embed. - /// - [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)] - public required Uri Src { get; set; } - - /// - /// The width of the frame in CSS pixels. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int Width { get; set; } = -1; - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - attributes["src"] = Src.ToString(); - if (!string.IsNullOrWhiteSpace(Allow)) attributes["allow"] = Allow; - if (Height >= 0) attributes["height"] = Height.ToString(CultureInfo.InvariantCulture); - if (Loading is not null) attributes["loading"] = Loading; - if (!string.IsNullOrWhiteSpace(Name)) attributes["name"] = Name; - if (ReferrerPolicy is not null) attributes["referrerpolicy"] = ReferrerPolicy; - if (Sandbox.Length > 0) attributes["sandbox"] = string.Join(' ', Sandbox).Trim(); - if (Width >= 0) attributes["width"] = Width.ToString(CultureInfo.InvariantCulture); - } -} diff --git a/src/Elements/New-IframeElement.psm1 b/src/Elements/New-IframeElement.psm1 new file mode 100644 index 0000000..b8558b9 --- /dev/null +++ b/src/Elements/New-IframeElement.psm1 @@ -0,0 +1,82 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `iframe` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlIframeElement"), Alias("iframe"), OutputType(typeof(string))] +function New-HtmlIframeElement: NewElementCommand("iframe", isVoid: false) { + + <# + .SYNOPSIS + Specifies a permissions policy thaht defines what features are available to the frame based on the origin of the request. + #> + [string] $Allow + + <# + .SYNOPSIS + The height of the frame in CSS pixels. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int Height = -1; + + <# + .SYNOPSIS + Value indicating how the browser should load the frame. + #> + [ValidateSet("eager", "lazy")] + [string] $Loading + + <# + .SYNOPSIS + A targetable name for the embedded browsing context. + #> + [string] $Name + + <# + .SYNOPSIS + Value indicating which referrer to send when fetching the frame's resource. + #> + [ValidateSet( + "no-referrer-when-downgrade", "no-referrer", "origin-when-cross-origin", "origin", + "same-origin", "strict-origin-when-cross-origin", "strict-origin", "unsafe-url" + )] + [string] $ReferrerPolicy + + <# + .SYNOPSIS + The restrictions applied to the content embedded in the frame. + #> + [string[]] $Sandbox = @(), + + <# + .SYNOPSIS + The URL of the page to embed. + #> + [Parameter(Mandatory)] + required Uri Src + + <# + .SYNOPSIS + The width of the frame in CSS pixels. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int Width = -1; + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + $attributesToRender.src"] = Src.ToString(); + if ($Allow) { $attributesToRender.allow"] = Allow; + if (Height >= 0) $attributesToRender.height"] = Height + if (Loading is not null) $attributesToRender.loading"] = Loading; + if ($Name) { $attributesToRender.name"] = Name; + if (ReferrerPolicy is not null) $attributesToRender.referrerpolicy"] = ReferrerPolicy; + if (Sandbox.Length > 0) $attributesToRender.sandbox"] = string.Join(' ', Sandbox).Trim(); + if (Width >= 0) $attributesToRender.width"] = Width + } +} diff --git a/src/Elements/New-ImgElement.cs b/src/Elements/New-ImgElement.cs deleted file mode 100644 index 57122ce..0000000 --- a/src/Elements/New-ImgElement.cs +++ /dev/null @@ -1,81 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new img element. -/// -[Cmdlet(VerbsCommon.New, "HtmlImgElement"), Alias("img"), OutputType(typeof(string))] -public class NewImgElementCommand(): NewElementCommand("img", isVoid: true) { - - /// - /// A text to display on browsers that do not display images. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Alt { get; set; } - - /// - /// The intrinsic height of the image, in CSS pixels. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int Height { get; set; } = -1; - - /// - /// Value indicating whether the image is part of a server-side map. - /// - [Parameter] - public SwitchParameter IsMap { get; set; } - - /// - /// Value indicating how the browser should load the image. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("eager", "lazy")] - public string? Loading { get; set; } - - /// - /// The intended display sizes of the image. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string[] Sizes { get; set; } = []; - - /// - /// The image URL. - /// - [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)] - public required Uri Src { get; set; } - - /// - /// The possible image sources for the user agent to use. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string[] SrcSet { get; set; } = []; - - /// - /// The partial URL (starting with #) of an image map associated with the element. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? UseMap { get; set; } - - /// - /// The intrinsic width of the image, in CSS pixels. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int Width { get; set; } = -1; - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - attributes["src"] = Src.ToString(); - if (Alt is not null) attributes["alt"] = Alt; - if (Height >= 0) attributes["height"] = Height.ToString(CultureInfo.InvariantCulture); - if (IsMap) attributes["ismap"] = true; - if (Loading is not null) attributes["loading"] = Loading; - if (Sizes.Length > 0) attributes["sizes"] = string.Join(", ", Sizes); - if (SrcSet.Length > 0) attributes["srcset"] = string.Join(", ", SrcSet); - if (!string.IsNullOrWhiteSpace(UseMap)) attributes["usemap"] = UseMap.StartsWith('#') ? UseMap : $"#{UseMap}"; - if (Width >= 0) attributes["width"] = Width.ToString(CultureInfo.InvariantCulture); - } -} diff --git a/src/Elements/New-ImgElement.psm1 b/src/Elements/New-ImgElement.psm1 new file mode 100644 index 0000000..56e9de0 --- /dev/null +++ b/src/Elements/New-ImgElement.psm1 @@ -0,0 +1,86 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `img` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlImgElement"), Alias("img"), OutputType(typeof(string))] +function New-HtmlImgElement: NewElementCommand("img", isVoid: true) { + + <# + .SYNOPSIS + A text to display on browsers that do not display images. + #> + [string] $Alt + + <# + .SYNOPSIS + The intrinsic height of the image, in CSS pixels. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int Height = -1; + + <# + .SYNOPSIS + Value indicating whether the image is part of a server-side map. + #> + [Parameter] + [switch] $IsMap + + <# + .SYNOPSIS + Value indicating how the browser should load the image. + #> + [ValidateSet("eager", "lazy")] + [string] $Loading + + <# + .SYNOPSIS + The intended display sizes of the image. + #> + [string[]] $Sizes = @(), + + <# + .SYNOPSIS + The image URL. + #> + [Parameter(Mandatory)] + required Uri Src + + <# + .SYNOPSIS + The possible image sources for the user agent to use. + #> + [string[]] $SrcSet = @(), + + <# + .SYNOPSIS + The partial URL (starting with `#`) of an image map associated with the element. + #> + [string] $UseMap + + <# + .SYNOPSIS + The intrinsic width of the image, in CSS pixels. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int Width = -1; + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + $attributesToRender.src"] = Src.ToString(); + if (Alt is not null) $attributesToRender.alt"] = Alt; + if (Height >= 0) $attributesToRender.height"] = Height + if (IsMap) $attributesToRender.ismap"] = true; + if (Loading is not null) $attributesToRender.loading"] = Loading; + if (Sizes.Length > 0) $attributesToRender.sizes"] = string.Join(", ", Sizes); + if (SrcSet.Length > 0) $attributesToRender.srcset"] = string.Join(", ", SrcSet); + if ($UseMap) { $attributesToRender.usemap"] = UseMap.StartsWith('#') ? UseMap : $"#{UseMap}"; + if (Width >= 0) $attributesToRender.width"] = Width + } +} diff --git a/src/Elements/New-InputElement.cs b/src/Elements/New-InputElement.cs deleted file mode 100644 index 3c64022..0000000 --- a/src/Elements/New-InputElement.cs +++ /dev/null @@ -1,265 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; -using System.Net.Mime; -using System.Text.RegularExpressions; - -/// -/// Creates a new input element. -/// -[Cmdlet(VerbsCommon.New, "HtmlInputElement"), Alias("input"), OutputType(typeof(string))] -public class NewInputElementCommand(): NewElementCommand("input", isVoid: true) { - - /// - /// Defines which file types are selectable in a file upload control. - /// Valid for the file input type only. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Accept { get; set; } - - /// - /// A text to display on browsers that do not display images. - /// Valid for the image input type only. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Alt { get; set; } - - /// - /// A hint for a user agent's autocomplete feature. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string[] AutoComplete { get; set; } = []; - - /// - /// Value indicating which camera to use for capture of image or video data. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("environment", "user")] - public string? Capture { get; set; } - - /// - /// Value indicating whether the checkbox is checked or the radio button is the currently selected one. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Checked { get; set; } - - /// - /// The field name to use for sending the element's directionality in form submission. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? DirName { get; set; } - - /// - /// Value indicating whether to prevent the user from interacting with the element. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Disabled { get; set; } - - /// - /// The identifier of a form element to associate with the element. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Form { get; set; } - - /// - /// The URL that processes the information submitted by the button. - /// Valid for the image and submit input types only. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public Uri? FormAction { get; set; } - - /// - /// Value indicating how to encode the form data that is submitted. - /// Valid for the image and submit input types only. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet(MediaTypeNames.Application.FormUrlEncoded, MediaTypeNames.Multipart.FormData, MediaTypeNames.Text.Plain)] - public string? FormEnctype { get; set; } - - /// - /// The HTTP method used to submit the form. - /// Valid for the image and submit input types only. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("dialog", "get", "post")] - public string? FormMethod { get; set; } - - /// - /// Value indicating whether the form is not to be validated when it is submitted. - /// Valid for the image and submit input types only. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter FormNoValidate { get; set; } - - /// - /// The browsing context to show the response after submitting the form. - /// Valid for the image and submit input types only. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? FormTarget { get; set; } - - /// - /// The intrinsic height of the image, in CSS pixels. - /// Valid for the image input type only. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int Height { get; set; } = -1; - - /// - /// The identifier of a datalist element located in the same document.. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? List { get; set; } - - /// - /// The greatest value in the range of permitted values. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public string? Max { get; set; } - - /// - /// The maximum string length that the user can enter. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int MaxLength { get; set; } = -1; - - /// - /// The lowest value in the range of permitted values. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public string? Min { get; set; } - - /// - /// The minimum string length required that the user should enter. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int MinLength { get; set; } = -1; - - /// - /// Value indicating whether the user can enter comma separated email addresses in the email widget or can choose more than one file with the file input. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Multiple { get; set; } - - /// - /// The name of the control. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Name { get; set; } - - /// - /// The regular expression that the must match in order for the value to pass constraint validation. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public Regex? Pattern { get; set; } - - /// - /// A hint to the user of what can be entered in the control. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Placeholder { get; set; } - - /// - /// The identifier of a popover element to control. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? PopoverTarget { get; set; } - - /// - /// The action to be performed on a popover element being controlled via the attribute. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("hide", "show", "toggle")] - public string? PopoverTargetAction { get; set; } - - /// - /// Value indicating whether the user cannot modify the value of the control. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter ReadOnly { get; set; } - - /// - /// Value indicating whether the user must fill in a value before submitting a form. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Required { get; set; } - - /// - /// Value indicating how much of the input is shown. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.Positive)] - public int Size { get; set; } - - /// - /// The URL of the image file to display to represent the graphical button. - /// Valid for the image input type only. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public Uri? Src { get; set; } - - /// - /// A number that specifies the granularity that the value must adhere to, or the special value any. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public string? Step { get; set; } - - /// - /// The type of control to render. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet( - "button", "checkbox", "color", "date", "datetime-local", "email", - "file", "hidden", "image", "month", "number", "password", - "radio", "range", "reset", "search", "submit", "tel", - "text", "time", "url", "week" - )] - public string? Type { get; set; } - - /// - /// The value of the control. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public object? Value { get; set; } - - /// - /// The intrinsic width of the image, in CSS pixels. - /// Valid for the image input type only. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int Width { get; set; } = -1; - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (!string.IsNullOrWhiteSpace(Accept)) attributes["accept"] = Accept; - if (Alt is not null) attributes["alt"] = Alt; - if (AutoComplete.Length > 0) attributes["autocomplete"] = string.Join(' ', AutoComplete).Trim(); - if (Capture is not null) attributes["capture"] = Capture; - if (Checked) attributes["checked"] = true; - if (!string.IsNullOrWhiteSpace(DirName)) attributes["dirname"] = DirName; - if (Disabled) attributes["disabled"] = true; - if (!string.IsNullOrWhiteSpace(Form)) attributes["form"] = Form; - if (FormAction is not null) attributes["formaction"] = FormAction.ToString(); - if (FormEnctype is not null) attributes["formenctype"] = FormEnctype; - if (FormMethod is not null) attributes["formmethod"] = FormMethod; - if (FormNoValidate) attributes["formnovalidate"] = true; - if (!string.IsNullOrWhiteSpace(FormTarget)) attributes["formtarget"] = FormTarget; - if (Height >= 0) attributes["height"] = Height.ToString(CultureInfo.InvariantCulture); - if (!string.IsNullOrWhiteSpace(List)) attributes["list"] = List; - if (!string.IsNullOrWhiteSpace(Max)) attributes["max"] = Max; - if (MaxLength >= 0) attributes["maxlength"] = MaxLength.ToString(CultureInfo.InvariantCulture); - if (!string.IsNullOrWhiteSpace(Min)) attributes["min"] = Min; - if (MinLength >= 0) attributes["minlength"] = MinLength.ToString(CultureInfo.InvariantCulture); - if (Multiple) attributes["multiple"] = true; - if (!string.IsNullOrWhiteSpace(Name)) attributes["name"] = Name; - if (Pattern is not null) attributes["pattern"] = Pattern.ToString().Replace(@"\", @"\\"); - if (!string.IsNullOrWhiteSpace(Placeholder)) attributes["placeholder"] = Placeholder; - if (!string.IsNullOrWhiteSpace(PopoverTarget)) attributes["popovertarget"] = PopoverTarget; - if (PopoverTargetAction is not null) attributes["popovertargetaction"] = PopoverTargetAction; - if (ReadOnly) attributes["readonly"] = true; - if (Required) attributes["required"] = true; - if (Size > 0) attributes["size"] = Size.ToString(CultureInfo.InvariantCulture); - if (!string.IsNullOrWhiteSpace(Step)) attributes["step"] = Step; - if (Type is not null) attributes["type"] = Type; - if (Value is not null) attributes["value"] = Value; - if (Width >= 0) attributes["width"] = Width.ToString(CultureInfo.InvariantCulture); - } -} diff --git a/src/Elements/New-InputElement.psm1 b/src/Elements/New-InputElement.psm1 new file mode 100644 index 0000000..62a8579 --- /dev/null +++ b/src/Elements/New-InputElement.psm1 @@ -0,0 +1,277 @@ +using namespace System.Net.Mime +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `input` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlInputElement"), Alias("input"), OutputType(typeof(string))] +function New-HtmlInputElement: NewElementCommand("input", isVoid: true) { + + <# + .SYNOPSIS + Defines which file types are selectable in a file upload control. + /// Valid for the `file` input type only. + #> + [string] $Accept + + <# + .SYNOPSIS + A text to display on browsers that do not display images. + /// Valid for the `image` input type only. + #> + [string] $Alt + + <# + .SYNOPSIS + A hint for a user agent's autocomplete feature. + #> + [string[]] $AutoComplete = @(), + + <# + .SYNOPSIS + Value indicating which camera to use for capture of image or video data. + #> + [ValidateSet("environment", "user")] + [string] $Capture + + <# + .SYNOPSIS + Value indicating whether the checkbox is checked or the radio button is the currently selected one. + #> + [switch] $Checked + + <# + .SYNOPSIS + The field name to use for sending the element's directionality in form submission. + #> + [string] $DirName + + <# + .SYNOPSIS + Value indicating whether to prevent the user from interacting with the element. + #> + [switch] $Disabled + + <# + .SYNOPSIS + The identifier of a `form` element to associate with the element. + #> + [string] $Form + + <# + .SYNOPSIS + The URL that processes the information submitted by the button. + /// Valid for the `image` and `submit` input types only. + #> + Uri? FormAction + + <# + .SYNOPSIS + Value indicating how to encode the form data that is submitted. + /// Valid for the `image` and `submit` input types only. + #> + [ValidateSet(MediaTypeNames.Application.FormUrlEncoded, MediaTypeNames.Multipart.FormData, MediaTypeNames.Text.Plain)] + [string] $FormEnctype + + <# + .SYNOPSIS + The HTTP method used to submit the form. + /// Valid for the `image` and `submit` input types only. + #> + [ValidateSet("dialog", "get", "post")] + [string] $FormMethod + + <# + .SYNOPSIS + Value indicating whether the form is not to be validated when it is submitted. + /// Valid for the `image` and `submit` input types only. + #> + [switch] $FormNoValidate + + <# + .SYNOPSIS + The browsing context to show the response after submitting the form. + /// Valid for the `image` and `submit` input types only. + #> + [string] $FormTarget + + <# + .SYNOPSIS + The intrinsic height of the image, in CSS pixels. + /// Valid for the `image` input type only. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int Height = -1; + + <# + .SYNOPSIS + The identifier of a `datalist` element located in the same document.. + #> + [string] $List + + <# + .SYNOPSIS + The greatest value in the range of permitted values. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + [string] $Max + + <# + .SYNOPSIS + The maximum string length that the user can enter. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int MaxLength = -1; + + <# + .SYNOPSIS + The lowest value in the range of permitted values. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + [string] $Min + + <# + .SYNOPSIS + The minimum string length required that the user should enter. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int MinLength = -1; + + <# + .SYNOPSIS + Value indicating whether the user can enter comma separated email addresses in the `email` widget or can choose more than one file with the `file` input. + #> + [switch] $Multiple + + <# + .SYNOPSIS + The name of the control. + #> + [string] $Name + + <# + .SYNOPSIS + The regular expression that the must match in order for the value to pass constraint validation. + #> + Regex? Pattern + + <# + .SYNOPSIS + A hint to the user of what can be entered in the control. + #> + [string] $Placeholder + + <# + .SYNOPSIS + The identifier of a popover element to control. + #> + [string] $PopoverTarget + + <# + .SYNOPSIS + The action to be performed on a popover element being controlled via the attribute. + #> + [ValidateSet("hide", "show", "toggle")] + [string] $PopoverTargetAction + + <# + .SYNOPSIS + Value indicating whether the user cannot modify the value of the control. + #> + [switch] $ReadOnly + + <# + .SYNOPSIS + Value indicating whether the user must fill in a value before submitting a form. + #> + [switch] $Required + + <# + .SYNOPSIS + Value indicating how much of the input is shown. + #> + [ValidateRange(ValidateRangeKind.Positive)] + int Size + + <# + .SYNOPSIS + The URL of the image file to display to represent the graphical button. + /// Valid for the `image` input type only. + #> + Uri? Src + + <# + .SYNOPSIS + A number that specifies the granularity that the value must adhere to, or the special value `any`. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + [string] $Step + + <# + .SYNOPSIS + The type of control to render. + #> + [ValidateSet( + "button", "checkbox", "color", "date", "datetime-local", "email", + "file", "hidden", "image", "month", "number", "password", + "radio", "range", "reset", "search", "submit", "tel", + "text", "time", "url", "week" + )] + [string] $Type + + <# + .SYNOPSIS + The value of the control. + #> + [object] $Value + + <# + .SYNOPSIS + The intrinsic width of the image, in CSS pixels. + /// Valid for the `image` input type only. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int Width = -1; + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if ($Accept) { $attributesToRender.accept"] = Accept; + if (Alt is not null) $attributesToRender.alt"] = Alt; + if (AutoComplete.Length > 0) $attributesToRender.autocomplete"] = string.Join(' ', AutoComplete).Trim(); + if (Capture is not null) $attributesToRender.capture"] = Capture; + if (Checked) $attributesToRender.checked"] = true; + if ($DirName) { $attributesToRender.dirname"] = DirName; + if (Disabled) $attributesToRender.disabled"] = true; + if ($Form) { $attributesToRender.form"] = Form; + if (FormAction is not null) $attributesToRender.formaction"] = FormAction.ToString(); + if (FormEnctype is not null) $attributesToRender.formenctype"] = FormEnctype; + if (FormMethod is not null) $attributesToRender.formmethod"] = FormMethod; + if (FormNoValidate) $attributesToRender.formnovalidate"] = true; + if ($FormTarget) { $attributesToRender.formtarget"] = FormTarget; + if (Height >= 0) $attributesToRender.height"] = Height + if ($List) { $attributesToRender.list"] = List; + if ($Max) { $attributesToRender.max"] = Max; + if (MaxLength >= 0) $attributesToRender.maxlength"] = MaxLength + if ($Min) { $attributesToRender.min"] = Min; + if (MinLength >= 0) $attributesToRender.minlength"] = MinLength + if (Multiple) $attributesToRender.multiple"] = true; + if ($Name) { $attributesToRender.name"] = Name; + if (Pattern is not null) $attributesToRender.pattern"] = Pattern.ToString().Replace(@"\", @"\\"); + if ($Placeholder) { $attributesToRender.placeholder"] = Placeholder; + if ($PopoverTarget) { $attributesToRender.popovertarget"] = PopoverTarget; + if (PopoverTargetAction is not null) $attributesToRender.popovertargetaction"] = PopoverTargetAction; + if (ReadOnly) $attributesToRender.readonly"] = true; + if (Required) $attributesToRender.required"] = true; + if (Size > 0) $attributesToRender.size"] = Size + if ($Step) { $attributesToRender.step"] = Step; + if (Type is not null) $attributesToRender.type"] = Type; + if (Value is not null) $attributesToRender.value"] = Value; + if (Width >= 0) $attributesToRender.width"] = Width + } +} diff --git a/src/Elements/New-InsElement.cs b/src/Elements/New-InsElement.cs deleted file mode 100644 index c344bb8..0000000 --- a/src/Elements/New-InsElement.cs +++ /dev/null @@ -1,42 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new ins element. -/// -[Cmdlet(VerbsCommon.New, "HtmlInsElement"), Alias("ins"), OutputType(typeof(string))] -public class NewInsElementCommand(): NewElementCommand("ins", isVoid: false) { - - /// - /// A URI for a resource that explains the change. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public Uri? Cite { get; set; } - - /// - /// The date and time of the change. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public object? DateTime { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (Cite is not null) attributes["cite"] = Cite.ToString(); - - if (DateTime is not null) { - try { - attributes["datetime"] = (DateTime is PSObject psObject ? psObject.BaseObject : DateTime) switch { - DateOnly value => value.ToString("o"), - DateTime value => value.ToString("o"), - _ => throw new NotSupportedException("The specified date/time value is not supported.") - }; - } - catch (NotSupportedException e) { - WriteError(new ErrorRecord(e, "New-InsElement:NotSupportedException", ErrorCategory.InvalidArgument, DateTime)); - } - } - } -} diff --git a/src/Elements/New-InsElement.psm1 b/src/Elements/New-InsElement.psm1 new file mode 100644 index 0000000..31e0ecc --- /dev/null +++ b/src/Elements/New-InsElement.psm1 @@ -0,0 +1,44 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `ins` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlInsElement"), Alias("ins"), OutputType(typeof(string))] +function New-HtmlInsElement: NewElementCommand("ins", isVoid: false) { + + <# + .SYNOPSIS + A URI for a resource that explains the change. + #> + Uri? Cite + + <# + .SYNOPSIS + The date and time of the change. + #> + [object] $DateTime + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (Cite is not null) $attributesToRender.cite"] = Cite.ToString(); + + if (DateTime is not null) { + try { + $attributesToRender.datetime"] = (DateTime is PSObject psObject ? psObject.BaseObject : DateTime) switch { + DateOnly value => value.ToString("o"), + DateTime value => value.ToString("o"), + _ => throw new NotSupportedException("The specified date/time value is not supported.") + }; + } + catch (NotSupportedException e) { + WriteError(new ErrorRecord(e, "New-InsElement:NotSupportedException", ErrorCategory.InvalidArgument, DateTime)); + } + } + } +} diff --git a/src/Elements/New-LabelElement.cs b/src/Elements/New-LabelElement.cs deleted file mode 100644 index 268637c..0000000 --- a/src/Elements/New-LabelElement.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new label element. -/// -[Cmdlet(VerbsCommon.New, "HtmlLabelElement"), Alias("label"), OutputType(typeof(string))] -public class NewLabelElementCommand(): NewElementCommand("label", isVoid: false) { - - /// - /// The identifier of the labelable form control in the same document. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? For { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (!string.IsNullOrWhiteSpace(For)) attributes["for"] = For; - } -} diff --git a/src/Elements/New-LabelElement.psm1 b/src/Elements/New-LabelElement.psm1 new file mode 100644 index 0000000..5f0a5c5 --- /dev/null +++ b/src/Elements/New-LabelElement.psm1 @@ -0,0 +1,25 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `label` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlLabelElement"), Alias("label"), OutputType(typeof(string))] +function New-HtmlLabelElement: NewElementCommand("label", isVoid: false) { + + <# + .SYNOPSIS + The identifier of the labelable form control in the same document. + #> + [string] $For + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if ($For) { $attributesToRender.for"] = For; + } +} diff --git a/src/Elements/New-LiElement.cs b/src/Elements/New-LiElement.cs deleted file mode 100644 index b9430a0..0000000 --- a/src/Elements/New-LiElement.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new li element. -/// -[Cmdlet(VerbsCommon.New, "HtmlLiElement"), Alias("li"), OutputType(typeof(string))] -public class NewLiElementCommand(): NewElementCommand("li", isVoid: false) { - - /// - /// The ordinal value of the list item as defined by the ol element. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public int? Value { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (Value is not null) attributes["value"] = Value.Value.ToString(CultureInfo.InvariantCulture); - } -} diff --git a/src/Elements/New-LiElement.psm1 b/src/Elements/New-LiElement.psm1 new file mode 100644 index 0000000..05e9aa1 --- /dev/null +++ b/src/Elements/New-LiElement.psm1 @@ -0,0 +1,25 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `li` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlLiElement"), Alias("li"), OutputType(typeof(string))] +function New-HtmlLiElement: NewElementCommand("li", isVoid: false) { + + <# + .SYNOPSIS + The ordinal value of the list item as defined by the `ol` element. + #> + [int] $Value + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (Value is not null) $attributesToRender.value"] = Value.Value + } +} diff --git a/src/Elements/New-LinkElement.cs b/src/Elements/New-LinkElement.cs deleted file mode 100644 index 32a00cb..0000000 --- a/src/Elements/New-LinkElement.cs +++ /dev/null @@ -1,72 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new link element. -/// -[Cmdlet(VerbsCommon.New, "HtmlLinkElement"), Alias("link"), OutputType(typeof(string))] -public class NewLinkElementCommand(): NewElementCommand("link", isVoid: true) { - - /// - /// Specifies the type of content being loaded by the link. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? As { get; set; } - - /// - /// Value indicating whether CORS must be used when fetching the resource. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("anonymous", "use-credentials")] - public string? CrossOrigin { get; set; } - - /// - /// The URL of the linked resource. - /// - [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)] - public required Uri Href { get; set; } - - /// - /// A base64-encoded cryptographic hash of the resource (file) to fetch. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Integrity { get; set; } - - /// - /// The media that the linked resource applies to. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Media { get; set; } - - /// - /// The relationship of the linked resource to the current document. - /// - [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)] - public required string[] Rel { get; set; } - - /// - /// The sizes of the icons for visual media contained in the resource. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string[] Sizes { get; set; } = []; - - /// - /// The media type of the content linked to. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Type { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - attributes["rel"] = string.Join(' ', Rel).Trim(); - attributes["href"] = Href.ToString(); - if (!string.IsNullOrWhiteSpace(As)) attributes["as"] = As; - if (CrossOrigin is not null) attributes["crossorigin"] = CrossOrigin; - if (!string.IsNullOrWhiteSpace(Integrity)) attributes["integrity"] = Integrity; - if (!string.IsNullOrWhiteSpace(Media)) attributes["media"] = Media; - if (Sizes.Length > 0) attributes["sizes"] = string.Join(' ', Sizes).Trim(); - if (!string.IsNullOrWhiteSpace(Type)) attributes["type"] = Type; - } -} diff --git a/src/Elements/New-LinkElement.psm1 b/src/Elements/New-LinkElement.psm1 new file mode 100644 index 0000000..3d82069 --- /dev/null +++ b/src/Elements/New-LinkElement.psm1 @@ -0,0 +1,77 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `link` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlLinkElement"), Alias("link"), OutputType(typeof(string))] +function New-HtmlLinkElement: NewElementCommand("link", isVoid: true) { + + <# + .SYNOPSIS + Specifies the type of content being loaded by the `link`. + #> + [string] $As + + <# + .SYNOPSIS + Value indicating whether CORS must be used when fetching the resource. + #> + [ValidateSet("anonymous", "use-credentials")] + [string] $CrossOrigin + + <# + .SYNOPSIS + The URL of the linked resource. + #> + [Parameter(Mandatory)] + [uri] $Href + + <# + .SYNOPSIS + A base64-encoded cryptographic hash of the resource (file) to fetch. + #> + [string] $Integrity + + <# + .SYNOPSIS + The media that the linked resource applies to. + #> + [string] $Media + + <# + .SYNOPSIS + The relationship of the linked resource to the current document. + #> + [Parameter(Mandatory)] + required [string[]] $Rel + + <# + .SYNOPSIS + The sizes of the icons for visual media contained in the resource. + #> + [string[]] $Sizes = @(), + + <# + .SYNOPSIS + The media type of the content linked to. + #> + [string] $Type + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + $attributesToRender.rel"] = string.Join(' ', Rel).Trim(); + $attributesToRender.href"] = Href.ToString(); + if ($As) { $attributesToRender.as"] = As; + if (CrossOrigin is not null) $attributesToRender.crossorigin"] = CrossOrigin; + if ($Integrity) { $attributesToRender.integrity"] = Integrity; + if ($Media) { $attributesToRender.media"] = Media; + if (Sizes.Length > 0) $attributesToRender.sizes"] = string.Join(' ', Sizes).Trim(); + if ($Type) { $attributesToRender.type"] = Type; + } +} diff --git a/src/Elements/New-MapElement.cs b/src/Elements/New-MapElement.cs deleted file mode 100644 index 5d5ad3c..0000000 --- a/src/Elements/New-MapElement.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new map element. -/// -[Cmdlet(VerbsCommon.New, "HtmlMapElement"), Alias("map"), OutputType(typeof(string))] -public class NewMapElementCommand(): NewElementCommand("map", isVoid: false) { - - /// - /// The map name so that it can be referenced. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Name { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (!string.IsNullOrWhiteSpace(Name)) attributes["name"] = Name; - } -} diff --git a/src/Elements/New-MapElement.psm1 b/src/Elements/New-MapElement.psm1 new file mode 100644 index 0000000..a79d43a --- /dev/null +++ b/src/Elements/New-MapElement.psm1 @@ -0,0 +1,25 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `map` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlMapElement"), Alias("map"), OutputType(typeof(string))] +function New-HtmlMapElement: NewElementCommand("map", isVoid: false) { + + <# + .SYNOPSIS + The map name so that it can be referenced. + #> + [string] $Name + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if ($Name) { $attributesToRender.name"] = Name; + } +} diff --git a/src/Elements/New-MetaElement.cs b/src/Elements/New-MetaElement.cs deleted file mode 100644 index 7ac5eb8..0000000 --- a/src/Elements/New-MetaElement.cs +++ /dev/null @@ -1,55 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new meta element. -/// -[Cmdlet(VerbsCommon.New, "HtmlMetaElement", DefaultParameterSetName = nameof(Name)), Alias("meta"), OutputType(typeof(string))] -public class NewMetaElementCommand(): NewElementCommand("meta", isVoid: true) { - - /// - /// A charset declaration, giving the character encoding in which the document is encoded. - /// - [Parameter(Mandatory = true, ParameterSetName = nameof(Charset), ValueFromPipelineByPropertyName = true)] - public required string Charset { get; set; } - - /// - /// Contains the value for the http-equiv or name attribute, depending on which is used. - /// - [Parameter(Mandatory = true, ParameterSetName = nameof(HttpEquiv), ValueFromPipelineByPropertyName = true)] - [Parameter(Mandatory = true, ParameterSetName = nameof(Name), ValueFromPipelineByPropertyName = true)] - public override object? Content { get => base.Content; set => base.Content = value; } - - /// - /// A pragma directive to simulate directives that could otherwise be given by an HTTP header. - /// - [Parameter(Mandatory = true, ParameterSetName = nameof(HttpEquiv), ValueFromPipelineByPropertyName = true)] - public required string HttpEquiv { get; set; } - - /// - /// Document-level metadata that applies to the whole page. - /// - [Parameter(Mandatory = true, ParameterSetName = nameof(Name), ValueFromPipelineByPropertyName = true)] - public required string Name { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - - switch (ParameterSetName) { - case nameof(Charset): - attributes["charset"] = Charset; - break; - case nameof(HttpEquiv): - attributes["http-equiv"] = HttpEquiv; - attributes["content"] = Content; - break; - case nameof(Name): - attributes["name"] = Name; - attributes["content"] = Content; - break; - } - } -} diff --git a/src/Elements/New-MetaElement.psm1 b/src/Elements/New-MetaElement.psm1 new file mode 100644 index 0000000..506e90b --- /dev/null +++ b/src/Elements/New-MetaElement.psm1 @@ -0,0 +1,61 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `meta` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlMetaElement", DefaultParameterSetName = nameof(Name)), Alias("meta"), OutputType(typeof(string))] +function New-HtmlMetaElement: NewElementCommand("meta", isVoid: true) { + + <# + .SYNOPSIS + A charset declaration, giving the character encoding in which the document is encoded. + #> + [Parameter(Mandatory, ParameterSetName = nameof(Charset))] + required string Charset + + <# + .SYNOPSIS + Contains the value for the `http-equiv` or `name attribute`, depending on which is used. + #> + [Parameter(Mandatory, ParameterSetName = nameof(HttpEquiv))] + [Parameter(Mandatory, ParameterSetName = nameof(Name))] + override [object] $Content { get => base.Content; set => base.Content = value; } + + <# + .SYNOPSIS + A pragma directive to simulate directives that could otherwise be given by an HTTP header. + #> + [Parameter(Mandatory, ParameterSetName = nameof(HttpEquiv))] + required string HttpEquiv + + <# + .SYNOPSIS + Document-level metadata that applies to the whole page. + #> + [Parameter(Mandatory, ParameterSetName = nameof(Name))] + required string Name + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + + switch (ParameterSetName) { + case nameof(Charset): + $attributesToRender.charset"] = Charset; + break; + case nameof(HttpEquiv): + $attributesToRender.http-equiv"] = HttpEquiv; + $attributesToRender.content"] = Content; + break; + case nameof(Name): + $attributesToRender.name"] = Name; + $attributesToRender.content"] = Content; + break; + } + } +} diff --git a/src/Elements/New-MeterElement.cs b/src/Elements/New-MeterElement.cs deleted file mode 100644 index 3b9b448..0000000 --- a/src/Elements/New-MeterElement.cs +++ /dev/null @@ -1,60 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new meter element. -/// -[Cmdlet(VerbsCommon.New, "HtmlMeterElement"), Alias("meter"), OutputType(typeof(string))] -public class NewMeterElementCommand(): NewElementCommand("meter", isVoid: false) { - - /// - /// The lower numeric bound of the high end of the measured range. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public double? High { get; set; } - - /// - /// The upper numeric bound of the low end of the measured range. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public double? Low { get; set; } - - /// - /// The upper numeric bound of the measured range. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public double? Max { get; set; } - - /// - /// The lower numeric bound of the measured range. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public double? Min { get; set; } - - /// - /// The optimal numeric value. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public double? Optimum { get; set; } - - /// - /// The current numeric value. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public double? Value { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (High is not null) attributes["high"] = High.Value.ToString(CultureInfo.InvariantCulture); - if (Low is not null) attributes["low"] = Low.Value.ToString(CultureInfo.InvariantCulture); - if (Max is not null) attributes["max"] = Max.Value.ToString(CultureInfo.InvariantCulture); - if (Min is not null) attributes["min"] = Min.Value.ToString(CultureInfo.InvariantCulture); - if (Optimum is not null) attributes["optimum"] = Optimum.Value.ToString(CultureInfo.InvariantCulture); - if (Value is not null) attributes["value"] = Value.Value.ToString(CultureInfo.InvariantCulture); - } -} diff --git a/src/Elements/New-MeterElement.psm1 b/src/Elements/New-MeterElement.psm1 new file mode 100644 index 0000000..68ebf19 --- /dev/null +++ b/src/Elements/New-MeterElement.psm1 @@ -0,0 +1,60 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `meter` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlMeterElement"), Alias("meter"), OutputType(typeof(string))] +function New-HtmlMeterElement: NewElementCommand("meter", isVoid: false) { + + <# + .SYNOPSIS + The lower numeric bound of the high end of the measured range. + #> + double? High + + <# + .SYNOPSIS + The upper numeric bound of the low end of the measured range. + #> + double? Low + + <# + .SYNOPSIS + The upper numeric bound of the measured range. + #> + double? Max + + <# + .SYNOPSIS + The lower numeric bound of the measured range. + #> + double? Min + + <# + .SYNOPSIS + The optimal numeric value. + #> + double? Optimum + + <# + .SYNOPSIS + The current numeric value. + #> + double? Value + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (High is not null) $attributesToRender.high"] = High.Value + if (Low is not null) $attributesToRender.low"] = Low.Value + if (Max is not null) $attributesToRender.max"] = Max.Value + if (Min is not null) $attributesToRender.min"] = Min.Value + if (Optimum is not null) $attributesToRender.optimum"] = Optimum.Value + if (Value is not null) $attributesToRender.value"] = Value.Value + } +} diff --git a/src/Elements/New-ObjectElement.cs b/src/Elements/New-ObjectElement.cs deleted file mode 100644 index 19f06a4..0000000 --- a/src/Elements/New-ObjectElement.cs +++ /dev/null @@ -1,60 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new object element. -/// -[Cmdlet(VerbsCommon.New, "HtmlObjectElement"), Alias("object"), OutputType(typeof(string))] -public class NewObjectElementCommand(): NewElementCommand("object", isVoid: false) { - - /// - /// The URL of the resource being embedded. - /// - [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)] - public required Uri Data { get; set; } - - /// - /// The identifier of a form element to associate with the element. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Form { get; set; } - - /// - /// The height of the display resource, in CSS pixels. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int Height { get; set; } = -1; - - /// - /// The name of valid browsing context (HTML 5), or the name of the control (HTML 4). - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Name { get; set; } - - /// - /// The media type to use, optionally including a codecs parameter. - /// - [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)] - public required string Type { get; set; } - - /// - /// The width of the display resource, in CSS pixels. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int Width { get; set; } = -1; - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - attributes["data"] = Data.ToString(); - attributes["type"] = Type; - if (!string.IsNullOrWhiteSpace(Form)) attributes["form"] = Form; - if (Height >= 0) attributes["height"] = Height.ToString(CultureInfo.InvariantCulture); - if (!string.IsNullOrWhiteSpace(Name)) attributes["name"] = Name; - if (Width >= 0) attributes["width"] = Width.ToString(CultureInfo.InvariantCulture); - } -} diff --git a/src/Elements/New-ObjectElement.psm1 b/src/Elements/New-ObjectElement.psm1 new file mode 100644 index 0000000..c6bacb0 --- /dev/null +++ b/src/Elements/New-ObjectElement.psm1 @@ -0,0 +1,64 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `object` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlObjectElement"), Alias("object"), OutputType(typeof(string))] +function New-HtmlObjectElement: NewElementCommand("object", isVoid: false) { + + <# + .SYNOPSIS + The URL of the resource being embedded. + #> + [Parameter(Mandatory)] + required Uri Data + + <# + .SYNOPSIS + The identifier of a `form` element to associate with the element. + #> + [string] $Form + + <# + .SYNOPSIS + The height of the display resource, in CSS pixels. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int Height = -1; + + <# + .SYNOPSIS + The name of valid browsing context (HTML 5), or the name of the control (HTML 4). + #> + [string] $Name + + <# + .SYNOPSIS + The media type to use, optionally including a `codecs` parameter. + #> + [Parameter(Mandatory)] + required string Type + + <# + .SYNOPSIS + The width of the display resource, in CSS pixels. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int Width = -1; + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + $attributesToRender.data"] = Data.ToString(); + $attributesToRender.type"] = Type; + if ($Form) { $attributesToRender.form"] = Form; + if (Height >= 0) $attributesToRender.height"] = Height + if ($Name) { $attributesToRender.name"] = Name; + if (Width >= 0) $attributesToRender.width"] = Width + } +} diff --git a/src/Elements/New-OlElement.cs b/src/Elements/New-OlElement.cs deleted file mode 100644 index cea43ab..0000000 --- a/src/Elements/New-OlElement.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new ol element. -/// -[Cmdlet(VerbsCommon.New, "HtmlOlElement"), Alias("ol"), OutputType(typeof(string))] -public class NewOlElementCommand(): NewElementCommand("ol", isVoid: false) { - - /// - /// Value indicating whether the list's items are in reverse order. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Reversed { get; set; } - - /// - /// An integer to start counting from for the list items. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public int? Start { get; set; } - - /// - /// Value indicating the current ordinal value of the list item as defined by the ol element. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("1", "A", "a", "I", "i")] - public string? Type { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (Reversed) attributes["reversed"] = true; - if (Start is not null) attributes["start"] = Start.Value.ToString(CultureInfo.InvariantCulture); - if (Type is not null) attributes["type"] = Type; - } -} diff --git a/src/Elements/New-OlElement.psm1 b/src/Elements/New-OlElement.psm1 new file mode 100644 index 0000000..767daef --- /dev/null +++ b/src/Elements/New-OlElement.psm1 @@ -0,0 +1,40 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `ol` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlOlElement"), Alias("ol"), OutputType(typeof(string))] +function New-HtmlOlElement: NewElementCommand("ol", isVoid: false) { + + <# + .SYNOPSIS + Value indicating whether the list's items are in reverse order. + #> + [switch] $Reversed + + <# + .SYNOPSIS + An integer to start counting from for the list items. + #> + [int] $Start + + <# + .SYNOPSIS + Value indicating the current ordinal value of the list item as defined by the `ol` element. + #> + [ValidateSet("1", "A", "a", "I", "i")] + [string] $Type + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (Reversed) $attributesToRender.reversed"] = true; + if (Start is not null) $attributesToRender.start"] = Start.Value + if (Type is not null) $attributesToRender.type"] = Type; + } +} diff --git a/src/Elements/New-OptgroupElement.cs b/src/Elements/New-OptgroupElement.cs deleted file mode 100644 index dafb281..0000000 --- a/src/Elements/New-OptgroupElement.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new optgroup element. -/// -[Cmdlet(VerbsCommon.New, "HtmlOptgroupElement"), Alias("optgroup"), OutputType(typeof(string))] -public class NewOptgroupElementCommand(): NewElementCommand("optgroup", isVoid: false) { - - /// - /// Value indicating whether none of the items in the option group is selectable. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Disabled { get; set; } - - /// - /// The name of the group of options. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public required string Label { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - attributes["label"] = Label; - if (Disabled) attributes["disabled"] = true; - } -} diff --git a/src/Elements/New-OptgroupElement.psm1 b/src/Elements/New-OptgroupElement.psm1 new file mode 100644 index 0000000..055ab32 --- /dev/null +++ b/src/Elements/New-OptgroupElement.psm1 @@ -0,0 +1,32 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `optgroup` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlOptgroupElement"), Alias("optgroup"), OutputType(typeof(string))] +function New-HtmlOptgroupElement: NewElementCommand("optgroup", isVoid: false) { + + <# + .SYNOPSIS + Value indicating whether none of the items in the option group is selectable. + #> + [switch] $Disabled + + <# + .SYNOPSIS + The name of the group of options. + #> + required string Label + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + $attributesToRender.label"] = Label; + if (Disabled) $attributesToRender.disabled"] = true; + } +} diff --git a/src/Elements/New-OptionElement.cs b/src/Elements/New-OptionElement.cs deleted file mode 100644 index a491f63..0000000 --- a/src/Elements/New-OptionElement.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new option element. -/// -[Cmdlet(VerbsCommon.New, "HtmlOptionElement"), Alias("option"), OutputType(typeof(string))] -public class NewOptionElementCommand(): NewElementCommand("option", isVoid: false) { - - /// - /// Value indicating whether the option is not checkable. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Disabled { get; set; } - - /// - /// The label indicating the meaning of the option. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Label { get; set; } - - /// - /// Value indicating whether the option is initially selected. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Selected { get; set; } - - /// - /// The value to be submitted with the form. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Value { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (Disabled) attributes["disabled"] = true; - if (!string.IsNullOrWhiteSpace(Label)) attributes["label"] = Label; - if (Selected) attributes["selected"] = true; - if (Value is not null) attributes["value"] = Value; - } -} diff --git a/src/Elements/New-OptionElement.psm1 b/src/Elements/New-OptionElement.psm1 new file mode 100644 index 0000000..b05b710 --- /dev/null +++ b/src/Elements/New-OptionElement.psm1 @@ -0,0 +1,46 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `option` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlOptionElement"), Alias("option"), OutputType(typeof(string))] +function New-HtmlOptionElement: NewElementCommand("option", isVoid: false) { + + <# + .SYNOPSIS + Value indicating whether the option is not checkable. + #> + [switch] $Disabled + + <# + .SYNOPSIS + The label indicating the meaning of the option. + #> + [string] $Label + + <# + .SYNOPSIS + Value indicating whether the option is initially selected. + #> + [switch] $Selected + + <# + .SYNOPSIS + The value to be submitted with the form. + #> + [string] $Value + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (Disabled) $attributesToRender.disabled"] = true; + if ($Label) { $attributesToRender.label"] = Label; + if (Selected) $attributesToRender.selected"] = true; + if (Value is not null) $attributesToRender.value"] = Value; + } +} diff --git a/src/Elements/New-OutputElement.cs b/src/Elements/New-OutputElement.cs deleted file mode 100644 index b8eab1f..0000000 --- a/src/Elements/New-OutputElement.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new output element. -/// -[Cmdlet(VerbsCommon.New, "HtmlOutputElement"), Alias("output"), OutputType(typeof(string))] -public class NewOutputElementCommand(): NewElementCommand("output", isVoid: false) { - - /// - /// A list of other elements' identifiers, indicating that those elements contributed input values to the calculation. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string[] For { get; set; } = []; - - /// - /// The identifier of a form element to associate with the element. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Form { get; set; } - - /// - /// The element's name. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Name { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (For.Length > 0) attributes["for"] = string.Join(' ', For).Trim(); - if (!string.IsNullOrWhiteSpace(Form)) attributes["form"] = Form; - if (!string.IsNullOrWhiteSpace(Name)) attributes["name"] = Name; - } -} diff --git a/src/Elements/New-OutputElement.psm1 b/src/Elements/New-OutputElement.psm1 new file mode 100644 index 0000000..2101869 --- /dev/null +++ b/src/Elements/New-OutputElement.psm1 @@ -0,0 +1,39 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `output` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlOutputElement"), Alias("output"), OutputType(typeof(string))] +function New-HtmlOutputElement: NewElementCommand("output", isVoid: false) { + + <# + .SYNOPSIS + A list of other elements' identifiers, indicating that those elements contributed input values to the calculation. + #> + [string[]] $For = @(), + + <# + .SYNOPSIS + The identifier of a `form` element to associate with the element. + #> + [string] $Form + + <# + .SYNOPSIS + The element's name. + #> + [string] $Name + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (For.Length > 0) $attributesToRender.for"] = string.Join(' ', For).Trim(); + if ($Form) { $attributesToRender.form"] = Form; + if ($Name) { $attributesToRender.name"] = Name; + } +} diff --git a/src/Elements/New-ProgressElement.cs b/src/Elements/New-ProgressElement.cs deleted file mode 100644 index c22d8e5..0000000 --- a/src/Elements/New-ProgressElement.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new progress element. -/// -[Cmdlet(VerbsCommon.New, "HtmlProgressElement"), Alias("progress"), OutputType(typeof(string))] -public class NewProgressElementCommand(): NewElementCommand("progress", isVoid: false) { - - /// - /// Describes how much work the task requires. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public double? Max { get; set; } - - /// - /// Specifies how much of the task that has been completed. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public double? Value { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (Max is not null) attributes["max"] = Max.Value.ToString(CultureInfo.InvariantCulture); - if (Value is not null) attributes["value"] = Value.Value.ToString(CultureInfo.InvariantCulture); - } -} diff --git a/src/Elements/New-ProgressElement.psm1 b/src/Elements/New-ProgressElement.psm1 new file mode 100644 index 0000000..7207d2f --- /dev/null +++ b/src/Elements/New-ProgressElement.psm1 @@ -0,0 +1,34 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `progress` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlProgressElement"), Alias("progress"), OutputType(typeof(string))] +function New-HtmlProgressElement: NewElementCommand("progress", isVoid: false) { + + <# + .SYNOPSIS + Describes how much work the task requires. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + double? Max + + <# + .SYNOPSIS + Specifies how much of the task that has been completed. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + double? Value + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (Max is not null) $attributesToRender.max"] = Max.Value + if (Value is not null) $attributesToRender.value"] = Value.Value + } +} diff --git a/src/Elements/New-QElement.cs b/src/Elements/New-QElement.cs deleted file mode 100644 index 15d5f4c..0000000 --- a/src/Elements/New-QElement.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new q element. -/// -[Cmdlet(VerbsCommon.New, "HtmlQElement"), Alias("q"), OutputType(typeof(string))] -public class NewQElementCommand(): NewElementCommand("q", isVoid: false) { - - /// - /// A URL that designates a source document or message for the information quoted. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public Uri? Cite { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (Cite is not null) attributes["cite"] = Cite.ToString(); - } -} diff --git a/src/Elements/New-QElement.psm1 b/src/Elements/New-QElement.psm1 new file mode 100644 index 0000000..8109048 --- /dev/null +++ b/src/Elements/New-QElement.psm1 @@ -0,0 +1,25 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `q` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlQElement"), Alias("q"), OutputType(typeof(string))] +function New-HtmlQElement: NewElementCommand("q", isVoid: false) { + + <# + .SYNOPSIS + A URL that designates a source document or message for the information quoted. + #> + Uri? Cite + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (Cite is not null) $attributesToRender.cite"] = Cite.ToString(); + } +} diff --git a/src/Elements/New-ScriptElement.cs b/src/Elements/New-ScriptElement.cs deleted file mode 100644 index fb478a5..0000000 --- a/src/Elements/New-ScriptElement.cs +++ /dev/null @@ -1,58 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new script element. -/// -[Cmdlet(VerbsCommon.New, "HtmlScriptElement"), Alias("script"), OutputType(typeof(string))] -public class NewScriptElementCommand(): NewElementCommand("script", isVoid: false) { - - /// - /// Value indicating whether the script will be fetched in parallel to parsing and evaluated as soon as it is available. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Async { get; set; } - - /// - /// Value indicating whether CORS must be used when fetching the resource. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("anonymous", "use-credentials")] - public string? CrossOrigin { get; set; } - - /// - /// Value indicating whether the script is meant to be executed after the document has been parsed, but before firing DOMContentLoaded event. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Defer { get; set; } - - /// - /// A base64-encoded cryptographic hash of the resource (file) to fetch. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Integrity { get; set; } - - /// - /// The URI of an external script. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public Uri? Src { get; set; } - - /// - /// The type of script represented. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Type { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (Src is not null) attributes["src"] = Src.ToString(); - if (Async) attributes["async"] = true; - if (CrossOrigin is not null) attributes["crossorigin"] = CrossOrigin; - if (Defer) attributes["defer"] = true; - if (!string.IsNullOrWhiteSpace(Integrity)) attributes["integrity"] = Integrity; - if (!string.IsNullOrWhiteSpace(Type)) attributes["type"] = Type; - } -} diff --git a/src/Elements/New-ScriptElement.psm1 b/src/Elements/New-ScriptElement.psm1 new file mode 100644 index 0000000..582286e --- /dev/null +++ b/src/Elements/New-ScriptElement.psm1 @@ -0,0 +1,61 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `script` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlScriptElement"), Alias("script"), OutputType(typeof(string))] +function New-HtmlScriptElement: NewElementCommand("script", isVoid: false) { + + <# + .SYNOPSIS + Value indicating whether the script will be fetched in parallel to parsing and evaluated as soon as it is available. + #> + [switch] $Async + + <# + .SYNOPSIS + Value indicating whether CORS must be used when fetching the resource. + #> + [ValidateSet("anonymous", "use-credentials")] + [string] $CrossOrigin + + <# + .SYNOPSIS + Value indicating whether the script is meant to be executed after the document has been parsed, but before firing `DOMContentLoaded` event. + #> + [switch] $Defer + + <# + .SYNOPSIS + A base64-encoded cryptographic hash of the resource (file) to fetch. + #> + [string] $Integrity + + <# + .SYNOPSIS + The URI of an external script. + #> + Uri? Src + + <# + .SYNOPSIS + The type of script represented. + #> + [string] $Type + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (Src is not null) $attributesToRender.src"] = Src.ToString(); + if (Async) $attributesToRender.async"] = true; + if (CrossOrigin is not null) $attributesToRender.crossorigin"] = CrossOrigin; + if (Defer) $attributesToRender.defer"] = true; + if ($Integrity) { $attributesToRender.integrity"] = Integrity; + if ($Type) { $attributesToRender.type"] = Type; + } +} diff --git a/src/Elements/New-SelectElement.cs b/src/Elements/New-SelectElement.cs deleted file mode 100644 index 4d38e55..0000000 --- a/src/Elements/New-SelectElement.cs +++ /dev/null @@ -1,67 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new select element. -/// -[Cmdlet(VerbsCommon.New, "HtmlSelectElement"), Alias("selectTag"), OutputType(typeof(string))] -public class NewSelectElementCommand(): NewElementCommand("select", isVoid: false) { - - /// - /// A hint for a user agent's autocomplete feature. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string[] AutoComplete { get; set; } = []; - - /// - /// Value indicating whether to prevent the user from interacting with the element. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Disabled { get; set; } - - /// - /// The identifier of a form element to associate with the element. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Form { get; set; } - - /// - /// Value indicating whether multiple options can be selected in the list. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Multiple { get; set; } - - /// - /// The name of the control. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Name { get; set; } - - /// - /// Value indicating whether an option with a non-empty string value must be selected. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Required { get; set; } - - /// - /// The number of rows in the list that should be visible at one time. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int Size { get; set; } = -1; - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (AutoComplete.Length > 0) attributes["autocomplete"] = string.Join(' ', AutoComplete).Trim(); - if (Disabled) attributes["disabled"] = true; - if (!string.IsNullOrWhiteSpace(Form)) attributes["form"] = Form; - if (Multiple) attributes["multiple"] = true; - if (!string.IsNullOrWhiteSpace(Name)) attributes["name"] = Name; - if (Required) attributes["required"] = true; - if (Size >= 0) attributes["size"] = Size.ToString(CultureInfo.InvariantCulture); - } -} diff --git a/src/Elements/New-SelectElement.psm1 b/src/Elements/New-SelectElement.psm1 new file mode 100644 index 0000000..7fa9d12 --- /dev/null +++ b/src/Elements/New-SelectElement.psm1 @@ -0,0 +1,68 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `select` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlSelectElement"), Alias("selectTag"), OutputType(typeof(string))] +function New-HtmlSelectElement: NewElementCommand("select", isVoid: false) { + + <# + .SYNOPSIS + A hint for a user agent's autocomplete feature. + #> + [string[]] $AutoComplete = @(), + + <# + .SYNOPSIS + Value indicating whether to prevent the user from interacting with the element. + #> + [switch] $Disabled + + <# + .SYNOPSIS + The identifier of a `form` element to associate with the element. + #> + [string] $Form + + <# + .SYNOPSIS + Value indicating whether multiple options can be selected in the list. + #> + [switch] $Multiple + + <# + .SYNOPSIS + The name of the control. + #> + [string] $Name + + <# + .SYNOPSIS + Value indicating whether an option with a non-empty string value must be selected. + #> + [switch] $Required + + <# + .SYNOPSIS + The number of rows in the list that should be visible at one time. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int Size = -1; + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (AutoComplete.Length > 0) $attributesToRender.autocomplete"] = string.Join(' ', AutoComplete).Trim(); + if (Disabled) $attributesToRender.disabled"] = true; + if ($Form) { $attributesToRender.form"] = Form; + if (Multiple) $attributesToRender.multiple"] = true; + if ($Name) { $attributesToRender.name"] = Name; + if (Required) $attributesToRender.required"] = true; + if (Size >= 0) $attributesToRender.size"] = Size + } +} diff --git a/src/Elements/New-SlotElement.cs b/src/Elements/New-SlotElement.cs deleted file mode 100644 index 1e44c34..0000000 --- a/src/Elements/New-SlotElement.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new slot element. -/// -[Cmdlet(VerbsCommon.New, "HtmlSlotElement"), Alias("slot"), OutputType(typeof(string))] -public class NewSlotElementCommand(): NewElementCommand("slot", isVoid: false) { - - /// - /// The slot's name. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Name { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (!string.IsNullOrWhiteSpace(Name)) attributes["name"] = Name; - } -} diff --git a/src/Elements/New-SlotElement.psm1 b/src/Elements/New-SlotElement.psm1 new file mode 100644 index 0000000..2064e5e --- /dev/null +++ b/src/Elements/New-SlotElement.psm1 @@ -0,0 +1,25 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `slot` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlSlotElement"), Alias("slot"), OutputType(typeof(string))] +function New-HtmlSlotElement: NewElementCommand("slot", isVoid: false) { + + <# + .SYNOPSIS + The slot's name. + #> + [string] $Name + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if ($Name) { $attributesToRender.name"] = Name; + } +} diff --git a/src/Elements/New-SourceElement.cs b/src/Elements/New-SourceElement.cs deleted file mode 100644 index 879e941..0000000 --- a/src/Elements/New-SourceElement.cs +++ /dev/null @@ -1,75 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new source element. -/// -[Cmdlet(VerbsCommon.New, "HtmlSourceElement", DefaultParameterSetName = nameof(Src)), Alias("source"), OutputType(typeof(string))] -public class NewSourceElementCommand(): NewElementCommand("source", isVoid: true) { - - /// - /// The intrinsic height of the image, in CSS pixels. - /// - [Parameter(ParameterSetName = nameof(SrcSet), ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int Height { get; set; } = -1; - - /// - /// The media query for the resource's intended media. - /// - [Parameter(ParameterSetName = nameof(SrcSet), ValueFromPipelineByPropertyName = true)] - public string? Media { get; set; } - - /// - /// A list of source sizes that describe the final rendered width of the image. - /// - [Parameter(ParameterSetName = nameof(SrcSet), ValueFromPipelineByPropertyName = true)] - public string[] Sizes { get; set; } = []; - - /// - /// The URL of the media resource - /// - [Parameter(Mandatory = true, ParameterSetName = nameof(Src), ValueFromPipelineByPropertyName = true)] - public required Uri Src { get; set; } - - /// - /// A list of one or more image URLs and their descriptors. - /// - [Parameter(Mandatory = true, ParameterSetName = nameof(SrcSet), ValueFromPipelineByPropertyName = true)] - public string[] SrcSet { get; set; } = []; - - /// - /// The media type to use, optionally including a codecs parameter. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Type { get; set; } - - /// - /// The intrinsic width of the image, in CSS pixels. - /// - [Parameter(ParameterSetName = nameof(SrcSet), ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int Width { get; set; } = -1; - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (!string.IsNullOrWhiteSpace(Type)) attributes["type"] = Type; - - switch (ParameterSetName) { - case nameof(Src): - attributes["src"] = Src.ToString(); - break; - - case nameof(SrcSet): - attributes["srcset"] = string.Join(", ", SrcSet); - if (Height >= 0) attributes["height"] = Height.ToString(CultureInfo.InvariantCulture); - if (!string.IsNullOrWhiteSpace(Media)) attributes["media"] = Media; - if (Sizes.Length > 0) attributes["sizes"] = string.Join(", ", Sizes); - if (Width >= 0) attributes["width"] = Width.ToString(CultureInfo.InvariantCulture); - break; - } - } -} diff --git a/src/Elements/New-SourceElement.psm1 b/src/Elements/New-SourceElement.psm1 new file mode 100644 index 0000000..e73672c --- /dev/null +++ b/src/Elements/New-SourceElement.psm1 @@ -0,0 +1,81 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `source` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlSourceElement", DefaultParameterSetName = nameof(Src)), Alias("source"), OutputType(typeof(string))] +function New-HtmlSourceElement: NewElementCommand("source", isVoid: true) { + + <# + .SYNOPSIS + The intrinsic height of the image, in CSS pixels. + #> + [Parameter(ParameterSetName = nameof(SrcSet)), ValidateRange(ValidateRangeKind.NonNegative)] + int Height = -1; + + <# + .SYNOPSIS + The media query for the resource's intended media. + #> + [Parameter(ParameterSetName = nameof(SrcSet))] + [string] $Media + + <# + .SYNOPSIS + A list of source sizes that describe the final rendered width of the image. + #> + [Parameter(ParameterSetName = nameof(SrcSet))] + [string[]] $Sizes = @(), + + <# + .SYNOPSIS + The URL of the media resource + #> + [Parameter(Mandatory, ParameterSetName = nameof(Src))] + required Uri Src + + <# + .SYNOPSIS + A list of one or more image URLs and their descriptors. + #> + [Parameter(Mandatory, ParameterSetName = nameof(SrcSet))] + [string[]] $SrcSet = @(), + + <# + .SYNOPSIS + The media type to use, optionally including a `codecs` parameter. + #> + [string] $Type + + <# + .SYNOPSIS + The intrinsic width of the image, in CSS pixels. + #> + [Parameter(ParameterSetName = nameof(SrcSet)), ValidateRange(ValidateRangeKind.NonNegative)] + int Width = -1; + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if ($Type) { $attributesToRender.type"] = Type; + + switch (ParameterSetName) { + case nameof(Src): + $attributesToRender.src"] = Src.ToString(); + break; + + case nameof(SrcSet): + $attributesToRender.srcset"] = string.Join(", ", SrcSet); + if (Height >= 0) $attributesToRender.height"] = Height + if ($Media) { $attributesToRender.media"] = Media; + if (Sizes.Length > 0) $attributesToRender.sizes"] = string.Join(", ", Sizes); + if (Width >= 0) $attributesToRender.width"] = Width + break; + } + } +} diff --git a/src/Elements/New-StyleElement.cs b/src/Elements/New-StyleElement.cs deleted file mode 100644 index f3f3bef..0000000 --- a/src/Elements/New-StyleElement.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new style element. -/// -[Cmdlet(VerbsCommon.New, "HtmlStyleElement"), Alias("style"), OutputType(typeof(string))] -public class NewStyleElementCommand(): NewElementCommand("style", isVoid: false) { - - /// - /// Defines which media the style should be applied to. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Media { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (!string.IsNullOrWhiteSpace(Media)) attributes["media"] = Media; - } -} diff --git a/src/Elements/New-StyleElement.psm1 b/src/Elements/New-StyleElement.psm1 new file mode 100644 index 0000000..b333be2 --- /dev/null +++ b/src/Elements/New-StyleElement.psm1 @@ -0,0 +1,25 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `style` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlStyleElement"), Alias("style"), OutputType(typeof(string))] +function New-HtmlStyleElement: NewElementCommand("style", isVoid: false) { + + <# + .SYNOPSIS + Defines which media the style should be applied to. + #> + [string] $Media + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if ($Media) { $attributesToRender.media"] = Media; + } +} diff --git a/src/Elements/New-TdElement.cs b/src/Elements/New-TdElement.cs deleted file mode 100644 index bb71239..0000000 --- a/src/Elements/New-TdElement.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new th element. -/// -[Cmdlet(VerbsCommon.New, "HtmlTdElement"), Alias("td"), OutputType(typeof(string))] -public class NewTdElementCommand(): NewElementCommand("td", isVoid: false) { - - /// - /// An integer indicating how many columns the header cell spans or extends. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int ColSpan { get; set; } = -1; - - /// - /// A list of strings corresponding to the id attributes of the th elements that provide the headers for this header cell. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string[] Headers { get; set; } = []; - - /// - /// An integer indicating how many rows the header cell spans or extends. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int RowSpan { get; set; } = -1; - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (ColSpan >= 0) attributes["colspan"] = ColSpan.ToString(CultureInfo.InvariantCulture); - if (Headers.Length > 0) attributes["headers"] = string.Join(' ', Headers).Trim(); - if (RowSpan >= 0) attributes["rowspan"] = RowSpan.ToString(CultureInfo.InvariantCulture); - } -} diff --git a/src/Elements/New-TdElement.psm1 b/src/Elements/New-TdElement.psm1 new file mode 100644 index 0000000..0603607 --- /dev/null +++ b/src/Elements/New-TdElement.psm1 @@ -0,0 +1,41 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `th` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlTdElement"), Alias("td"), OutputType(typeof(string))] +function New-HtmlTdElement: NewElementCommand("td", isVoid: false) { + + <# + .SYNOPSIS + An integer indicating how many columns the header cell spans or extends. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int ColSpan = -1; + + <# + .SYNOPSIS + A list of strings corresponding to the `id` attributes of the `th` elements that provide the headers for this header cell. + #> + [string[]] $Headers = @(), + + <# + .SYNOPSIS + An integer indicating how many rows the header cell spans or extends. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int RowSpan = -1; + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (ColSpan >= 0) $attributesToRender.colspan"] = ColSpan + if (Headers.Length > 0) $attributesToRender.headers"] = string.Join(' ', Headers).Trim(); + if (RowSpan >= 0) $attributesToRender.rowspan"] = RowSpan + } +} diff --git a/src/Elements/New-TemplateElement.cs b/src/Elements/New-TemplateElement.cs deleted file mode 100644 index 2cca45c..0000000 --- a/src/Elements/New-TemplateElement.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace Belin.Html.Elements; - -/// -/// Creates a new template element. -/// -[Cmdlet(VerbsCommon.New, "HtmlTemplateElement"), Alias("template"), OutputType(typeof(string))] -public class NewTemplateElementCommand(): NewElementCommand("template", isVoid: false) { - - /// - /// Value indicating whether the shadow root is clonable. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter ShadowRootClonable { get; set; } - - /// - /// Value indicating whether the shadow root delegates focus. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter ShadowRootDelegatesFocus { get; set; } - - /// - /// Value indicating whether to create a shadow root for the parent element. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("closed", "open")] - public string? ShadowRootMode { get; set; } - - /// - /// Value indicating whether the shadow root is serializable. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter ShadowRootSerializable { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (ShadowRootMode is not null) attributes["shadowrootmode"] = ShadowRootMode; - if (ShadowRootClonable) attributes["shadowrootclonable"] = true; - if (ShadowRootDelegatesFocus) attributes["shadowrootdelegatesfocus"] = true; - if (ShadowRootSerializable) attributes["shadowrootserializable"] = true; - } -} diff --git a/src/Elements/New-TemplateElement.psm1 b/src/Elements/New-TemplateElement.psm1 new file mode 100644 index 0000000..4f370c3 --- /dev/null +++ b/src/Elements/New-TemplateElement.psm1 @@ -0,0 +1,47 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `template` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlTemplateElement"), Alias("template"), OutputType(typeof(string))] +function New-HtmlTemplateElement: NewElementCommand("template", isVoid: false) { + + <# + .SYNOPSIS + Value indicating whether the shadow root is clonable. + #> + [switch] $ShadowRootClonable + + <# + .SYNOPSIS + Value indicating whether the shadow root delegates focus. + #> + [switch] $ShadowRootDelegatesFocus + + <# + .SYNOPSIS + Value indicating whether to create a shadow root for the parent element. + #> + [ValidateSet("closed", "open")] + [string] $ShadowRootMode + + <# + .SYNOPSIS + Value indicating whether the shadow root is serializable. + #> + [switch] $ShadowRootSerializable + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (ShadowRootMode is not null) $attributesToRender.shadowrootmode"] = ShadowRootMode; + if (ShadowRootClonable) $attributesToRender.shadowrootclonable"] = true; + if (ShadowRootDelegatesFocus) $attributesToRender.shadowrootdelegatesfocus"] = true; + if (ShadowRootSerializable) $attributesToRender.shadowrootserializable"] = true; + } +} diff --git a/src/Elements/New-TextareaElement.cs b/src/Elements/New-TextareaElement.cs deleted file mode 100644 index 2145bd8..0000000 --- a/src/Elements/New-TextareaElement.cs +++ /dev/null @@ -1,116 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new textarea element. -/// -[Cmdlet(VerbsCommon.New, "HtmlTextareaElement"), Alias("textarea"), OutputType(typeof(string))] -public class NewTextareaElementCommand(): NewElementCommand("textarea", isVoid: false) { - - /// - /// A hint for a user agent's autocomplete feature. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string[] AutoComplete { get; set; } = []; - - /// - /// Value indicating whether automatic spelling correction and processing of text is enabled. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("off", "on")] - public string? AutoCorrect { get; set; } - - /// - /// The visible width of the text control, in average character widths. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.Positive)] - public int Cols { get; set; } - - /// - /// The field name to use for sending the element's directionality in form submission. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? DirName { get; set; } - - /// - /// Value indicating whether to prevent the user from interacting with the element. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Disabled { get; set; } - - /// - /// The identifier of a form element to associate with the element. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Form { get; set; } - - /// - /// The maximum string length that the user can enter. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int MaxLength { get; set; } = -1; - - /// - /// The minimum string length required that the user should enter. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int MinLength { get; set; } = -1; - - /// - /// The name of the control. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Name { get; set; } - - /// - /// A hint to the user of what can be entered in the control. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Placeholder { get; set; } - - /// - /// Value indicating whether the user cannot modify the value of the control. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter ReadOnly { get; set; } - - /// - /// Value indicating whether the user must fill in a value before submitting a form. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Required { get; set; } - - /// - /// The number of visible text lines for the control. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.Positive)] - public int Rows { get; set; } - - /// - /// Value indicating whether the control should wrap the value for form submission. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("hard", "soft")] - public string? Wrap { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (AutoComplete.Length > 0) attributes["autocomplete"] = string.Join(' ', AutoComplete).Trim(); - if (AutoCorrect is not null) attributes["autocorrect"] = AutoCorrect; - if (Cols > 0) attributes["cols"] = Cols.ToString(CultureInfo.InvariantCulture); - if (!string.IsNullOrWhiteSpace(DirName)) attributes["dirname"] = DirName; - if (Disabled) attributes["disabled"] = true; - if (!string.IsNullOrWhiteSpace(Form)) attributes["form"] = Form; - if (MaxLength >= 0) attributes["maxlength"] = MaxLength.ToString(CultureInfo.InvariantCulture); - if (MinLength >= 0) attributes["minlength"] = MinLength.ToString(CultureInfo.InvariantCulture); - if (!string.IsNullOrWhiteSpace(Name)) attributes["name"] = Name; - if (!string.IsNullOrWhiteSpace(Placeholder)) attributes["placeholder"] = Placeholder; - if (ReadOnly) attributes["readonly"] = true; - if (Required) attributes["required"] = true; - if (Rows > 0) attributes["rows"] = Rows.ToString(CultureInfo.InvariantCulture); - if (Wrap is not null) attributes["wrap"] = Wrap; - } -} diff --git a/src/Elements/New-TextareaElement.psm1 b/src/Elements/New-TextareaElement.psm1 new file mode 100644 index 0000000..ebf5b95 --- /dev/null +++ b/src/Elements/New-TextareaElement.psm1 @@ -0,0 +1,122 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `textarea` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlTextareaElement"), Alias("textarea"), OutputType(typeof(string))] +function New-HtmlTextareaElement: NewElementCommand("textarea", isVoid: false) { + + <# + .SYNOPSIS + A hint for a user agent's autocomplete feature. + #> + [string[]] $AutoComplete = @(), + + <# + .SYNOPSIS + Value indicating whether automatic spelling correction and processing of text is enabled. + #> + [ValidateSet("off", "on")] + [string] $AutoCorrect + + <# + .SYNOPSIS + The visible width of the text control, in average character widths. + #> + [ValidateRange(ValidateRangeKind.Positive)] + int Cols + + <# + .SYNOPSIS + The field name to use for sending the element's directionality in form submission. + #> + [string] $DirName + + <# + .SYNOPSIS + Value indicating whether to prevent the user from interacting with the element. + #> + [switch] $Disabled + + <# + .SYNOPSIS + The identifier of a `form` element to associate with the element. + #> + [string] $Form + + <# + .SYNOPSIS + The maximum string length that the user can enter. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int MaxLength = -1; + + <# + .SYNOPSIS + The minimum string length required that the user should enter. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int MinLength = -1; + + <# + .SYNOPSIS + The name of the control. + #> + [string] $Name + + <# + .SYNOPSIS + A hint to the user of what can be entered in the control. + #> + [string] $Placeholder + + <# + .SYNOPSIS + Value indicating whether the user cannot modify the value of the control. + #> + [switch] $ReadOnly + + <# + .SYNOPSIS + Value indicating whether the user must fill in a value before submitting a form. + #> + [switch] $Required + + <# + .SYNOPSIS + The number of visible text lines for the control. + #> + [ValidateRange(ValidateRangeKind.Positive)] + int Rows + + <# + .SYNOPSIS + Value indicating whether the control should wrap the value for form submission. + #> + [ValidateSet("hard", "soft")] + [string] $Wrap + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (AutoComplete.Length > 0) $attributesToRender.autocomplete"] = string.Join(' ', AutoComplete).Trim(); + if (AutoCorrect is not null) $attributesToRender.autocorrect"] = AutoCorrect; + if (Cols > 0) $attributesToRender.cols"] = Cols + if ($DirName) { $attributesToRender.dirname"] = DirName; + if (Disabled) $attributesToRender.disabled"] = true; + if ($Form) { $attributesToRender.form"] = Form; + if (MaxLength >= 0) $attributesToRender.maxlength"] = MaxLength + if (MinLength >= 0) $attributesToRender.minlength"] = MinLength + if ($Name) { $attributesToRender.name"] = Name; + if ($Placeholder) { $attributesToRender.placeholder"] = Placeholder; + if (ReadOnly) $attributesToRender.readonly"] = true; + if (Required) $attributesToRender.required"] = true; + if (Rows > 0) $attributesToRender.rows"] = Rows + if (Wrap is not null) $attributesToRender.wrap"] = Wrap; + } +} diff --git a/src/Elements/New-ThElement.cs b/src/Elements/New-ThElement.cs deleted file mode 100644 index e8fd3f7..0000000 --- a/src/Elements/New-ThElement.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new th element. -/// -[Cmdlet(VerbsCommon.New, "HtmlThElement"), Alias("th"), OutputType(typeof(string))] -public class NewThElementCommand(): NewElementCommand("th", isVoid: false) { - - /// - /// A short, abbreviated description of the header cell's content provided as an alternative label to use for the header cell when referencing the cell in other contexts. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Abbr { get; set; } - - /// - /// An integer indicating how many columns the header cell spans or extends. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int ColSpan { get; set; } = -1; - - /// - /// A list of strings corresponding to the id attributes of the th elements that provide the headers for this header cell. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string[] Headers { get; set; } = []; - - /// - /// An integer indicating how many rows the header cell spans or extends. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int RowSpan { get; set; } = -1; - - /// - /// Defines the cells that the header element relates to. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("col", "colgroup", "row", "rowgroup")] - public string? Scope { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (!string.IsNullOrWhiteSpace(Abbr)) attributes["abbr"] = Abbr; - if (ColSpan >= 0) attributes["colspan"] = ColSpan.ToString(CultureInfo.InvariantCulture); - if (Headers.Length > 0) attributes["headers"] = string.Join(' ', Headers).Trim(); - if (RowSpan >= 0) attributes["rowspan"] = RowSpan.ToString(CultureInfo.InvariantCulture); - if (Scope is not null) attributes["scope"] = Scope; - } -} diff --git a/src/Elements/New-ThElement.psm1 b/src/Elements/New-ThElement.psm1 new file mode 100644 index 0000000..8b75251 --- /dev/null +++ b/src/Elements/New-ThElement.psm1 @@ -0,0 +1,56 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `th` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlThElement"), Alias("th"), OutputType(typeof(string))] +function New-HtmlThElement: NewElementCommand("th", isVoid: false) { + + <# + .SYNOPSIS + A short, abbreviated description of the header cell's content provided as an alternative label to use for the header cell when referencing the cell in other contexts. + #> + [string] $Abbr + + <# + .SYNOPSIS + An integer indicating how many columns the header cell spans or extends. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int ColSpan = -1; + + <# + .SYNOPSIS + A list of strings corresponding to the `id` attributes of the `th` elements that provide the headers for this header cell. + #> + [string[]] $Headers = @(), + + <# + .SYNOPSIS + An integer indicating how many rows the header cell spans or extends. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int RowSpan = -1; + + <# + .SYNOPSIS + Defines the cells that the header element relates to. + #> + [ValidateSet("col", "colgroup", "row", "rowgroup")] + [string] $Scope + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if ($Abbr) { $attributesToRender.abbr"] = Abbr; + if (ColSpan >= 0) $attributesToRender.colspan"] = ColSpan + if (Headers.Length > 0) $attributesToRender.headers"] = string.Join(' ', Headers).Trim(); + if (RowSpan >= 0) $attributesToRender.rowspan"] = RowSpan + if (Scope is not null) $attributesToRender.scope"] = Scope; + } +} diff --git a/src/Elements/New-TimeElement.cs b/src/Elements/New-TimeElement.psm1 similarity index 57% rename from src/Elements/New-TimeElement.cs rename to src/Elements/New-TimeElement.psm1 index 260771a..fd72353 100644 --- a/src/Elements/New-TimeElement.cs +++ b/src/Elements/New-TimeElement.psm1 @@ -1,29 +1,30 @@ -namespace Belin.Html.Elements; +using namespace System.Xml +using module ../Write-Element.psm1 -using System.Xml; - -/// -/// Creates a new time element. -/// +<# +.SYNOPSIS + Creates a new `time` element. +#> [Cmdlet(VerbsCommon.New, "HtmlTimeElement"), Alias("time"), OutputType(typeof(string))] -public class NewTimeElementCommand(): NewElementCommand("time", isVoid: false) { +function New-HtmlTimeElement: NewElementCommand("time", isVoid: false) { - /// - /// The time and/or date of the element. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public object? DateTime { get; set; } + <# + .SYNOPSIS + The time and/or date of the element. + #> + [object] $DateTime - /// - /// Populates the specified attribute collection with the element attributes. - /// + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> /// The attribute collection to populate. protected override void RenderAttributes(IDictionary attributes) { base.RenderAttributes(attributes); if (DateTime is not null) { try { - attributes["datetime"] = (DateTime is PSObject psObject ? psObject.BaseObject : DateTime) switch { + $attributesToRender.datetime"] = (DateTime is PSObject psObject ? psObject.BaseObject : DateTime) switch { DateOnly value => value.ToString("o"), DateTime value => value.ToString("o"), TimeOnly value => value.ToString("o"), diff --git a/src/Elements/New-TrackElement.cs b/src/Elements/New-TrackElement.cs deleted file mode 100644 index 97df30e..0000000 --- a/src/Elements/New-TrackElement.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new track element. -/// -[Cmdlet(VerbsCommon.New, "HtmlTrackElement"), Alias("track"), OutputType(typeof(string))] -public class NewTrackElementCommand(): NewElementCommand("track", isVoid: true) { - - /// - /// Value indicating whether the track should be enabled unless the user's preferences indicate that another track is more appropriate. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Default { get; set; } - - /// - /// Value indicating how the text track is meant to be used. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("captions", "chapters", "descriptions", "metadata", "subtitles")] - public string? Kind { get; set; } - - /// - /// A user-readable title of the text track which is used by the browser when listing available text tracks. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Label { get; set; } - - /// - /// The address of the track (.vtt file). - /// - [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)] - public required Uri Src { get; set; } - - /// - /// The language of the track text data. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public CultureInfo? SrcLang { get; set; } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - attributes["src"] = Src.ToString(); - if (Default) attributes["default"] = true; - if (Kind is not null) attributes["kind"] = Kind; - if (!string.IsNullOrWhiteSpace(Label)) attributes["label"] = Label; - if (SrcLang is not null) attributes["srclang"] = SrcLang.Name; - } -} diff --git a/src/Elements/New-TrackElement.psm1 b/src/Elements/New-TrackElement.psm1 new file mode 100644 index 0000000..9fe630b --- /dev/null +++ b/src/Elements/New-TrackElement.psm1 @@ -0,0 +1,55 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `track` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlTrackElement"), Alias("track"), OutputType(typeof(string))] +function New-HtmlTrackElement: NewElementCommand("track", isVoid: true) { + + <# + .SYNOPSIS + Value indicating whether the track should be enabled unless the user's preferences indicate that another track is more appropriate. + #> + [switch] $Default + + <# + .SYNOPSIS + Value indicating how the text track is meant to be used. + #> + [ValidateSet("captions", "chapters", "descriptions", "metadata", "subtitles")] + [string] $Kind + + <# + .SYNOPSIS + A user-readable title of the text track which is used by the browser when listing available text tracks. + #> + [string] $Label + + <# + .SYNOPSIS + The address of the track (`.vtt` file). + #> + [Parameter(Mandatory)] + required Uri Src + + <# + .SYNOPSIS + The language of the track text data. + #> + [cultureinfo] $SrcLang + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + $attributesToRender.src"] = Src.ToString(); + if (Default) $attributesToRender.default"] = true; + if (Kind is not null) $attributesToRender.kind"] = Kind; + if ($Label) { $attributesToRender.label"] = Label; + if (SrcLang is not null) $attributesToRender.srclang"] = SrcLang.Name; + } +} diff --git a/src/Elements/New-VideoElement.cs b/src/Elements/New-VideoElement.cs deleted file mode 100644 index c904aef..0000000 --- a/src/Elements/New-VideoElement.cs +++ /dev/null @@ -1,109 +0,0 @@ -namespace Belin.Html.Elements; - -using System.Globalization; - -/// -/// Creates a new video element. -/// -[Cmdlet(VerbsCommon.New, "HtmlVideoElement"), Alias("video"), OutputType(typeof(string))] -public class NewVideoElementCommand(): NewElementCommand("video", isVoid: false) { - - /// - /// Value indicating whether playback should start automatically as soon as the video signal allows. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter AutoPlay { get; set; } - - /// - /// Value indicating whether to offer controls to allow the user to control video playback. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Controls { get; set; } - - /// - /// Value indicating whether CORS must be used when fetching the resource. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("anonymous", "use-credentials")] - public string? CrossOrigin { get; set; } - - /// - /// Value indicating whether to prevent the browser from suggesting a Picture-in-Picture context menu or to request Picture-in-Picture automatically. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter DisablePictureInPicture { get; set; } - - /// - /// Value indicating whether to disable the capability of remote playback in devices that are attached using wired and wireless technologies. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter DisableRemotePlayback { get; set; } - - /// - /// The height of the video's display area, in CSS pixels. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int Height { get; set; } = -1; - - /// - /// Value indicating whether the video player will automatically seek back to the start upon reaching the end of the video. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Loop { get; set; } - - /// - /// Value indicating whether the audio will be initially silenced. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Muted { get; set; } - - /// - /// Value indicating whether the video is to be played "inline", that is, within the element's playback area. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter PlaysInline { get; set; } - - /// - /// The URL for an image to be shown while the video is downloading. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public Uri? Poster { get; set; } - - /// - /// Value providing a hint to the browser about what the author thinks will lead to the best user experience. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("auto", "none", "metadata")] - public string? Preload { get; set; } - - /// - /// The URL of the video to embed. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public Uri? Src { get; set; } - - /// - /// The width of the video's display area, in CSS pixels. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateRange(ValidateRangeKind.NonNegative)] - public int Width { get; set; } = -1; - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected override void RenderAttributes(IDictionary attributes) { - base.RenderAttributes(attributes); - if (AutoPlay) attributes["autoplay"] = true; - if (Controls) attributes["controls"] = true; - if (CrossOrigin is not null) attributes["crossorigin"] = CrossOrigin; - if (DisablePictureInPicture) attributes["disablepictureinpicture"] = true; - if (DisableRemotePlayback) attributes["disableremoteplayback"] = true; - if (Height >= 0) attributes["height"] = Height.ToString(CultureInfo.InvariantCulture); - if (Loop) attributes["loop"] = true; - if (Muted) attributes["muted"] = true; - if (PlaysInline) attributes["playsinline"] = true; - if (Poster is not null) attributes["poster"] = Poster.ToString(); - if (Preload is not null) attributes["preload"] = Preload; - if (Src is not null) attributes["src"] = Src.ToString(); - if (Width >= 0) attributes["width"] = Width.ToString(CultureInfo.InvariantCulture); - } -} diff --git a/src/Elements/New-VideoElement.psm1 b/src/Elements/New-VideoElement.psm1 new file mode 100644 index 0000000..f493770 --- /dev/null +++ b/src/Elements/New-VideoElement.psm1 @@ -0,0 +1,113 @@ +using module ../Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new `video` element. +#> +[Cmdlet(VerbsCommon.New, "HtmlVideoElement"), Alias("video"), OutputType(typeof(string))] +function New-HtmlVideoElement: NewElementCommand("video", isVoid: false) { + + <# + .SYNOPSIS + Value indicating whether playback should start automatically as soon as the video signal allows. + #> + [switch] $AutoPlay + + <# + .SYNOPSIS + Value indicating whether to offer controls to allow the user to control video playback. + #> + [switch] $Controls + + <# + .SYNOPSIS + Value indicating whether CORS must be used when fetching the resource. + #> + [ValidateSet("anonymous", "use-credentials")] + [string] $CrossOrigin + + <# + .SYNOPSIS + Value indicating whether to prevent the browser from suggesting a Picture-in-Picture context menu or to request Picture-in-Picture automatically. + #> + [switch] $DisablePictureInPicture + + <# + .SYNOPSIS + Value indicating whether to disable the capability of remote playback in devices that are attached using wired and wireless technologies. + #> + [switch] $DisableRemotePlayback + + <# + .SYNOPSIS + The height of the video's display area, in CSS pixels. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int Height = -1; + + <# + .SYNOPSIS + Value indicating whether the video player will automatically seek back to the start upon reaching the end of the video. + #> + [switch] $Loop + + <# + .SYNOPSIS + Value indicating whether the audio will be initially silenced. + #> + [switch] $Muted + + <# + .SYNOPSIS + Value indicating whether the video is to be played "inline", that is, within the element's playback area. + #> + [switch] $PlaysInline + + <# + .SYNOPSIS + The URL for an image to be shown while the video is downloading. + #> + Uri? Poster + + <# + .SYNOPSIS + Value providing a hint to the browser about what the author thinks will lead to the best user experience. + #> + [ValidateSet("auto", "none", "metadata")] + [string] $Preload + + <# + .SYNOPSIS + The URL of the video to embed. + #> + Uri? Src + + <# + .SYNOPSIS + The width of the video's display area, in CSS pixels. + #> + [ValidateRange(ValidateRangeKind.NonNegative)] + int Width = -1; + + <# + .SYNOPSIS + Populates the specified attribute collection with the element attributes. + #> + /// The attribute collection to populate. + protected override void RenderAttributes(IDictionary attributes) { + base.RenderAttributes(attributes); + if (AutoPlay) $attributesToRender.autoplay"] = true; + if (Controls) $attributesToRender.controls"] = true; + if (CrossOrigin is not null) $attributesToRender.crossorigin"] = CrossOrigin; + if (DisablePictureInPicture) $attributesToRender.disablepictureinpicture"] = true; + if (DisableRemotePlayback) $attributesToRender.disableremoteplayback"] = true; + if (Height >= 0) $attributesToRender.height"] = Height + if (Loop) $attributesToRender.loop"] = true; + if (Muted) $attributesToRender.muted"] = true; + if (PlaysInline) $attributesToRender.playsinline"] = true; + if (Poster is not null) $attributesToRender.poster"] = Poster.ToString(); + if (Preload is not null) $attributesToRender.preload"] = Preload; + if (Src is not null) $attributesToRender.src"] = Src.ToString(); + if (Width >= 0) $attributesToRender.width"] = Width + } +} diff --git a/src/Format-KebabCase.psm1 b/src/Format-KebabCase.psm1 new file mode 100644 index 0000000..d1451ca --- /dev/null +++ b/src/Format-KebabCase.psm1 @@ -0,0 +1,24 @@ +using namespace System.Text.Json + +<# +.SYNOPSIS + Converts the specified name according to lowercase kebab-casing. +.INPUTS + The name to convert. +.OUTPUTS + The converted name. +#> +function Format-KebabCase { + [CmdletBinding()] + [OutputType([string])] + param ( + # The name to convert. + [Parameter(Mandatory, Position = 0)] + [AllowEmptyString()] + [string] $InputObject + ) + + process { + [JsonNamingPolicy]::KebabCaseLower.ConvertName($InputObject) + } +} diff --git a/src/Html.csproj b/src/Html.csproj deleted file mode 100644 index 8e4f6ed..0000000 --- a/src/Html.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - Cedric-Belin.fr - © Cédric Belin - PowerShell cmdlets for rendering HTML documents. - HTML Renderer for PS - 1.2.0 - - - - false - Belin.Html - true - enable - enable - ../bin - Belin.Html - net10.0 - - - - - - - - - - diff --git a/src/New-CustomElement.cs b/src/New-CustomElement.cs deleted file mode 100644 index 59f302b..0000000 --- a/src/New-CustomElement.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace Belin.Html; - -/// -/// Creates a new custom element. -/// -[Cmdlet(VerbsCommon.New, "HtmlCustomElement"), Alias("tag"), OutputType(typeof(string))] -public class NewCustomElementCommand(): NewElementCommand("", isVoid: false) { - - /// - /// The inner HTML of the element. - /// - [Parameter(Position = 1, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] - public override object? Content { get => base.Content; set => base.Content = value; } - - /// - /// The tag name of the element to create. - /// - [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)] - public required string Name { get => TagName; set => TagName = value; } - - /// - /// Value indicating whether the element to create is a void element. - /// - [Parameter] - public SwitchParameter Void { get => IsVoid; set => IsVoid = value; } -} diff --git a/src/New-CustomElement.psm1 b/src/New-CustomElement.psm1 new file mode 100644 index 0000000..17f6b1f --- /dev/null +++ b/src/New-CustomElement.psm1 @@ -0,0 +1,36 @@ +using module ./Write-Element.psm1 + +<# +.SYNOPSIS + Creates a new custom element. +.INPUTS + The inner HTML of the custom element. +.OUTPUTS + The newly created custom element. +#> +function New-HtmlCustomElement { + [Alias("tag")] + [CmdletBinding()] + [OutputType([string])] + param ( + # The tag name of the custom element to create. + [Parameter(Mandatory, Position = 0)] + [ValidateScript({ + $index = $_.IndexOf("-") + ($index -gt 0) -and ($index -lt $_.Length) -and ($_.Length -ge 3) + }, ErrorMessage = "The specified tag name is not a valid custom element name.")] + [string] $TagName, + + # The inner HTML of the element. + [Parameter(Position = 1, ValueFromPipeline)] + [object] $Content, + + # The custom attributes to render. + [hashtable] $Attributes = @{} + ) + + process { + $MyInvocation.MyCommand.Parameters.Keys.ForEach{ $PSBoundParameters.Remove($_) | Out-Null } + Write-HtmlElement -TagName $TagName.ToLowerInvariant() -Attributes $Attributes.Clone() -Content $Content @PSBoundParameters + } +} diff --git a/src/New-Element.cs b/src/New-Element.cs deleted file mode 100644 index f81ce8c..0000000 --- a/src/New-Element.cs +++ /dev/null @@ -1,211 +0,0 @@ -namespace Belin.Html; - -using System.Collections; -using System.Globalization; -using System.Net; -using System.Text; -using System.Text.Json; - -/// -/// Provides the abstract base class for a cmdlet rendering an HTML element. -/// -/// The tag name of the element to create. -/// Value indicating whether the element to create is a void element. -public abstract class NewElementCommand(string tagName, bool isVoid = false): PSCmdlet { - - /// - /// The HTML-encoded string corresponding to a double quote. - /// - private static readonly string encodedDoubleQuote = WebUtility.HtmlEncode("\""); - - /// - /// The custom attributes to render. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public Hashtable Attributes { get; set; } = []; - - /// - /// Value indicating whether inputted text is automatically capitalized. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("characters", "none", "off", "on", "sentences", "words")] - public string? AutoCapitalize { get; set; } - - /// - /// Value indicating whether the element should have input focus when the page loads. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter AutoFocus { get; set; } - - /// - /// The CSS class names applied to the element. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string[] Class { get; set; } = []; - - /// - /// The inner HTML of the element. - /// - [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] - public virtual object? Content { get; set; } - - /// - /// Value indicating whether the element is editable by the user. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("false", "plaintext-only", "true")] - public string? ContentEditable { get; set; } - - /// - /// The data attributes to render. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public Hashtable DataSet { get; set; } = []; - - /// - /// The directionality of the element's text. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("auto", "ltr", "rtl")] - public string? Dir { get; set; } - - /// - /// Value indicating whether the element can be dragged. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("false", "true")] - public string? Draggable { get; set; } - - /// - /// Value indicating whether the browser should not render the contents of the element. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public SwitchParameter Hidden { get; set; } - - /// - /// The element identifier. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Id { get; set; } - - /// - /// A hint at the type of data that might be entered by the user while editing the element or its contents. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("decimal", "email", "none", "numeric", "search", "tel", "text", "url")] - public string? InputMode { get; set; } - - /// - /// The element's language. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public CultureInfo? Lang { get; set; } - - /// - /// Value indicating whether the element is a popover element. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("auto", "hint", "manual")] - public string? Popover { get; set; } - - /// - /// The event handler attributes to render. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public Hashtable On { get; set; } = []; - - /// - /// Value indicating whether the element is subject to spell-checking by the underlying browser/OS. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("false", "true")] - public string? SpellCheck { get; set; } - - /// - /// The CSS styling declarations applied to the element. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public OrderedHashtable Style { get; set; } = []; - - /// - /// Determines the relative ordering of the element for sequential focus navigation. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public int? TabIndex { get; set; } - - /// - /// A text representing advisory information related to the element. - /// - [Parameter(ValueFromPipelineByPropertyName = true)] - public string? Title { get; set; } - - /// - /// Value indicating whether the element's text should be translated when the page is localized. - /// - [Parameter(ValueFromPipelineByPropertyName = true), ValidateSet("no", "yes")] - public string? Translate { get; set; } - - /// - /// Value indicating whether the element to create is a void element. - /// - protected bool IsVoid { get; set; } = isVoid; - - /// - /// The tag name of the element to create. - /// - protected string TagName { get; set; } = tagName; - - /// - /// Performs execution of this command. - /// - protected override void ProcessRecord() { - var attributes = Attributes.Cast().ToDictionary(entry => entry.Key.ToString() ?? "", entry => entry.Value, StringComparer.OrdinalIgnoreCase); - RenderAttributes(attributes); - - var builder = new StringBuilder($"<{TagName}"); - foreach (var (key, value) in attributes.Where(attribute => attribute.Value is not null)) { - if (value is bool booleanValue) { - if (booleanValue) builder.Append($" {key}"); - } - else if (value is SwitchParameter switchParameter) { - if (switchParameter.IsPresent) builder.Append($" {key}"); - } - else { - var stringValue = Convert.ToString(value, CultureInfo.InvariantCulture)?.Replace("\"", encodedDoubleQuote); - builder.Append($" {key}=\"{stringValue}\""); - } - } - - if (IsVoid) builder.Append('>'); - else { - var output = Content is ScriptBlock scriptBlock ? scriptBlock.Invoke().Select(psObject => psObject.BaseObject) : (Content is not null ? [Content] : []); - builder.Append('>'); - foreach (var value in output) builder.Append(value); - builder.Append($""); - } - - WriteObject(builder.ToString()); - } - - /// - /// Populates the specified attribute collection with the element attributes. - /// - /// The attribute collection to populate. - protected virtual void RenderAttributes(IDictionary attributes) { - var kebabCase = JsonNamingPolicy.KebabCaseLower.ConvertName; - - if (!string.IsNullOrWhiteSpace(Id)) attributes["id"] = Id; - if (AutoCapitalize is not null) attributes["autocapitalize"] = AutoCapitalize; - if (AutoFocus) attributes["autofocus"] = true; - if (Class.Length > 0) attributes["class"] = string.Join(' ', Class).Trim(); - if (ContentEditable is not null) attributes["contenteditable"] = ContentEditable; - foreach (DictionaryEntry entry in DataSet) attributes[$"data-{kebabCase(entry.Key.ToString() ?? "")}"] = entry.Value; - if (Dir is not null) attributes["dir"] = Dir; - if (Draggable is not null) attributes["draggable"] = Draggable; - if (Hidden) attributes["hidden"] = true; - if (InputMode is not null) attributes["inputmode"] = InputMode; - if (Lang is not null) attributes["lang"] = Lang.Name; - foreach (DictionaryEntry entry in On) attributes[$"on{entry.Key.ToString()?.ToLowerInvariant()}"] = entry.Value; - if (Popover is not null) attributes["popover"] = Popover; - if (SpellCheck is not null) attributes["spellcheck"] = SpellCheck; - if (TabIndex is not null) attributes["tabindex"] = TabIndex.Value.ToString(CultureInfo.InvariantCulture); - if (!string.IsNullOrWhiteSpace(Title)) attributes["title"] = Title; - if (Translate is not null) attributes["translate"] = Translate; - - if (Style.Count > 0) attributes["style"] = string.Join("; ", Style.Cast() - .Select(entry => $"{kebabCase(entry.Key.ToString() ?? "")}: {Convert.ToString(entry.Value, CultureInfo.InvariantCulture)?.Replace("\"", encodedDoubleQuote)}")); - } -} diff --git a/src/Write-Element.psm1 b/src/Write-Element.psm1 new file mode 100644 index 0000000..e357ca6 --- /dev/null +++ b/src/Write-Element.psm1 @@ -0,0 +1,139 @@ +using namespace System.Collections.Specialized +using namespace System.Net +using namespace System.Text +using module ./Format-KebabCase.psm1 + +<# +.SYNOPSIS + The HTML-encoded string corresponding to a double quote. +#> +$EncodedDoubleQuote = [WebUtility]::HtmlEncode('"') + +<# +.SYNOPSIS + Creates a new HTML element. +.OUTPUTS + The newly created HTML element. +#> +function Write-HtmlElement { + [CmdletBinding()] + [OutputType([string])] + param ( + # The tag name of the element to create. + [Parameter(Mandatory)] + [string] $TagName, + + # The inner HTML of the element. + [Parameter(Position = 0, ValueFromPipeline)] + [object] $Content, + + # The custom attributes to render. + [hashtable] $Attributes = @{}, + + # Value indicating whether inputted text is automatically capitalized. + [ValidateSet("characters", "none", "off", "on", "sentences", "words")] + [string] $AutoCapitalize, + + # Value indicating whether the element should have input focus when the page loads. + [switch] $AutoFocus, + + # The CSS class names applied to the element. + [string[]] $Class = @(), + + # Value indicating whether the element is editable by the user. + [ValidateSet("false", "plaintext-only", "true")] + [string] $ContentEditable, + + # The data attributes to render. + [hashtable] $Data = @{}, + + # The directionality of the element's text. + [ValidateSet("auto", "ltr", "rtl")] + [string] $Dir, + + # Value indicating whether the element can be dragged. + [ValidateSet("false", "true")] + [string] $Draggable, + + # Value indicating whether the browser should not render the contents of the element. + [switch] $Hidden, + + # The element identifier. + [string] $Id, + + # A hint at the type of data that might be entered by the user while editing the element or its contents. + [ValidateSet("decimal", "email", "none", "numeric", "search", "tel", "text", "url")] + [string] $InputMode, + + # The element's language. + [cultureinfo] $Lang, + + # Value indicating whether the element is a popover element. + [ValidateSet("auto", "hint", "manual")] + [string] $Popover, + + # The event handler attributes to render. + [hashtable] $On = @{}, + + # Value indicating whether the element is subject to spell-checking by the underlying browser/OS. + [ValidateSet("false", "true")] + [string] $SpellCheck, + + # The CSS styling declarations applied to the element. + [OrderedDictionary] $Style = [ordered]@{}, + + # Determines the relative ordering of the element for sequential focus navigation. + [int] $TabIndex, + + # A text representing advisory information related to the element. + [string] $Title, + + # Value indicating whether the element's text should be translated when the page is localized. + [ValidateSet("no", "yes")] + [string] $Translate, + + # Value indicating whether the element to create is a void element. + [switch] $Void + ) + + process { + if ($Id) { $Attributes["id"] = $Id } + if ($AutoCapitalize) { $Attributes["autocapitalize"] = $AutoCapitalize } + if ($AutoFocus) { $Attributes["autofocus"] = $true } + if ($Class.Count) { $Attributes["class"] = ($Class -join " ").Trim() } + if ($ContentEditable) { $Attributes["contenteditable"] = $ContentEditable } + $Data.Keys.ForEach{ $Attributes["data-$(Format-KebabCase $_)"] = $Data.$_ } # TODO test numbers with comma / ToString() conversion + if ($Dir) { $Attributes["dir"] = $Dir } + if ($Draggable) { $Attributes["draggable"] = $Draggable } + if ($Hidden) { $Attributes["hidden"] = $true } + if ($InputMode) { $Attributes["inputmode"] = $InputMode } + if ($Lang) { $Attributes["lang"] = $Lang.Name } + $On.Keys.ForEach{ $Attributes["on$(([string] $_).ToLowerInvariant())"] = $On.$_ } # TODO test numbers with comma / ToString() conversion, double-quotes, etc. + if ($Popover) { $Attributes["popover"] = $Popover } + if ($SpellCheck) { $Attributes["spellcheck"] = $SpellCheck } + if ($Style.Count) { $Attributes["style"] = $Style.ForEach{ "$(Format-KebabCase $_.Key): $($_.Value)" } -join "; " } # TODO test numbers with comma / ToString() conversion, double-quotes, etc. + if ($TabIndex) { $Attributes["tabindex"] = $TabIndex } + if ($Title) { $Attributes["title"] = $Title } + if ($Translate) { $Attributes["translate"] = $Translate } + + # TODO test numbers with comma / ToString() conversion, double-quotes, etc. + $builder = [StringBuilder] "<$TagName" + foreach ($key in $Attributes.Keys) { + switch ($Attributes.$key) { + { $null -eq $_ } { break } + { $_ -is [bool] } { if ($_) { $builder.Append(" $key") | Out-Null }; break } + { $_ -is [switch] } { if ($_.IsPresent) { $builder.Append(" $key") | Out-Null }; break } + default { $builder.Append(" $key=""$(([string] $_).Replace('"', $Script:EncodedDoubleQuote))""") | Out-Null } + } + } + + $builder.Append(">") | Out-Null + if (-not $Void) { + $output = $Content -is [scriptblock] ? (& $Content) : ($null -ne $Content ? @($Content) : @()) + foreach ($value in $output) { $builder.Append($value) | Out-Null } + $builder.Append("") | Out-Null + } + + $builder.ToString() + } +} diff --git a/test/Elements/New-AElement.Tests.ps1 b/test/Elements/New-AElement.Tests.ps1 index 9841f87..d2c269c 100644 --- a/test/Elements/New-AElement.Tests.ps1 +++ b/test/Elements/New-AElement.Tests.ps1 @@ -9,24 +9,25 @@ Describe "New-AElement" { It 'should support the "download" attribute' { $expected = 'Click me', 'Click me' - a "Click me" -href Index.html -download Evil.js | Should -BeIn $expected + a "Click me" -Href Index.html -Download Evil.js | Should -BeIn $expected } It 'should support the "href" attribute' -ForEach "./Index.html", "mailto:dummy@example.com", "tel:+33123456789" { - a "Click me" -href $_ | Should -BeExactly "Click me" + a "Click me" -Href $_ | Should -BeExactly "Click me" } It 'should support the "ping" attribute' { - $expected = '', 'Click me' - a -href Index.html -ping "https://example.com/", Tracking.php | Should -BeIn $expected + $expected = '', '' + a -Href Index.html -Ping "https://example.com/", Tracking.php | Should -BeIn $expected } It 'should support the "rel" attribute' { - $expected = '', 'Click me' - a -href Index.html -rel external, nofollow | Should -BeIn $expected + $expected = '', '' + a -Href Index.html -Rel external, nofollow | Should -BeIn $expected } It 'should support the "target" attribute' -ForEach "_blank", "my-iframe" { - a "Click me" -href Index.html -target $_ | Should -BeExactly "Click me" + $expected = "Click me", "Click me" + a "Click me" -Href Index.html -Target $_ | Should -BeIn $expected } } diff --git a/test/Elements/New-AreaElement.Tests.ps1 b/test/Elements/New-AreaElement.Tests.ps1 index fef9f54..1d58c55 100644 --- a/test/Elements/New-AreaElement.Tests.ps1 +++ b/test/Elements/New-AreaElement.Tests.ps1 @@ -8,7 +8,7 @@ Describe "New-AreaElement" { } It 'should support the "shape" and "coords" attributes' { - $area = area -href Index.html -shape circle -coords 100, 200, 64.7 + $area = area -Href Index.html -Shape circle -Coords 100, 200, 64.7 $area | Should -BeLikeExactly "" + base -Href $_ | Should -BeExactly "" } It 'should support the "target" attribute' -ForEach "_blank", "my-iframe" { - base -href /base/ -target $_ | Should -BeExactly "" + base -Href /base/ -Target $_ | Should -BeExactly "" } } diff --git a/test/Elements/New-ButtonElement.Tests.ps1 b/test/Elements/New-ButtonElement.Tests.ps1 index a770353..9f1a90c 100644 --- a/test/Elements/New-ButtonElement.Tests.ps1 +++ b/test/Elements/New-ButtonElement.Tests.ps1 @@ -21,6 +21,6 @@ Describe "New-ButtonElement" { } It 'should support the "type" attribute' -ForEach button, reset, submit { - button -type $_ | Should -BeExactly "" + button -Type $_ | Should -BeExactly "" } } diff --git a/test/Elements/New-CanvasElement.Tests.ps1 b/test/Elements/New-CanvasElement.Tests.ps1 index a395c69..0f2d24b 100644 --- a/test/Elements/New-CanvasElement.Tests.ps1 +++ b/test/Elements/New-CanvasElement.Tests.ps1 @@ -8,7 +8,7 @@ Describe "New-CanvasElement" { } It 'should support the "height" and "width" attributes' { - canvas -height 200 | Should -BeExactly '' - canvas -width 460 | Should -BeExactly '' + canvas -Height 200 | Should -BeExactly '' + canvas -Width 460 | Should -BeExactly '' } } diff --git a/test/Elements/New-DetailsElement.Tests.ps1 b/test/Elements/New-DetailsElement.Tests.ps1 index 99470ea..1f1a4c0 100644 --- a/test/Elements/New-DetailsElement.Tests.ps1 +++ b/test/Elements/New-DetailsElement.Tests.ps1 @@ -8,7 +8,7 @@ Describe "New-DetailsElement" { } It 'should support the "name" attribute' { - details -name MyGroup | Should -BeExactly '
' + details -Name MyGroup | Should -BeExactly '
' } It 'should support the "open" attribute' { diff --git a/test/Elements/New-EmbedElement.Tests.ps1 b/test/Elements/New-EmbedElement.Tests.ps1 index d3db4a1..c5eb2a8 100644 --- a/test/Elements/New-EmbedElement.Tests.ps1 +++ b/test/Elements/New-EmbedElement.Tests.ps1 @@ -8,6 +8,6 @@ Describe "New-EmbedElement" { } It 'should support the "src" and "type" attributes' { - embed -src Image.jpg -type image/jpeg | Should -BeIn '', '' + embed -Src Image.jpg -Type image/jpeg | Should -BeIn '', '' } } diff --git a/test/Elements/New-FormElement.Tests.ps1 b/test/Elements/New-FormElement.Tests.ps1 index eab1976..b3c0f5b 100644 --- a/test/Elements/New-FormElement.Tests.ps1 +++ b/test/Elements/New-FormElement.Tests.ps1 @@ -24,7 +24,7 @@ Describe "New-FormElement" { } It "should allow inner content" { - form (button OK -type submit) | Should -BeExactly '
' - form (input -name UserName) | Should -BeExactly '
' + form (button OK -Type submit) | Should -BeExactly '
' + form (input -Name UserName) | Should -BeExactly '
' } } diff --git a/test/Elements/New-IframeElement.Tests.ps1 b/test/Elements/New-IframeElement.Tests.ps1 index d5fa52c..616d5e4 100644 --- a/test/Elements/New-IframeElement.Tests.ps1 +++ b/test/Elements/New-IframeElement.Tests.ps1 @@ -8,16 +8,16 @@ Describe "New-IframeElement" { } It 'should support the "height" and "width" attributes' { - iframe -src Index.php -height 200 | Should -BeIn '', '' - iframe -src Index.php -width 460 | Should -BeIn '', '' + iframe -Src Index.php -Height 200 | Should -BeIn '', '' + iframe -Src Index.php -Width 460 | Should -BeIn '', '' } It 'should support the "loading" attribute' -ForEach eager, lazy { - iframe -src Index.php -loading $_ | Should -BeIn "", "" + iframe -Src Index.php -loading $_ | Should -BeIn "", "" } It 'should support the "sandbox" attribute' { $expected = '', '' - iframe -src Index.php -sandbox allow-downloads, allow-popups | Should -BeIn $expected + iframe -Src Index.php -sandbox allow-downloads, allow-popups | Should -BeIn $expected } } diff --git a/test/Elements/New-ImgElement.Tests.ps1 b/test/Elements/New-ImgElement.Tests.ps1 index 15a653f..382b563 100644 --- a/test/Elements/New-ImgElement.Tests.ps1 +++ b/test/Elements/New-ImgElement.Tests.ps1 @@ -12,22 +12,22 @@ Describe "New-ImgElement" { @{ Src = "Assets/Icon.gif"; Alt = "" } @{ Src = "Assets/Picture.jpg"; Alt = "A label describing the image." } ) { - $img = img -src $src -alt $alt + $img = img -Src $src -Alt $alt if ($null -eq $alt) { $img | Should -BeExactly "" } else { $img | Should -BeIn "", "" } } It 'should support the "ismap" and "usemap" attributes' { - img -src Image.webp -ismap | Should -BeIn '', '' - img -src Image.webp -usemap my-map | Should -BeIn '', '' + img -Src Image.webp -ismap | Should -BeIn '', '' + img -Src Image.webp -usemap my-map | Should -BeIn '', '' } It 'should support the "height" and "width" attributes' { - img -src Image.webp -height 200 | Should -BeIn '', '' - img -src Image.webp -width 460 | Should -BeIn '', '' + img -Src Image.webp -Height 200 | Should -BeIn '', '' + img -Src Image.webp -Width 460 | Should -BeIn '', '' } It 'should support the "loading" attribute' -ForEach eager, lazy { - img -src Image.webp -loading $_ | Should -BeIn "", "" + img -Src Image.webp -loading $_ | Should -BeIn "", "" } } diff --git a/test/Elements/New-InputElement.Tests.ps1 b/test/Elements/New-InputElement.Tests.ps1 index c8b154a..0ebc764 100644 --- a/test/Elements/New-InputElement.Tests.ps1 +++ b/test/Elements/New-InputElement.Tests.ps1 @@ -63,6 +63,6 @@ Describe "New-InputElement" { @{ Type = "submit"; Value = "OK" } ) { $expected = "", "" - input -type $type -value $value | Should -BeIn $expected + input -Type $type -value $value | Should -BeIn $expected } } diff --git a/test/Elements/New-LinkElement.Tests.ps1 b/test/Elements/New-LinkElement.Tests.ps1 index 9b1e087..f68a969 100644 --- a/test/Elements/New-LinkElement.Tests.ps1 +++ b/test/Elements/New-LinkElement.Tests.ps1 @@ -8,17 +8,17 @@ Describe "New-LinkElement" { } It 'should support the "href" and "rel" attributes' { - link -rel icon -href /Favicon.ico | Should -BeExactly '' - link -rel stylesheet -href /Assets/Styles.css | Should -BeExactly '' + link -Rel icon -Href /Favicon.ico | Should -BeExactly '' + link -Rel stylesheet -Href /Assets/Styles.css | Should -BeExactly '' } It 'should support the "media" attribute' { - link -rel alternate, stylesheet -href Styles.css -media print | Should -BeExactly '' - link -rel stylesheet -href Styles.css -media "screen and (width >= 600px)" | Should -BeExactly '' + link -Rel alternate, stylesheet -Href Styles.css -media print | Should -BeExactly '' + link -Rel stylesheet -Href Styles.css -media "screen and (width >= 600px)" | Should -BeExactly '' } It 'should support the "sizes" attribute' { - link -rel icon -href Favicon.ico -sizes any | Should -BeExactly '' - link -rel icon -href Favicon.ico -sizes 320x200, 160x100 | Should -BeExactly '' + link -Rel icon -Href Favicon.ico -sizes any | Should -BeExactly '' + link -Rel icon -Href Favicon.ico -sizes 320x200, 160x100 | Should -BeExactly '' } } diff --git a/test/Elements/New-MapElement.Tests.ps1 b/test/Elements/New-MapElement.Tests.ps1 index 3e4ce1a..d9e6b45 100644 --- a/test/Elements/New-MapElement.Tests.ps1 +++ b/test/Elements/New-MapElement.Tests.ps1 @@ -8,6 +8,6 @@ Describe "New-MapElement" { } It 'should support the "name" attribute' { - map -name MyMap | Should -BeExactly '' + map -Name MyMap | Should -BeExactly '' } } diff --git a/test/Elements/New-MetaElement.Tests.ps1 b/test/Elements/New-MetaElement.Tests.ps1 index b3511ef..30efff8 100644 --- a/test/Elements/New-MetaElement.Tests.ps1 +++ b/test/Elements/New-MetaElement.Tests.ps1 @@ -8,20 +8,20 @@ Describe "New-MetaElement" { } It 'should support the "charset" attribute' -ForEach "iso-8859-1", "utf-8" { - meta -charset $_ | Should -BeExactly "" + meta -Charset $_ | Should -BeExactly "" } It 'should support the "http-equiv" and "content" attributes' -ForEach @( @{ HttpEquiv = "content-type"; Content = "text/html; charset=utf-8" } @{ HttpEquiv = "refresh"; Content = 300 } ) { - meta -httpEquiv $httpEquiv -content $content | Should -BeExactly "" + meta -httpEquiv $httpEquiv -Content $content | Should -BeExactly "" } It 'should support the "name" and "content" attributes' -ForEach @( @{ Name = "application-name"; Content = "Belin.Html" } @{ Name = "color-scheme"; Content = "light dark" } ) { - meta -name $name -content $content | Should -BeExactly "" + meta -Name $name -Content $content | Should -BeExactly "" } } diff --git a/test/Elements/New-ObjectElement.Tests.ps1 b/test/Elements/New-ObjectElement.Tests.ps1 index 5bad26b..f4461e6 100644 --- a/test/Elements/New-ObjectElement.Tests.ps1 +++ b/test/Elements/New-ObjectElement.Tests.ps1 @@ -8,6 +8,6 @@ Describe "New-ObjectElement" { } It 'should support the "data" and "type" attributes' { - object -data Image.jpg -type image/jpeg | Should -BeIn '', '' + object -Data Image.jpg -Type image/jpeg | Should -BeIn '', '' } } diff --git a/test/Elements/New-OlElement.Tests.ps1 b/test/Elements/New-OlElement.Tests.ps1 index a101e51..9a3d1cc 100644 --- a/test/Elements/New-OlElement.Tests.ps1 +++ b/test/Elements/New-OlElement.Tests.ps1 @@ -12,6 +12,6 @@ Describe "New-OlElement" { } It 'should support the "type" attribute' -ForEach 1, A, a, I, i { - ol -type $_ | Should -BeExactly "
    " + ol -Type $_ | Should -BeExactly "
      " } } diff --git a/test/Elements/New-ScriptElement.Tests.ps1 b/test/Elements/New-ScriptElement.Tests.ps1 index 0c49839..a01cba4 100644 --- a/test/Elements/New-ScriptElement.Tests.ps1 +++ b/test/Elements/New-ScriptElement.Tests.ps1 @@ -11,20 +11,20 @@ Describe "New-ScriptElement" { @{ Src = "Scripts.js"; Type = "module" } @{ Src = "Scripts._hs"; Type = "text/hyperscript" } ) { - script -src $src -type $type | Should -BeExactly "" + script -Src $src -Type $type | Should -BeExactly "" } It 'should support the "async" and "defer" attributes' -ForEach @( @{ Async = $true; Defer = $false } @{ Async = $false; Defer = $true } ) { - script -src Scripts.js -async:$async -defer:$defer | Should -BeExactly ($async ? '' : '') + script -Src Scripts.js -async:$async -defer:$defer | Should -BeExactly ($async ? '' : '') } It "should allow inner content" -ForEach @( @{ Content = "alert('Hello World!');"; Type = "" } @{ Content = "on click call alert('Hello World!')"; Type = "text/hyperscript" } ) { - script $content -type $type | Should -BeExactly ($type ? "" : "") + script $content -Type $type | Should -BeExactly ($type ? "" : "") } } diff --git a/test/Elements/New-SlotElement.Tests.ps1 b/test/Elements/New-SlotElement.Tests.ps1 index d8fce58..6d22f5d 100644 --- a/test/Elements/New-SlotElement.Tests.ps1 +++ b/test/Elements/New-SlotElement.Tests.ps1 @@ -8,6 +8,6 @@ Describe "New-SlotElement" { } It 'should support the "name" attribute' { - slot -name MyMap | Should -BeExactly '' + slot -Name MyMap | Should -BeExactly '' } } diff --git a/test/Elements/New-SourceElement.Tests.ps1 b/test/Elements/New-SourceElement.Tests.ps1 index 719e6f5..a833e90 100644 --- a/test/Elements/New-SourceElement.Tests.ps1 +++ b/test/Elements/New-SourceElement.Tests.ps1 @@ -8,7 +8,7 @@ Describe "New-SourceElement" { } It 'should support the "src" and "type" attributes' { - source -src Video.webm -type video/webm | Should -BeIn '', '' + source -Src Video.webm -Type video/webm | Should -BeIn '', '' } It 'should support the "srcset" and "media" attributes' { diff --git a/test/Elements/New-TemplateElement.Tests.ps1 b/test/Elements/New-TemplateElement.Tests.ps1 index b22dda4..3b8f003 100644 --- a/test/Elements/New-TemplateElement.Tests.ps1 +++ b/test/Elements/New-TemplateElement.Tests.ps1 @@ -25,6 +25,6 @@ Describe "New-TemplateElement" { It "should allow inner content" { template (b "Hello World!") | Should -BeExactly "" - template (button OK -type submit) | Should -BeExactly '' + template (button OK -Type submit) | Should -BeExactly '' } } diff --git a/test/Elements/New-TrackElement.Tests.ps1 b/test/Elements/New-TrackElement.Tests.ps1 index 01a8833..1e316ea 100644 --- a/test/Elements/New-TrackElement.Tests.ps1 +++ b/test/Elements/New-TrackElement.Tests.ps1 @@ -8,10 +8,10 @@ Describe "New-TrackElement" { } It 'should support the "default" attribute' { - track -src Subtitles.vtt -default | Should -BeIn '', '' + track -Src Subtitles.vtt -default | Should -BeIn '', '' } It 'should support the "kind" attribute' -ForEach captions, chapters, descriptions, metadata, subtitles { - track -src Subtitles.vtt -kind $_ | Should -BeIn "", "" + track -Src Subtitles.vtt -kind $_ | Should -BeIn "", "" } } diff --git a/test/Elements/New-VideoElement.Tests.ps1 b/test/Elements/New-VideoElement.Tests.ps1 index 30f4edb..1dc69a7 100644 --- a/test/Elements/New-VideoElement.Tests.ps1 +++ b/test/Elements/New-VideoElement.Tests.ps1 @@ -23,6 +23,6 @@ Describe "New-VideoElement" { } It 'should support the "height" and "width" attributes' { - video -width 460 -height 200 | Should -BeIn '', '' + video -Width 460 -Height 200 | Should -BeIn '', '' } } diff --git a/test/New-CustomElement.Tests.ps1 b/test/New-CustomElement.Tests.ps1 index b190bf2..2f4a49b 100644 --- a/test/New-CustomElement.Tests.ps1 +++ b/test/New-CustomElement.Tests.ps1 @@ -11,45 +11,41 @@ Describe "New-CustomElement" { tag my-element | Should -BeExactly "" } - It "should handle void elements" { - tag my-element -Void | Should -BeExactly "" - } - It 'should handle the "id" attribute' { - tag my-element -id foo | Should -BeExactly '' + tag my-element -Id foo | Should -BeExactly '' } It 'should handle the "class" attribute' { - tag my-element -class btn, btn-danger | Should -BeExactly '' - tag my-element -class "btn btn-info", btn-sm | Should -BeExactly '' + tag my-element -Class btn, btn-danger | Should -BeExactly '' + tag my-element -Class "btn btn-info", btn-sm | Should -BeExactly '' } It 'should handle the "style" attribute' { $expected = '' - tag my-element -style ([ordered]@{ FontFamily = '"Segoe UI"'; FontSize = "1rem" }) | Should -BeExactly $expected + tag my-element -Style ([ordered]@{ FontFamily = '"Segoe UI"'; FontSize = "1rem" }) | Should -BeExactly $expected } It 'should handle the "tabindex" attribute' -ForEach -1, 0 { - tag my-element -tabindex $_ | Should -BeExactly "" + tag my-element -TabIndex $_ | Should -BeExactly "" } It 'should handle the "title" attribute' -ForEach "", 'A "custom" label.' { - tag my-element -title $_ | Should -BeExactly ($_ ? '' : "") + tag my-element -Title $_ | Should -BeExactly ($_ ? '' : "") } It "should handle custom attributes" { $expected = '', '' - tag my-element -attributes @{ "data-foo" = '"bar"'; disabled = $false; required = $true } -Void | Should -BeIn $expected + tag my-element -Attributes @{ "data-foo" = '"bar"'; disabled = $false; required = $true } -Void | Should -BeIn $expected } It "should handle data attributes" { $expected = '', '' - tag my-element -dataset @{ BsToggle = "tooltip"; PushUrl = $true } | Should -BeIn $expected + tag my-element -Data @{ BsToggle = "tooltip"; PushUrl = $true } | Should -BeIn $expected } It "should handle event handler attributes" { $expected = '', '' - tag my-element -on @{ Click = "submit(event)"; ContextMenu = "showMenu()" } | Should -BeIn $expected + tag my-element -On @{ Click = "submit(event)"; ContextMenu = "showMenu()" } | Should -BeIn $expected } It "should handle the inner content" { diff --git a/test/New-DocumentType.Tests.ps1 b/test/New-DocumentType.Tests.ps1 index 383a923..91f4a08 100644 --- a/test/New-DocumentType.Tests.ps1 +++ b/test/New-DocumentType.Tests.ps1 @@ -8,7 +8,7 @@ Describe "New-DocumentType" { } It "should return a document type declaration" -ForEach @( - @{ Value = ""; Expected = "" } + @{ Value = $null; Expected = "" } @{ Value = 'html public "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"'; Expected = '' } @{ Value = 'html public "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"'; Expected = ''} ) { diff --git a/test/Use-Layout.Tests.ps1 b/test/Use-Layout.Tests.ps1 index bdfbde2..a39bac7 100644 --- a/test/Use-Layout.Tests.ps1 +++ b/test/Use-Layout.Tests.ps1 @@ -9,7 +9,7 @@ Describe "Use-Layout" { It "should render the specified HTML content inside the given layout" { $data = @{ AppName = "My Application"; Title = "The headline"; Year = 2025 } - $html = layout "$PSScriptRoot/../res/Layout.ps1" (& "$PSScriptRoot/../res/Content.ps1" $data) -data $data + $html = layout "$PSScriptRoot/../res/Layout.ps1" (& "$PSScriptRoot/../res/Content.ps1" $data) -Data $data $html | Should -BeLikeExactly '*My Application*' $html | Should -BeLikeExactly '*
      *
      My Application
      *
      *' $html | Should -BeLikeExactly '*

      The headline

      Welcome to my website!
      *' diff --git a/test/New-Element.Tests.ps1 b/test/Write-Element.Tests.ps1 similarity index 69% rename from test/New-Element.Tests.ps1 rename to test/Write-Element.Tests.ps1 index 9baad47..ea9491f 100644 --- a/test/New-Element.Tests.ps1 +++ b/test/Write-Element.Tests.ps1 @@ -1,8 +1,8 @@ <# .SYNOPSIS - Tests the features of the `New-Element` cmdlet. + Tests the features of the `Write-Element` cmdlet. #> -Describe "New-Element" { +Describe "Write-Element" { BeforeAll { Import-Module "$PSScriptRoot/../Html.psd1" } @@ -22,52 +22,52 @@ Describe "New-Element" { } It 'should handle the "class" attribute' { - body -class btn, btn-danger | Should -BeExactly '' - body -class "btn btn-info", btn-sm | Should -BeExactly '' + body -Class btn, btn-danger | Should -BeExactly '' + body -Class "btn btn-info", btn-sm | Should -BeExactly '' } It 'should support the "dir" attribute' -ForEach auto, ltr, rtl { - html -dir $_ | Should -BeExactly "" + html -Dir $_ | Should -BeExactly "" } It 'should handle the "id" attribute' { - article -id foo | Should -BeExactly '
      ' + article -Id foo | Should -BeExactly '
      ' } It 'should support the "lang" attribute' -ForEach "fr-FR", "en-US" { - html -lang $_ | Should -BeExactly "" + html -Lang $_ | Should -BeExactly "" } It 'should handle the "style" attribute' { $expected = '' - code -style ([ordered]@{ FontFamily = '"Segoe UI"'; FontSize = "1rem" }) | Should -BeExactly $expected + code -Style ([ordered]@{ FontFamily = '"Segoe UI"'; FontSize = "1rem" }) | Should -BeExactly $expected } It 'should handle the "tabindex" attribute' -ForEach -1, 0 { - div -tabindex $_ | Should -BeExactly "
      " + div -TabIndex $_ | Should -BeExactly "
      " } It 'should handle the "title" attribute' -ForEach "", 'A "custom" label.' { - div -title $_ | Should -BeExactly ($_ ? '
      ' : "
      ") + div -Title $_ | Should -BeExactly ($_ ? '
      ' : "
      ") } It "should handle custom attributes" { $expected = '', '' - input -attributes @{ "data-foo" = '"bar"'; disabled = $false; required = $true } | Should -BeIn $expected + input -Attributes @{ "data-foo" = '"bar"'; disabled = $false; required = $true } | Should -BeIn $expected } It "should handle data attributes" { $expected = '', '' - button -dataset @{ BsToggle = "tooltip"; PushUrl = $true } | Should -BeIn $expected + button -Data @{ BsToggle = "tooltip"; PushUrl = $true } | Should -BeIn $expected } It "should handle event handler attributes" { $expected = '', '' - button -on @{ Click = "submit(event)"; ContextMenu = "showMenu()" } | Should -BeIn $expected + button -On @{ Click = "submit(event)"; ContextMenu = "showMenu()" } | Should -BeIn $expected } It "should handle switch parameters in attribute values" { - input -attributes @{ disabled = [switch] $false; required = [switch] $true } | Should -BeExactly "" + input -Attributes @{ disabled = [switch] $false; required = [switch] $true } | Should -BeExactly "" } It "should handle the inner content" { @@ -75,6 +75,6 @@ Describe "New-Element" { main { div { "Foo > Bar"; " "; span "Baz < Qux" } } | Should -BeExactly $expected $expected = '' - head { meta -charset utf-8 } | Should -BeExactly $expected + head { meta -Charset utf-8 } | Should -BeExactly $expected } } diff --git a/tool/Assets.ps1 b/tool/Assets.ps1 deleted file mode 100644 index 7c166c0..0000000 --- a/tool/Assets.ps1 +++ /dev/null @@ -1,28 +0,0 @@ -using namespace System.Collections.Generic - -"Deploying the assets..." -$cmdletTemplate = Get-Content share/Cmdlet.Template.cs -Raw -$cmdletsToExport = [List[string]]::new([string[]] @("New-HtmlCustomElement")) - -New-Item src/Generated -Force -ItemType Directory | Out-Null -foreach ($element in (Import-PowerShellDataFile share/HtmlElements.psd1).Elements) { - $parameters = @{ - Alias = (Get-Alias $element.Tag -ErrorAction Ignore) ? "$($element.Tag)Tag" : $element.Tag - CapitalizedTag = [char]::ToUpperInvariant($element.Tag[0]) + $element.Tag.Substring(1) - IsVoid = $element.IsVoid.ToString().ToLowerInvariant() - Tag = $element.Tag - } - - $cmdletsToExport.Add("New-Html$($parameters.CapitalizedTag)Element") - $fileName = "New-$($parameters.CapitalizedTag)Element" - if (Test-Path "src/Elements/$fileName.cs") { continue } - - $content = $cmdletTemplate - foreach ($key in $parameters.Keys) { $content = $content -replace "{$key}", $parameters.$key } - Set-Content "src/Generated/$fileName.g.cs" $content -NoNewline -} - -$cmdletsToExport.Sort() -$cmdlets = $cmdletsToExport.PSForEach{ "`t`t""$_""" } -join [Environment]::NewLine -$content = (Get-Content Html.psd1 -Raw) -replace "CmdletsToExport = @\([^)]+\)", "CmdletsToExport = @(`n$cmdlets`n`t)" -Set-Content Html.psd1 $content -NoNewline diff --git a/tool/Build.ps1 b/tool/Build.ps1 index ad2af98..b76af26 100644 --- a/tool/Build.ps1 +++ b/tool/Build.ps1 @@ -1,5 +1,67 @@ -using module ./Cmdlets.psm1 -& "$PSScriptRoot/Assets.ps1" +using namespace System.Collections.Generic -"Building the solution..." -Build-DotNetSolution ($Release ? "Release" : "Debug") +"Deploying the assets..." +$cmdlets = [pscustomobject]@{ + Aliases = [List[string]]::new([string[]] @( + "doctype" # New-HtmlDocumentType + # "layout" # Use-HtmlLayout + "tag" # New-HtmlCustomElement + )) + Functions = [List[string]]::new([string[]] @( + "New-HtmlCustomElement" + "New-HtmlDocumentType" + # "Use-HtmlLayout" + # "Write-HtmlView" + )) + Modules = [List[string]]::new([string[]] @( + "src/New-CustomElement.psm1" + "src/New-DocumentType.psm1" + # "src/Use-Layout.psm1" + # "src/Write-View.psm1" + )) +} + +# Generate the cmdlets. +New-Item src/Generated -Force -ItemType Directory | Out-Null +$cmdletTemplate = Get-Content share/Cmdlet.Template.psm1 -Raw + +foreach ($element in (Import-PowerShellDataFile share/HtmlElements.psd1).Elements) { + $parameters = @{ + Alias = (Get-Alias $element.Tag -ErrorAction Ignore) ? "$($element.Tag)Tag" : $element.Tag + CapitalizedTag = [char]::ToUpperInvariant($element.Tag[0]) + $element.Tag.Substring(1) + IsVoid = $element.IsVoid.ToString().ToLowerInvariant() + Tag = $element.Tag + } + + $cmdlets.Aliases.Add($parameters.Alias) + $cmdlets.Functions.Add("New-Html$($parameters.CapitalizedTag)Element") + + $fileName = "New-$($parameters.CapitalizedTag)Element" + $existingCmdlet = "src/Elements/$fileName.psm1" + if (Test-Path $existingCmdlet) { $cmdlets.Modules.Add($existingCmdlet) } + else { + $generatedCmdlet = "src/Generated/$fileName.g.psm1" + $cmdlets.Modules.Add($generatedCmdlet) + + $content = $cmdletTemplate + foreach ($key in $parameters.Keys) { $content = $content -replace "{$key}", $parameters.$key } + Set-Content $generatedCmdlet $content -NoNewline + } +} + +# Update the module manifest. +$cmdlets.Aliases.Sort() +$aliases = $cmdlets.Aliases.PSForEach{ "`t`t""$_""" } -join [Environment]::NewLine + +$cmdlets.Functions.Sort() +$functions = $cmdlets.Functions.PSForEach{ "`t`t""$_""" } -join [Environment]::NewLine + +$cmdlets.Modules.Sort() +$modules = $cmdlets.Modules.PSForEach{ "`t`t""$_""" } -join [Environment]::NewLine + +$content = (Get-Content Html.psd1 -Raw) ` + -replace "AliasesToExport = @\([^)]+\)", "AliasesToExport = @(`n$aliases`n`t)" ` + -replace "FunctionsToExport = @\([^)]+\)", "FunctionsToExport = @(`n$functions`n`t)" ` + -replace "NestedModules = @\([^)]+\)", "NestedModules = @(`n$modules`n`t)" + +Set-Content Html.psd1 $content -NoNewline diff --git a/tool/Clean.ps1 b/tool/Clean.ps1 index d5e902d..e463583 100644 --- a/tool/Clean.ps1 +++ b/tool/Clean.ps1 @@ -1,4 +1,3 @@ "Deleting all generated files..." -Remove-Item bin, src/Generated -ErrorAction Ignore -Force -Recurse -Remove-Item */obj -Force -Recurse +Remove-Item src/Generated -ErrorAction Ignore -Force -Recurse Remove-Item var/* -Exclude .gitkeep -Force -Recurse diff --git a/tool/Cmdlets.psm1 b/tool/Cmdlets.psm1 index bc2d5fa..d7e2f45 100644 --- a/tool/Cmdlets.psm1 +++ b/tool/Cmdlets.psm1 @@ -1,69 +1,8 @@ -using namespace System.Diagnostics.CodeAnalysis - -<# -.SYNOPSIS - Builds the .NET solution and all of its dependencies. -#> -function Build-DotNetSolution { - param ( - # The configuration to use for generating the project. - [Parameter(Position = 0)] - [string] $Configuration - ) - - $argumentList = $Configuration ? "--configuration", $Configuration : @() - dotnet build @argumentList -} - -<# -.SYNOPSIS - Applies style preferences and static analysis recommendations to the .NET solution. -#> -function Format-DotNetSolution { - dotnet format -} - -<# -.SYNOPSIS - Invokes the .NET test runner. -#> -function Invoke-DotNetTest { - param ( - # The path to the settings file to use for running the tests. - [ValidateScript({ Test-Path $_ -PathType Leaf }, ErrorMessage = "The specified settings file does not exist.")] - [string] $Settings - ) - - $argumentList = $Settings ? "--settings", $Settings : @() - dotnet test @argumentList -} - -<# -.SYNOPSIS - Invokes the PowerShell test runner. -#> -function Invoke-PowerShellTest { - param ( - # The path to the file or directory to be tested. - [Parameter(Mandatory, Position = 0)] - [string[]] $Path, - - # Value indicating whether, on completion of the tests, to exit the PowerShell session - # and return an exit code equal to the number of failed tests. - [switch] $EnableExit - ) - - Import-Module Pester - Invoke-Pester $Path - if ($EnableExit) { exit $LASTEXITCODE } -} - <# .SYNOPSIS Creates a new Git tag. #> function New-GitTag { - [SuppressMessage("PSUseShouldProcessForStateChangingFunctions", "")] param ( # The tag name. [Parameter(Mandatory, Position = 0)] @@ -76,42 +15,21 @@ function New-GitTag { <# .SYNOPSIS - Publishes the project package to the NuGet registry. + Publishes the project package to the PowerShell Gallery registry. #> -function Publish-NuGetPackage { - param ( - # Value indicating whether to not build the solution before compression. - [switch] $NoBuild - ) +function Publish-PSGalleryModule { + $root = Join-Path $PSScriptRoot .. - $output = "$PSScriptRoot/../var/NuGet" - $argumentList = "--output", $output - if ($NoBuild) { $argumentList += "--no-build" } - dotnet pack @argumentList - foreach ($package in Get-Item $output/*.nupkg) { dotnet nuget push $package --api-key $Env:NUGET_API_KEY --source NuGet } -} + $output = "$root/var/PSModule" + New-Item $output -ItemType Directory | Out-Null + Copy-Item $root/Html.psd1 $output/Belin.Html.psd1 + Copy-Item $root/*.md $output + Copy-Item $root/src $output -Recurse -<# -.SYNOPSIS - Installs the specified NuGet package, if any. Otherwise, installs all packages. -#> -function Restore-NuGetPackage { - param ( - # The package to install. - [Parameter(Position = 0)] - [string] $Package - ) - - if ($Package) { dotnet package add $Package } - else { dotnet restore } -} - -<# -.SYNOPSIS - Checks whether an update is available for the NuGet packages. -#> -function Test-NuGetPackageUpdate { - dotnet package list --outdated + $output = "$root/var/PSGallery" + New-Item $output -ItemType Directory | Out-Null + Compress-PSResource $root/var/PSModule $output + foreach ($package in Get-Item $output/*.nupkg) { Publish-PSResource -ApiKey $Env:PSGALLERY_API_KEY -NupkgPath $package -Repository PSGallery } } <# diff --git a/tool/Default.ps1 b/tool/Default.ps1 index b3a7a6a..df4ed3b 100644 --- a/tool/Default.ps1 +++ b/tool/Default.ps1 @@ -1,3 +1,2 @@ & "$PSScriptRoot/Clean.ps1" -& "$PSScriptRoot/Version.ps1" & "$PSScriptRoot/Build.ps1" diff --git a/tool/Format.ps1 b/tool/Format.ps1 deleted file mode 100644 index 4b16ae6..0000000 --- a/tool/Format.ps1 +++ /dev/null @@ -1,4 +0,0 @@ -using module ./Cmdlets.psm1 - -"Formatting the source code..." -Format-DotNetSolution diff --git a/tool/Install.ps1 b/tool/Install.ps1 index 4795143..6687fd2 100644 --- a/tool/Install.ps1 +++ b/tool/Install.ps1 @@ -1,5 +1,2 @@ -using module ./Cmdlets.psm1 - "Installing the dependencies..." Install-PSResource -RequiredResourceFile PSModules.psd1 -TrustRepository -WarningAction Ignore -Restore-NuGetPackage diff --git a/tool/Lint.ps1 b/tool/Lint.ps1 index 50086db..4a26630 100644 --- a/tool/Lint.ps1 +++ b/tool/Lint.ps1 @@ -1,5 +1,5 @@ using module PSScriptAnalyzer "Performing the static analysis of source code..." -Invoke-ScriptAnalyzer $PSScriptRoot, "test" -Recurse +$PSScriptRoot, "src", "test" | Invoke-ScriptAnalyzer -ExcludeRule PSUseShouldProcessForStateChangingFunctions -Recurse Test-ModuleManifest Html.psd1 | Out-Null diff --git a/tool/Outdated.ps1 b/tool/Outdated.ps1 index e228eee..35b5327 100644 --- a/tool/Outdated.ps1 +++ b/tool/Outdated.ps1 @@ -2,4 +2,3 @@ using module ./Cmdlets.psm1 "Checking for outdated dependencies..." (Import-PowerShellDataFile PSModules.psd1).Keys | Get-InstalledPSResource | Test-PSResourceUpdate -Test-NuGetPackageUpdate diff --git a/tool/Publish.ps1 b/tool/Publish.ps1 index b23e112..d92ea26 100644 --- a/tool/Publish.ps1 +++ b/tool/Publish.ps1 @@ -1,24 +1,7 @@ using module ./Cmdlets.psm1 - -if ($Release) { & "$PSScriptRoot/Default.ps1" } -else { - "The ""-Release"" switch must be set!" - exit 1 -} +& "$PSScriptRoot/Default.ps1" "Publishing the package..." -$module = Import-PowerShellDataFile Html.psd1 -$version = $module.ModuleVersion +$version = (Import-PowerShellDataFile Html.psd1).ModuleVersion New-GitTag "v$version" - -$output = "var/PSModule" -New-Item $output/bin, $output/src -ItemType Directory | Out-Null -Copy-Item Html.psd1 $output/Belin.Html.psd1 -Copy-Item *.md $output -Copy-Item src/*.psm1 $output/src -Recurse -$module.RootModule | Copy-Item -Destination $output/bin - -$output = "var/PSGallery" -New-Item $output -ItemType Directory | Out-Null -Compress-PSResource var/PSModule $output -Get-Item "$output/*.nupkg" | ForEach-Object { Publish-PSResource -ApiKey $Env:PSGALLERY_API_KEY -NupkgPath $_ -Repository PSGallery } +Publish-PSGalleryModule diff --git a/tool/Test.ps1 b/tool/Test.ps1 index 3095a97..226e684 100644 --- a/tool/Test.ps1 +++ b/tool/Test.ps1 @@ -1,5 +1,6 @@ -using module ./Cmdlets.psm1 -& "$PSScriptRoot/Build.ps1" - "Running the test suite..." -Invoke-PowerShellTest test -EnableExit +pwsh -Command { + Import-Module Pester + Invoke-Pester test + exit $LASTEXITCODE +} diff --git a/tool/Update.ps1 b/tool/Update.ps1 index 19d51aa..6c564d1 100644 --- a/tool/Update.ps1 +++ b/tool/Update.ps1 @@ -1,5 +1,2 @@ -using module ./Cmdlets.psm1 - "Updating the dependencies..." (Import-PowerShellDataFile PSModules.psd1).Keys | Update-PSResource -TrustRepository -Restore-NuGetPackage diff --git a/tool/Version.ps1 b/tool/Version.ps1 deleted file mode 100644 index e532688..0000000 --- a/tool/Version.ps1 +++ /dev/null @@ -1,5 +0,0 @@ -"Updating the version number in the sources..." -$version = (Import-PowerShellDataFile Html.psd1).ModuleVersion -foreach ($file in Get-ChildItem -Filter *.csproj -Recurse) { - (Get-Content $file -Raw) -replace "\d+(\.\d+){2}.*", "$version" | Set-Content $file -NoNewLine -} diff --git a/tool/Watch.ps1 b/tool/Watch.ps1 deleted file mode 100644 index 4240334..0000000 --- a/tool/Watch.ps1 +++ /dev/null @@ -1,5 +0,0 @@ -& "$PSScriptRoot/Assets.ps1" - -"Watching for file changes..." -$configuration = $Release ? "Release" : "Debug" -Start-Process dotnet -ArgumentList "watch", "build", "--configuration", $configuration -NoNewWindow -Wait -WorkingDirectory src