core/modules/monkeyhtml/private/Modal/New-HtmlModal.ps1
# Monkey365 - the PowerShell Cloud Security Tool for Azure and Microsoft 365 (copyright 2022) by Juan Garrido # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. Function New-HtmlModal{ <# .SYNOPSIS .DESCRIPTION .INPUTS .OUTPUTS .EXAMPLE .NOTES Author : Juan Garrido Twitter : @tr1ana File Name : New-HtmlModal Version : 1.0 .LINK https://github.com/silverhack/monkey365 #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "", Scope="Function")] [CmdletBinding()] [OutputType([System.Xml.XmlDocument])] Param ( [parameter(Mandatory= $false, HelpMessage= "ID Modal")] [String]$Id, [parameter(Mandatory= $false, HelpMessage= "Style Modal")] [String]$Style, [parameter(Mandatory= $false, HelpMessage= "Icon class")] [String]$IconHeaderClass, [parameter(Mandatory= $false, HelpMessage= "Modal extra header class")] [String[]]$HeaderClass, [parameter(Mandatory= $false, HelpMessage= "Modal header Object")] [AllowNull()] [Object]$HeaderObject, [parameter(Mandatory= $false, HelpMessage= "Modal content extra class")] [String[]]$ContentClass, [parameter(Mandatory= $false, HelpMessage= "Modal dialog extra class")] [String[]]$DialogClass, [parameter(Mandatory= $false, HelpMessage= "Modal title")] [String]$Title, [parameter(Mandatory= $false, HelpMessage= "Modal title extra class")] [String[]]$TitleClass, [parameter(Mandatory= $false, HelpMessage= "Modal Body class name")] [String[]]$BodyClass, [parameter(Mandatory= $false, HelpMessage= "Modal Body Object")] [AllowNull()] [Object]$BodyObject, [parameter(Mandatory= $false, HelpMessage= "Footer text")] [String]$FooterText, [parameter(Mandatory= $false, HelpMessage= "Footer Object")] [AllowNull()] [Object]$FooterObject, [parameter(Mandatory= $false, HelpMessage= "Modal footer class")] [String[]]$FooterClass, [parameter(Mandatory= $false, HelpMessage= "Modal size")] [ValidateSet("small","large","extra")] [String]$Size, [parameter(Mandatory= $false, HelpMessage= "Add close button")] [Switch]$AddCloseButton, [parameter(Mandatory= $false, HelpMessage= "Static backdrop")] [Switch]$StaticBackdrop, [parameter(Mandatory= $false, HelpMessage= "vertically centered modal")] [Switch]$Centered, [parameter(Mandatory= $false, HelpMessage= "vertically centered scrollable modal")] [Switch]$CenteredScrollable, [Parameter(Mandatory= $false, HelpMessage="remove modal animation")] [Switch]$RemoveAnimation, [parameter(Mandatory= $false, HelpMessage= "Template")] [System.Xml.XmlDocument]$Template ) Begin{ #Set null $modalSize = $null; If($PSBoundParameters.ContainsKey('Template') -and $PSBoundParameters['Template']){ $TemplateObject = $PSBoundParameters['Template'] } ElseIf($null -ne (Get-Variable -Name Template -Scope Script -ErrorAction Ignore)){ $TemplateObject = $script:Template } Else{ [xml]$TemplateObject = "<html></html>" } #main modal [xml]$modal = '<div class="modal fade"></div>' [void]$modal.div.SetAttribute('tabindex',"-1") [void]$modal.div.SetAttribute('role',"dialog") #Add modal dialog $modalDialog = $modal.CreateNode([System.Xml.XmlNodeType]::Element, $modal.Prefix, 'div', $modal.NamespaceURI); [void]$modalDialog.SetAttribute('role',"document") #Add extra class to dialog If($PSBoundParameters.ContainsKey('DialogClass') -and $PSBoundParameters['DialogClass']){ $_Class = [String]::Join(' ',$DialogClass); $div_class = ("modal-dialog {0}" -f $_Class) [void]$modalDialog.SetAttribute('class',$div_class) } Else{ [void]$modalDialog.SetAttribute('class',"modal-dialog") } #Add modal header $modalHeader = $modal.CreateNode([System.Xml.XmlNodeType]::Element, $modal.Prefix, 'div', $modal.NamespaceURI); #Add extra class to header If($PSBoundParameters.ContainsKey('HeaderClass') -and $PSBoundParameters['HeaderClass']){ $_Class = [String]::Join(' ',$HeaderClass); $div_class = ("modal-header {0}" -f $_Class) [void]$modalHeader.SetAttribute('class',$div_class) } Else{ [void]$modalHeader.SetAttribute('class',"modal-header") } #Add modal body $modalBody = $modal.CreateNode([System.Xml.XmlNodeType]::Element, $modal.Prefix, 'div', $modal.NamespaceURI); #Add extra class to body If($PSBoundParameters.ContainsKey('BodyClass') -and $PSBoundParameters['BodyClass']){ $_Class = [String]::Join(' ',$BodyClass); $div_class = ("modal-body overflow-auto {0}" -f $_Class) [void]$modalBody.SetAttribute('class',$div_class) } Else{ [void]$modalBody.SetAttribute('class',"modal-body overflow-auto") } #Add card footer $modalFooter = $modal.CreateNode([System.Xml.XmlNodeType]::Element, $modal.Prefix, 'div', $modal.NamespaceURI); #Add extra class to footer If($PSBoundParameters.ContainsKey('FooterClass') -and $PSBoundParameters['FooterClass']){ $_Class = [String]::Join(' ',$FooterClass); $div_class = ("modal-footer {0}" -f $_Class) [void]$modalFooter.SetAttribute('class',$div_class) } Else{ [void]$modalFooter.SetAttribute('class',"modal-footer") } #Check if remove animation should be removed to modal If($RemoveAnimation){ $main_modal = $modal.SelectSingleNode('//div[contains(@class,"modal")]') [void]$main_modal.SetAttribute('class',"modal") } #Add modal content $modalContent = $modal.CreateNode([System.Xml.XmlNodeType]::Element, $modal.Prefix, 'div', $modal.NamespaceURI); #Add extra class to content If($PSBoundParameters.ContainsKey('ContentClass') -and $PSBoundParameters['ContentClass']){ $_Class = [String]::Join(' ',$ContentClass); $div_class = ("modal-content {0}" -f $_Class) [void]$modalContent.SetAttribute('class',$div_class) } Else{ [void]$modalContent.SetAttribute('class',"modal-content") } #Check modal size If($Size){ Switch ($Size.ToLower()) { 'small'{ $modalSize = "modal-sm" } 'large'{ $modalSize = "modal-lg" } 'extra'{ $modalSize = "modal-xl" } } $current_class = $modalDialog.class $div_class = ('{0} {1}' -f $current_class,$modalSize) [void]$modalDialog.SetAttribute('class',$div_class) } #Check if a static backdrop class must be added If($StaticBackdrop){ $main_modal = $modal.SelectSingleNode('//div[contains(@class,"modal")]') [void]$main_modal.SetAttribute('data-bs-backdrop',"static") [void]$main_modal.SetAttribute('data-bs-keyboard',"false") } #Check if a centered or centered scrollable class should be added If($Centered){ $dialog_div = $modal.SelectSingleNode('//div[contains(@class,"modal-dialog")]') $current_class = $dialog_div.class $div_class = ('{0} modal-dialog-centered' -f $current_class) [void]$dialog_div.SetAttribute('class',$div_class) } #Check if an scrollable class should be added If($CenteredScrollable){ $dialog_div = $modal.SelectSingleNode('//div[contains(@class,"modal-dialog")]') $current_class = $dialog_div.class $div_class = ('{0} modal-dialog-centered modal-dialog-scrollable' -f $current_class) [void]$dialog_div.SetAttribute('class',$div_class) } } Process{ #Set ID card If($Id){ $myId = $Id $main_node = $modal.SelectSingleNode('//div[contains(@class,"modal")]') [void]$main_node.SetAttribute('id',$myId) #Set aria labelled [void]$main_node.SetAttribute('aria-labelledby',("{0}Label" -f $myId)) } Else{ #Set random number $rnd = Get-Random -Maximum 1500 -Minimum 1 $myId = ("monkey_modal_{0}" -f $rnd) $main_node = $modal.SelectSingleNode('//div[contains(@class,"modal")]') [void]$main_node.SetAttribute('id',("{0}" -f $myId)) #Set aria labelled [void]$main_node.SetAttribute('aria-labelledby',("{0}Label" -f $myId)) } #Check if a close button must be added If($AddCloseButton){ $close_button = $modal.CreateNode([System.Xml.XmlNodeType]::Element, $modal.Prefix, 'button', $modal.NamespaceURI); [void]$close_button.SetAttribute('type',"button") [void]$close_button.SetAttribute('class',"btn btn-secondary") [void]$close_button.SetAttribute('data-bs-dismiss',"modal") #set close string to button [void]$close_button.AppendChild($modal.CreateTextNode("Close")) #Add button to footer [void]$modalFooter.AppendChild($close_button) } #Check if Header object If($PSBoundParameters.ContainsKey('HeaderObject')){ If($HeaderObject -is [System.Xml.XmlDocument]){ Write-Verbose ($Script:messages.AppendDocElementTo -f "Card header") [void]$cardHeader.AppendChild($card.ImportNode($HeaderObject.get_DocumentElement(), $True)) } ElseIf($HeaderObject -is [System.Xml.XmlElement]){ Write-Verbose ($Script:messages.AppendXmlElementTo -f "Card header") [void]$cardHeader.AppendChild($card.ImportNode($HeaderObject,$True)) } ElseIf($null -eq $HeaderObject){ Write-Verbose ($Script:messages.EmptyDiv -f "Card header") #set blank [void]$cardHeader.AppendChild($card.CreateTextNode([string]::Empty)) } Else{ #Add text [void]$cardHeader.AppendChild($card.CreateTextNode($PSBoundParameters['HeaderObject'].ToString())) } } #Check if Body object If($PSBoundParameters.ContainsKey('BodyObject')){ If($BodyObject -is [System.Xml.XmlDocument]){ Write-Verbose ($Script:messages.AppendDocElementTo -f "Modal body") [void]$modalBody.AppendChild($modal.ImportNode($BodyObject.get_DocumentElement(), $True)) } ElseIf($BodyObject -is [System.Xml.XmlElement]){ Write-Verbose ($Script:messages.AppendXmlElementTo -f "Card body") [void]$modalBody.AppendChild($modal.ImportNode($BodyObject,$True)) } ElseIf($null -eq $BodyObject){ Write-Verbose ($Script:messages.EmptyDiv -f "Modal body") #set blank [void]$modalBody.AppendChild($modal.CreateTextNode([string]::Empty)) } Else{ #Add text [void]$modalBody.AppendChild($modal.CreateTextNode($PSBoundParameters['BodyObject'].ToString())) } } #Check if modal footer text If($PSBoundParameters.ContainsKey('FooterText') -and $PSBoundParameters['FooterText']){ #Add text [void]$modalFooter.AppendChild($modal.CreateTextNode($PSBoundParameters['FooterText'].ToString())) } #Check if should add footer elements If($PSBoundParameters.ContainsKey('FooterObject')){ If($FooterObject -is [System.Xml.XmlDocument]){ Write-Verbose ($Script:messages.AppendDocElementTo -f "modal footer") [void]$modalFooter.AppendChild($modal.ImportNode($FooterObject.get_DocumentElement(), $True)) } ElseIf($FooterObject -is [System.Xml.XmlElement]){ Write-Verbose ($Script:messages.AppendXmlElementTo -f "modal footer") [void]$modalFooter.AppendChild($modal.ImportNode($FooterObject,$True)) } Else{ #Add text [void]$modalFooter.AppendChild($modal.CreateTextNode($PSBoundParameters['FooterObject'].ToString())) } } #check if an icon must be added If($IconHeaderClass){ $icon = $modal.CreateNode([System.Xml.XmlNodeType]::Element, $modal.Prefix, 'i', $modal.NamespaceURI); [void]$icon.SetAttribute('class',$IconHeaderClass) #Add icon to div [void]$modalHeader.AppendChild($icon) } #Check if modal title If($PSBoundParameters.ContainsKey('Title') -and $PSBoundParameters['Title']){ $h5Title = $modal.CreateNode([System.Xml.XmlNodeType]::Element, $modal.Prefix, 'h5', $modal.NamespaceURI); If($PSBoundParameters.ContainsKey('TitleClass') -and $PSBoundParameters['TitleClass']){ $_Class = [String]::Join(' ',$TitleClass); $div_class = ("modal-title-header {0}" -f $_Class) [void]$h5Title.SetAttribute('class',$div_class) } Else{ [void]$h5Title.SetAttribute('class','modal-title-header') } #Add title [void]$h5Title.AppendChild($modal.CreateTextNode($PSBoundParameters['Title'].ToString())) #Add id [void]$h5Title.SetAttribute('id',("{0}Label" -f $myId)) #Add to header [void]$modalHeader.AppendChild($h5Title) } #Add close button $close_button = $modal.CreateNode([System.Xml.XmlNodeType]::Element, $modal.Prefix, 'button', $modal.NamespaceURI); [void]$close_button.SetAttribute('type',"button") [void]$close_button.SetAttribute('class',"btn-close") [void]$close_button.SetAttribute('data-bs-dismiss',"modal") [void]$close_button.SetAttribute('aria-label',"Close") #set empty string to close button [void]$close_button.AppendChild($modal.CreateTextNode([string]::Empty)) #Add button to footer [void]$modalHeader.AppendChild($close_button) #force close i $all_i = $modal.SelectNodes("//i") ForEach($i in $all_i){ [void]$i.AppendChild($modal.CreateWhitespace("")) } #Close potentially divs $allDivs = $modal.SelectNodes("//div") ForEach($div in $allDivs){ If($div.HasChildNodes -eq $false){ $div.InnerText = [string]::Empty } } #Compile modal #Add comment $comment = $modal.CreateComment('Content'); [void]$modalContent.PrependChild($comment); #Add modal header, body and footer into modal content #Add comment $comment = $modal.CreateComment('Modal Header'); [void]$modalHeader.PrependChild($comment); [void]$modalContent.AppendChild($modalHeader); #Add comment $comment = $modal.CreateComment('Modal Body'); [void]$modalBody.PrependChild($comment); [void]$modalContent.AppendChild($modalBody); #Check if modal footer must be added If($modalFooter.HasChildNodes){ #Add comment $comment = $modal.CreateComment('Modal Footer'); [void]$modalFooter.PrependChild($comment); #Add to modal [void]$modalContent.AppendChild($modalFooter) } #Add modal content into modal dialog #Add comment $comment = $modal.CreateComment('Modal dialog'); [void]$modalDialog.PrependChild($comment); [void]$modalDialog.AppendChild($modalContent) #Add dialog to main modal [void]$modal.DocumentElement.AppendChild($modalDialog); } End{ #Close i tags $i = $modal.SelectNodes("//i") $i | ForEach-Object {[void]$_.AppendChild($modal.CreateWhitespace(""))} #Import node $newModal = $TemplateObject.ImportNode($modal.DocumentElement,$true); return $newModal } } |