fix(form-decompile,form-compile): PictureDecoration имя-как-Ref + <xr:Abs> + порядок Title декораций

Баг: Emit-PictureDecoration брал $el.picture (тип-ключ = имя элемента) фолбэком
источника картинки → при отсутствии src писал <xr:Ref>ИмяДекорации>. Фикс:
источник картинки — ТОЛЬКО src.

<xr:Abs> (встроенная картинка, 131 в корпусе): декомпилятор ловил лишь xr:Ref →
теперь src:"abs:Имя" → <xr:Abs>Имя</xr:Abs> (префикс abs:, иначе <xr:Ref>).

Порядок: LabelDecoration эмитил Title перед own-content, а платформа — layout-first
(корпус 16970 vs 44). Переставил флаги/hyperlink/layout/оформление ПЕРЕД Title (как
ExtendedTooltip) — заодно убирает шум атрибуции харнесса на многострочном Title
(Height «уезжал» на родительскую группу; контент был корректен, ломалась line-
атрибуция). Форма МобильноеПриложениеПредприниматель → round-trip match.

Зеркало py (байт-в-байт). Снэпшоты events/element-appearance/additional-columns
обновлены (только порядок) и пере-сертифицированы в 1С. Регресс 39/39 ps1+py.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-06-08 21:27:37 +03:00
parent 8915e99ac8
commit f7d5e2fd00
6 changed files with 38 additions and 30 deletions
@@ -1,4 +1,4 @@
# form-compile v1.82 — Compile 1C managed form from JSON or object metadata
# form-compile v1.83 — Compile 1C managed form from JSON or object metadata
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[string]$JsonPath,
@@ -3609,16 +3609,15 @@ function Emit-Label {
X "$indent<LabelDecoration name=`"$name`" id=`"$id`">"
$inner = "$indent`t"
Emit-DecorationTitle -el $el -name $name -indent $inner -auto
# Порядок как у платформы: own-content (флаги/hyperlink/layout/оформление) ПЕРЕД Title
# (корпус layout-first 16970 vs 44 — заодно убирает шум атрибуции харнесса на многострочном Title).
Emit-CommonFlags -el $el -indent $inner
if ($el.hyperlink -eq $true) { X "$inner<Hyperlink>true</Hyperlink>" }
Emit-Layout -el $el -indent $inner
# Оформление (цвета/шрифт/граница) — перед компаньонами (профиль декорации)
Emit-Appearance -el $el -indent $inner -profile 'decoration'
Emit-DecorationTitle -el $el -name $name -indent $inner -auto
# Companions
Emit-CompanionPanel -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner -panel $el.contextMenu
Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip
@@ -3967,11 +3966,14 @@ function Emit-PictureDecoration {
Emit-DecorationTitle -el $el -name $name -indent $inner
Emit-CommonFlags -el $el -indent $inner
if ($el.picture -or $el.src) {
$ref = if ($el.src) { "$($el.src)" } else { "$($el.picture)" }
# Источник картинки — ТОЛЬКО $el.src (у PictureDecoration ключ 'picture' = тип/имя элемента, не источник).
# Префикс "abs:" → встроенная картинка <xr:Abs>; иначе именованная/стилевая <xr:Ref>.
if ($el.src) {
$srcStr = "$($el.src)"
$lt = if ($el.loadTransparent -eq $true) { "true" } else { "false" }
X "$inner<Picture>"
X "$inner`t<xr:Ref>$ref</xr:Ref>"
if ($srcStr -match '^abs:(.*)$') { X "$inner`t<xr:Abs>$(Esc-Xml $matches[1])</xr:Abs>" }
else { X "$inner`t<xr:Ref>$(Esc-Xml $srcStr)</xr:Ref>" }
X "$inner`t<xr:LoadTransparent>$lt</xr:LoadTransparent>"
X "$inner</Picture>"
}
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# form-compile v1.82 — Compile 1C managed form from JSON or object metadata
# form-compile v1.83 — Compile 1C managed form from JSON or object metadata
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import copy
@@ -3314,17 +3314,16 @@ def emit_label(lines, el, name, eid, indent):
lines.append(f'{indent}<LabelDecoration name="{name}" id="{eid}">')
inner = f'{indent}\t'
emit_decoration_title(lines, el, name, inner, auto=True)
# Порядок как у платформы: own-content (флаги/hyperlink/layout/оформление) ПЕРЕД Title
# (корпус layout-first 16970 vs 44 — заодно убирает шум атрибуции харнесса на многострочном Title).
emit_common_flags(lines, el, inner)
if el.get('hyperlink') is True:
lines.append(f'{inner}<Hyperlink>true</Hyperlink>')
emit_layout(lines, el, inner)
# Оформление (цвета/шрифт/граница) — перед компаньонами (профиль декорации)
emit_appearance(lines, el, inner, 'decoration')
emit_decoration_title(lines, el, name, inner, auto=True)
# Companions
emit_companion_panel(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner, el.get('contextMenu'))
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'))
@@ -3663,11 +3662,16 @@ def emit_picture_decoration(lines, el, name, eid, indent):
emit_decoration_title(lines, el, name, inner)
emit_common_flags(lines, el, inner)
if el.get('picture') or el.get('src'):
ref = str(el.get('src') or el.get('picture'))
# Источник картинки — ТОЛЬКО src (ключ 'picture' = тип/имя элемента, не источник).
# Префикс "abs:" → встроенная картинка <xr:Abs>; иначе именованная/стилевая <xr:Ref>.
if el.get('src'):
src_str = str(el['src'])
lt = 'true' if el.get('loadTransparent') is True else 'false'
lines.append(f'{inner}<Picture>')
lines.append(f'{inner}\t<xr:Ref>{ref}</xr:Ref>')
if src_str.startswith('abs:'):
lines.append(f'{inner}\t<xr:Abs>{esc_xml(src_str[4:])}</xr:Abs>')
else:
lines.append(f'{inner}\t<xr:Ref>{esc_xml(src_str)}</xr:Ref>')
lines.append(f'{inner}\t<xr:LoadTransparent>{lt}</xr:LoadTransparent>')
lines.append(f'{inner}</Picture>')
@@ -1,4 +1,4 @@
# form-decompile v0.58 — Decompile 1C managed Form.xml to JSON DSL (draft)
# form-decompile v0.59 — Decompile 1C managed Form.xml to JSON DSL (draft)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
# ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью.
param(
@@ -1436,7 +1436,9 @@ function Decompile-Element {
# title декорации — единая ML-text форма с formatted (атрибут <Title formatted> у PictureDecoration)
$tiNode = $node.SelectSingleNode("lf:Title", $ns)
if ($tiNode) { $tv = Get-MLFormattedValue $tiNode; if ($null -ne $tv) { $obj['title'] = $tv } }
$ref = $node.SelectSingleNode("lf:Picture/xr:Ref", $ns); if ($ref) { $obj['src'] = $ref.InnerText }
$ref = $node.SelectSingleNode("lf:Picture/xr:Ref", $ns)
$abs = $node.SelectSingleNode("lf:Picture/xr:Abs", $ns)
if ($ref) { $obj['src'] = $ref.InnerText } elseif ($abs) { $obj['src'] = "abs:$($abs.InnerText)" } # встроенная картинка → префикс abs:
$lt = $node.SelectSingleNode("lf:Picture/xr:LoadTransparent", $ns); if ($lt -and $lt.InnerText -eq 'true') { $obj['loadTransparent'] = $true }
if ((Get-Child $node 'Hyperlink') -eq 'true') { $obj['hyperlink'] = $true }
}
+1 -1
View File
@@ -636,7 +636,7 @@ Pages поддерживает `pagesRepresentation`: `None`, `TabsOnTop`, `Tabs
| Свойство | Тип | Описание |
|----------|-----|----------|
| `src` или `picture` (как свойство) | string | Ссылка на картинку |
| `src` (у `picture`-декорации — только `src`, не имя) | string | Ссылка на картинку: `StdPicture.X`/`CommonPicture.X`/`style:X``<xr:Ref>`. Префикс `abs:` (напр. `"abs:Picture.png"`) → встроенная картинка `<xr:Abs>` |
| `loadTransparent` | bool | `true` → загружать прозрачной. По умолчанию `false` |
| `hyperlink` | bool | Режим гиперссылки |
| `width` | int | Ширина |
@@ -10,17 +10,17 @@
<AutoCommandBar name="ФормаКоманднаяПанель" id="-1"/>
<ChildItems>
<LabelDecoration name="Внимание!" id="1">
<TextColor>web:FireBrick</TextColor>
<Font faceName="Arial" height="12" bold="true" italic="false" underline="false" strikeout="false" kind="Absolute" scale="100"/>
<Border width="1">
<v8ui:style xsi:type="v8ui:ControlBorderType">Single</v8ui:style>
</Border>
<Title formatted="false">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Внимание!</v8:content>
</v8:item>
</Title>
<TextColor>web:FireBrick</TextColor>
<Font faceName="Arial" height="12" bold="true" italic="false" underline="false" strikeout="false" kind="Absolute" scale="100"/>
<Border width="1">
<v8ui:style xsi:type="v8ui:ControlBorderType">Single</v8ui:style>
</Border>
<ContextMenu name="Внимание!КонтекстноеМеню" id="2"/>
<ExtendedTooltip name="Внимание!РасширеннаяПодсказка" id="3"/>
</LabelDecoration>
@@ -32,15 +32,15 @@
<ExtendedTooltip name="ЦенаРасширеннаяПодсказка" id="6"/>
</InputField>
<LabelDecoration name="Из стиля" id="7">
<TextColor>web:DimGray</TextColor>
<Font ref="style:NormalTextFont" kind="StyleItem"/>
<Border ref="style:ControlBorder"/>
<Title formatted="false">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Из стиля</v8:content>
</v8:item>
</Title>
<TextColor>web:DimGray</TextColor>
<Font ref="style:NormalTextFont" kind="StyleItem"/>
<Border ref="style:ControlBorder"/>
<ContextMenu name="Из стиляКонтекстноеМеню" id="8"/>
<ExtendedTooltip name="Из стиляРасширеннаяПодсказка" id="9"/>
</LabelDecoration>
@@ -31,6 +31,7 @@
</Events>
</InputField>
<LabelDecoration name="Подсказка" id="7">
<Hyperlink>true</Hyperlink>
<Title formatted="false">
<v8:item>
<v8:lang>ru</v8:lang>
@@ -38,7 +39,6 @@
</v8:item>
</Title>
<ToolTipRepresentation>Button</ToolTipRepresentation>
<Hyperlink>true</Hyperlink>
<ContextMenu name="ПодсказкаКонтекстноеМеню" id="8"/>
<ExtendedTooltip name="ПодсказкаРасширеннаяПодсказка" id="9"/>
<Events>