diff --git a/.claude/skills/form-compile/scripts/form-compile.ps1 b/.claude/skills/form-compile/scripts/form-compile.ps1
index cc234b1c..9568800e 100644
--- a/.claude/skills/form-compile/scripts/form-compile.ps1
+++ b/.claude/skills/form-compile/scripts/form-compile.ps1
@@ -2329,20 +2329,85 @@ function Emit-CompanionPanel {
X "$indent$tag>"
}
-# Табличный addition (СтрокаПоиска/СостояниеПросмотра/УправлениеПоиском) с AdditionSource.
-# Item = имя таблицы, Type фиксирован по виду; внутри — companion ContextMenu/ExtendedTooltip.
+# Дополнения командной панели таблицы: тип DSL → XML-тег + AdditionSource.Type.
+$script:additionTypeMap = [ordered]@{
+ 'searchString' = @{ Tag = 'SearchStringAddition'; Type = 'SearchStringRepresentation'; Suffix = 'СтрокаПоиска' }
+ 'viewStatus' = @{ Tag = 'ViewStatusAddition'; Type = 'ViewStatusRepresentation'; Suffix = 'СостояниеПросмотра' }
+ 'searchControl' = @{ Tag = 'SearchControlAddition'; Type = 'SearchControl'; Suffix = 'УправлениеПоиском' }
+}
+# Синонимы типа дополнения (для override-карты additions и резолва тип-ключа).
+$script:additionKeySynonyms = @{
+ 'searchString' = @('SearchStringAddition','SearchStringRepresentation','строкаПоиска','отображениеСтрокиПоиска')
+ 'viewStatus' = @('ViewStatusAddition','ViewStatusRepresentation','состояниеПросмотра')
+ 'searchControl' = @('SearchControlAddition','SearchControl','управлениеПоиском')
+}
+
+# HorizontalLocation: auto (дефолт, тег опускаем) / left / right; forgiving + рус.синонимы.
+function Get-HLocation {
+ param($el)
+ $v = if ($el -and $el.PSObject.Properties['horizontalLocation']) { $el.horizontalLocation } else { $null }
+ if (-not $v) { return $null }
+ switch -Regex ("$v".ToLower()) {
+ '^(auto|авто)$' { return $null } # дефолт — не эмитим
+ '^(left|слева|лево)$' { return 'Left' }
+ '^(right|справа|право)$' { return 'Right' }
+ default { return "$v" }
+ }
+}
+
+# Тело дополнения: AdditionSource + свойства (как у поля) + companions. $props может быть $null
+# (стандартное дополнение без отклонений). Порядок 1С-толерантен (diff порядок-независим).
+function Emit-AdditionBody {
+ param($props, [string]$source, [string]$srcType, [string]$addName, [string]$indent)
+ $inner = "$indent`t"
+ X "$inner"
+ X "$inner`t- $source
"
+ X "$inner`t$srcType"
+ X "$inner"
+ if ($props) {
+ if ($props.PSObject.Properties['title'] -and $props.title) { Emit-MLText -tag "Title" -text $props.title -indent $inner }
+ Emit-CommonFlags -el $props -indent $inner
+ if ($props.tooltip) { Emit-MLText -tag "ToolTip" -text $props.tooltip -indent $inner }
+ if ($props.tooltipRepresentation) { X "$inner$($props.tooltipRepresentation)" }
+ $hl = Get-HLocation $props; if ($hl) { X "$inner$hl" }
+ Emit-Layout -el $props -indent $inner
+ Emit-Appearance -el $props -indent $inner -profile 'field'
+ }
+ Emit-Companion -tag "ContextMenu" -name "${addName}КонтекстноеМеню" -indent $inner
+ Emit-Companion -tag "ExtendedTooltip" -name "${addName}РасширеннаяПодсказка" -indent $inner
+}
+
+# Кастомное дополнение (тип-элемент в commandBar): source дефолтит в текущую таблицу.
+function Emit-Addition {
+ param($el, [string]$name, [int]$id, [string]$typeKey, [string]$indent)
+ $map = $script:additionTypeMap[$typeKey]
+ $source = if ($el.source) { "$($el.source)" } elseif ($script:currentTableName) { $script:currentTableName } else { '' }
+ X "$indent<$($map.Tag) name=`"$name`" id=`"$id`">"
+ Emit-AdditionBody -props $el -source $source -srcType $map.Type -addName $name -indent $indent
+ X "$indent$($map.Tag)>"
+}
+
+# Стандартное табличное дополнение (авто-генерация на уровне таблицы). $override — объект отклонений
+# из per-table карты additions (или $null = чистый дефолт).
function Emit-TableAddition {
- param([string]$tag, [string]$tableName, [string]$nameSuffix, [string]$srcType, [string]$indent)
- $addName = "$tableName$nameSuffix"
+ param([string]$typeKey, [string]$tableName, [string]$indent, $override = $null)
+ $map = $script:additionTypeMap[$typeKey]
+ $addName = "$tableName$($map.Suffix)"
$id = New-Id
- X "$indent<$tag name=`"$addName`" id=`"$id`">"
- X "$indent`t"
- X "$indent`t`t- $tableName
"
- X "$indent`t`t$srcType"
- X "$indent`t"
- Emit-Companion -tag "ContextMenu" -name "${addName}КонтекстноеМеню" -indent "$indent`t"
- Emit-Companion -tag "ExtendedTooltip" -name "${addName}РасширеннаяПодсказка" -indent "$indent`t"
- X "$indent$tag>"
+ X "$indent<$($map.Tag) name=`"$addName`" id=`"$id`">"
+ Emit-AdditionBody -props $override -source $tableName -srcType $map.Type -addName $addName -indent $indent
+ X "$indent$($map.Tag)>"
+}
+
+# Прочитать override-объект для типа дополнения из per-table карты additions (с синонимами).
+function Get-AdditionOverride {
+ param($additions, [string]$typeKey)
+ if ($null -eq $additions) { return $null }
+ foreach ($k in @($typeKey) + $script:additionKeySynonyms[$typeKey]) {
+ $p = $additions.PSObject.Properties[$k]
+ if ($p) { return $p.Value }
+ }
+ return $null
}
function Emit-Element {
@@ -2392,6 +2457,20 @@ function Emit-Element {
"Кнопка" = "button"
"Popup" = "popup"
"ВсплывающееМеню" = "popup"
+ # Дополнения командной панели таблицы (тип-как-ключ) — forgiving: XML-тег/Type/рус.имя → канон
+ "SearchStringAddition" = "searchString"
+ "SearchStringRepresentation" = "searchString"
+ "строкаПоиска" = "searchString"
+ "отображениеСтрокиПоиска" = "searchString"
+ "Отображение строки поиска" = "searchString"
+ "ViewStatusAddition" = "viewStatus"
+ "ViewStatusRepresentation" = "viewStatus"
+ "состояниеПросмотра" = "viewStatus"
+ "Состояние просмотра" = "viewStatus"
+ "SearchControlAddition" = "searchControl"
+ "SearchControl" = "searchControl"
+ "управлениеПоиском" = "searchControl"
+ "Управление поиском" = "searchControl"
}
foreach ($pair in $synonyms.GetEnumerator()) {
if ($null -ne $el.PSObject.Properties[$pair.Key] -and $null -eq $el.PSObject.Properties[$pair.Value]) {
@@ -2410,7 +2489,7 @@ function Emit-Element {
# у popup/button/cmdBar. Тип-ключ владельца (popup/button/…) должен выиграть.
# pages/page ПЕРЕД group: у Page/Pages ключ 'group' — это направление раскладки детей
# (Horizontal), а не тип UsualGroup. Реальная UsualGroup ключа page/pages не несёт.
- foreach ($key in @("columnGroup","buttonGroup","pages","page","group","input","check","radio","label","labelField","table","button","calendar","cmdBar","popup","picField","picture")) {
+ foreach ($key in @("columnGroup","buttonGroup","pages","page","group","input","check","radio","label","labelField","table","button","calendar","cmdBar","popup","searchString","viewStatus","searchControl","picField","picture")) {
if ($el.$key -ne $null) {
$typeKey = $key
break
@@ -2484,6 +2563,8 @@ function Emit-Element {
"autofill"=1
# AutoCommandBar-маркер (autofill heuristic) на элементе/таблице
"autoCmdBar"=1
+ # дополнения командной панели таблицы (тип-ключи + свойства)
+ "searchString"=1;"viewStatus"=1;"searchControl"=1;"source"=1;"horizontalLocation"=1;"additions"=1
}
# Оформление (цвета/шрифты/граница) — авто-регистрация из самих структур, чтобы allowlist
# не дрейфовал при добавлении новых ключей/синонимов. Канонические + forgiving-синонимы.
@@ -2514,6 +2595,9 @@ function Emit-Element {
"page" { Emit-Page -el $el -name $name -id $id -indent $indent }
"button" { Emit-Button -el $el -name $name -id $id -indent $indent -inCmdBar $inCmdBar }
"picture" { Emit-PictureDecoration -el $el -name $name -id $id -indent $indent }
+ "searchString" { Emit-Addition -el $el -name $name -typeKey "searchString" -id $id -indent $indent }
+ "viewStatus" { Emit-Addition -el $el -name $name -typeKey "viewStatus" -id $id -indent $indent }
+ "searchControl" { Emit-Addition -el $el -name $name -typeKey "searchControl" -id $id -indent $indent }
"picField" { Emit-PictureField -el $el -name $name -id $id -indent $indent }
"calendar" { Emit-Calendar -el $el -name $name -id $id -indent $indent }
"cmdBar" { Emit-CommandBar -el $el -name $name -id $id -indent $indent }
@@ -3529,6 +3613,7 @@ function Emit-DynListTableBlock {
function Emit-Table {
param($el, [string]$name, [int]$id, [string]$indent)
+ $script:currentTableName = $name # дефолт source для кастомных дополнений в commandBar
X "$indent
"
$inner = "$indent`t"
@@ -3606,9 +3691,10 @@ function Emit-Table {
Emit-Companion -tag "AutoCommandBar" -name "${name}КоманднаяПанель" -indent $inner
}
Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip
- Emit-TableAddition -tag "SearchStringAddition" -tableName $name -nameSuffix "СтрокаПоиска" -srcType "SearchStringRepresentation" -indent $inner
- Emit-TableAddition -tag "ViewStatusAddition" -tableName $name -nameSuffix "СостояниеПросмотра" -srcType "ViewStatusRepresentation" -indent $inner
- Emit-TableAddition -tag "SearchControlAddition" -tableName $name -nameSuffix "УправлениеПоиском" -srcType "SearchControl" -indent $inner
+ $adds = $el.additions
+ Emit-TableAddition -typeKey 'searchString' -tableName $name -indent $inner -override (Get-AdditionOverride $adds 'searchString')
+ Emit-TableAddition -typeKey 'viewStatus' -tableName $name -indent $inner -override (Get-AdditionOverride $adds 'viewStatus')
+ Emit-TableAddition -typeKey 'searchControl' -tableName $name -indent $inner -override (Get-AdditionOverride $adds 'searchControl')
# Columns
if ($el.columns -and $el.columns.Count -gt 0) {
diff --git a/.claude/skills/form-compile/scripts/form-compile.py b/.claude/skills/form-compile/scripts/form-compile.py
index 7bf3b570..7ea65a06 100644
--- a/.claude/skills/form-compile/scripts/form-compile.py
+++ b/.claude/skills/form-compile/scripts/form-compile.py
@@ -1811,6 +1811,8 @@ KNOWN_KEYS = {
"userSettingsGroup", "rowsPicture",
# AutoCommandBar-маркер (autofill heuristic) на элементе/таблице
"autoCmdBar",
+ # дополнения командной панели таблицы (тип-ключи + свойства)
+ "searchString", "viewStatus", "searchControl", "source", "horizontalLocation", "additions",
}
# picture/picField — НИЗКИЙ приоритет: 'picture' это и тип (PictureDecoration), и свойство-иконка
@@ -1818,7 +1820,7 @@ KNOWN_KEYS = {
# pages/page ПЕРЕД group: у Page/Pages ключ 'group' — это направление раскладки детей
# (Horizontal), а не тип UsualGroup. Реальная UsualGroup ключа page/pages не несёт.
TYPE_KEYS = ["columnGroup", "buttonGroup", "pages", "page", "group", "input", "check", "radio", "label", "labelField", "table",
- "button", "calendar", "cmdBar", "popup", "picField", "picture"]
+ "button", "calendar", "cmdBar", "popup", "searchString", "viewStatus", "searchControl", "picField", "picture"]
# Synonyms: model often writes XML name or Russian (ПолеПереключателя/RadioButtonField → radio)
ELEMENT_TYPE_SYNONYMS = {
@@ -1857,6 +1859,20 @@ ELEMENT_TYPE_SYNONYMS = {
"Кнопка": "button",
"Popup": "popup",
"ВсплывающееМеню": "popup",
+ # дополнения командной панели таблицы — forgiving: XML-тег/Type/рус.имя → канон
+ "SearchStringAddition": "searchString",
+ "SearchStringRepresentation": "searchString",
+ "строкаПоиска": "searchString",
+ "отображениеСтрокиПоиска": "searchString",
+ "Отображение строки поиска": "searchString",
+ "ViewStatusAddition": "viewStatus",
+ "ViewStatusRepresentation": "viewStatus",
+ "состояниеПросмотра": "viewStatus",
+ "Состояние просмотра": "viewStatus",
+ "SearchControlAddition": "searchControl",
+ "SearchControl": "searchControl",
+ "управлениеПоиском": "searchControl",
+ "Управление поиском": "searchControl",
}
# Тип-синонимы, применяемые ТОЛЬКО к строковому значению (имя элемента); объект/массив
@@ -2324,18 +2340,89 @@ def emit_companion_panel(lines, tag, name, indent, panel):
lines.append(f'{indent}{tag}>')
-def emit_table_addition(lines, tag, table_name, name_suffix, src_type, indent):
- # Табличный addition с AdditionSource (Item = имя таблицы, Type фиксирован).
- add_name = f'{table_name}{name_suffix}'
+# Дополнения командной панели таблицы: тип DSL → XML-тег + AdditionSource.Type + суффикс имени.
+ADDITION_TYPE_MAP = {
+ 'searchString': {'tag': 'SearchStringAddition', 'type': 'SearchStringRepresentation', 'suffix': 'СтрокаПоиска'},
+ 'viewStatus': {'tag': 'ViewStatusAddition', 'type': 'ViewStatusRepresentation', 'suffix': 'СостояниеПросмотра'},
+ 'searchControl': {'tag': 'SearchControlAddition', 'type': 'SearchControl', 'suffix': 'УправлениеПоиском'},
+}
+ADDITION_KEY_SYNONYMS = {
+ 'searchString': ['SearchStringAddition', 'SearchStringRepresentation', 'строкаПоиска', 'отображениеСтрокиПоиска'],
+ 'viewStatus': ['ViewStatusAddition', 'ViewStatusRepresentation', 'состояниеПросмотра'],
+ 'searchControl': ['SearchControlAddition', 'SearchControl', 'управлениеПоиском'],
+}
+# Имя текущей таблицы — дефолт source для кастомных дополнений в commandBar.
+_current_table_name = {'name': None}
+
+
+def get_hlocation(el):
+ # HorizontalLocation: auto (дефолт, опускаем) / left / right; forgiving + рус.
+ if not isinstance(el, dict):
+ return None
+ v = el.get('horizontalLocation')
+ if not v:
+ return None
+ s = str(v).lower()
+ if s in ('auto', 'авто'):
+ return None
+ if s in ('left', 'слева', 'лево'):
+ return 'Left'
+ if s in ('right', 'справа', 'право'):
+ return 'Right'
+ return str(v)
+
+
+def emit_addition_body(lines, props, source, src_type, add_name, indent):
+ # Тело дополнения: AdditionSource + свойства (как у поля) + companions. props может быть None.
+ inner = f'{indent}\t'
+ lines.append(f'{inner}')
+ lines.append(f'{inner}\t- {source}
')
+ lines.append(f'{inner}\t{src_type}')
+ lines.append(f'{inner}')
+ if props:
+ if props.get('title'):
+ emit_mltext(lines, inner, 'Title', props['title'])
+ emit_common_flags(lines, props, inner)
+ if props.get('tooltip'):
+ emit_mltext(lines, inner, 'ToolTip', props['tooltip'])
+ if props.get('tooltipRepresentation'):
+ lines.append(f'{inner}{props["tooltipRepresentation"]}')
+ hl = get_hlocation(props)
+ if hl:
+ lines.append(f'{inner}{hl}')
+ emit_layout(lines, props, inner)
+ emit_appearance(lines, props, inner, 'field')
+ emit_companion(lines, 'ContextMenu', f'{add_name}КонтекстноеМеню', inner)
+ emit_companion(lines, 'ExtendedTooltip', f'{add_name}РасширеннаяПодсказка', inner)
+
+
+def emit_addition(lines, el, name, eid, type_key, indent):
+ # Кастомное дополнение (тип-элемент в commandBar): source дефолтит в текущую таблицу.
+ m = ADDITION_TYPE_MAP[type_key]
+ source = el.get('source') or _current_table_name['name'] or ''
+ lines.append(f'{indent}<{m["tag"]} name="{name}" id="{eid}">')
+ emit_addition_body(lines, el, source, m['type'], name, indent)
+ lines.append(f'{indent}{m["tag"]}>')
+
+
+def emit_table_addition(lines, type_key, table_name, indent, override=None):
+ # Стандартное табличное дополнение (авто-генерация). override — объект отклонений из карты additions.
+ m = ADDITION_TYPE_MAP[type_key]
+ add_name = f'{table_name}{m["suffix"]}'
aid = new_id()
- lines.append(f'{indent}<{tag} name="{add_name}" id="{aid}">')
- lines.append(f'{indent}\t')
- lines.append(f'{indent}\t\t- {table_name}
')
- lines.append(f'{indent}\t\t{src_type}')
- lines.append(f'{indent}\t')
- emit_companion(lines, 'ContextMenu', f'{add_name}КонтекстноеМеню', f'{indent}\t')
- emit_companion(lines, 'ExtendedTooltip', f'{add_name}РасширеннаяПодсказка', f'{indent}\t')
- lines.append(f'{indent}{tag}>')
+ lines.append(f'{indent}<{m["tag"]} name="{add_name}" id="{aid}">')
+ emit_addition_body(lines, override, table_name, m['type'], add_name, indent)
+ lines.append(f'{indent}{m["tag"]}>')
+
+
+def get_addition_override(additions, type_key):
+ # Прочитать override-объект для типа из per-table карты additions (с синонимами).
+ if not isinstance(additions, dict):
+ return None
+ for k in [type_key] + ADDITION_KEY_SYNONYMS[type_key]:
+ if k in additions:
+ return additions[k]
+ return None
# Role-adjustable boolean (xr:Common + 0..N xr:Value name="Role.X").
@@ -2866,6 +2953,9 @@ def emit_element(lines, el, indent, in_cmd_bar=False):
'calendar': emit_calendar,
'cmdBar': emit_command_bar,
'popup': emit_popup,
+ 'searchString': lambda lines, el, name, eid, indent: emit_addition(lines, el, name, eid, 'searchString', indent),
+ 'viewStatus': lambda lines, el, name, eid, indent: emit_addition(lines, el, name, eid, 'viewStatus', indent),
+ 'searchControl': lambda lines, el, name, eid, indent: emit_addition(lines, el, name, eid, 'searchControl', indent),
}
emitter = emitters.get(type_key)
@@ -3240,6 +3330,7 @@ def emit_dynlist_table_block(lines, el, indent):
def emit_table(lines, el, name, eid, indent):
+ _current_table_name['name'] = name # дефолт source для кастомных дополнений в commandBar
lines.append(f'{indent}')
inner = f'{indent}\t'
@@ -3331,9 +3422,10 @@ def emit_table(lines, el, name, eid, indent):
else:
emit_companion(lines, 'AutoCommandBar', f'{name}\u041a\u043e\u043c\u0430\u043d\u0434\u043d\u0430\u044f\u041f\u0430\u043d\u0435\u043b\u044c', inner)
emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip'))
- emit_table_addition(lines, 'SearchStringAddition', name, '\u0421\u0442\u0440\u043e\u043a\u0430\u041f\u043e\u0438\u0441\u043a\u0430', 'SearchStringRepresentation', inner)
- emit_table_addition(lines, 'ViewStatusAddition', name, '\u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430', 'ViewStatusRepresentation', inner)
- emit_table_addition(lines, 'SearchControlAddition', name, '\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u041f\u043e\u0438\u0441\u043a\u043e\u043c', 'SearchControl', inner)
+ adds = el.get('additions')
+ emit_table_addition(lines, 'searchString', name, inner, get_addition_override(adds, 'searchString'))
+ emit_table_addition(lines, 'viewStatus', name, inner, get_addition_override(adds, 'viewStatus'))
+ emit_table_addition(lines, 'searchControl', name, inner, get_addition_override(adds, 'searchControl'))
# Columns
if el.get('columns') and len(el['columns']) > 0:
diff --git a/.claude/skills/form-decompile/scripts/form-decompile.ps1 b/.claude/skills/form-decompile/scripts/form-decompile.ps1
index 6ac1cd1a..b49cae83 100644
--- a/.claude/skills/form-decompile/scripts/form-decompile.ps1
+++ b/.claude/skills/form-decompile/scripts/form-decompile.ps1
@@ -1,4 +1,4 @@
-# form-decompile v0.50 — Decompile 1C managed Form.xml to JSON DSL (draft)
+# form-decompile v0.51 — Decompile 1C managed Form.xml to JSON DSL (draft)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
# ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью.
param(
@@ -214,7 +214,9 @@ function ConvertTo-CompactJson {
# --- 2. Helpers ---
# Companion-элементы (авто-генерируемые компилятором) — пропускаем при обходе детей.
-$COMPANION_TAGS = @('ContextMenu','ExtendedTooltip','AutoCommandBar','SearchStringAddition','ViewStatusAddition','SearchControlAddition')
+# Дополнения (Search*/ViewStatus) БОЛЬШЕ не companion — декомпилируются как тип-элементы
+# (кастомные в AutoCommandBar/ChildItems → commandBar.children; стандартные на уровне таблицы → карта additions).
+$COMPANION_TAGS = @('ContextMenu','ExtendedTooltip','AutoCommandBar')
# Извлечь мультиязычный Title/Presentation → string (ru) или ordered hash {ru,en,...}
function Get-LangText {
@@ -1114,7 +1116,8 @@ $ELEMENT_KEY = @{
'UsualGroup'='group'; 'ColumnGroup'='columnGroup'; 'ButtonGroup'='buttonGroup'; 'InputField'='input'; 'CheckBoxField'='check';
'RadioButtonField'='radio'; 'LabelDecoration'='label'; 'LabelField'='labelField';
'PictureDecoration'='picture'; 'PictureField'='picField'; 'CalendarField'='calendar';
- 'Table'='table'; 'Pages'='pages'; 'Page'='page'; 'Button'='button'; 'CommandBar'='cmdBar'; 'Popup'='popup'
+ 'Table'='table'; 'Pages'='pages'; 'Page'='page'; 'Button'='button'; 'CommandBar'='cmdBar'; 'Popup'='popup';
+ 'SearchStringAddition'='searchString'; 'ViewStatusAddition'='viewStatus'; 'SearchControlAddition'='searchControl'
}
function Decompile-Children {
@@ -1256,6 +1259,37 @@ function Add-FormatProps {
$efmt = $node.SelectSingleNode("lf:EditFormat", $ns); if ($efmt) { $t = Get-LangText $efmt; if ($null -ne $t -and $t -ne '') { $obj['editFormat'] = $t } }
}
+# Ядро дополнения: source + общие свойства (Add-CommonProps) + horizontalLocation.
+# Layout (Add-Layout) добавляется ОТДЕЛЬНО (в Decompile-Element — пост-обработкой, в standalone — явно).
+function Add-AdditionCore {
+ param($obj, $node, [string]$elName)
+ $src = $node.SelectSingleNode("lf:AdditionSource/lf:Item", $ns); if ($src) { $obj['source'] = $src.InnerText }
+ Add-CommonProps $obj $node $elName
+ $hl = Get-Child $node 'HorizontalLocation'; if ($hl) { $obj['horizontalLocation'] = $hl.ToLower() }
+}
+
+# Стандартные дополнения уровня таблицы (прямые дети ): извлечь ТОЛЬКО отклонения в карту
+# { тип: {свойства} }. Имя (=tableName+suffix) и source (=tableName) — дефолтные, опускаем.
+function Decompile-TableAdditions {
+ param($tableNode, [string]$tableName)
+ $tagToKey = @{ 'SearchStringAddition'='searchString'; 'ViewStatusAddition'='viewStatus'; 'SearchControlAddition'='searchControl' }
+ $map = [ordered]@{}
+ foreach ($child in $tableNode.ChildNodes) {
+ if ($child.NodeType -ne [System.Xml.XmlNodeType]::Element) { continue }
+ if (-not $tagToKey.ContainsKey($child.LocalName)) { continue }
+ $key = $tagToKey[$child.LocalName]
+ $nm = $child.GetAttribute("name")
+ $o = [ordered]@{}; $o[$key] = $nm
+ Add-AdditionCore $o $child $nm
+ Add-Layout $o $child
+ $o.Remove($key) # имя авто
+ if ($o.Contains('source') -and $o['source'] -eq $tableName) { $o.Remove('source') } # source=таблица дефолт
+ if ($o.Count -gt 0) { $map[$key] = $o }
+ }
+ if ($map.Count -gt 0) { return $map }
+ return $null
+}
+
function Decompile-Element {
param($node)
$tag = $node.LocalName
@@ -1410,7 +1444,13 @@ function Decompile-Element {
if ((Get-Child $node 'Header') -eq 'false') { $obj['header'] = $false }
if ((Get-Child $node 'Footer') -eq 'true') { $obj['footer'] = $true }
$htr = Get-Child $node 'HeightInTableRows'; if ($htr) { $obj['height'] = [int]$htr }
- $cbl = Get-Child $node 'CommandBarLocation'; if ($cbl) { $obj['commandBarLocation'] = $cbl }
+ # CommandBarLocation: для дин-список-таблицы компилятор авто-инжектит "None" → инвертируем
+ # (нет тега → суппресс-маркер ""; "None" → опускаем = авто-дефолт; иначе → захват).
+ $cbl = Get-Child $node 'CommandBarLocation'
+ if (Has-Child $node 'UpdateOnDataChange') {
+ if ($null -eq $cbl) { $obj['commandBarLocation'] = '' }
+ elseif ($cbl -ne 'None') { $obj['commandBarLocation'] = $cbl }
+ } elseif ($cbl) { $obj['commandBarLocation'] = $cbl }
$ssl = Get-Child $node 'SearchStringLocation'; if ($ssl) { $obj['searchStringLocation'] = $ssl }
$vsl = Get-Child $node 'ViewStatusLocation'; if ($vsl) { $obj['viewStatusLocation'] = $vsl }
$scl = Get-Child $node 'SearchControlLocation'; if ($scl) { $obj['searchControlLocation'] = $scl }
@@ -1447,6 +1487,9 @@ function Decompile-Element {
}
$cols = Decompile-Children $node
if ($cols) { $obj['columns'] = $cols }
+ # Стандартные дополнения уровня таблицы (прямые дети) → карта отклонений additions
+ $addMap = Decompile-TableAdditions $node $name
+ if ($addMap) { $obj['additions'] = $addMap }
}
'Pages' {
$obj[$key] = $name
@@ -1510,6 +1553,9 @@ function Decompile-Element {
$kids = Decompile-Children $node
if ($kids) { $obj['children'] = $kids }
}
+ 'SearchStringAddition' { $obj[$key] = $name; Add-AdditionCore $obj $node $name }
+ 'ViewStatusAddition' { $obj[$key] = $name; Add-AdditionCore $obj $node $name }
+ 'SearchControlAddition' { $obj[$key] = $name; Add-AdditionCore $obj $node $name }
}
# title: "" — подавление авто-вывода: для типов, где компилятор вывел бы
# заголовок из имени, а в оригинале отсутствует.
diff --git a/docs/form-dsl-spec.md b/docs/form-dsl-spec.md
index 2fbb32d7..b47d6c37 100644
--- a/docs/form-dsl-spec.md
+++ b/docs/form-dsl-spec.md
@@ -511,6 +511,30 @@ companion-панели с собственным контентом. Оба не
| `viewStatusLocation` | string | `None`, `Top`, `Bottom`, `Auto` |
| `searchControlLocation` | string | `None`, `Top`, `Bottom`, `Auto` |
| `excludedCommands` | string[] | Исключённые стандартные команды таблицы (`Add`, `Delete`, `MoveUp`, `SortListAsc`, …) → `` |
+| `additions` | object | Отклонения стандартных дополнений командной панели (см. ниже) |
+
+> `commandBarLocation` у **дин-список-таблицы** компилятор авто-подставляет `None`. Чтобы оставить тег пустым (платформа не написала его) — задайте `commandBarLocation: ""` (суппресс-маркер); декомпилятор так и делает.
+
+##### Дополнения командной панели (поиск / состояние / управление)
+
+Дополнения — «представления» встроенного поиска таблицы: `searchString` (отображение строки поиска), `viewStatus` (состояние просмотра), `searchControl` (управление поиском). Это полноценные элементы (полный набор свойств поля). Две позиции:
+
+**(1) Стандартные** (платформа авто-генерит на уровне таблицы) — указываются ТОЛЬКО отклонения, через карту `additions` (ключ = тип):
+```json
+{ "table": "Список", "additions": { "viewStatus": { "horizontalLocation": "left" } } }
+```
+
+**(2) Кастомные** (размещённые в командной панели) — обычные элементы в `commandBar`:
+```json
+{ "table": "Список", "commandBar": [
+ { "searchString": "ПоискСписка", "source": "Список", "width": 15, "horizontalStretch": true }
+]}
+```
+
+- Тип-ключ: `searchString` / `viewStatus` / `searchControl` (forgiving: XML-тег `SearchStringAddition`, `` `SearchStringRepresentation`, рус. `строкаПоиска`/«Отображение строки поиска»).
+- `source` → `AdditionSource.Item`; **дефолт = имя родительской таблицы**.
+- `horizontalLocation`: `auto` (дефолт) / `left` / `right` (+ рус. `слева`/`справа`). Применимо и к обычным элементам командных панелей.
+- Прочие свойства (`title`, `visible`, `userVisible`, `enabled`, `tooltip`, оформление, `width`/`maxWidth`/`autoMaxWidth`/`horizontalStretch`/`groupHorizontalAlign`/…) — как у поля.
##### Таблица динамического списка
diff --git a/tests/skills/cases/form-compile/dynamic-list-form.json b/tests/skills/cases/form-compile/dynamic-list-form.json
index 5d80f9e1..f3e58d45 100644
--- a/tests/skills/cases/form-compile/dynamic-list-form.json
+++ b/tests/skills/cases/form-compile/dynamic-list-form.json
@@ -24,10 +24,15 @@
} }
],
"elements": [
- { "table": "Список", "path": "Список", "columns": [
- { "input": "Код", "path": "Список.Code" },
- { "input": "Наименование", "path": "Список.Description" }
- ]}
+ { "table": "Список", "path": "Список",
+ "additions": { "viewStatus": { "horizontalLocation": "left" } },
+ "commandBar": [
+ { "searchString": "ПоискСписка", "source": "Список", "width": 15, "horizontalStretch": true }
+ ],
+ "columns": [
+ { "input": "Код", "path": "Список.Code" },
+ { "input": "Наименование", "path": "Список.Description" }
+ ]}
]
}
}
diff --git a/tests/skills/cases/form-compile/snapshots/dynamic-list-form/Catalogs/Товары/Forms/ФормаСписка/Ext/Form.xml b/tests/skills/cases/form-compile/snapshots/dynamic-list-form/Catalogs/Товары/Forms/ФормаСписка/Ext/Form.xml
index 86620112..333ca92a 100644
--- a/tests/skills/cases/form-compile/snapshots/dynamic-list-form/Catalogs/Товары/Forms/ФормаСписка/Ext/Form.xml
+++ b/tests/skills/cases/form-compile/snapshots/dynamic-list-form/Catalogs/Товары/Forms/ФормаСписка/Ext/Form.xml
@@ -29,49 +29,61 @@
true
- false
+
+
+
+ - Список
+ SearchStringRepresentation
+
+ 15
+ true
+
+
+
+
-
-
+
+
- Список
SearchStringRepresentation
-
-
+
+
-
+
- Список
ViewStatusRepresentation
-
-
+ Left
+
+
-
+
- Список
SearchControl
-
-
+
+
-
+
Список.Code
-
-
+
+
-
+
Список.Description
-
-
+
+
-
+
cfg:DynamicList