Attribute VB_Name = "VBAForm2HTML"
' VBAForm2HTML v1.0.0
' https://github.com/GUI-Conversion-Tools/VBAForm2HTML
' Copyright (c) 2026 ZeeZeX
' This software is released under the MIT License.
' https://opensource.org/licenses/MIT
Option Explicit
#If VBA7 = 0 Then
' Define a placeholder LongPtr type for VBA6 or earlier.
' This allows code that uses LongPtr to compile in older VBA versions,
' even though those versions do not natively support the LongPtr type.
Private Enum LongPtr
[_]
End Enum
#End If
#If VBA7 Then
' 64bit Office / VBA7 or later
Private Declare PtrSafe Function GetSysColor Lib "user32" (ByVal nIndex As Long) As Long
Private Declare PtrSafe Function GdiplusStartup Lib "gdiplus" (ByRef token As LongPtr, ByRef inputbuf As GDIPlusStartupInput, Optional ByVal outputbuf As LongPtr = 0) As Long
Private Declare PtrSafe Sub GdiplusShutdown Lib "gdiplus" (ByVal token As LongPtr)
Private Declare PtrSafe Function GdipLoadImageFromFile Lib "gdiplus" (ByVal filename As LongPtr, ByRef image As LongPtr) As Long
Private Declare PtrSafe Function GdipDisposeImage Lib "gdiplus" (ByVal image As LongPtr) As Long
Private Declare PtrSafe Function GdipGetImageWidth Lib "gdiplus" (ByVal image As LongPtr, ByRef width As Long) As Long
Private Declare PtrSafe Function GdipGetImageHeight Lib "gdiplus" (ByVal image As LongPtr, ByRef height As Long) As Long
Private Declare PtrSafe Function GdipCreateBitmapFromScan0 Lib "gdiplus" (ByVal width As Long, ByVal height As Long, ByVal stride As Long, ByVal format As Long, ByVal scan0 As LongPtr, ByRef bitmap As LongPtr) As Long
Private Declare PtrSafe Function GdipGetImageGraphicsContext Lib "gdiplus" (ByVal image As LongPtr, ByRef graphics As LongPtr) As Long
Private Declare PtrSafe Function GdipDeleteGraphics Lib "gdiplus" (ByVal graphics As LongPtr) As Long
Private Declare PtrSafe Function GdipSetInterpolationMode Lib "gdiplus" (ByVal graphics As LongPtr, ByVal Mode As Long) As Long
Private Declare PtrSafe Function GdipDrawImageRectI Lib "gdiplus" (ByVal graphics As LongPtr, ByVal image As LongPtr, ByVal x As Long, ByVal y As Long, ByVal width As Long, ByVal height As Long) As Long
Private Declare PtrSafe Function GdipSaveImageToFile Lib "gdiplus" (ByVal image As LongPtr, ByVal filename As LongPtr, ByRef clsidEncoder As GUID, ByVal encoderParams As LongPtr) As Long
Private Declare PtrSafe Function CLSIDFromString Lib "ole32" (ByVal lpsz As LongPtr, ByRef pclsid As GUID) As Long
Private Declare PtrSafe Function CryptBinaryToStringW Lib "crypt32" (ByVal pbBinary As LongPtr, ByVal cbBinary As Long, ByVal dwFlags As Long, ByVal pszString As LongPtr, ByRef pcchString As Long) As Long
#Else
' 32bit Office
Private Declare Function GetSysColor Lib "user32" (ByVal nIndex As Long) As Long
Private Declare Function GdiplusStartup Lib "gdiplus" (ByRef token As Long, ByRef inputbuf As GDIPlusStartupInput, Optional ByVal outputbuf As Long = 0) As Long
Private Declare Sub GdiplusShutdown Lib "gdiplus" (ByVal token As Long)
Private Declare Function GdipLoadImageFromFile Lib "gdiplus" (ByVal filename As Long, ByRef image As Long) As Long
Private Declare Function GdipDisposeImage Lib "gdiplus" (ByVal image As Long) As Long
Private Declare Function GdipGetImageWidth Lib "gdiplus" (ByVal image As Long, ByRef width As Long) As Long
Private Declare Function GdipGetImageHeight Lib "gdiplus" (ByVal image As Long, ByRef height As Long) As Long
Private Declare Function GdipCreateBitmapFromScan0 Lib "gdiplus" (ByVal width As Long, ByVal height As Long, ByVal stride As Long, ByVal format As Long, ByVal scan0 As Long, ByRef bitmap As Long) As Long
Private Declare Function GdipGetImageGraphicsContext Lib "gdiplus" (ByVal image As Long, ByRef graphics As Long) As Long
Private Declare Function GdipDeleteGraphics Lib "gdiplus" (ByVal graphics As Long) As Long
Private Declare Function GdipSetInterpolationMode Lib "gdiplus" (ByVal graphics As Long, ByVal Mode As Long) As Long
Private Declare Function GdipDrawImageRectI Lib "gdiplus" (ByVal graphics As Long, ByVal image As Long, ByVal x As Long, ByVal y As Long, ByVal width As Long, ByVal height As Long) As Long
Private Declare Function GdipSaveImageToFile Lib "gdiplus" (ByVal image As Long, ByVal filename As Long, ByRef clsidEncoder As GUID, ByVal encoderParams As Long) As Long
Private Declare Function CLSIDFromString Lib "ole32" (ByVal lpsz As Long, ByRef pclsid As GUID) As Long
Private Declare Function CryptBinaryToStringW Lib "crypt32" (ByVal pbBinary As Long, ByVal cbBinary As Long, ByVal dwFlags As Long, ByVal pszString As Long, ByRef pcchString As Long) As Long
#End If
Private Type GDIPlusStartupInput: GdiPlusVersion As Long: DebugEventCallback As LongPtr: SuppressBackgroundThread As Long: SuppressExternalCodecs As Long: End Type
Private Type GUID: Data1 As Long: Data2 As Integer: Data3 As Integer: Data4(0 To 7) As Byte: End Type
Private Const OUTPUT_FOLDER_NAME As String = "VBAForm2HTML_output"
Public Sub TestRunConversion2Html()
Call ConvertForm2HTML(UserForm1)
End Sub
Public Sub TestRunConversion2Html_2()
Call ConvertForm2HTML(Array(UserForm1, UserForm2))
End Sub
Public Sub ConvertForm2HTML(ByVal frms As Variant, Optional ByVal usePrefix As Boolean = False, Optional ByVal imageMode As String = "file", Optional ByVal langAttribute As String = "")
' frms: Variant
' Accepts a single UserForm object or an Array of UserForm objects to be converted.
' usePrefix: Boolean
' If set to True, the form name will be added to each element name.
' This is automatically set to True if frms is an array.
' imageMode: String
' Determines how image files used in the UserForm are handled during conversion. You can choose one of the following options:
' "file" (Default): Images are saved as separate external files in the output directory, and the generated code references these files.
' "disabled": Image processing is disabled, and no image-related code is generated.
' "reference-only": Similar to "file", generates code that references image files, but does not export the image files. Useful when the image files already exist.
' "base64": Images are embedded directly into the generated code as Base64-encoded strings, keeping everything in a single file.
' langAttribute: String
' Specifies the language code for the "lang" attribute of the generated tag (e.g., "en" for English, "zh" for Chinese, "ja" for Japanese).
' If omitted, the attribute will be left empty.
Dim code As String
Dim filePath As String
Dim saveDir As String
code = GenerateHTMLCode(frms, usePrefix, imageMode, langAttribute)
If code <> "" Then
saveDir = GetSaveDirPath()
Call CreateFolderIfDoesNotExist(saveDir)
filePath = saveDir & "\output.html"
Call SaveUtf8TextNoBom(filePath, code)
MsgBox "Saved: " & filePath
Else
MsgBox "Conversion failed."
End If
End Sub
Public Function GenerateHTMLCode(ByVal frms As Variant, Optional ByVal usePrefix As Boolean = False, Optional ByVal imageMode As String = "file", Optional ByVal langAttribute As String = "") As String
Dim root As Variant
Dim indent As String
Dim prefix As String
Dim formName As String
Dim controlVarName As String
Dim parentVarName As String
Dim unavailableNames() As Variant
Dim ctrl As MSForms.Control
Dim ctrls As Collection
Dim item As Variant
Dim result As String
Dim codeList As New Collection
Const q As String = """"
Dim pixelWidth As Long
Dim pixelHeight As Long
Dim pixelTop As Long
Dim pixelLeft As Long
Dim i As Long
Dim cursorType As String
Dim caption As String
Dim colorSetting As String
Dim cssSelectorProperties As Collection
Dim tabPageProperties As Collection
Dim activeTabProperties As Collection
Dim inactiveTabProperties As Collection
Dim tabContainerProperties As Collection
Dim tabScrollWrapperProperties As Collection
Dim tabNavButtonProperties As Collection
Dim tabNavButtonTriangleProperties As Collection
Dim toggleButtonInputProperties As Collection
Dim toggleButtonSettingProperties As Collection
Dim toggleButtonCheckedProperties As Collection
Dim buttonTextLabelProperties As Collection
Dim listViewHeaderProperties As Collection
Dim listViewHeaderAndDataProperties As Collection
Dim treeViewDetailsUlProperties As Collection
Dim ctrlValue As String
Dim spaceCnt As Long
Dim temp As Variant
Dim picSize As String
Dim picPosition As String
Dim allElementStyleList As New Collection
Dim allJsCodeList As New Collection
Dim allHtmlBodyList As New Collection
Dim currentFormElementStyleList As Collection
Dim currentFormJsCodeList As Collection
Dim currentFormHtmlBodyList As Collection
Dim elementStyle As String
Dim jsCode As String
Dim htmlBody As String
Dim tabHeight As Long
Dim tabPixelHeight As Long
Dim positionProperties As Collection
Dim colorProperties As Collection
Dim fontProperties As Collection
Dim otherProperties As Collection
Dim htmlTitle As String
Dim isHtmlTitleSet As Boolean: isHtmlTitleSet = False
Dim enableScrollBar As Boolean
Dim hasPicture As Boolean
Dim tempPath As String
Dim picturePath As String
Dim pictureName As String
Dim saveDir As String
Dim base64Str As String
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim supportedImageModeValues() As Variant
imageMode = LCase$(imageMode)
supportedImageModeValues = Array("file", "disabled", "reference-only", "base64")
If Not ContainsValue(supportedImageModeValues, imageMode) Then
MsgBox "[imageMode] Invalid value: " & q & imageMode & q & vbLf & "Supported values are " & q & Join(supportedImageModeValues, q & ", " & q) & q
GenerateHTMLCode = ""
Exit Function
End If
saveDir = GetSaveDirPath()
Call CreateFolderIfDoesNotExist(saveDir)
If IsArray(frms) Then
usePrefix = True
Else
frms = VBA.Array(frms)
End If
Set cssSelectorProperties = New Collection
With cssSelectorProperties
.Add "background: #ffffff"
.Add "display: flex"
.Add "flex-direction: column"
.Add "align-items: flex-start"
.Add "min-width: max-content"
.Add "gap: 0px"
End With
elementStyle = GenerateCssSelector("body", cssSelectorProperties, "") & vbLf
allElementStyleList.Add elementStyle
Set cssSelectorProperties = New Collection
' Always show up/down button of
Set temp = New Collection
With temp
.Add "input[type=""number""]::-webkit-inner-spin-button,"
.Add "input[type=""number""]::-webkit-outer-spin-button {"
.Add " opacity: 1;", " display: block;"
.Add "}"
End With
allElementStyleList.Add JoinCollection(temp, vbLf) & vbLf
For Each root In frms
Set cssSelectorProperties = New Collection
Set currentFormElementStyleList = New Collection
Set currentFormJsCodeList = New Collection
Set currentFormHtmlBodyList = New Collection
unavailableNames = VBA.Array("class", "script", "body", "id", "style")
For i = LBound(unavailableNames) To UBound(unavailableNames)
unavailableNames(i) = LCase$(unavailableNames(i))
Next
If ContainsValue(unavailableNames, LCase$(root.Name)) Then
MsgBox GenerateUnavailableNameMessage(root)
result = ""
GenerateHTMLCode = result
Exit Function
End If
If usePrefix Then
prefix = root.Name & "-"
Else
prefix = ""
End If
pixelWidth = UserFormSizeToPixel(root.InsideWidth)
pixelHeight = UserFormSizeToPixel(root.InsideHeight)
formName = root.Name
caption = root.caption
caption = Convert2HTMLFormatText(caption)
If Not isHtmlTitleSet Then
htmlTitle = caption
isHtmlTitleSet = True
End If
Set cssSelectorProperties = New Collection
With cssSelectorProperties
.Add "position: relative"
.Add "margin-left: auto"
.Add "margin-right: auto"
.Add "box-sizing: border-box"
.Add "overflow: hidden"
.Add "width: " & pixelWidth & "px"
.Add "height: " & pixelHeight & "px"
.Add "background: " & LCase$(FormColorToHex(root.BackColor))
.Add "cursor: " & GetControlCursorType(root)
End With
Set temp = GetBorderSetting(root)
Call ExtendCollection(cssSelectorProperties, temp)
currentFormElementStyleList.Add GenerateCssSelector(formName, cssSelectorProperties) & vbLf & vbLf
Set cssSelectorProperties = New Collection
currentFormElementStyleList.Add vbLf
Set ctrls = GetAllChildCtrlsDfs(root)
For Each ctrl In ctrls
controlVarName = GenerateCtrlVarName(ctrl, prefix)
parentVarName = GenerateCtrlVarName(ctrl.Parent, prefix)
enableScrollBar = False
hasPicture = False
base64Str = ""
If usePrefix Then
pictureName = "img_" & root.Name & "_" & ctrl.Name
Else
pictureName = "img_" & ctrl.Name
End If
Set cssSelectorProperties = New Collection
Set tabPageProperties = New Collection
Set activeTabProperties = New Collection
Set inactiveTabProperties = New Collection
Set tabContainerProperties = New Collection
Set tabScrollWrapperProperties = New Collection
Set tabNavButtonProperties = New Collection
Set tabNavButtonTriangleProperties = New Collection
Set toggleButtonInputProperties = New Collection
Set toggleButtonSettingProperties = New Collection
Set toggleButtonCheckedProperties = New Collection
Set buttonTextLabelProperties = New Collection
Set listViewHeaderProperties = New Collection
Set listViewHeaderAndDataProperties = New Collection
Set treeViewDetailsUlProperties = New Collection
Set positionProperties = New Collection
Set colorProperties = New Collection
Set fontProperties = New Collection
Set otherProperties = New Collection
If ContainsValue(unavailableNames, LCase$(ctrl.Name)) Then
MsgBox GenerateUnavailableNameMessage(ctrl)
result = ""
GenerateHTMLCode = result
Exit Function
End If
If IsSupportedCtrlType(ctrl) Then
If TypeName(ctrl) <> "Page" Then
pixelLeft = UserFormSizeToPixel(ctrl.Left)
pixelTop = UserFormSizeToPixel(ctrl.Top)
pixelWidth = UserFormSizeToPixel(ctrl.width)
pixelHeight = UserFormSizeToPixel(ctrl.height)
With positionProperties
.Add "position: absolute"
.Add "box-sizing: border-box"
If TypeName(ctrl) = "Frame" Then
.Add "overflow: hidden"
End If
.Add "left: " & pixelLeft & "px"
.Add "top: " & pixelTop & "px"
.Add "width: " & pixelWidth & "px"
.Add "height: " & pixelHeight & "px"
End With
End If
If ContainsValue(Array("Label", "CommandButton", "Frame", "TextBox", "SpinButton", "ListBox", "CheckBox", "OptionButton", "ToggleButton", "ComboBox"), TypeName(ctrl)) Or IsListView(ctrl) Then
' Set ForeColor
colorProperties.Add "color: " & LCase$(FormColorToHex(ctrl.ForeColor))
End If
If ContainsValue(Array("Label", "CommandButton", "Frame", "TextBox", "SpinButton", "ListBox", "CheckBox", "OptionButton", "ToggleButton", "Image", "ComboBox"), TypeName(ctrl)) Or IsListView(ctrl) Then
' Set BackColor
colorSetting = LCase$(FormColorToHex(ctrl.BackColor))
If ContainsValue(Array("ComboBox", "Label", "TextBox", "CommandButton", "CheckBox", "OptionButton", "ToggleButton", "Image"), TypeName(ctrl)) Then
If ctrl.BackStyle = fmBackStyleTransparent Then
colorSetting = "transparent"
End If
End If
colorProperties.Add "background-color: " & colorSetting
End If
If TypeName(ctrl) = "ToggleButton" Then
toggleButtonInputProperties.Add "display: none"
With buttonTextLabelProperties
.Add "border-top: 2px solid #ffffff"
.Add "border-left: 2px solid #ffffff"
.Add "border-right: 2px solid #7a7a7a"
.Add "border-bottom: 2px solid #7a7a7a"
.Add "box-sizing: border-box"
.Add "user-select: none"
.Add "-ms-user-select: none"
End With
With toggleButtonCheckedProperties
.Add "border-top: 2px solid #7a7a7a"
.Add "border-left: 2px solid #7a7a7a"
.Add "border-right: 2px solid #ffffff"
.Add "border-bottom: 2px solid #ffffff"
End With
End If
If TypeName(ctrl) = "TextBox" Then
If ctrl.MultiLine Then
With otherProperties
Select Case ctrl.ScrollBars
Case fmScrollBarsNone
.Add "overflow-x: hidden"
.Add "overflow-y: hidden"
Case fmScrollBarsHorizontal
.Add "overflow-x: hidden"
.Add "overflow-y: auto"
Case fmScrollBarsVertical
.Add "overflow-x: auto"
.Add "overflow-y: hidden"
Case fmScrollBarsBoth
.Add "overflow-x: auto"
.Add "overflow-y: auto"
End Select
End With
End If
End If
If TypeName(ctrl) = "MultiPage" Then
activeTabProperties.Add "padding: 2px 10px"
activeTabProperties.Add "background-color: " & LCase$(FormColorToHex(&H8000000F))
inactiveTabProperties.Add "padding: 2px 8px"
inactiveTabProperties.Add "background-color: " & LCase$(AddRGB(FormColorToHex(&H8000000F), -20, -20, -20))
With tabContainerProperties
.Add "position: relative"
.Add "width: 100%"
.Add "box-sizing: border-box"
.Add "white-space: nowrap"
.Add "font-size: 0"
.Add "padding-right: 36px"
End With
With tabScrollWrapperProperties
.Add "overflow: hidden"
.Add "white-space: nowrap"
.Add "width: 100%"
End With
With tabNavButtonProperties
.Add "position: absolute"
If ctrl.TabOrientation = fmTabOrientationBottom Then
.Add "top: 0"
Else
.Add "bottom: 0"
End If
.Add "width: 16px"
.Add "height: 16px"
.Add "box-sizing: border-box"
.Add "overflow: hidden"
.Add "padding: 0"
.Add "margin: 0"
.Add "cursor: pointer"
.Add "vertical-align: middle"
End With
With tabNavButtonTriangleProperties
.Add "display: block"
.Add "width: 0"
.Add "height: 0"
.Add "border-left: 4px solid transparent"
.Add "border-right: 4px solid transparent"
.Add "border-bottom: 7px solid #000000"
.Add "margin: auto"
End With
With tabPageProperties
.Add "box-sizing: border-box"
.Add "box-shadow: -1px -1px 0 #ffffff, 1px 1px 0 #666666, -2px -2px 0 #eeeeee, 2px 2px 0 #444444"
.Add "cursor: default"
If ctrl.Style = fmTabStyleNone Then
.Add "display: none;"
Else
.Add "display: inline-block;"
End If
.Add "vertical-align: top;"
.Add "color: " & LCase$(FormColorToHex(ctrl.ForeColor))
End With
End If
If ContainsValue(Array("Label", "CommandButton", "Frame", "TextBox", "ListBox", "CheckBox", "OptionButton", "ComboBox", "ToggleButton", "MultiPage"), TypeName(ctrl)) Or IsListView(ctrl) Or IsTreeView(ctrl) Then
With fontProperties
.Add "font-family: " & ctrl.Font.Name
.Add "font-size: " & Round(ctrl.Font.size * 1.33, 2) & "px"
If ctrl.Font.Bold Then .Add "font-weight: bold"
If ctrl.Font.Italic Then .Add "font-style: italic"
If ctrl.Font.Underline And ctrl.Font.Strikethrough Then
.Add "text-decoration: underline line-through"
ElseIf ctrl.Font.Underline Then
.Add "text-decoration: underline"
ElseIf ctrl.Font.Strikethrough Then
.Add "text-decoration: line-through"
End If
End With
End If
If TypeName(ctrl) = "Page" Then
tabHeight = GetTextSizeFromCtrlFontSetting(ctrl.Parent, "TEST")(1)
tabPixelHeight = UserFormSizeToPixel(tabHeight)
pixelWidth = UserFormSizeToPixel(ctrl.Parent.width)
pixelHeight = UserFormSizeToPixel(ctrl.Parent.height)
If ctrl.Parent.Style <> fmTabStyleNone Then
pixelHeight = pixelHeight - tabPixelHeight - 10
End If
With positionProperties
.Add "position: relative"
.Add "box-sizing: border-box"
.Add "overflow: hidden"
.Add "width: " & pixelWidth & "px"
.Add "height: " & pixelHeight & "px"
End With
With otherProperties
.Add "padding: 2px 8px"
.Add "background-color: " & LCase$(FormColorToHex(&H8000000F))
If ctrl.Parent.Style = fmTabStyleTabs Then
.Add "box-shadow: -1px -1px 0 #ffffff, 1px 1px 0 #666666, -2px -2px 0 #eeeeee, 2px 2px 0 #444444"
Else
.Add "border: none"
End If
.Add "display: none"
End With
End If
If IsListView(ctrl) Then
positionProperties.Add "border: 1px solid #666666"
positionProperties.Add "outline: 1px solid #ffffff"
positionProperties.Add "outline-offset: -2px"
otherProperties.Add "overflow: auto"
With listViewHeaderProperties
.Add "position: sticky"
.Add "top: 0"
.Add "background-color: " & LCase$(FormColorToHex(&H8000000F))
.Add "color: #000000"
' To avoid the strikethrough or underline on table header elements being affected by the font color of the parent element, set them explicitly on the header elements.
' If they are not set individually, according to the HTML specification, the underline and strikethrough defined on the parent element will use the same color as the parent element's font color.
' As a result, when the font colors of the parent and header elements differ, the line color may not match the text color.
If ctrl.Font.Underline And ctrl.Font.Strikethrough Then
.Add "text-decoration: underline line-through"
ElseIf ctrl.Font.Underline Then
.Add "text-decoration: underline"
ElseIf ctrl.Font.Strikethrough Then
.Add "text-decoration: line-through"
End If
End With
With listViewHeaderAndDataProperties
.Add "border: 1px solid #ccc"
.Add "padding: 8px 12px"
.Add "word-wrap: break-word"
.Add "overflow: break-word"
.Add "text-overflow: ellipsis"
End With
End If
If IsTreeView(ctrl) Then
otherProperties.Add "overflow: auto"
positionProperties.Add "box-shadow: 1px 1px 0 #ffffff, -1px -1px 0 #666666, 2px 2px 0 #eeeeee, -2px -2px 0 #444444"
colorProperties.Add "color: #000000"
colorProperties.Add "background-color: #ffffff"
treeViewDetailsUlProperties.Add "list-style: none"
treeViewDetailsUlProperties.Add "margin: 0"
If HasScrollProperty(ctrl) Then
enableScrollBar = ctrl.Scroll
Else
enableScrollBar = True
End If
With otherProperties
If enableScrollBar Then
.Add "overflow-x: auto"
.Add "overflow-y: auto"
Else
.Add "overflow-x: hidden"
.Add "overflow-y: hidden"
End If
End With
End If
If ContainsValue(Array("Frame", "TextBox", "ComboBox", "Label", "ListBox", "Image"), TypeName(ctrl)) Then
Set temp = GetBorderSetting(ctrl)
Call ExtendCollection(positionProperties, temp)
End If
If ContainsValue(Array("Label", "TextBox", "ComboBox", "CheckBox", "OptionButton", "ToggleButton", "ListBox"), TypeName(ctrl)) Then
Set temp = GetTextAlignSetting(ctrl)
Call ExtendCollection(positionProperties, temp)
End If
If TypeName(ctrl) = "ScrollBar" Then
If IsVerticalScrollBar(ctrl) Then
otherProperties.Add "writing-mode: vertical-lr"
End If
End If
' Set mouse cursor
If TypeName(ctrl) <> "MultiPage" And TypeName(ctrl) <> "Page" Then
cursorType = GetControlCursorType(ctrl)
otherProperties.Add "cursor: " & cursorType
End If
If TypeName(ctrl) = "Image" Then
Select Case ctrl.PictureSizeMode
Case fmPictureSizeModeClip
picSize = "auto"
Case fmPictureSizeModeStretch
picSize = "cover"
Case fmPictureSizeModeZoom
picSize = "contain"
Case Else
picSize = "auto"
End Select
Select Case ctrl.PictureAlignment
Case fmPictureAlignmentTopLeft
picPosition = "left top"
Case fmPictureAlignmentTopRight
picPosition = "right top"
Case fmPictureAlignmentCenter
picPosition = "center center"
Case fmPictureAlignmentBottomLeft
picPosition = "left bottom"
Case fmPictureAlignmentBottomRight
picPosition = "right bottom"
Case Else
picPosition = "left top"
End Select
If ctrl.Picture Is Nothing Or imageMode = "disabled" Then
hasPicture = False
Else
hasPicture = True
End If
If hasPicture Then
tempPath = fso.BuildPath(fso.GetSpecialFolder(2).Path, fso.GetTempName())
If ContainsValue(Array("base64"), imageMode) Then
picturePath = tempPath & "tmp2.png"
Else
picturePath = saveDir & "\" & pictureName & ".png"
End If
tempPath = tempPath & ".bmp"
If ContainsValue(Array("file", "base64"), imageMode) Then
Call SavePicture(ctrl.Picture, tempPath)
Call ConvertImageFormat(tempPath, picturePath, False)
If fso.FileExists(tempPath) Then Call fso.DeleteFile(tempPath)
End If
If ContainsValue(Array("base64"), imageMode) Then
base64Str = FileToBase64(picturePath)
If fso.FileExists(picturePath) Then Call fso.DeleteFile(picturePath)
End If
If ContainsValue(Array("file", "reference-only"), imageMode) Then
otherProperties.Add "background-image: url(" & q & fso.GetFileName(picturePath) & q & ")"
ElseIf imageMode = "base64" Then
otherProperties.Add "background-image: url(" & q & "data:image/png;base64," & base64Str & q & ")"
End If
Else
otherProperties.Add "background-image: url(" & q & "" & q & ")"
End If
With otherProperties
.Add "background-size: " & picSize
.Add "background-position: " & picPosition
.Add "background-repeat: no-repeat"
End With
End If
If TypeName(ctrl) = "CheckBox" Or TypeName(ctrl) = "OptionButton" Then
Call ExtendCollection(buttonTextLabelProperties, positionProperties)
Call ExtendCollection(buttonTextLabelProperties, colorProperties)
Call ExtendCollection(buttonTextLabelProperties, fontProperties)
Call ExtendCollection(buttonTextLabelProperties, otherProperties)
ElseIf TypeName(ctrl) = "ToggleButton" Then
Call ExtendCollection(buttonTextLabelProperties, positionProperties)
Call ExtendCollection(toggleButtonSettingProperties, colorProperties)
Call ExtendCollection(toggleButtonSettingProperties, fontProperties)
Call ExtendCollection(toggleButtonSettingProperties, otherProperties)
ElseIf TypeName(ctrl) = "MultiPage" Then
Call ExtendCollection(tabPageProperties, fontProperties)
Call ExtendCollection(cssSelectorProperties, positionProperties)
Call ExtendCollection(cssSelectorProperties, otherProperties)
Else
Call ExtendCollection(cssSelectorProperties, positionProperties)
Call ExtendCollection(cssSelectorProperties, colorProperties)
Call ExtendCollection(cssSelectorProperties, fontProperties)
Call ExtendCollection(cssSelectorProperties, otherProperties)
End If
currentFormElementStyleList.Add GenerateCssSelector(controlVarName, cssSelectorProperties) & vbLf & vbLf
If TypeName(ctrl) = "CheckBox" Or TypeName(ctrl) = "OptionButton" Then
currentFormElementStyleList.Add GenerateCssSelector(controlVarName & "-label", buttonTextLabelProperties, ".") & vbLf & vbLf
End If
If TypeName(ctrl) = "ToggleButton" Then
currentFormElementStyleList.Add GenerateCssSelector(controlVarName & "-label", buttonTextLabelProperties, ".") & vbLf & vbLf
currentFormElementStyleList.Add GenerateCssSelector(controlVarName & "-input", toggleButtonInputProperties, ".") & vbLf & vbLf
currentFormElementStyleList.Add GenerateCssSelector(controlVarName & "-setting", toggleButtonSettingProperties, ".") & vbLf & vbLf
currentFormElementStyleList.Add GenerateCssSelector(controlVarName & "-input:checked + ." & controlVarName & "-label", toggleButtonCheckedProperties, ".") & vbLf & vbLf
End If
If TypeName(ctrl) = "MultiPage" Then
currentFormElementStyleList.Add GenerateCssSelector(controlVarName & "-TabPages", tabPageProperties, ".") & vbLf & vbLf
currentFormElementStyleList.Add GenerateCssSelector(controlVarName & "-ActiveTab", activeTabProperties, ".") & vbLf & vbLf
currentFormElementStyleList.Add GenerateCssSelector(controlVarName & "-InactiveTab", inactiveTabProperties, ".") & vbLf & vbLf
currentFormElementStyleList.Add GenerateCssSelector(controlVarName & "-TabContainer", tabContainerProperties, ".") & vbLf & vbLf
currentFormElementStyleList.Add GenerateCssSelector(controlVarName & "-TabScrollWrapper", tabScrollWrapperProperties, ".") & vbLf & vbLf
currentFormElementStyleList.Add GenerateCssSelector(controlVarName & "-TabNavBtn", tabNavButtonProperties, ".") & vbLf & vbLf
currentFormElementStyleList.Add GenerateCssSelector(controlVarName & "-TabNavBtnTriangle", tabNavButtonTriangleProperties, ".") & vbLf & vbLf
End If
If IsListView(ctrl) Then
currentFormElementStyleList.Add GenerateCssSelector(controlVarName & " th", listViewHeaderProperties, "#") & vbLf & vbLf
currentFormElementStyleList.Add GenerateCssSelector(controlVarName & " th, #" & controlVarName & " td", listViewHeaderAndDataProperties, "#") & vbLf & vbLf
End If
If IsTreeView(ctrl) Then
currentFormElementStyleList.Add GenerateCssSelector(controlVarName & " details ul", treeViewDetailsUlProperties, "#") & vbLf & vbLf
End If
currentFormElementStyleList.Add vbLf
Else
MsgBox GenerateUnsupportedControlMessage(ctrl)
result = ""
GenerateHTMLCode = result
Exit Function
End If
Next ctrl
currentFormHtmlBodyList.Add "
" & vbLf
For Each ctrl In ctrls
If TypeName(ctrl) = "MultiPage" Then
currentFormJsCodeList.Add GenerateTabPageSwitchingFunc(ctrl, prefix)
currentFormJsCodeList.Add vbLf
End If
Next
elementStyle = JoinCollection(currentFormElementStyleList, "")
htmlBody = JoinCollection(currentFormHtmlBodyList, "")
jsCode = JoinCollection(currentFormJsCodeList, "")
allElementStyleList.Add elementStyle
allHtmlBodyList.Add htmlBody
allJsCodeList.Add jsCode
Next root
With codeList
.Add "" & vbLf
.Add "" & vbLf
.Add "" & vbLf
.Add Space$(2) & "" & vbLf
.Add Space$(2) & "" & vbLf
.Add Space$(2) & "" & htmlTitle & "" & vbLf
.Add vbLf
.Add Space$(2) & "" & vbLf
.Add "" & vbLf
.Add "" & vbLf
temp = JoinCollection(allHtmlBodyList, vbLf) & vbLf
temp = AdjustIndent(temp, 2)
.Add temp & vbLf
.Add Space$(2) & "" & vbLf
.Add "" & vbLf
.Add ""
End With
result = JoinCollection(codeList, "")
GenerateHTMLCode = result
End Function
Private Function GetSaveDirPath() As String
Dim result As String
Dim wsh As Object
result = ""
On Error Resume Next
result = CallByName(Application, "ThisWorkbook", VbGet).Path ' Excel VBA
result = CallByName(Application, "MacroContainer", VbGet).Path ' Word VBA
On Error GoTo 0
If result = "" Then ' Other Office / Unsaved Workbook
On Error Resume Next
Set wsh = CreateObject("WScript.Shell")
result = wsh.SpecialFolders("MyDocuments")
On Error GoTo 0
End If
If result = "" Then ' If fail to retrieve the path to the Documents folder
result = "C:"
End If
result = result & "\" & OUTPUT_FOLDER_NAME
GetSaveDirPath = result
End Function
Private Sub CreateFolderIfDoesNotExist(ByVal folderPath As String)
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FolderExists(folderPath) Then
Call fso.CreateFolder(folderPath)
End If
End Sub
Private Function IsSupportedCtrlType(ByVal ctrl As Object) As Boolean
' Check if the control can be converted to CSS element
Dim result As Boolean
Select Case TypeName(ctrl)
Case "Label", "CommandButton", "Frame", "TextBox", "SpinButton", "ListBox", "CheckBox", _
"OptionButton", "Image", "ScrollBar", "ComboBox", "MultiPage", "Page", "ToggleButton"
result = True
Case Else
result = False
If result = False Then result = IsListView(ctrl)
If result = False Then result = IsTreeView(ctrl)
End Select
IsSupportedCtrlType = result
End Function
Private Function SetCssElement(ByVal ctrl As Variant, ByVal prefix As String) As String
Dim codeList As New Collection
Dim controlVarName As String
Dim parentVarName As String
Dim ctrlValue As String
Dim spaceCnt As Long
Dim result As String
Const q As String = """"
Dim ctrlDepth As Long
Dim temp As Variant
Dim listBoxSize As Long
controlVarName = GenerateCtrlVarName(ctrl, prefix)
parentVarName = GenerateCtrlVarName(ctrl.Parent, prefix)
ctrlValue = ""
If ContainsValue(Array("Label", "CommandButton", "CheckBox", "OptionButton", "ToggleButton"), TypeName(ctrl)) Then
ctrlValue = Convert2HTMLFormatText(ctrl.caption)
End If
If ContainsValue(Array("TextBox", "ComboBox"), TypeName(ctrl)) Then
ctrlValue = Convert2HTMLFormatText(ctrl.value, useBrTag:=False)
End If
ctrlDepth = GetFormControlDepth(ctrl)
spaceCnt = ctrlDepth * 2
Select Case TypeName(ctrl)
Case "Label"
codeList.Add Space$(spaceCnt) & "
" & ctrlValue & "
"
Case "TextBox"
If ctrl.MultiLine Then
codeList.Add Space$(spaceCnt) & ""
Else
codeList.Add Space$(spaceCnt) & ""
End If
Case "SpinButton"
codeList.Add Space$(spaceCnt) & ""
Case "ComboBox"
If ctrl.Style = fmStyleDropDownList Then
codeList.Add Space$(spaceCnt) & ""
Else
codeList.Add Space$(spaceCnt) & "" & vbLf
codeList.Add GenerateCssDataList(ctrl, spaceCnt, prefix)
End If
Case "ListBox"
codeList.Add Space$(spaceCnt) & ""
Case "CheckBox"
codeList.Add Space$(spaceCnt) & ""
Else
codeList.Add temp & ctrlValue & ""
End If
Case "OptionButton"
codeList.Add Space$(spaceCnt) & ""
Else
codeList.Add temp & ctrlValue & ""
End If
Case "ToggleButton"
temp = Space$(spaceCnt) & ""
Else
temp = temp & ">"
End If
temp = temp & ""
codeList.Add temp
Case "Image"
codeList.Add Space$(spaceCnt) & ""
Case "ScrollBar"
codeList.Add Space$(spaceCnt) & ""
Case "CommandButton"
codeList.Add Space$(spaceCnt) & ""
End Select
If IsListView(ctrl) Then
codeList.Add Space$(spaceCnt) & "
"
End If
codeList.Add vbLf
result = JoinCollection(codeList, "")
SetCssElement = result
End Function
Private Function SetCssAllCtrlsDfs(ByVal parentCtrl As Object, ByVal prefix As String) As String
Dim codeList As New Collection
Dim resultCode As String
Dim children As Variant
Dim recursiveResult As Collection
Set children = GetDirectChildCtrls(parentCtrl)
Set recursiveResult = SetCssAllCtrlsDfsRecursive(children, codeList, prefix)
resultCode = JoinCollection(codeList, "")
SetCssAllCtrlsDfs = resultCode
End Function
Private Function SetCssAllCtrlsDfsRecursive(ByVal ctrls As Variant, ByRef codeList As Collection, ByVal prefix As String) As Collection
Dim shouldProcess As Boolean: shouldProcess = False
Dim results As New Collection
Dim ctrl As Variant
Dim ctrlDepth As Long
Dim children As Variant
Dim controlVarName As String
Dim i As Long
Const q As String = """"
If ctrls.count > 0 Then shouldProcess = True
If shouldProcess Then
For Each ctrl In ctrls
results.Add ctrl
controlVarName = GenerateCtrlVarName(ctrl, prefix)
ctrlDepth = GetFormControlDepth(ctrl)
codeList.Add SetCssElement(ctrl, prefix)
Set children = GetDirectChildCtrls(ctrl)
If TypeName(ctrl) = "Frame" Then
codeList.Add Space$(ctrlDepth * 2) & "