Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions mdl/executor/cmd_pages_describe_output.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,32 @@ func (e *Executor) outputWidgetMDLV3(w rawWidget, indent int) {
prefix := strings.Repeat(" ", indent)

switch w.Type {
case "Forms$TabControl", "Pages$TabControl":
header := fmt.Sprintf("TABCONTAINER %s", w.Name)
props := appendAppearanceProps(nil, w)
if len(w.Children) > 0 {
formatWidgetProps(e.output, prefix, header, props, " {\n")
for _, child := range w.Children {
e.outputWidgetMDLV3(child, indent+1)
}
fmt.Fprintf(e.output, "%s}\n", prefix)
} else {
formatWidgetProps(e.output, prefix, header, props, "\n")
}

case "Forms$ScrollContainer", "Pages$ScrollContainer":
header := fmt.Sprintf("SCROLLCONTAINER %s", w.Name)
props := appendAppearanceProps(nil, w)
if len(w.Children) > 0 {
formatWidgetProps(e.output, prefix, header, props, " {\n")
for _, child := range w.Children {
e.outputWidgetMDLV3(child, indent+1)
}
fmt.Fprintf(e.output, "%s}\n", prefix)
} else {
formatWidgetProps(e.output, prefix, header, props, "\n")
}

case "Forms$DivContainer", "Pages$DivContainer":
header := fmt.Sprintf("CONTAINER %s", w.Name)
props := appendAppearanceProps(nil, w)
Expand Down
48 changes: 48 additions & 0 deletions mdl/executor/cmd_pages_describe_parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,54 @@ func (e *Executor) parseRawWidget(w map[string]any, parentEntityContext ...strin
typeName, _ := w["$Type"].(string)
name, _ := w["Name"].(string)

// ScrollContainer: children live in CenterRegion.Widgets (not Widgets directly).
// We keep the scrollContainer widget ID in the output but also expose all nested
// widgets so DESCRIBE PAGE shows what's inside and the extractor can find them.
if typeName == "Forms$ScrollContainer" || typeName == "Pages$ScrollContainer" {
widget := rawWidget{
Type: typeName,
Name: name,
}
// Children are nested inside CenterRegion.Widgets
var children []any
if centerRegion, ok := w["CenterRegion"].(map[string]any); ok {
children = getBsonArrayElements(centerRegion["Widgets"])
}
// Fallback: some older formats may use Widgets directly
if children == nil {
children = getBsonArrayElements(w["Widgets"])
}
for _, c := range children {
if cMap, ok := c.(map[string]any); ok {
widget.Children = append(widget.Children, e.parseRawWidget(cMap, inheritedCtx)...)
}
}
return []rawWidget{widget}
}

// TabControl: children live in TabPages[].Widgets — recurse so nested widget IDs
// (e.g. text widgets inside each tab) are included in the output.
if typeName == "Forms$TabControl" || typeName == "Pages$TabControl" {
widget := rawWidget{
Type: typeName,
Name: name,
}
tabPages := getBsonArrayElements(w["TabPages"])
for _, tp := range tabPages {
tpMap, ok := tp.(map[string]any)
if !ok {
continue
}
tabWidgets := getBsonArrayElements(tpMap["Widgets"])
for _, tw := range tabWidgets {
if twMap, ok := tw.(map[string]any); ok {
widget.Children = append(widget.Children, e.parseRawWidget(twMap, inheritedCtx)...)
}
}
}
return []rawWidget{widget}
}

// Parse DivContainer as a proper CONTAINER widget with children
if typeName == "Forms$DivContainer" || typeName == "Pages$DivContainer" ||
typeName == "Forms$GroupBox" || typeName == "Pages$GroupBox" {
Expand Down