mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-10 16:14:54 +03:00
fix(cfe-borrow): strip DataPath, Events and preserve form properties in Borrow-Form
Borrowed forms failed to load with "Неверный путь к данным" and "Событие не было загружено" errors. Root cause: base form elements contained DataPath and Events referencing attributes and handlers not present in the extension. Changes: - Strip <DataPath> from base elements in both AutoCommandBar and ChildItems - Strip element-level <Events> from both sections - Collect form-level properties (AutoTitle, WindowOpeningMode, etc.) and write them into both main and BaseForm sections - Update 1c-extension-spec.md with rules 5-7 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -476,13 +476,23 @@ function Borrow-Form {
|
||||
$formVersion = $srcFormEl.GetAttribute("version")
|
||||
if (-not $formVersion) { $formVersion = "2.17" }
|
||||
|
||||
# Find direct children: AutoCommandBar, ChildItems (visual elements only)
|
||||
# Find direct children: form properties, AutoCommandBar, ChildItems
|
||||
$srcAutoCmd = $null
|
||||
$srcChildItems = $null
|
||||
$formProps = @()
|
||||
$reachedVisual = $false
|
||||
foreach ($fc in $srcFormEl.ChildNodes) {
|
||||
if ($fc.NodeType -ne 'Element') { continue }
|
||||
if ($fc.LocalName -eq 'AutoCommandBar' -and -not $srcAutoCmd) { $srcAutoCmd = $fc }
|
||||
elseif ($fc.LocalName -eq 'ChildItems' -and -not $srcChildItems) { $srcChildItems = $fc }
|
||||
if ($fc.LocalName -eq 'AutoCommandBar' -and -not $srcAutoCmd) {
|
||||
$reachedVisual = $true; $srcAutoCmd = $fc; continue
|
||||
}
|
||||
if ($fc.LocalName -eq 'ChildItems' -and -not $srcChildItems) {
|
||||
$reachedVisual = $true; $srcChildItems = $fc; continue
|
||||
}
|
||||
if (-not $reachedVisual) {
|
||||
# Form-level properties before AutoCommandBar (WindowOpeningMode, AutoFillCheck, etc.)
|
||||
$formProps += $fc.OuterXml
|
||||
}
|
||||
}
|
||||
|
||||
# Get OuterXml and strip redundant namespace redeclarations (they're on root <Form>)
|
||||
@@ -496,6 +506,10 @@ function Borrow-Form {
|
||||
$autoCmdXml = [regex]::Replace($autoCmdXml, '<CommandName>[^<]*</CommandName>', '<CommandName>0</CommandName>')
|
||||
# Replace Autofill true → false
|
||||
$autoCmdXml = $autoCmdXml -replace '<Autofill>true</Autofill>', '<Autofill>false</Autofill>'
|
||||
# Strip DataPath (references base form attributes not present in extension)
|
||||
$autoCmdXml = [regex]::Replace($autoCmdXml, '\s*<DataPath>[^<]*</DataPath>', '')
|
||||
# Strip element-level Events (base form event handlers not present in extension)
|
||||
$autoCmdXml = [regex]::Replace($autoCmdXml, '(?s)\s*<Events>.*?</Events>', '')
|
||||
}
|
||||
|
||||
$childItemsXml = ""
|
||||
@@ -504,6 +518,9 @@ function Borrow-Form {
|
||||
$childItemsXml = [regex]::Replace($childItemsXml, $nsStripPattern, '')
|
||||
# Replace all CommandName values with 0 in ChildItems too
|
||||
$childItemsXml = [regex]::Replace($childItemsXml, '<CommandName>[^<]*</CommandName>', '<CommandName>0</CommandName>')
|
||||
# Strip DataPath and element-level Events
|
||||
$childItemsXml = [regex]::Replace($childItemsXml, '\s*<DataPath>[^<]*</DataPath>', '')
|
||||
$childItemsXml = [regex]::Replace($childItemsXml, '(?s)\s*<Events>.*?</Events>', '')
|
||||
} else {
|
||||
$childItemsXml = "<ChildItems/>"
|
||||
}
|
||||
@@ -521,7 +538,11 @@ function Borrow-Form {
|
||||
$formXmlSb.Append($formTag) | Out-Null
|
||||
$formXmlSb.Append("`r`n") | Out-Null
|
||||
|
||||
# Part 1: visual elements (add leading tab to first line of each block)
|
||||
# Part 1: form properties + visual elements
|
||||
foreach ($propXml in $formProps) {
|
||||
$propXml = [regex]::Replace($propXml, $nsStripPattern, '')
|
||||
$formXmlSb.Append("`t$propXml`r`n") | Out-Null
|
||||
}
|
||||
if ($autoCmdXml) {
|
||||
$formXmlSb.Append("`t$autoCmdXml") | Out-Null
|
||||
$formXmlSb.Append("`r`n") | Out-Null
|
||||
@@ -531,10 +552,14 @@ function Borrow-Form {
|
||||
$formXmlSb.Append("`t<Attributes/>") | Out-Null
|
||||
$formXmlSb.Append("`r`n") | Out-Null
|
||||
|
||||
# BaseForm: same visual elements, indented one more level
|
||||
# BaseForm: form properties + same visual elements, indented one more level
|
||||
$formXmlSb.Append("`t<BaseForm version=`"${formVersion}`">") | Out-Null
|
||||
$formXmlSb.Append("`r`n") | Out-Null
|
||||
|
||||
foreach ($propXml in $formProps) {
|
||||
$propXml = [regex]::Replace($propXml, $nsStripPattern, '')
|
||||
$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"
|
||||
|
||||
@@ -653,14 +653,23 @@ def main():
|
||||
|
||||
src_auto_cmd = None
|
||||
src_child_items = None
|
||||
form_props = []
|
||||
reached_visual = False
|
||||
for fc in src_form_el:
|
||||
if not isinstance(fc.tag, str):
|
||||
continue
|
||||
ln = localname(fc)
|
||||
if ln == "AutoCommandBar" and src_auto_cmd is None:
|
||||
reached_visual = True
|
||||
src_auto_cmd = fc
|
||||
elif ln == "ChildItems" and src_child_items is None:
|
||||
continue
|
||||
if ln == "ChildItems" and src_child_items is None:
|
||||
reached_visual = True
|
||||
src_child_items = fc
|
||||
continue
|
||||
if not reached_visual:
|
||||
# Form-level properties before AutoCommandBar (WindowOpeningMode, AutoFillCheck, etc.)
|
||||
form_props.append(etree.tostring(fc, encoding="unicode"))
|
||||
|
||||
ns_strip_pattern = re.compile(r'\s+xmlns(?::\w+)?="[^"]*"')
|
||||
|
||||
@@ -670,12 +679,19 @@ def main():
|
||||
auto_cmd_xml = ns_strip_pattern.sub("", auto_cmd_xml)
|
||||
auto_cmd_xml = re.sub(r'<CommandName>[^<]*</CommandName>', '<CommandName>0</CommandName>', auto_cmd_xml)
|
||||
auto_cmd_xml = auto_cmd_xml.replace('<Autofill>true</Autofill>', '<Autofill>false</Autofill>')
|
||||
# Strip DataPath (references base form attributes not present in extension)
|
||||
auto_cmd_xml = re.sub(r'\s*<DataPath>[^<]*</DataPath>', '', auto_cmd_xml)
|
||||
# Strip element-level Events (base form event handlers not present in extension)
|
||||
auto_cmd_xml = re.sub(r'\s*<Events>.*?</Events>', '', auto_cmd_xml, flags=re.DOTALL)
|
||||
|
||||
child_items_xml = ""
|
||||
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)
|
||||
child_items_xml = re.sub(r'<CommandName>[^<]*</CommandName>', '<CommandName>0</CommandName>', child_items_xml)
|
||||
# Strip DataPath and element-level Events
|
||||
child_items_xml = re.sub(r'\s*<DataPath>[^<]*</DataPath>', '', child_items_xml)
|
||||
child_items_xml = re.sub(r'\s*<Events>.*?</Events>', '', child_items_xml, flags=re.DOTALL)
|
||||
else:
|
||||
child_items_xml = "<ChildItems/>"
|
||||
|
||||
@@ -696,6 +712,10 @@ def main():
|
||||
parts.append(form_tag)
|
||||
parts.append("\r\n")
|
||||
|
||||
# Form properties (WindowOpeningMode, AutoFillCheck, etc.)
|
||||
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")
|
||||
parts.append(f"\t{child_items_xml}\r\n")
|
||||
@@ -704,6 +724,9 @@ def main():
|
||||
# BaseForm
|
||||
parts.append(f'\t<BaseForm version="{form_version}">\r\n')
|
||||
|
||||
for prop_xml in form_props:
|
||||
prop_xml_clean = ns_strip_pattern.sub("", prop_xml)
|
||||
parts.append(f"\t\t{prop_xml_clean}\r\n")
|
||||
if auto_cmd_xml:
|
||||
ac_lines = auto_cmd_xml.split("\n")
|
||||
for li, line in enumerate(ac_lines):
|
||||
|
||||
@@ -422,6 +422,12 @@ Form.xml заимствованной формы — **двухчастный ф
|
||||
|
||||
4. Элемент `<BaseForm>` всегда идёт **последним** в `<Form>` и имеет атрибут `version`.
|
||||
|
||||
5. **Правило `<DataPath>`: удаление** — все элементы `<DataPath>...</DataPath>` из базовых визуальных элементов удаляются (и в Part 1, и в BaseForm). DataPath ссылается на реквизиты формы базовой конфигурации, которые не включены в расширение. Сохраняются только DataPath элементов, добавленных расширением (ссылающихся на собственные реквизиты расширения).
|
||||
|
||||
6. **Правило `<Events>` элементов: удаление** — все блоки `<Events>` внутри визуальных элементов (AutoCommandBar и ChildItems) удаляются (и в Part 1, и в BaseForm). Обработчики событий базовой конфигурации не переносятся. При модификации формы обработчики расширения добавляются только в Part 1 с атрибутом `callType`.
|
||||
|
||||
7. **Свойства формы** — элементы между `<Form>` и `<AutoCommandBar>` (например, `WindowOpeningMode`, `AutoFillCheck`, `AutoTitle`, `AutoTime`, `UsePostingMode`, `RepostOnWrite`, `Customizable`, `CommandBarLocation`) копируются из исходной формы в обе части (Part 1 и BaseForm).
|
||||
|
||||
#### 5.4.3. Нумерация ID элементов
|
||||
|
||||
| Диапазон | Принадлежность |
|
||||
|
||||
Reference in New Issue
Block a user