feat(form-decompile,form-compile): InputField choice-скаляры verbatim + Button Check + FixingInTable + слой рус.синонимов ключей

Раундтрип TOTAL 121→86 (−35), match 114→124.

- InputField choice-кнопки: захват/эмит «как есть» (ChoiceButton/ClearButton/
  DropListButton/SpinButton эмитились только при true, теряя явный false;
  ChoiceButton=true сидел под лишним StartChoice-гейтом). Убран дефолт
  choiceButton=true у ref-полей в from-object — вывод не изменился.
- Новые InputField-скаляры: choiceListButton/quickChoice/autoChoiceIncomplete
  (bool), choiceForm/choiceHistoryOnInput/choiceFoldersAndItems/footerDataPath (value).
- Button checked → <Check>true</Check> (пометка toggle-кнопки). Ключ checked,
  не check (check — тип-ключ CheckBoxField, был бы конфликт диспетчера типов).
- fixingInTable — в generic-скаляры (input/labelField/колонки).
- Общий слой русских синонимов ключей-свойств ($propSynonyms/PROP_SYNONYMS):
  Пометка/Заголовок/Ширина/КнопкаВыбора/ФормаВыбора/… → канон. Нормализация
  в Emit-Element рядом с тип-синонимами; case/space-insensitive; англ. побеждает.

Зеркало py (контент байт-в-байт). Кейсы input-fields/table/synonyms расширены
и сертифицированы загрузкой в 1С. Регресс 39/39 зелёный в обоих рантаймах.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-06-08 22:34:15 +03:00
parent 4a68a977dc
commit 7882c1cc2b
10 changed files with 166 additions and 40 deletions
@@ -1,4 +1,4 @@
# form-compile v1.84 — Compile 1C managed form from JSON or object metadata
# form-compile v1.86 — Compile 1C managed form from JSON or object metadata
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[string]$JsonPath,
@@ -380,10 +380,9 @@ function New-FieldElement {
$el = [ordered]@{ $elType = $attrName; path = $dataPath }
# Apply ref defaults
if ($isRef -and $fieldDefaults -and $fieldDefaults.ref) {
if ($fieldDefaults.ref.choiceButton -eq $true) { $el["choiceButton"] = $true }
}
# (ChoiceButton у ref-полей платформа выводит сама; компилятор эмитит true по StartChoice-эвристике.
# Явный choiceButton из декомпиляции эмитится verbatim. Дефолт-«true» здесь НЕ ставим, чтобы
# from-object вывод совпадал с сертифицированным и не плодил ChoiceButton на каждом ref-поле.)
# Extra props
if ($extraProps) {
@@ -2527,6 +2526,20 @@ function Emit-Element {
}
}
# Синонимы ключей-свойств (русские имена 1С → канон. англ.). Case/space-insensitive.
# Канон побеждает: если задан и русский, и англ. ключ — англ. остаётся, русский отбрасываем.
foreach ($pn in @($el.PSObject.Properties.Name)) {
$norm = ($pn -replace '\s','').ToLower()
$canon = $script:propSynonyms[$norm]
if ($canon -and $pn -ne $canon) {
if ($null -eq $el.PSObject.Properties[$canon]) {
$val = $el.($pn)
$el | Add-Member -NotePropertyName $canon -NotePropertyValue $val -Force
}
$el.PSObject.Properties.Remove($pn) | Out-Null
}
}
# Determine element type from key
$typeKey = $null
$xmlTag = $null
@@ -2614,12 +2627,18 @@ function Emit-Element {
# generic-скаляры (pass-through) + точечные
"verticalAlign"=1;"throughAlign"=1;"enableContentChange"=1;"pictureSize"=1;"titleHeight"=1
"childItemsWidth"=1;"showLeftMargin"=1;"cellHyperlink"=1;"viewMode"=1;"verticalScrollBar"=1
"rowInputMode"=1;"mask"=1;"createButton"=1
"rowInputMode"=1;"mask"=1;"createButton"=1;"fixingInTable"=1
# InputField choice-скаляры
"choiceListButton"=1;"quickChoice"=1;"autoChoiceIncomplete"=1
"choiceForm"=1;"choiceHistoryOnInput"=1;"footerDataPath"=1
# Button — пометка toggle-кнопки (ключ 'checked', не 'check' — во избежание конфликта с типом)
"checked"=1
}
# Оформление (цвета/шрифты/граница) — авто-регистрация из самих структур, чтобы allowlist
# не дрейфовал при добавлении новых ключей/синонимов. Канонические + forgiving-синонимы.
foreach ($k in $script:appearanceSpec.Keys) { $knownKeys[$k] = 1 }
foreach ($k in $script:appearanceSynonyms.Keys) { $knownKeys[$k] = 1 }
foreach ($k in $script:propSynonyms.Keys) { $knownKeys[$k] = 1 }
foreach ($p in $el.PSObject.Properties) {
if ($p.Name -like '_*') { continue } # внутренние маркеры (напр. _dynList)
if (-not $knownKeys.ContainsKey($p.Name)) {
@@ -2782,6 +2801,22 @@ $script:appearanceSynonyms = @{
'цветтекстаподвала'='footerTextColor'; 'цветфонаподвала'='footerBackColor'; 'шрифтподвала'='footerFont'
'шрифт'='font'; 'рамка'='border'
}
# Синонимы ключей-свойств: русские имена свойств 1С (как в Конфигураторе) → канон. англ. ключ.
# Ключи карты нормализованы (lowercase, без пробелов); сопоставление в Normalize-PropSynonyms тоже.
# Прощающий ввод: модель может писать свойство по-русски. Англ. ключ работает всегда (это доп. слой).
# Видимость/Доступность НЕ включаем — наш hidden/disabled инвертирован, был бы баг семантики.
$script:propSynonyms = @{
'пометка'='checked'
'кнопкавыбора'='choiceButton'; 'кнопкаочистки'='clearButton'; 'кнопкарегулирования'='spinButton'
'кнопкавыпадающегосписка'='dropListButton'; 'кнопкасписковоговыбора'='choiceListButton'
'кнопкаоткрытия'='openButton'; 'кнопкапоумолчанию'='defaultButton'
'быстрыйвыбор'='quickChoice'; 'формавыбора'='choiceForm'; 'историявыборапривводе'='choiceHistoryOnInput'
'выборгруппиэлементов'='choiceFoldersAndItems'; 'фиксациявтаблице'='fixingInTable'
'путькданнымподвала'='footerDataPath'; 'автоотметканезаполненного'='markIncomplete'
'многострочныйрежим'='multiLine'; 'режимпароля'='passwordMode'; 'переноспословам'='wrap'
'расположениезаголовка'='titleLocation'; 'пропускатьпривводе'='skipOnInput'
'заголовок'='title'; 'ширина'='width'; 'высота'='height'; 'подсказкаввода'='inputHint'
}
# Профили порядка тегов по базовым типам (XSD-последовательность)
$script:appOrderField = @('titleTextColor','titleBackColor','titleFont','footerTextColor','footerBackColor','footerFont','textColor','backColor','borderColor','border','font')
$script:appOrderDecoration = @('textColor','font','backColor','borderColor','border')
@@ -2803,6 +2838,7 @@ $script:genericScalars = @(
@{ Tag='RowInputMode'; Key='rowInputMode'; Kind='value' }
@{ Tag='Mask'; Key='mask'; Kind='value' }
@{ Tag='CreateButton'; Key='createButton'; Kind='bool' }
@{ Tag='FixingInTable'; Key='fixingInTable'; Kind='value' }
)
function Emit-GenericScalars {
@@ -3107,11 +3143,14 @@ function Emit-Input {
if ($el.multiLine -eq $true) { X "$inner<MultiLine>true</MultiLine>" }
if ($el.passwordMode -eq $true) { X "$inner<PasswordMode>true</PasswordMode>" }
if ($el.choiceButton -eq $false) { X "$inner<ChoiceButton>false</ChoiceButton>" }
elseif ($el.choiceButton -eq $true -and (Test-ElementEvent $el 'StartChoice')) { X "$inner<ChoiceButton>true</ChoiceButton>" }
if ($el.clearButton -eq $true) { X "$inner<ClearButton>true</ClearButton>" }
if ($el.spinButton -eq $true) { X "$inner<SpinButton>true</SpinButton>" }
if ($el.dropListButton -eq $true) { X "$inner<DropListButton>true</DropListButton>" }
# ChoiceButton — захват «как есть» (платформа эмитит явное значение; ref-поля выводят сама,
# декомпилятор фиксирует факт. значение). Нет ключа → не эмитим (не додумываем по событию).
if ($null -ne $el.choiceButton) { X "$inner<ChoiceButton>$(if ($el.choiceButton){'true'}else{'false'})</ChoiceButton>" }
# Кнопки поля ввода — захват «как есть» (платформа эмитит явное значение, в т.ч. false)
if ($null -ne $el.clearButton) { X "$inner<ClearButton>$(if ($el.clearButton){'true'}else{'false'})</ClearButton>" }
if ($null -ne $el.spinButton) { X "$inner<SpinButton>$(if ($el.spinButton){'true'}else{'false'})</SpinButton>" }
if ($null -ne $el.dropListButton) { X "$inner<DropListButton>$(if ($el.dropListButton){'true'}else{'false'})</DropListButton>" }
if ($null -ne $el.choiceListButton) { X "$inner<ChoiceListButton>$(if ($el.choiceListButton){'true'}else{'false'})</ChoiceListButton>" }
if ($el.markIncomplete -eq $true) { X "$inner<AutoMarkIncomplete>true</AutoMarkIncomplete>" }
if ($el.editMode) { X "$inner<EditMode>$($el.editMode)</EditMode>" }
Emit-ColumnPics -el $el -indent $inner
@@ -3119,10 +3158,18 @@ function Emit-Input {
# InputField-специфичные скаляры (захват «как есть»: платформа эмитит явное не-дефолтное значение)
foreach ($p in @(
@('wrap','Wrap'), @('openButton','OpenButton'), @('listChoiceMode','ListChoiceMode'),
@('extendedEditMultipleValues','ExtendedEditMultipleValues'), @('chooseType','ChooseType')
@('extendedEditMultipleValues','ExtendedEditMultipleValues'), @('chooseType','ChooseType'),
@('quickChoice','QuickChoice'), @('autoChoiceIncomplete','AutoChoiceIncomplete')
)) {
if ($null -ne $el.($p[0])) { X "$inner<$($p[1])>$(if ($el.($p[0])){'true'}else{'false'})</$($p[1])>" }
}
# InputField-специфичные value-скаляры
foreach ($p in @(
@('choiceForm','ChoiceForm'), @('choiceHistoryOnInput','ChoiceHistoryOnInput'),
@('choiceFoldersAndItems','ChoiceFoldersAndItems'), @('footerDataPath','FooterDataPath')
)) {
if ($el.($p[0])) { X "$inner<$($p[1])>$(Esc-Xml "$($el.($p[0]))")</$($p[1])>" }
}
if ($el.choiceButtonRepresentation) { X "$inner<ChoiceButtonRepresentation>$($el.choiceButtonRepresentation)</ChoiceButtonRepresentation>" }
Emit-Layout -el $el -indent $inner -multiLineDefault ([bool]($el.multiLine -eq $true))
@@ -3935,6 +3982,9 @@ function Emit-Button {
Emit-CommonFlags -el $el -indent $inner
if ($el.defaultButton -eq $true) { X "$inner<DefaultButton>true</DefaultButton>" }
# Check (пометка toggle-кнопки командной панели) — платформа эмитит только true.
# Ключ 'checked' (не 'check': 'check' — тип-ключ CheckBoxField, был бы конфликт диспетчера типов)
if ($el.checked -eq $true) { X "$inner<Check>true</Check>" }
# Picture
Emit-CommandPicture -pic $el.picture -elemLt $el.loadTransparent -indent $inner
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# form-compile v1.84 — Compile 1C managed form from JSON or object metadata
# form-compile v1.86 — Compile 1C managed form from JSON or object metadata
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import copy
@@ -357,10 +357,9 @@ def new_field_element(attr_name, data_path, attr_type, field_defaults, extra_pro
el[el_type] = attr_name
el['path'] = data_path
# Apply ref defaults
if is_ref and field_defaults and field_defaults.get('ref'):
if field_defaults['ref'].get('choiceButton') is True:
el['choiceButton'] = True
# (ChoiceButton у ref-полей платформа выводит сама; компилятор эмитит true по StartChoice-эвристике.
# Явный choiceButton из декомпиляции эмитится verbatim. Дефолт-«true» здесь НЕ ставим, чтобы
# from-object вывод совпадал с сертифицированным и не плодил ChoiceButton на каждом ref-поле.)
# Extra props
if extra_props:
@@ -1816,7 +1815,12 @@ KNOWN_KEYS = {
# generic-скаляры (pass-through)
"verticalAlign", "throughAlign", "enableContentChange", "pictureSize", "titleHeight",
"childItemsWidth", "showLeftMargin", "cellHyperlink", "viewMode", "verticalScrollBar",
"rowInputMode", "mask", "createButton",
"rowInputMode", "mask", "createButton", "fixingInTable",
# InputField choice-скаляры
"choiceListButton", "quickChoice", "autoChoiceIncomplete",
"choiceForm", "choiceHistoryOnInput", "footerDataPath",
# Button — пометка toggle-кнопки
"checked",
}
# picture/picField — НИЗКИЙ приоритет: 'picture' это и тип (PictureDecoration), и свойство-иконка
@@ -2588,7 +2592,22 @@ APPEARANCE_SYNONYMS = {
'цветтекстаподвала': 'footerTextColor', 'цветфонаподвала': 'footerBackColor', 'шрифтподвала': 'footerFont',
'шрифт': 'font', 'рамка': 'border',
}
APP_ORDER_FIELD = ['titleTextColor', 'titleBackColor', 'titleFont', 'footerTextColor', 'footerBackColor', 'footerFont', 'textColor', 'backColor', 'borderColor', 'border', 'font']
# Синонимы ключей-свойств: русские имена свойств 1С (как в Конфигураторе) → канон. англ. ключ.
# Ключи нормализованы (lowercase, без пробелов); сопоставление в emit_element тоже. Англ. ключ
# работает всегда (доп. слой прощающего ввода). Видимость/Доступность НЕ включаем (hidden/disabled инвертирован).
PROP_SYNONYMS = {
'пометка': 'checked',
'кнопкавыбора': 'choiceButton', 'кнопкаочистки': 'clearButton', 'кнопкарегулирования': 'spinButton',
'кнопкавыпадающегосписка': 'dropListButton', 'кнопкасписковоговыбора': 'choiceListButton',
'кнопкаоткрытия': 'openButton', 'кнопкапоумолчанию': 'defaultButton',
'быстрыйвыбор': 'quickChoice', 'формавыбора': 'choiceForm', 'историявыборапривводе': 'choiceHistoryOnInput',
'выборгруппиэлементов': 'choiceFoldersAndItems', 'фиксациявтаблице': 'fixingInTable',
'путькданнымподвала': 'footerDataPath', 'автоотметканезаполненного': 'markIncomplete',
'многострочныйрежим': 'multiLine', 'режимпароля': 'passwordMode', 'переноспословам': 'wrap',
'расположениезаголовка': 'titleLocation', 'пропускатьпривводе': 'skipOnInput',
'заголовок': 'title', 'ширина': 'width', 'высота': 'height', 'подсказкаввода': 'inputHint',
}
APP_ORDER_FIELD =['titleTextColor', 'titleBackColor', 'titleFont', 'footerTextColor', 'footerBackColor', 'footerFont', 'textColor', 'backColor', 'borderColor', 'border', 'font']
APP_ORDER_DECORATION = ['textColor', 'font', 'backColor', 'borderColor', 'border']
APP_ORDER_BUTTON = ['textColor', 'backColor', 'borderColor', 'font']
@@ -2668,6 +2687,7 @@ GENERIC_SCALARS = [
('RowInputMode', 'rowInputMode', 'value'),
('Mask', 'mask', 'value'),
('CreateButton', 'createButton', 'bool'),
('FixingInTable', 'fixingInTable', 'value'),
]
@@ -2985,6 +3005,16 @@ def emit_element(lines, el, indent, in_cmd_bar=False):
continue
el[dst] = el.pop(src)
# Синонимы ключей-свойств (русские имена 1С → канон. англ.). Case/space-insensitive.
# Канон побеждает: если задан и русский, и англ. ключ — англ. остаётся, русский отбрасываем.
for p_name in list(el.keys()):
norm = p_name.replace(' ', '').lower()
canon = PROP_SYNONYMS.get(norm)
if canon and p_name != canon:
val = el.pop(p_name)
if canon not in el:
el[canon] = val
type_key = None
for key in TYPE_KEYS:
if el.get(key) is not None:
@@ -3165,16 +3195,19 @@ def emit_input(lines, el, name, eid, indent):
lines.append(f'{inner}<MultiLine>true</MultiLine>')
if el.get('passwordMode') is True:
lines.append(f'{inner}<PasswordMode>true</PasswordMode>')
if el.get('choiceButton') is False:
lines.append(f'{inner}<ChoiceButton>false</ChoiceButton>')
elif el.get('choiceButton') is True and test_element_event(el, 'StartChoice'):
lines.append(f'{inner}<ChoiceButton>true</ChoiceButton>')
if el.get('clearButton') is True:
lines.append(f'{inner}<ClearButton>true</ClearButton>')
if el.get('spinButton') is True:
lines.append(f'{inner}<SpinButton>true</SpinButton>')
if el.get('dropListButton') is True:
lines.append(f'{inner}<DropListButton>true</DropListButton>')
# ChoiceButton — захват «как есть» (платформа эмитит явное значение; ref-поля выводят сама,
# декомпилятор фиксирует факт. значение). Нет ключа → не эмитим (не додумываем по событию).
if el.get('choiceButton') is not None:
lines.append(f'{inner}<ChoiceButton>{"true" if el["choiceButton"] else "false"}</ChoiceButton>')
# Кнопки поля ввода — захват «как есть» (платформа эмитит явное значение, в т.ч. false)
if el.get('clearButton') is not None:
lines.append(f'{inner}<ClearButton>{"true" if el["clearButton"] else "false"}</ClearButton>')
if el.get('spinButton') is not None:
lines.append(f'{inner}<SpinButton>{"true" if el["spinButton"] else "false"}</SpinButton>')
if el.get('dropListButton') is not None:
lines.append(f'{inner}<DropListButton>{"true" if el["dropListButton"] else "false"}</DropListButton>')
if el.get('choiceListButton') is not None:
lines.append(f'{inner}<ChoiceListButton>{"true" if el["choiceListButton"] else "false"}</ChoiceListButton>')
if el.get('markIncomplete') is True:
lines.append(f'{inner}<AutoMarkIncomplete>true</AutoMarkIncomplete>')
if el.get('editMode'):
@@ -3184,9 +3217,15 @@ def emit_input(lines, el, name, eid, indent):
lines.append(f'{inner}<TextEdit>false</TextEdit>')
# InputField-специфичные скаляры (захват «как есть»: платформа эмитит явное не-дефолтное значение)
for key, tag in (('wrap', 'Wrap'), ('openButton', 'OpenButton'), ('listChoiceMode', 'ListChoiceMode'),
('extendedEditMultipleValues', 'ExtendedEditMultipleValues'), ('chooseType', 'ChooseType')):
('extendedEditMultipleValues', 'ExtendedEditMultipleValues'), ('chooseType', 'ChooseType'),
('quickChoice', 'QuickChoice'), ('autoChoiceIncomplete', 'AutoChoiceIncomplete')):
if el.get(key) is not None:
lines.append(f'{inner}<{tag}>{"true" if el[key] else "false"}</{tag}>')
# InputField-специфичные value-скаляры
for key, tag in (('choiceForm', 'ChoiceForm'), ('choiceHistoryOnInput', 'ChoiceHistoryOnInput'),
('choiceFoldersAndItems', 'ChoiceFoldersAndItems'), ('footerDataPath', 'FooterDataPath')):
if el.get(key):
lines.append(f'{inner}<{tag}>{esc_xml(str(el[key]))}</{tag}>')
if el.get('choiceButtonRepresentation'):
lines.append(f'{inner}<ChoiceButtonRepresentation>{el["choiceButtonRepresentation"]}</ChoiceButtonRepresentation>')
emit_layout(lines, el, inner, multi_line_default=(el.get('multiLine') is True))
@@ -3636,6 +3675,10 @@ def emit_button(lines, el, name, eid, indent, in_cmd_bar=False):
if el.get('defaultButton') is True:
lines.append(f'{inner}<DefaultButton>true</DefaultButton>')
# Check (пометка toggle-кнопки командной панели) — платформа эмитит только true.
# Ключ 'checked' (не 'check': 'check' — тип-ключ CheckBoxField, был бы конфликт диспетчера типов)
if el.get('checked') is True:
lines.append(f'{inner}<Check>true</Check>')
# Picture
emit_command_picture(lines, el.get('picture'), el.get('loadTransparent'), inner)
@@ -1,4 +1,4 @@
# form-decompile v0.61 — Decompile 1C managed Form.xml to JSON DSL (draft)
# form-decompile v0.62 — Decompile 1C managed Form.xml to JSON DSL (draft)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
# ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью.
param(
@@ -1135,6 +1135,7 @@ $GENERIC_SCALARS = @(
@{ Tag='RowInputMode'; Key='rowInputMode'; Kind='value' }
@{ Tag='Mask'; Key='mask'; Kind='value' }
@{ Tag='CreateButton'; Key='createButton'; Kind='bool' }
@{ Tag='FixingInTable'; Key='fixingInTable'; Kind='value' }
)
# Захват generic-скаляров. Специфичная обработка (если ключ уже задан) — побеждает.
@@ -1376,13 +1377,17 @@ function Decompile-Element {
$em = Get-Child $node 'EditMode'; if ($em) { $obj['editMode'] = $em }
$tl = Get-Child $node 'TitleLocation'; if ($tl) { $obj['titleLocation'] = $tl.ToLower() }
$ih = $node.SelectSingleNode("lf:InputHint", $ns); if ($ih) { $t = Get-LangText $ih; if ($t) { $obj['inputHint'] = $t } }
foreach ($p in @('ChoiceButton','ClearButton','SpinButton','DropListButton')) {
foreach ($p in @('ChoiceButton','ClearButton','SpinButton','DropListButton','ChoiceListButton')) {
$v = Get-Child $node $p; if ($null -ne $v) { $obj[($p.Substring(0,1).ToLower()+$p.Substring(1))] = (To-Bool $v) }
}
# InputField-специфичные скаляры (захват «как есть»)
foreach ($p in @('Wrap','OpenButton','ListChoiceMode','ExtendedEditMultipleValues','ChooseType')) {
# InputField-специфичные bool-скаляры (захват «как есть»)
foreach ($p in @('Wrap','OpenButton','ListChoiceMode','ExtendedEditMultipleValues','ChooseType','QuickChoice','AutoChoiceIncomplete')) {
$v = Get-Child $node $p; if ($null -ne $v) { $obj[($p.Substring(0,1).ToLower()+$p.Substring(1))] = (To-Bool $v) }
}
# InputField-специфичные value-скаляры (захват «как есть»)
foreach ($p in @('ChoiceForm','ChoiceHistoryOnInput','ChoiceFoldersAndItems','FooterDataPath')) {
$v = Get-Child $node $p; if ($null -ne $v) { $obj[($p.Substring(0,1).ToLower()+$p.Substring(1))] = $v }
}
$cbr = Get-Child $node 'ChoiceButtonRepresentation'; if ($cbr) { $obj['choiceButtonRepresentation'] = $cbr }
if ((Get-Child $node 'TextEdit') -eq 'false') { $obj['textEdit'] = $false }
$cl = Decompile-ChoiceList $node; if ($cl) { $obj['choiceList'] = $cl }
@@ -1554,6 +1559,7 @@ function Decompile-Element {
$type = Get-Child $node 'Type'
if ($type) { $tmap=@{'CommandBarButton'='commandBar';'UsualButton'='usual';'Hyperlink'='hyperlink';'CommandBarHyperlink'='hyperlink'}; if ($tmap.ContainsKey($type)) { $obj['type']=$tmap[$type] } else { $obj['type']=$type } }
if ((Get-Child $node 'DefaultButton') -eq 'true') { $obj['defaultButton'] = $true }
if ((Get-Child $node 'Check') -eq 'true') { $obj['checked'] = $true }
$ref = $node.SelectSingleNode("lf:Picture/xr:Ref", $ns); if ($ref) { $obj['picture'] = $ref.InnerText }
# Дефолт у picture кнопки/попапа = true → фиксируем только отклонение false (true опускаем)
$lt = $node.SelectSingleNode("lf:Picture/xr:LoadTransparent", $ns); if ($lt -and $lt.InnerText -eq 'false') { $obj['loadTransparent'] = $false }
+13
View File
@@ -135,6 +135,10 @@
Флаг авто-детектится по наличию известной разметки/`</>`: для plain-строки объект не нужен. Явная форма `{text, formatted}` — только когда авто-детект неверен (formatted-текст без разметки, либо буквальные `<…>`-плейсхолдеры в неформатированном).
#### Русские синонимы ключей-свойств (прощающий ввод)
Скалярные свойства элементов можно писать русскими именами 1С (как в Конфигураторе) — компилятор молча нормализует их в канонические англ. ключи. Сопоставление **регистро- и пробело-независимое** (`Пометка` = `пометка`, `Быстрый выбор` = `быстрыйВыбор`). Англ. ключ работает всегда; если заданы оба — побеждает англ. Поддержаны (в т.ч.): `Пометка``checked`, `Заголовок``title`, `Ширина``width`, `Высота``height`, `КнопкаВыбора``choiceButton`, `КнопкаОчистки``clearButton`, `КнопкаВыпадающегоСписка``dropListButton`, `КнопкаСписковогоВыбора``choiceListButton`, `БыстрыйВыбор``quickChoice`, `ФормаВыбора``choiceForm`, `ИсторияВыбораПриВводе``choiceHistoryOnInput`, `ВыборГруппИЭлементов``choiceFoldersAndItems`, `ФиксацияВТаблице``fixingInTable`, `ПутьКДаннымПодвала``footerDataPath`, `МногострочныйРежим``multiLine`, `РежимПароля``passwordMode`, `РасположениеЗаголовка``titleLocation`. (`Видимость`/`Доступность` НЕ синонимы — у нас `hidden`/`disabled` с обратной полярностью.) Оформление имеет свой набор рус. синонимов (§4.1e).
### 4.1c. Доступ по ролям (`userVisible` / `view` / `edit` / `use`)
Единый механизм платформы (role-adjustable boolean): «общее значение + исключения по ролям».
@@ -373,6 +377,14 @@ companion-панели с собственным контентом. Оба не
| `listChoiceMode` | bool | Режим выбора из списка (`<ListChoiceMode>`) |
| `extendedEditMultipleValues` | bool | Расширенное редактирование нескольких значений |
| `chooseType` | bool | Выбор типа (`<ChooseType>`) |
| `choiceListButton` | bool | Кнопка списочного выбора (`<ChoiceListButton>`) |
| `quickChoice` | bool | Быстрый выбор (`<QuickChoice>`) |
| `autoChoiceIncomplete` | bool | Автоматический выбор незаполненного (`<AutoChoiceIncomplete>`) |
| `choiceForm` | string | Форма выбора (`<ChoiceForm>`), напр. `Catalog.X.Form.ФормаВыбора` |
| `choiceHistoryOnInput` | string | История выбора при вводе (`<ChoiceHistoryOnInput>`): `Auto`, `DontUse` |
| `choiceFoldersAndItems` | string | Выбор групп и элементов (`<ChoiceFoldersAndItems>`): `Items`, `Folders`, `FoldersAndItems` |
| `fixingInTable` | string | Фиксация колонки в таблице (`<FixingInTable>`): `Left`, `Right`, `None`. Так же у `labelField` и др. полей |
| `footerDataPath` | string | DataPath подвала колонки таблицы (`<FooterDataPath>`) |
| `choiceButtonRepresentation` | string | `ShowInInputField`, `ShowInDropList`, `ShowInDropListAndInInputField` |
| `width` | int | Ширина |
| `height` | int | Высота |
@@ -623,6 +635,7 @@ Pages поддерживает `pagesRepresentation`: `None`, `TabsOnTop`, `Tabs
| `stdCommand` | string | Стандартная команда (→ `Form.StandardCommand.<name>`; `X.Y``Form.Item.X.StandardCommand.Y`) |
| `type` | string | `usual`, `hyperlink`, `commandBar` |
| `defaultButton` | bool | Кнопка по умолчанию |
| `checked` | bool | Пометка (нажатое состояние toggle-кнопки командной панели) → `<Check>true</Check>`. Платформа эмитит только `true`. Ключ `checked` (не `check``check` — тип-ключ ПоляФлажка) |
| `picture` | string \| object | Ссылка на картинку (`StdPicture.Name`). Скаляр-строка ИЛИ объект `{src, loadTransparent}` (прощающий ввод — флаг можно задать прямо в объекте) |
| `loadTransparent` | bool | Загружать картинку прозрачной (у `<Picture>` кнопки/команды/попапа). **Дефолт `true`** (эмитится всегда; `false` — явно). Элемент-уровневый ключ ИЛИ поле объекта `picture`. Также у `command` (§7) и `popup`. ⚠️ Полярность обратна `headerPicture`/`valuesPicture` (там дефолт `false`, см. §4.1) |
| `path` | string | DataPath кнопки общей команды (`Объект.Ref`, `Items.X.CurrentData.Поле`) — привязка к контексту |
@@ -20,7 +20,7 @@
{ "labelField": "Ссылка", "path": "ОбычноеПоле", "titleLocation": "left", "hyperlink": true, "format": { "ru": "ДЛФ=D", "en": "DLF=D" } },
{ "input": "МногострочноеПоле", "path": "МногострочноеПоле", "multiLine": true, "height": 5, "title": "Комментарий", "wrap": false, "showInHeader": false, "showInFooter": false, "autoCellHeight": true, "footerHorizontalAlign": "Right", "openButton": false, "chooseType": false },
{ "input": "ПолеПароля", "path": "ПолеПароля", "passwordMode": true, "title": "Пароль" },
{ "input": "ПолеСКнопками", "path": "ПолеСКнопками", "choiceButton": true, "clearButton": true, "title": "Выбор" },
{ "input": "ПолеСКнопками", "path": "ПолеСКнопками", "choiceButton": true, "clearButton": true, "dropListButton": false, "spinButton": true, "choiceListButton": true, "quickChoice": false, "autoChoiceIncomplete": true, "choiceHistoryOnInput": "DontUse", "choiceForm": "DataProcessor.ПоляВвода.Form.Форма", "title": "Выбор" },
{ "input": "ПолеСписокВыбора", "path": "ПолеСписокВыбора", "title": "Список выбора", "choiceList": [
{ "value": "", "presentation": "Все" },
{ "value": "Первый" },
@@ -109,7 +109,15 @@
<v8:content>Выбор</v8:content>
</v8:item>
</Title>
<ChoiceButton>true</ChoiceButton>
<ClearButton>true</ClearButton>
<SpinButton>true</SpinButton>
<DropListButton>false</DropListButton>
<ChoiceListButton>true</ChoiceListButton>
<QuickChoice>false</QuickChoice>
<AutoChoiceIncomplete>true</AutoChoiceIncomplete>
<ChoiceForm>DataProcessor.ПоляВвода.Form.Форма</ChoiceForm>
<ChoiceHistoryOnInput>DontUse</ChoiceHistoryOnInput>
<ContextMenu name="ПолеСКнопкамиКонтекстноеМеню" id="14"/>
<ExtendedTooltip name="ПолеСКнопкамиРасширеннаяПодсказка" id="15"/>
</InputField>
@@ -19,6 +19,9 @@
<ChildItems>
<InputField name="Поле" id="3">
<DataPath>Поле</DataPath>
<ChoiceButton>true</ChoiceButton>
<QuickChoice>false</QuickChoice>
<Width>15</Width>
<ContextMenu name="ПолеКонтекстноеМеню" id="4"/>
<ExtendedTooltip name="ПолеРасширеннаяПодсказка" id="5"/>
</InputField>
@@ -28,6 +31,7 @@
<Button name="Кн2" id="8">
<Type>CommandBarButton</Type>
<CommandName>Form.Command.Кн2</CommandName>
<Check>true</Check>
<ExtendedTooltip name="Кн2РасширеннаяПодсказка" id="9"/>
</Button>
</ChildItems>
@@ -41,6 +41,7 @@
<Button name="ПанельОбновить" id="8">
<Type>CommandBarButton</Type>
<CommandName>Form.Command.Обновить</CommandName>
<Check>true</Check>
<ExtendedTooltip name="ПанельОбновитьРасширеннаяПодсказка" id="9"/>
</Button>
</ChildItems>
@@ -73,6 +74,7 @@
<ChildItems>
<InputField name="Дата" id="20">
<DataPath>Данные.Дата</DataPath>
<FixingInTable>Left</FixingInTable>
<ContextMenu name="ДатаКонтекстноеМеню" id="21"/>
<ExtendedTooltip name="ДатаРасширеннаяПодсказка" id="22"/>
</InputField>
@@ -1,5 +1,5 @@
{
"name": "Синонимы commandBar/autoCommandBar нормализуются молча",
"name": "Синонимы commandBar/autoCommandBar + русские имена свойств нормализуются молча",
"preRun": [
{
"script": "meta-compile/scripts/meta-compile",
@@ -23,9 +23,9 @@
{ "autoCommandBar": "ФормаКоманднаяПанель", "children": [
{ "button": "Кн1", "command": "Кн1" }
]},
{ "input": "Поле", "path": "Поле" },
{ "input": "Поле", "path": "Поле", "КнопкаВыбора": true, "Быстрый выбор": false, "Ширина": 15 },
{ "commandBar": "ДопПанель", "children": [
{ "button": "Кн2", "command": "Кн2" }
{ "button": "Кн2", "command": "Кн2", "Пометка": true }
]}
],
"commands": [
+2 -2
View File
@@ -20,7 +20,7 @@
"viewStatusLocation": "None", "searchControlLocation": "None",
"excludedCommands": ["Add", "Delete", "MoveUp", "MoveDown"],
"commandBar": { "autofill": false, "children": [
{ "button": "ПанельОбновить", "command": "Обновить" }
{ "button": "ПанельОбновить", "command": "Обновить", "checked": true }
]},
"contextMenu": { "children": [
{ "buttonGroup": "МенюГруппа", "children": [
@@ -28,7 +28,7 @@
]}
]},
"columns": [
{ "input": "Дата", "path": "Данные.Дата" },
{ "input": "Дата", "path": "Данные.Дата", "fixingInTable": "Left" },
{ "input": "Сумма", "path": "Данные.Сумма" },
{ "input": "Комментарий", "path": "Данные.Комментарий" }
]}