diff --git a/.claude/skills/cfe-borrow/scripts/cfe-borrow.ps1 b/.claude/skills/cfe-borrow/scripts/cfe-borrow.ps1 index 7f36640a..a64ec15b 100644 --- a/.claude/skills/cfe-borrow/scripts/cfe-borrow.ps1 +++ b/.claude/skills/cfe-borrow/scripts/cfe-borrow.ps1 @@ -1,4 +1,4 @@ -# cfe-borrow v1.0 — Borrow objects from configuration into extension (CFE) +# cfe-borrow v1.1 — Borrow objects from configuration into extension (CFE) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)][string]$ExtensionPath, @@ -476,8 +476,9 @@ function Borrow-Form { $formVersion = $srcFormEl.GetAttribute("version") if (-not $formVersion) { $formVersion = "2.17" } - # Find direct children: form properties and AutoCommandBar + # Find direct children: form properties, AutoCommandBar, ChildItems $srcAutoCmd = $null + $srcChildItems = $null $formProps = @() $reachedVisual = $false foreach ($fc in $srcFormEl.ChildNodes) { @@ -485,11 +486,13 @@ function Borrow-Form { if ($fc.LocalName -eq 'AutoCommandBar' -and -not $srcAutoCmd) { $reachedVisual = $true; $srcAutoCmd = $fc; continue } - if ($fc.LocalName -eq 'ChildItems' -or $fc.LocalName -eq 'Events' -or $fc.LocalName -eq 'Attributes' -or $fc.LocalName -eq 'Commands' -or $fc.LocalName -eq 'Parameters') { + if ($fc.LocalName -eq 'ChildItems' -and -not $srcChildItems) { + $reachedVisual = $true; $srcChildItems = $fc; continue + } + if ($fc.LocalName -eq 'Events' -or $fc.LocalName -eq 'Attributes' -or $fc.LocalName -eq 'Commands' -or $fc.LocalName -eq 'Parameters') { $reachedVisual = $true; continue } if (-not $reachedVisual) { - # Form-level properties before AutoCommandBar (WindowOpeningMode, AutoFillCheck, etc.) $formProps += $fc.OuterXml } } @@ -497,17 +500,187 @@ function Borrow-Form { # Get OuterXml and strip redundant namespace redeclarations (they're on root
) $nsStripPattern = '\s+xmlns(?::\w+)?="[^"]*"' - # AutoCommandBar: copy only properties (Autofill etc.), strip ChildItems + # AutoCommandBar: strip ChildItems (buttons), replace CommandName→0, Autofill→false $autoCmdXml = "" if ($srcAutoCmd) { $autoCmdXml = $srcAutoCmd.OuterXml $autoCmdXml = [regex]::Replace($autoCmdXml, $nsStripPattern, '') - # Strip ChildItems from AutoCommandBar (buttons will appear from base form at runtime) $autoCmdXml = [regex]::Replace($autoCmdXml, '(?s)\s*.*?', '') - # Replace Autofill true → false $autoCmdXml = $autoCmdXml -replace 'true', 'false' } + # ChildItems: copy full tree, clean up base-config references + $childItemsXml = "" + if ($srcChildItems) { + $childItemsXml = $srcChildItems.OuterXml + $childItemsXml = [regex]::Replace($childItemsXml, $nsStripPattern, '') + # Replace all CommandName values with 0 + $childItemsXml = [regex]::Replace($childItemsXml, '[^<]*', '0') + # Strip DataPath (references base form attributes not in extension) + $childItemsXml = [regex]::Replace($childItemsXml, '\s*[^<]*', '') + # Strip TitleDataPath (e.g. Объект.Товары.RowsCount — invalid without base attributes) + $childItemsXml = [regex]::Replace($childItemsXml, '\s*[^<]*', '') + # Strip TypeLink blocks with human-readable DataPath (Items.XXX — can't convert to UUID) + $childItemsXml = [regex]::Replace($childItemsXml, '(?s)\s*\s*Items\.[^<]*.*?', '') + # Strip element-level Events (base form handlers not in extension) + $childItemsXml = [regex]::Replace($childItemsXml, '(?s)\s*.*?', '') + + # Collect CommonPicture references from ChildItems + $picRefs = [regex]::Matches($childItemsXml, 'CommonPicture\.(\w+)') + $referencedPictures = @{} + foreach ($m in $picRefs) { $referencedPictures[$m.Groups[1].Value] = $true } + + # Auto-borrow referenced CommonPictures (if not already borrowed) + $autoBorrowedPics = @() + foreach ($picName in $referencedPictures.Keys) { + if (-not (Test-ObjectBorrowed "CommonPicture" $picName)) { + $picSrcFile = Join-Path (Join-Path $cfgDir "CommonPictures") "${picName}.xml" + if (Test-Path $picSrcFile) { + $src = Read-SourceObject "CommonPicture" $picName + $borrowedXml = Build-BorrowedObjectXml "CommonPicture" $picName $src.Uuid $src.Properties + $targetDir = Join-Path $extDir "CommonPictures" + if (-not (Test-Path $targetDir)) { + New-Item -ItemType Directory -Path $targetDir -Force | Out-Null + } + $targetFile = Join-Path $targetDir "${picName}.xml" + $encBom = New-Object System.Text.UTF8Encoding($true) + [System.IO.File]::WriteAllText($targetFile, $borrowedXml, $encBom) + Add-ToChildObjects "CommonPicture" $picName + $autoBorrowedPics += $picName + $borrowedFiles += $targetFile + Info " Auto-borrowed: CommonPicture.${picName}" + } else { + Warn " CommonPicture.${picName} not found in source config — will strip from form" + } + } + } + + # Collect all borrowed CommonPictures (including previously borrowed) + $borrowedPicSet = @{} + $nsMgr2 = New-Object System.Xml.XmlNamespaceManager($script:xmlDoc.NameTable) + $nsMgr2.AddNamespace("md", $script:mdNs) + $picNodes = $script:xmlDoc.SelectNodes("//md:ChildObjects/md:CommonPicture", $nsMgr2) + foreach ($pn in $picNodes) { $borrowedPicSet[$pn.InnerText] = $true } + + # Strip blocks referencing non-borrowed CommonPictures + $picBlockPattern = '(?s)\s*\s*CommonPicture\.(\w+).*?' + $picMatches = [regex]::Matches($childItemsXml, $picBlockPattern) + # Process in reverse order to preserve positions + for ($mi = $picMatches.Count - 1; $mi -ge 0; $mi--) { + $pm = $picMatches[$mi] + $cpName = $pm.Groups[1].Value + if (-not $borrowedPicSet.ContainsKey($cpName)) { + $childItemsXml = $childItemsXml.Remove($pm.Index, $pm.Length) + } + } + # Strip StdPicture blocks (except Print) + $childItemsXml = [regex]::Replace($childItemsXml, '(?s)\s*\s*StdPicture\.(?!Print\b)\w+.*?', '') + + # Auto-borrow StyleItems referenced in ChildItems + # Pattern 1: , + # Pattern 2: style:XXX, style:XXX, etc. + $referencedStyles = @{} + $styleRefs1 = [regex]::Matches($childItemsXml, 'ref="style:(\w+)"[^>]*kind="StyleItem"') + foreach ($m in $styleRefs1) { $referencedStyles[$m.Groups[1].Value] = $true } + $styleRefs2 = [regex]::Matches($childItemsXml, '>style:(\w+)') + foreach ($m in $styleRefs2) { $referencedStyles[$m.Groups[1].Value] = $true } + + foreach ($styleName in $referencedStyles.Keys) { + if (-not (Test-ObjectBorrowed "StyleItem" $styleName)) { + $styleSrcFile = Join-Path (Join-Path $cfgDir "StyleItems") "${styleName}.xml" + if (Test-Path $styleSrcFile) { + $src = Read-SourceObject "StyleItem" $styleName + $borrowedXml = Build-BorrowedObjectXml "StyleItem" $styleName $src.Uuid $src.Properties + $targetDir = Join-Path $extDir "StyleItems" + if (-not (Test-Path $targetDir)) { + New-Item -ItemType Directory -Path $targetDir -Force | Out-Null + } + $targetFile = Join-Path $targetDir "${styleName}.xml" + $encBom = New-Object System.Text.UTF8Encoding($true) + [System.IO.File]::WriteAllText($targetFile, $borrowedXml, $encBom) + Add-ToChildObjects "StyleItem" $styleName + $borrowedFiles += $targetFile + Info " Auto-borrowed: StyleItem.${styleName}" + } else { + Warn " StyleItem.${styleName} not found in source config" + } + } + } + # Auto-borrow Enums + EnumValues referenced via DesignTimeRef in ChoiceParameters + # Collect Enum -> [EnumValue names] map + $dtRefs = [regex]::Matches($childItemsXml, 'xr:DesignTimeRef">Enum\.(\w+)\.EnumValue\.(\w+)') + $referencedEnumValues = @{} + foreach ($m in $dtRefs) { + $eName = $m.Groups[1].Value + $evName = $m.Groups[2].Value + if (-not $referencedEnumValues.ContainsKey($eName)) { $referencedEnumValues[$eName] = @{} } + $referencedEnumValues[$eName][$evName] = $true + } + + foreach ($enumName in $referencedEnumValues.Keys) { + if (-not (Test-ObjectBorrowed "Enum" $enumName)) { + $enumSrcFile = Join-Path (Join-Path $cfgDir "Enums") "${enumName}.xml" + if (Test-Path $enumSrcFile) { + # Read source Enum to get UUID and EnumValue UUIDs + $srcParser = New-Object System.Xml.XmlDocument + $srcParser.PreserveWhitespace = $true + $srcParser.Load($enumSrcFile) + $srcEnumEl = $null + foreach ($cn in $srcParser.DocumentElement.ChildNodes) { + if ($cn.NodeType -eq 'Element') { $srcEnumEl = $cn; break } + } + $srcEnumUuid = $srcEnumEl.GetAttribute("uuid") + + # Find source EnumValues by name + $enumValueXmls = @() + $neededValues = $referencedEnumValues[$enumName] + $srcNsMgr = New-Object System.Xml.XmlNamespaceManager($srcParser.NameTable) + $srcNsMgr.AddNamespace("md", $script:mdNs) + $srcEvNodes = $srcEnumEl.SelectNodes("md:ChildObjects/md:EnumValue", $srcNsMgr) + foreach ($evNode in $srcEvNodes) { + $evUuid = $evNode.GetAttribute("uuid") + $evNameNode = $evNode.SelectSingleNode("md:Properties/md:Name", $srcNsMgr) + if ($evNameNode -and $neededValues.ContainsKey($evNameNode.InnerText)) { + $newEvUuid = [guid]::NewGuid().ToString() + $enumValueXmls += @" + + + + Adopted + $($evNameNode.InnerText) + + ${evUuid} + + +"@ + } + } + + # Build borrowed Enum with EnumValues in ChildObjects + $src = Read-SourceObject "Enum" $enumName + $borrowedXml = Build-BorrowedObjectXml "Enum" $enumName $src.Uuid $src.Properties + if ($enumValueXmls.Count -gt 0) { + $evBlock = ($enumValueXmls -join "`r`n") + $borrowedXml = $borrowedXml -replace '', "`r`n${evBlock}`r`n`t`t" + } + + $targetDir = Join-Path $extDir "Enums" + if (-not (Test-Path $targetDir)) { + New-Item -ItemType Directory -Path $targetDir -Force | Out-Null + } + $targetFile = Join-Path $targetDir "${enumName}.xml" + $encBom = New-Object System.Text.UTF8Encoding($true) + [System.IO.File]::WriteAllText($targetFile, $borrowedXml, $encBom) + Add-ToChildObjects "Enum" $enumName + $borrowedFiles += $targetFile + Info " Auto-borrowed: Enum.${enumName} (with $($enumValueXmls.Count) EnumValue(s))" + } else { + Warn " Enum.${enumName} not found in source config" + } + } + } + } + # Extract the opening tag from source text (preserves namespace declarations) $xmlDecl = '' $formTag = "" @@ -521,7 +694,7 @@ function Borrow-Form { $formXmlSb.Append($formTag) | Out-Null $formXmlSb.Append("`r`n") | Out-Null - # Part 1: form properties + AutoCommandBar (no ChildItems — they come from base form at runtime) + # Part 1: form properties + AutoCommandBar + ChildItems foreach ($propXml in $formProps) { $propXml = [regex]::Replace($propXml, $nsStripPattern, '') $formXmlSb.Append("`t$propXml`r`n") | Out-Null @@ -530,10 +703,14 @@ function Borrow-Form { $formXmlSb.Append("`t$autoCmdXml") | Out-Null $formXmlSb.Append("`r`n") | Out-Null } + if ($childItemsXml) { + $formXmlSb.Append("`t$childItemsXml") | Out-Null + $formXmlSb.Append("`r`n") | Out-Null + } $formXmlSb.Append("`t") | Out-Null $formXmlSb.Append("`r`n") | Out-Null - # BaseForm: same properties + AutoCommandBar (no ChildItems) + # BaseForm: same content, indented one more level $formXmlSb.Append("`t") | Out-Null $formXmlSb.Append("`r`n") | Out-Null @@ -542,7 +719,6 @@ function Borrow-Form { $formXmlSb.Append("`t`t$propXml`r`n") | Out-Null } if ($autoCmdXml) { - # Reindent for BaseForm: first line gets 2 tabs, other lines get +1 tab $acLines = $autoCmdXml -split "`r?`n" for ($li = 0; $li -lt $acLines.Count; $li++) { if ($li -eq 0) { $formXmlSb.Append("`t`t$($acLines[$li])") | Out-Null } @@ -550,6 +726,15 @@ function Borrow-Form { $formXmlSb.Append("`r`n") | Out-Null } } + if ($childItemsXml) { + # Reindent ChildItems for BaseForm (+1 tab level) + $ciLines = $childItemsXml -split "`r?`n" + for ($li = 0; $li -lt $ciLines.Count; $li++) { + if ($li -eq 0) { $formXmlSb.Append("`t`t$($ciLines[$li])") | Out-Null } + else { $formXmlSb.Append("`t$($ciLines[$li])") | Out-Null } + $formXmlSb.Append("`r`n") | Out-Null + } + } $formXmlSb.Append("`t`t") | Out-Null $formXmlSb.Append("`r`n") | Out-Null diff --git a/.claude/skills/cfe-borrow/scripts/cfe-borrow.py b/.claude/skills/cfe-borrow/scripts/cfe-borrow.py index 04c828f0..9db65bef 100644 --- a/.claude/skills/cfe-borrow/scripts/cfe-borrow.py +++ b/.claude/skills/cfe-borrow/scripts/cfe-borrow.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# cfe-borrow v1.0 — Borrow objects from configuration into extension (CFE) +# cfe-borrow v1.1 — Borrow objects from configuration into extension (CFE) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -671,17 +671,159 @@ def main(): ns_strip_pattern = re.compile(r'\s+xmlns(?::\w+)?="[^"]*"') - # AutoCommandBar: copy only properties (Autofill etc.), strip ChildItems + # AutoCommandBar: strip ChildItems (buttons), replace CommandName→0, Autofill→false auto_cmd_xml = "" if src_auto_cmd is not None: auto_cmd_xml = etree.tostring(src_auto_cmd, encoding="unicode") auto_cmd_xml = ns_strip_pattern.sub("", auto_cmd_xml) - # Strip ChildItems from AutoCommandBar (buttons will appear from base form at runtime) auto_cmd_xml = re.sub(r'\s*.*?', '', auto_cmd_xml, flags=re.DOTALL) - # Replace Autofill true -> false auto_cmd_xml = auto_cmd_xml.replace('true', 'false') - # Extract source form opening tag + # ChildItems: copy full tree, clean up base-config references + child_items_xml = "" + src_child_items = None + for fc in src_form_el: + if isinstance(fc.tag, str) and localname(fc) == "ChildItems": + src_child_items = fc + break + + if src_child_items is not None: + child_items_xml = etree.tostring(src_child_items, encoding="unicode") + child_items_xml = ns_strip_pattern.sub("", child_items_xml) + # Replace all CommandName values with 0 + child_items_xml = re.sub(r'[^<]*', '0', child_items_xml) + # Strip DataPath + child_items_xml = re.sub(r'\s*[^<]*', '', child_items_xml) + # Strip TitleDataPath + child_items_xml = re.sub(r'\s*[^<]*', '', child_items_xml) + # Strip TypeLink blocks with human-readable DataPath (Items.XXX) + child_items_xml = re.sub(r'\s*\s*Items\.[^<]*.*?', '', child_items_xml, flags=re.DOTALL) + # Strip element-level Events + child_items_xml = re.sub(r'\s*.*?', '', child_items_xml, flags=re.DOTALL) + + # Auto-borrow referenced CommonPictures + pic_refs = re.findall(r'CommonPicture\.(\w+)', child_items_xml) + referenced_pictures = {name: True for name in pic_refs} + + auto_borrowed_pics = [] + for pic_name in referenced_pictures: + if not test_object_borrowed("CommonPicture", pic_name): + pic_src_file = os.path.join(cfg_dir, "CommonPictures", f"{pic_name}.xml") + if os.path.isfile(pic_src_file): + src = read_source_object("CommonPicture", pic_name) + borrowed_xml = build_borrowed_object_xml("CommonPicture", pic_name, src["uuid"], src["properties"]) + target_dir = os.path.join(ext_dir, "CommonPictures") + os.makedirs(target_dir, exist_ok=True) + target_file = os.path.join(target_dir, f"{pic_name}.xml") + save_text_bom(target_file, borrowed_xml) + add_to_child_objects("CommonPicture", pic_name) + auto_borrowed_pics.append(pic_name) + info(f" Auto-borrowed: CommonPicture.{pic_name}") + else: + warn(f" CommonPicture.{pic_name} not found in source config — will strip from form") + + # Collect all borrowed CommonPictures for Picture stripping + borrowed_pic_set = set() + for co_child in child_objs_el: + if isinstance(co_child.tag, str) and localname(co_child) == "CommonPicture": + borrowed_pic_set.add((co_child.text or "").strip()) + + # Strip blocks referencing non-borrowed CommonPictures (reverse order) + pic_block_pattern = re.compile(r'\s*\s*CommonPicture\.(\w+).*?', re.DOTALL) + pic_matches = list(pic_block_pattern.finditer(child_items_xml)) + for pm in reversed(pic_matches): + cp_name = pm.group(1) + if cp_name not in borrowed_pic_set: + child_items_xml = child_items_xml[:pm.start()] + child_items_xml[pm.end():] + # Strip StdPicture blocks (except Print) + child_items_xml = re.sub(r'\s*\s*StdPicture\.(?!Print\b)\w+.*?', '', child_items_xml, flags=re.DOTALL) + + # Auto-borrow StyleItems referenced in ChildItems + referenced_styles = set() + for m in re.finditer(r'ref="style:(\w+)"[^>]*kind="StyleItem"', child_items_xml): + referenced_styles.add(m.group(1)) + for m in re.finditer(r'>style:(\w+)', child_items_xml): + referenced_styles.add(m.group(1)) + + for style_name in referenced_styles: + if not test_object_borrowed("StyleItem", style_name): + style_src_file = os.path.join(cfg_dir, "StyleItems", f"{style_name}.xml") + if os.path.isfile(style_src_file): + src = read_source_object("StyleItem", style_name) + borrowed_xml = build_borrowed_object_xml("StyleItem", style_name, src["uuid"], src["properties"]) + target_dir = os.path.join(ext_dir, "StyleItems") + os.makedirs(target_dir, exist_ok=True) + target_file = os.path.join(target_dir, f"{style_name}.xml") + save_text_bom(target_file, borrowed_xml) + add_to_child_objects("StyleItem", style_name) + info(f" Auto-borrowed: StyleItem.{style_name}") + else: + warn(f" StyleItem.{style_name} not found in source config") + + # Auto-borrow Enums + EnumValues referenced via DesignTimeRef + referenced_enum_values = {} # enum_name -> set of value_names + for m in re.finditer(r'xr:DesignTimeRef">Enum\.(\w+)\.EnumValue\.(\w+)', child_items_xml): + e_name, ev_name = m.group(1), m.group(2) + if e_name not in referenced_enum_values: + referenced_enum_values[e_name] = set() + referenced_enum_values[e_name].add(ev_name) + + for enum_name, needed_values in referenced_enum_values.items(): + if not test_object_borrowed("Enum", enum_name): + enum_src_file = os.path.join(cfg_dir, "Enums", f"{enum_name}.xml") + if os.path.isfile(enum_src_file): + # Read source Enum to find EnumValue UUIDs + src_enum_tree = etree.parse(enum_src_file, etree.XMLParser(remove_blank_text=False)) + src_enum_root = src_enum_tree.getroot() + src_enum_el = None + for cn in src_enum_root: + if isinstance(cn.tag, str): + src_enum_el = cn + break + + # Find needed EnumValues + ev_xmls = [] + for ev_node in src_enum_el.iter(): + if isinstance(ev_node.tag, str) and localname(ev_node) == "EnumValue": + ev_uuid = ev_node.get("uuid", "") + name_el = None + for props in ev_node: + if isinstance(props.tag, str) and localname(props) == "Properties": + for prop in props: + if isinstance(prop.tag, str) and localname(prop) == "Name": + name_el = prop + break + if name_el is not None and (name_el.text or "").strip() in needed_values: + new_ev_uuid = str(uuid.uuid4()) + ev_xmls.append( + f'\t\t\t\n' + f'\t\t\t\t\n' + f'\t\t\t\t\n' + f'\t\t\t\t\tAdopted\n' + f'\t\t\t\t\t{name_el.text.strip()}\n' + f'\t\t\t\t\t\n' + f'\t\t\t\t\t{ev_uuid}\n' + f'\t\t\t\t\n' + f'\t\t\t' + ) + + # Build borrowed Enum with EnumValues + src_obj = read_source_object("Enum", enum_name) + borrowed_xml = build_borrowed_object_xml("Enum", enum_name, src_obj["uuid"], src_obj["properties"]) + if ev_xmls: + ev_block = "\n".join(ev_xmls) + borrowed_xml = borrowed_xml.replace("", f"\n{ev_block}\n\t\t") + + target_dir = os.path.join(ext_dir, "Enums") + os.makedirs(target_dir, exist_ok=True) + target_file = os.path.join(target_dir, f"{enum_name}.xml") + save_text_bom(target_file, borrowed_xml) + add_to_child_objects("Enum", enum_name) + info(f" Auto-borrowed: Enum.{enum_name} (with {len(ev_xmls)} EnumValue(s))") + else: + warn(f" Enum.{enum_name} not found in source config") + + # Extract the opening tag from source text xml_decl = '' form_tag = f'' m_decl = re.search(r'^(<\?xml[^?]*\?>)', src_form_content) @@ -698,15 +840,17 @@ def main(): parts.append(form_tag) parts.append("\r\n") - # Part 1: form properties + AutoCommandBar (no ChildItems — they come from base form at runtime) + # Part 1: form properties + AutoCommandBar + ChildItems for prop_xml in form_props: prop_xml_clean = ns_strip_pattern.sub("", prop_xml) parts.append(f"\t{prop_xml_clean}\r\n") if auto_cmd_xml: parts.append(f"\t{auto_cmd_xml}\r\n") + if child_items_xml: + parts.append(f"\t{child_items_xml}\r\n") parts.append("\t\r\n") - # BaseForm: same properties + AutoCommandBar (no ChildItems) + # BaseForm: same content, indented one more level parts.append(f'\t\r\n') for prop_xml in form_props: @@ -720,6 +864,14 @@ def main(): else: parts.append(f"\t{line}") parts.append("\r\n") + if child_items_xml: + ci_lines = child_items_xml.split("\n") + for li, line in enumerate(ci_lines): + if li == 0: + parts.append(f"\t\t{line}") + else: + parts.append(f"\t{line}") + parts.append("\r\n") parts.append("\t\t\r\n") parts.append("\t\r\n") diff --git a/docs/1c-extension-spec.md b/docs/1c-extension-spec.md index 9208cca7..aaa2cfb2 100644 --- a/docs/1c-extension-spec.md +++ b/docs/1c-extension-spec.md @@ -356,77 +356,84 @@ Enums/ # Перечисления #### 5.4.2. Структура Form.xml заимствованной формы -Form.xml заимствованной формы — **двухчастный файл**: Part 1 (результирующая форма) и BaseForm (исходная форма). Обе части содержат **только визуальные элементы** — атрибуты, события, параметры и команды базовой конфигурации **НЕ включаются**. +Form.xml заимствованной формы — **двухчастный файл**: Part 1 (результирующая форма) и BaseForm (исходная форма). Существуют **два варианта** в зависимости от наличия модификаций модуля формы. + +##### Вариант A — Минимальная форма (чистое заимствование) + +Когда форма заимствована без модификации модуля — Form.xml содержит **только свойства формы**, AutoCommandBar без кнопок и пустые Attributes. **Нет ChildItems**. Обе секции (Part 1 и BaseForm) идентичны. ```xml - - + false + CurrentOrLast + - - - - - - + false - - - - - - - Расш1_ПриСозданииПосле - - - - - Расш1_НоваяКомандаВместо - - + + - + false + CurrentOrLast + - - - - + false - - - - - + - ``` -**Ключевые правила:** +##### Вариант B — Полная форма (заимствование процедуры модуля через `ИзменениеИКонтроль`) -1. **Часть 1** (до ``) — **результирующая форма**. Содержит визуальные элементы (AutoCommandBar + ChildItems) из базовой конфигурации плюс элементы расширения. Атрибуты базовой конфигурации (DynamicList, QueryText и др.) **не включаются** — только реквизиты расширения (id ≥ 1000000) или пустой ``. Events и Commands — только добавленные расширением (с `callType`). +Когда в расширении заимствуется процедура из модуля формы, Конфигуратор выгружает **полное дерево ChildItems** с применением правил очистки. -2. **Часть 2** (``) — **визуальный снимок исходной формы**. Содержит только AutoCommandBar + ChildItems + пустой ``. НЕ содержит Events, Commands, Parameters. Все `` в кнопках заменены на `0`. Платформа использует BaseForm для контроля совместимости при обновлении конфигурации. +```xml +
+ false + + + false + + + + + + + -3. **Правило `0`**: во всех кнопках базовой формы (как в Part 1, так и в BaseForm) значение `` заменяется на `0`. Ссылки на команды конфигурации не сохраняются. Только кнопки, добавленные расширением, сохраняют ссылку на команду (напр. `Form.Command.XXX`). + + + + +``` -4. Элемент `` всегда идёт **последним** в `
` и имеет атрибут `version`. +**Ключевые правила (для обоих вариантов):** -5. **Правило ``: удаление** — все элементы `...` из базовых визуальных элементов удаляются (и в Part 1, и в BaseForm). DataPath ссылается на реквизиты формы базовой конфигурации, которые не включены в расширение. Сохраняются только DataPath элементов, добавленных расширением (ссылающихся на собственные реквизиты расширения). +1. **Свойства формы** — элементы между `` и `` (напр. `AutoTitle`, `AutoTime`, `UsePostingMode`, `RepostOnWrite`, `WindowOpeningMode`, `Customizable`, `CommandBarLocation`) копируются из исходной формы в обе секции. -6. **Правило `` элементов: удаление** — все блоки `` внутри визуальных элементов (AutoCommandBar и ChildItems) удаляются (и в Part 1, и в BaseForm). Обработчики событий базовой конфигурации не переносятся. При модификации формы обработчики расширения добавляются только в Part 1 с атрибутом `callType`. +2. **AutoCommandBar** — присутствует всегда с `id="-1"`, но без `` (кнопки удаляются). `` = `false`. -7. **Свойства формы** — элементы между `` и `` (например, `WindowOpeningMode`, `AutoFillCheck`, `AutoTitle`, `AutoTime`, `UsePostingMode`, `RepostOnWrite`, `Customizable`, `CommandBarLocation`) копируются из исходной формы в обе части (Part 1 и BaseForm). +3. **Attributes** — пустой `` в обеих секциях. Атрибуты базовой конфигурации **не включаются**. Реквизиты расширения (id ≥ 1000000) добавляются только в Part 1. + +4. **BaseForm** — последний элемент в ``, атрибут `version`. В BaseForm **нет** Events, Commands, Parameters. + +5. **DataPath: удаление** (вариант B) — все `` из базовых элементов удаляются в обеих секциях. DataPath ссылается на реквизиты, не включённые в расширение. + +6. **TitleDataPath: удаление** (вариант B) — все `` удаляются (напр. `Объект.Товары.RowsCount` — путь недействителен без базовых атрибутов). + +7. **TypeLink: удаление** (вариант B) — блоки `` с `Items.*` удаляются (человекочитаемые пути, которые нельзя преобразовать в UUID-формат Конфигуратора). + +8. **Events элементов: удаление** (вариант B) — все `` внутри визуальных элементов удаляются в обеих секциях. Обработчики расширения добавляются через `elementEvents` в Part 1 с `callType`. + +9. **Picture stripping** (вариант B) — блоки `` с `CommonPicture.XXX` удаляются, если `CommonPicture.XXX` **не заимствован** в расширение. Сам элемент PictureDecoration остаётся, только `` убирается. `StdPicture.Print` сохраняется, остальные StdPicture удаляются. + +10. **Авто-заимствование CommonPictures** — при заимствовании формы автоматически заимствуются все CommonPictures, на которые ссылаются элементы формы. + +11. **Авто-заимствование StyleItems** — элементы формы ссылаются на StyleItems через `` и `style:XXX`. Все такие StyleItems должны быть заимствованы. Стандартные стили (NormalTextFont, AccentColor, FormBackColor и др.) не имеют файлов и автоматически пропускаются. + +12. **Авто-заимствование Enums + EnumValues** — `` могут содержать `Enum.XXX.EnumValue.YYY`. Перечисление `Enum.XXX` заимствуется вместе с конкретными `EnumValue` (borrowed с `ExtendedConfigurationObject` указывающим на UUID оригинального значения). #### 5.4.3. Нумерация ID элементов