mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-08-01 01:07:46 +03:00
feat(form-compile): нативная AutoCommandBar формы + autoCmdBar DSL
- Эвристика главной АКП: без cmdBar/autoCmdBar остаётся Autofill=true (как в Конфигураторе), с cmdBar — Autofill=false (обратная совместимость). - Новый элемент autoCmdBar для наполнения главной АКП кастомными кнопками. - Тихие синонимы commandBar↔cmdBar, autoCommandBar↔autoCmdBar. - Инференс main-реквизита по типу (*Object.*, *RecordSet.*, DynamicList, ConstantsSet) — единственный кандидат проставляется молча с [INFO]. - Эвристика DynamicList → таблица: tableAutofill=false + commandBarLocation=None для привязанной таблицы (соответствие ERP). - Косметика: <Autofill>true</Autofill> не эмитится явно. Snapshot'ы form-* также обновлены до актуального состояния cf-init (Ext/ClientApplicationInterface.xml). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
433a2955b5
commit
13174b63b1
@@ -73,7 +73,8 @@ powershell.exe -NoProfile -File .claude/skills/form-compile/scripts/form-compile
|
||||
| `"picture"` | PictureDecoration | имя |
|
||||
| `"picField"` | PictureField | имя |
|
||||
| `"calendar"` | CalendarField | имя |
|
||||
| `"cmdBar"` | CommandBar | имя |
|
||||
| `"cmdBar"` | CommandBar | имя (синоним: `"commandBar"`) |
|
||||
| `"autoCmdBar"` | AutoCommandBar формы | имя (синоним: `"autoCommandBar"`) — наполняет главную АКП формы (id=-1), не попадает в `<ChildItems>` |
|
||||
| `"popup"` | Popup | имя |
|
||||
|
||||
### Общие свойства (все типы элементов)
|
||||
@@ -202,11 +203,37 @@ powershell.exe -NoProfile -File .claude/skills/form-compile/scripts/form-compile
|
||||
|
||||
### Командная панель (cmdBar)
|
||||
|
||||
Дополнительная пользовательская панель команд, размещается как обычный элемент в layout формы.
|
||||
|
||||
| Ключ | Описание |
|
||||
|------|----------|
|
||||
| `autofill: true` | Автозаполнение стандартными командами |
|
||||
| `children: [...]` | Кнопки панели |
|
||||
|
||||
### Главная автокомандная панель формы (autoCmdBar)
|
||||
|
||||
Наполняет встроенную AutoCommandBar формы (id=-1) — ту самую верхнюю панель, на которой платформа автоматически размещает «Создать», «Записать», «Провести», «Заполнить» и т.п. По умолчанию `autoCmdBar` НЕ нужно указывать — компилятор сам решит, нужно ли отключать автозаполнение (см. «Эвристики» ниже). Используйте `autoCmdBar`, когда хотите добавить кастомные кнопки в эту главную панель или явно управлять автозаполнением.
|
||||
|
||||
| Ключ | Описание |
|
||||
|------|----------|
|
||||
| `autofill: true/false` | Явно включить/выключить автозаполнение стандартными командами |
|
||||
| `horizontalAlign` | `"Left"` / `"Right"` (по умолчанию `"Right"`) |
|
||||
| `children: [...]` | Кастомные кнопки/popup, добавляемые в главную панель |
|
||||
|
||||
```json
|
||||
{ "autoCmdBar": "ФормаКоманднаяПанель", "autofill": true, "children": [
|
||||
{ "button": "ИзменитьВыделенные", "command": "ИзменитьВыделенные",
|
||||
"locationInCommandBar": "InAdditionalSubmenu" }
|
||||
]}
|
||||
```
|
||||
|
||||
### Эвристики компилятора (что делается автоматически)
|
||||
|
||||
1. **Автозаполнение главной АКП.** Если в DSL нет ни одного `cmdBar` и нет `autoCmdBar` — главная АКП формы оставляется с автозаполнением `true` (нативное поведение платформы; платформа сама насыпает стандартные команды). Если есть хотя бы один `cmdBar` — автозаполнение выключается, чтобы команды не дублировались. Перекрывается явным `autoCmdBar`.
|
||||
2. **Главный реквизит выводится по типу.** Если ни у одного реквизита не указан `main: true`, компилятор пробует определить главный по типу: `*Object.*`, `*RecordSet.*`, `DynamicList`, `ConstantsSet`. Ровно один кандидат → проставляется `main: true` молча (с `[INFO]`-логом). Несколько → предупреждение, угадывания нет — нужно указать явно. Чтобы запретить инференс — поставьте `"main": false`.
|
||||
3. **Динамический список → командная панель таблицы.** Если главный реквизит формы — `DynamicList`, то для `table` с `path`, равным имени этого реквизита, автоматически: `tableAutofill: false` и `commandBarLocation: "None"` (если не заданы явно). Это убирает дублирование команд между главной АКП и панелью таблицы — типовой паттерн форм списков.
|
||||
4. **Косметика.** `<Autofill>true</Autofill>` не эмитится явно — соответствует поведению Конфигуратора и эталонным формам типовых.
|
||||
|
||||
### Выпадающее меню (popup)
|
||||
|
||||
| Ключ | Описание |
|
||||
@@ -239,6 +266,7 @@ powershell.exe -NoProfile -File .claude/skills/form-compile/scripts/form-compile
|
||||
```
|
||||
|
||||
- `savedData: true` — сохраняемые данные
|
||||
- `main: true` — главный реквизит формы. Если не указан ни у одного реквизита, компилятор сам выводит главный по типу: `*Object.*`, `*RecordSet.*`, `DynamicList`, `ConstantsSet`. Ровно один кандидат → проставляется молча. Несколько → нужно указать явно. Чтобы запретить инференс — поставьте `"main": false`.
|
||||
|
||||
### Команды (commands)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# form-compile v1.7 — Compile 1C managed form from JSON or object metadata
|
||||
# form-compile v1.8 — Compile 1C managed form from JSON or object metadata
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[string]$JsonPath,
|
||||
@@ -1823,6 +1823,17 @@ function Emit-Companion {
|
||||
function Emit-Element {
|
||||
param($el, [string]$indent)
|
||||
|
||||
# Silent synonyms: commandBar -> cmdBar, autoCommandBar -> autoCmdBar
|
||||
# (autoCmdBar inside def.elements is normally extracted in pre-pass; this is a safety net for nested cases)
|
||||
$synonyms = @{ "commandBar" = "cmdBar"; "autoCommandBar" = "autoCmdBar" }
|
||||
foreach ($pair in $synonyms.GetEnumerator()) {
|
||||
if ($null -ne $el.PSObject.Properties[$pair.Key] -and $null -eq $el.PSObject.Properties[$pair.Value]) {
|
||||
$val = $el.($pair.Key)
|
||||
$el.PSObject.Properties.Remove($pair.Key) | Out-Null
|
||||
$el | Add-Member -NotePropertyName $pair.Value -NotePropertyValue $val -Force
|
||||
}
|
||||
}
|
||||
|
||||
# Determine element type from key
|
||||
$typeKey = $null
|
||||
$xmlTag = $null
|
||||
@@ -2603,6 +2614,163 @@ function Emit-Properties {
|
||||
}
|
||||
}
|
||||
|
||||
# --- 11b. Pre-pass: synonyms, main attribute inference, heuristics, autoCmdBar extraction ---
|
||||
|
||||
function Normalize-ElementSynonyms {
|
||||
param($el)
|
||||
if ($null -eq $el) { return }
|
||||
$synonyms = @{ "commandBar" = "cmdBar"; "autoCommandBar" = "autoCmdBar" }
|
||||
foreach ($pair in $synonyms.GetEnumerator()) {
|
||||
if ($null -ne $el.PSObject.Properties[$pair.Key] -and $null -eq $el.PSObject.Properties[$pair.Value]) {
|
||||
$val = $el.($pair.Key)
|
||||
$el.PSObject.Properties.Remove($pair.Key) | Out-Null
|
||||
$el | Add-Member -NotePropertyName $pair.Value -NotePropertyValue $val -Force
|
||||
}
|
||||
}
|
||||
if ($el.PSObject.Properties["children"] -and $el.children) {
|
||||
foreach ($child in $el.children) { Normalize-ElementSynonyms $child }
|
||||
}
|
||||
if ($el.PSObject.Properties["columns"] -and $el.columns) {
|
||||
foreach ($child in $el.columns) { Normalize-ElementSynonyms $child }
|
||||
}
|
||||
}
|
||||
|
||||
function HasCmdBarRecursive {
|
||||
param($el)
|
||||
if ($null -eq $el) { return $false }
|
||||
if ($el.PSObject.Properties["cmdBar"] -and $null -ne $el.cmdBar) { return $true }
|
||||
if ($el.PSObject.Properties["children"] -and $el.children) {
|
||||
foreach ($child in $el.children) { if (HasCmdBarRecursive $child) { return $true } }
|
||||
}
|
||||
if ($el.PSObject.Properties["columns"] -and $el.columns) {
|
||||
foreach ($child in $el.columns) { if (HasCmdBarRecursive $child) { return $true } }
|
||||
}
|
||||
return $false
|
||||
}
|
||||
|
||||
function ApplyDynamicListTableHeuristic {
|
||||
param($el, [string]$listName)
|
||||
if ($null -eq $el) { return }
|
||||
if ($el.PSObject.Properties["table"] -and $null -ne $el.table -and "$($el.path)" -eq $listName) {
|
||||
if ($null -eq $el.PSObject.Properties["tableAutofill"]) {
|
||||
$el | Add-Member -NotePropertyName "tableAutofill" -NotePropertyValue $false -Force
|
||||
}
|
||||
if ($null -eq $el.PSObject.Properties["commandBarLocation"]) {
|
||||
$el | Add-Member -NotePropertyName "commandBarLocation" -NotePropertyValue "None" -Force
|
||||
}
|
||||
}
|
||||
if ($el.PSObject.Properties["children"] -and $el.children) {
|
||||
foreach ($child in $el.children) { ApplyDynamicListTableHeuristic $child $listName }
|
||||
}
|
||||
}
|
||||
|
||||
function Test-IsObjectLikeType {
|
||||
param([string]$type)
|
||||
if ([string]::IsNullOrEmpty($type)) { return $false }
|
||||
if ($type -eq "DynamicList" -or $type -eq "ConstantsSet") { return $true }
|
||||
$objectSuffixes = @(
|
||||
"CatalogObject", "DocumentObject", "DataProcessorObject", "ReportObject",
|
||||
"ExternalDataProcessorObject", "ExternalReportObject", "BusinessProcessObject",
|
||||
"TaskObject", "ChartOfAccountsObject", "ChartOfCharacteristicTypesObject",
|
||||
"ChartOfCalculationTypesObject", "ExchangePlanObject"
|
||||
)
|
||||
$recordSetPrefixes = @(
|
||||
"InformationRegisterRecordSet", "AccumulationRegisterRecordSet",
|
||||
"AccountingRegisterRecordSet", "CalculationRegisterRecordSet",
|
||||
"InformationRegisterRecordManager"
|
||||
)
|
||||
foreach ($suffix in $objectSuffixes) {
|
||||
if ($type -like "$suffix.*") { return $true }
|
||||
}
|
||||
foreach ($prefix in $recordSetPrefixes) {
|
||||
if ($type -like "$prefix.*") { return $true }
|
||||
}
|
||||
return $false
|
||||
}
|
||||
|
||||
# 11b.1: Normalize synonyms recursively
|
||||
if ($def.elements) {
|
||||
foreach ($el in $def.elements) { Normalize-ElementSynonyms $el }
|
||||
}
|
||||
|
||||
# 11b.2: Extract autoCmdBar element from def.elements
|
||||
$script:mainAcbDef = $null
|
||||
if ($def.elements) {
|
||||
$autoBars = @()
|
||||
$rest = @()
|
||||
foreach ($el in $def.elements) {
|
||||
if ($null -ne $el.PSObject.Properties["autoCmdBar"] -and $null -ne $el.autoCmdBar) {
|
||||
$autoBars += $el
|
||||
} else {
|
||||
$rest += $el
|
||||
}
|
||||
}
|
||||
if ($autoBars.Count -gt 1) {
|
||||
Write-Error "form-compile: more than one autoCmdBar in def.elements (found $($autoBars.Count)); only one allowed."
|
||||
exit 1
|
||||
}
|
||||
if ($autoBars.Count -eq 1) {
|
||||
$script:mainAcbDef = $autoBars[0]
|
||||
# Replace def.elements with the filtered list
|
||||
$def.PSObject.Properties.Remove("elements") | Out-Null
|
||||
$def | Add-Member -NotePropertyName "elements" -NotePropertyValue $rest -Force
|
||||
}
|
||||
}
|
||||
|
||||
# 11b.3: Infer main attribute (only if no attribute has main:true)
|
||||
if ($def.attributes) {
|
||||
$hasExplicitMain = $false
|
||||
foreach ($attr in $def.attributes) {
|
||||
if ($attr.main -eq $true) { $hasExplicitMain = $true; break }
|
||||
}
|
||||
if (-not $hasExplicitMain) {
|
||||
$candidates = @()
|
||||
foreach ($attr in $def.attributes) {
|
||||
# Skip if user explicitly opted out via main:false
|
||||
if ($null -ne $attr.PSObject.Properties["main"] -and $attr.main -eq $false) { continue }
|
||||
if (Test-IsObjectLikeType "$($attr.type)") {
|
||||
$candidates += $attr
|
||||
}
|
||||
}
|
||||
if ($candidates.Count -eq 1) {
|
||||
$candidates[0] | Add-Member -NotePropertyName "main" -NotePropertyValue $true -Force
|
||||
Write-Host "[INFO] Inferred main attribute: $($candidates[0].name) ($($candidates[0].type))"
|
||||
} elseif ($candidates.Count -gt 1) {
|
||||
$names = ($candidates | ForEach-Object { $_.name }) -join ", "
|
||||
Write-Host "[WARN] Multiple main-attribute candidates: $names; specify ""main"": true explicitly"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 11b.4: DynamicList → table heuristic
|
||||
if ($def.attributes -and $def.elements) {
|
||||
$mainAttr = $null
|
||||
foreach ($attr in $def.attributes) {
|
||||
if ($attr.main -eq $true) { $mainAttr = $attr; break }
|
||||
}
|
||||
if ($mainAttr -and "$($mainAttr.type)" -eq "DynamicList") {
|
||||
foreach ($el in $def.elements) {
|
||||
ApplyDynamicListTableHeuristic $el $mainAttr.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 11b.5: Compute main AutoCommandBar Autofill via heuristic B3
|
||||
function Compute-MainAcbAutofill {
|
||||
if ($script:mainAcbDef) {
|
||||
if ($null -ne $script:mainAcbDef.PSObject.Properties["autofill"]) {
|
||||
return [bool]$script:mainAcbDef.autofill
|
||||
}
|
||||
return $true
|
||||
}
|
||||
if ($def.elements) {
|
||||
foreach ($el in $def.elements) {
|
||||
if (HasCmdBarRecursive $el) { return $false }
|
||||
}
|
||||
}
|
||||
return $true
|
||||
}
|
||||
|
||||
# --- 12. Main compilation ---
|
||||
|
||||
# Title
|
||||
@@ -2656,10 +2824,37 @@ if ($def.excludedCommands -and $def.excludedCommands.Count -gt 0) {
|
||||
}
|
||||
|
||||
# 12d. AutoCommandBar (always present, id=-1)
|
||||
X "`t<AutoCommandBar name=`"ФормаКоманднаяПанель`" id=`"-1`">"
|
||||
X "`t`t<HorizontalAlign>Right</HorizontalAlign>"
|
||||
X "`t`t<Autofill>false</Autofill>"
|
||||
X "`t</AutoCommandBar>"
|
||||
$acbAutofill = Compute-MainAcbAutofill
|
||||
$acbName = "ФормаКоманднаяПанель"
|
||||
$acbHAlign = "Right"
|
||||
if ($script:mainAcbDef) {
|
||||
if ($null -ne $script:mainAcbDef.PSObject.Properties["autoCmdBar"] -and "$($script:mainAcbDef.autoCmdBar)" -ne "") {
|
||||
$acbName = "$($script:mainAcbDef.autoCmdBar)"
|
||||
}
|
||||
if ($null -ne $script:mainAcbDef.PSObject.Properties["name"] -and "$($script:mainAcbDef.name)" -ne "") {
|
||||
$acbName = "$($script:mainAcbDef.name)"
|
||||
}
|
||||
if ($null -ne $script:mainAcbDef.PSObject.Properties["horizontalAlign"] -and "$($script:mainAcbDef.horizontalAlign)" -ne "") {
|
||||
$acbHAlign = "$($script:mainAcbDef.horizontalAlign)"
|
||||
}
|
||||
}
|
||||
$hasAcbChildren = ($script:mainAcbDef -and $script:mainAcbDef.children -and $script:mainAcbDef.children.Count -gt 0)
|
||||
$acbHasInner = ($acbHAlign -or (-not $acbAutofill) -or $hasAcbChildren)
|
||||
if ($acbHasInner) {
|
||||
X "`t<AutoCommandBar name=`"$acbName`" id=`"-1`">"
|
||||
if ($acbHAlign) { X "`t`t<HorizontalAlign>$acbHAlign</HorizontalAlign>" }
|
||||
if (-not $acbAutofill) { X "`t`t<Autofill>false</Autofill>" }
|
||||
if ($hasAcbChildren) {
|
||||
X "`t`t<ChildItems>"
|
||||
foreach ($child in $script:mainAcbDef.children) {
|
||||
Emit-Element -el $child -indent "`t`t`t"
|
||||
}
|
||||
X "`t`t</ChildItems>"
|
||||
}
|
||||
X "`t</AutoCommandBar>"
|
||||
} else {
|
||||
X "`t<AutoCommandBar name=`"$acbName`" id=`"-1`"/>"
|
||||
}
|
||||
|
||||
# 12e. Events
|
||||
if ($def.events) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# form-compile v1.7 — Compile 1C managed form from JSON or object metadata
|
||||
# form-compile v1.8 — Compile 1C managed form from JSON or object metadata
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
import argparse
|
||||
import copy
|
||||
@@ -1602,6 +1602,12 @@ def emit_type(lines, type_str, indent):
|
||||
# --- Element emitters ---
|
||||
|
||||
def emit_element(lines, el, indent):
|
||||
# Silent synonyms (safety net; top-level autoCmdBar is normally extracted in pre-pass)
|
||||
_synonyms = {'commandBar': 'cmdBar', 'autoCommandBar': 'autoCmdBar'}
|
||||
for src, dst in _synonyms.items():
|
||||
if src in el and dst not in el:
|
||||
el[dst] = el.pop(src)
|
||||
|
||||
type_key = None
|
||||
for key in TYPE_KEYS:
|
||||
if el.get(key) is not None:
|
||||
@@ -2536,6 +2542,126 @@ def main():
|
||||
with open(json_path, 'r', encoding='utf-8-sig') as f:
|
||||
defn = json.load(f)
|
||||
|
||||
# --- 1b. Pre-pass: synonyms, main attribute inference, heuristics, autoCmdBar extraction ---
|
||||
def _normalize_synonyms(el):
|
||||
if not isinstance(el, dict):
|
||||
return
|
||||
synonyms = {'commandBar': 'cmdBar', 'autoCommandBar': 'autoCmdBar'}
|
||||
for src, dst in synonyms.items():
|
||||
if src in el and dst not in el:
|
||||
el[dst] = el.pop(src)
|
||||
if isinstance(el.get('children'), list):
|
||||
for child in el['children']:
|
||||
_normalize_synonyms(child)
|
||||
if isinstance(el.get('columns'), list):
|
||||
for child in el['columns']:
|
||||
_normalize_synonyms(child)
|
||||
|
||||
def _has_cmd_bar_recursive(el):
|
||||
if not isinstance(el, dict):
|
||||
return False
|
||||
if el.get('cmdBar') is not None:
|
||||
return True
|
||||
if isinstance(el.get('children'), list):
|
||||
for child in el['children']:
|
||||
if _has_cmd_bar_recursive(child):
|
||||
return True
|
||||
if isinstance(el.get('columns'), list):
|
||||
for child in el['columns']:
|
||||
if _has_cmd_bar_recursive(child):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _apply_dlist_table_heuristic(el, list_name):
|
||||
if not isinstance(el, dict):
|
||||
return
|
||||
if el.get('table') is not None and str(el.get('path', '')) == list_name:
|
||||
if 'tableAutofill' not in el:
|
||||
el['tableAutofill'] = False
|
||||
if 'commandBarLocation' not in el:
|
||||
el['commandBarLocation'] = 'None'
|
||||
if isinstance(el.get('children'), list):
|
||||
for child in el['children']:
|
||||
_apply_dlist_table_heuristic(child, list_name)
|
||||
|
||||
def _is_object_like_type(t):
|
||||
if not t:
|
||||
return False
|
||||
if t == 'DynamicList' or t == 'ConstantsSet':
|
||||
return True
|
||||
object_suffixes = (
|
||||
'CatalogObject', 'DocumentObject', 'DataProcessorObject', 'ReportObject',
|
||||
'ExternalDataProcessorObject', 'ExternalReportObject', 'BusinessProcessObject',
|
||||
'TaskObject', 'ChartOfAccountsObject', 'ChartOfCharacteristicTypesObject',
|
||||
'ChartOfCalculationTypesObject', 'ExchangePlanObject',
|
||||
)
|
||||
record_set_prefixes = (
|
||||
'InformationRegisterRecordSet', 'AccumulationRegisterRecordSet',
|
||||
'AccountingRegisterRecordSet', 'CalculationRegisterRecordSet',
|
||||
'InformationRegisterRecordManager',
|
||||
)
|
||||
for s in object_suffixes:
|
||||
if t.startswith(s + '.'):
|
||||
return True
|
||||
for s in record_set_prefixes:
|
||||
if t.startswith(s + '.'):
|
||||
return True
|
||||
return False
|
||||
|
||||
# 1b.1: Normalize synonyms recursively
|
||||
if isinstance(defn.get('elements'), list):
|
||||
for el in defn['elements']:
|
||||
_normalize_synonyms(el)
|
||||
|
||||
# 1b.2: Extract autoCmdBar element from defn['elements']
|
||||
main_acb_def = None
|
||||
if isinstance(defn.get('elements'), list):
|
||||
auto_bars = [el for el in defn['elements'] if isinstance(el, dict) and el.get('autoCmdBar') is not None]
|
||||
if len(auto_bars) > 1:
|
||||
print(f"form-compile: more than one autoCmdBar in def.elements (found {len(auto_bars)}); only one allowed.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
if len(auto_bars) == 1:
|
||||
main_acb_def = auto_bars[0]
|
||||
defn['elements'] = [el for el in defn['elements'] if el is not main_acb_def]
|
||||
|
||||
# 1b.3: Infer main attribute
|
||||
if isinstance(defn.get('attributes'), list):
|
||||
has_explicit_main = any(a.get('main') is True for a in defn['attributes'] if isinstance(a, dict))
|
||||
if not has_explicit_main:
|
||||
candidates = []
|
||||
for a in defn['attributes']:
|
||||
if not isinstance(a, dict):
|
||||
continue
|
||||
if 'main' in a and a.get('main') is False:
|
||||
continue
|
||||
if _is_object_like_type(str(a.get('type', ''))):
|
||||
candidates.append(a)
|
||||
if len(candidates) == 1:
|
||||
candidates[0]['main'] = True
|
||||
print(f"[INFO] Inferred main attribute: {candidates[0].get('name')} ({candidates[0].get('type')})")
|
||||
elif len(candidates) > 1:
|
||||
names = ', '.join(c.get('name', '') for c in candidates)
|
||||
print(f"[WARN] Multiple main-attribute candidates: {names}; specify \"main\": true explicitly")
|
||||
|
||||
# 1b.4: DynamicList → table heuristic
|
||||
if isinstance(defn.get('attributes'), list) and isinstance(defn.get('elements'), list):
|
||||
main_attr = next((a for a in defn['attributes'] if isinstance(a, dict) and a.get('main') is True), None)
|
||||
if main_attr and str(main_attr.get('type', '')) == 'DynamicList':
|
||||
for el in defn['elements']:
|
||||
_apply_dlist_table_heuristic(el, main_attr.get('name', ''))
|
||||
|
||||
# 1b.5: Compute main AutoCommandBar Autofill (B3)
|
||||
def _compute_main_acb_autofill():
|
||||
if main_acb_def is not None:
|
||||
if 'autofill' in main_acb_def:
|
||||
return bool(main_acb_def.get('autofill'))
|
||||
return True
|
||||
if isinstance(defn.get('elements'), list):
|
||||
for el in defn['elements']:
|
||||
if _has_cmd_bar_recursive(el):
|
||||
return False
|
||||
return True
|
||||
|
||||
# --- 2. Main compilation ---
|
||||
_next_id = 0
|
||||
lines = []
|
||||
@@ -2563,10 +2689,33 @@ def main():
|
||||
lines.append('\t</CommandSet>')
|
||||
|
||||
# AutoCommandBar (always present, id=-1)
|
||||
lines.append('\t<AutoCommandBar name="\u0424\u043e\u0440\u043c\u0430\u041a\u043e\u043c\u0430\u043d\u0434\u043d\u0430\u044f\u041f\u0430\u043d\u0435\u043b\u044c" id="-1">')
|
||||
lines.append('\t\t<HorizontalAlign>Right</HorizontalAlign>')
|
||||
lines.append('\t\t<Autofill>false</Autofill>')
|
||||
lines.append('\t</AutoCommandBar>')
|
||||
acb_autofill = _compute_main_acb_autofill()
|
||||
acb_name = '\u0424\u043e\u0440\u043c\u0430\u041a\u043e\u043c\u0430\u043d\u0434\u043d\u0430\u044f\u041f\u0430\u043d\u0435\u043b\u044c'
|
||||
acb_halign = 'Right'
|
||||
if main_acb_def is not None:
|
||||
v = main_acb_def.get('autoCmdBar')
|
||||
if v:
|
||||
acb_name = str(v)
|
||||
if main_acb_def.get('name'):
|
||||
acb_name = str(main_acb_def['name'])
|
||||
if main_acb_def.get('horizontalAlign'):
|
||||
acb_halign = str(main_acb_def['horizontalAlign'])
|
||||
has_acb_children = bool(main_acb_def and isinstance(main_acb_def.get('children'), list) and len(main_acb_def['children']) > 0)
|
||||
has_inner = bool(acb_halign) or (not acb_autofill) or has_acb_children
|
||||
if has_inner:
|
||||
lines.append(f'\t<AutoCommandBar name="{acb_name}" id="-1">')
|
||||
if acb_halign:
|
||||
lines.append(f'\t\t<HorizontalAlign>{acb_halign}</HorizontalAlign>')
|
||||
if not acb_autofill:
|
||||
lines.append('\t\t<Autofill>false</Autofill>')
|
||||
if has_acb_children:
|
||||
lines.append('\t\t<ChildItems>')
|
||||
for child in main_acb_def['children']:
|
||||
emit_element(lines, child, '\t\t\t')
|
||||
lines.append('\t\t</ChildItems>')
|
||||
lines.append('\t</AutoCommandBar>')
|
||||
else:
|
||||
lines.append(f'\t<AutoCommandBar name="{acb_name}" id="-1"/>')
|
||||
|
||||
# Events
|
||||
if defn.get('events'):
|
||||
|
||||
Reference in New Issue
Block a user