diff --git a/.claude/skills/form-compile/scripts/form-compile.ps1 b/.claude/skills/form-compile/scripts/form-compile.ps1 index 6aac38b0..58b253ff 100644 --- a/.claude/skills/form-compile/scripts/form-compile.ps1 +++ b/.claude/skills/form-compile/scripts/form-compile.ps1 @@ -1,4 +1,4 @@ -# form-compile v1.34 — Compile 1C managed form from JSON or object metadata +# form-compile v1.36 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [string]$JsonPath, @@ -1515,8 +1515,11 @@ function X { } function Esc-Xml { + # Экранирование ТЕКСТА элемента (, ): только & < > . + # Кавычки/апострофы в тексте экранировать НЕ нужно (1С их не экранирует — пишет литерально); + # " ломал бы раундтрип. Кавычки спецсимвольны лишь в значениях атрибутов. param([string]$s) - return $s.Replace('&','&').Replace('<','<').Replace('>','>').Replace('"','"') + return $s.Replace('&','&').Replace('<','<').Replace('>','>') } # --- 4. Multilang helper --- @@ -1956,7 +1959,7 @@ function Emit-Element { # radio-specific "radioButtonType"=1;"choiceList"=1;"columnsCount"=1;"checkBoxType"=1;"editMode"=1 # naming & binding - "name"=1;"path"=1;"title"=1 + "name"=1;"path"=1;"title"=1;"tooltip"=1 # visibility & state "visible"=1;"hidden"=1;"enabled"=1;"disabled"=1;"readOnly"=1;"userVisible"=1 # events ("events" — основной формат; on/handlers — legacy, принимаются ради совместимости) @@ -2091,6 +2094,8 @@ function Emit-Title { } elseif ($auto -and $name) { Emit-MLText -tag "Title" -text (Title-FromName -name $name) -indent $indent } + # ToolTip элемента (всплывающая подсказка) — по схеме сразу после Title. + if ($el.tooltip) { Emit-MLText -tag "ToolTip" -text $el.tooltip -indent $indent } } function Map-TitleLoc { @@ -2525,6 +2530,7 @@ function Emit-Label { Emit-MLItems -val $labelTitle -indent "$inner`t" X "$inner" } + if ($el.tooltip) { Emit-MLText -tag "ToolTip" -text $el.tooltip -indent $inner } Emit-CommonFlags -el $el -indent $inner @@ -2644,6 +2650,8 @@ function Emit-Pages { X "$indent" $inner = "$indent`t" + Emit-Title -el $el -name $name -indent $inner + if ($el.pagesRepresentation) { X "$inner$($el.pagesRepresentation)" } @@ -2906,6 +2914,8 @@ function Emit-CommandBar { X "$indent" $inner = "$indent`t" + Emit-Title -el $el -name $name -indent $inner + if ($el.autofill -eq $true) { X "$innertrue" } Emit-CommonFlags -el $el -indent $inner diff --git a/.claude/skills/form-compile/scripts/form-compile.py b/.claude/skills/form-compile/scripts/form-compile.py index 9dd3a3ac..dc80a973 100644 --- a/.claude/skills/form-compile/scripts/form-compile.py +++ b/.claude/skills/form-compile/scripts/form-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# form-compile v1.34 — Compile 1C managed form from JSON or object metadata +# form-compile v1.36 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import copy @@ -1251,7 +1251,9 @@ def generate_chart_of_accounts_choice_dsl(meta, preset_data): def esc_xml(s): - return s.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"') + # Экранирование ТЕКСТА элемента (, ): только & < > . + # Кавычки/апострофы в тексте 1С не экранирует (пишет литерально) — " ломал бы раундтрип. + return s.replace('&', '&').replace('<', '<').replace('>', '>') def emit_ml_items(lines, indent, val): @@ -1354,7 +1356,7 @@ KNOWN_KEYS = { "button", "picture", "picField", "calendar", "cmdBar", "popup", "showInHeader", "radioButtonType", "choiceList", "columnsCount", "checkBoxType", "editMode", - "name", "path", "title", + "name", "path", "title", "tooltip", "visible", "hidden", "enabled", "disabled", "readOnly", "userVisible", "events", "on", "handlers", "selectionMode", "showCurrentDate", "widthInMonths", "heightInMonths", "showMonthsPanel", @@ -1673,6 +1675,9 @@ def emit_title(lines, el, name, indent, auto=False): emit_mltext(lines, indent, 'Title', el['title']) elif auto and name: emit_mltext(lines, indent, 'Title', title_from_name(name)) + # ToolTip элемента (всплывающая подсказка) — по схеме сразу после Title. + if el.get('tooltip'): + emit_mltext(lines, indent, 'ToolTip', el['tooltip']) _TITLE_LOC_MAP = {'none': 'None', 'left': 'Left', 'right': 'Right', 'top': 'Top', 'bottom': 'Bottom', 'auto': 'Auto'} @@ -2173,6 +2178,8 @@ def emit_label(lines, el, name, eid, indent): lines.append(f'{inner}') emit_ml_items(lines, f'{inner}\t', label_title) lines.append(f'{inner}') + if el.get('tooltip'): + emit_mltext(lines, inner, 'ToolTip', el['tooltip']) emit_common_flags(lines, el, inner) @@ -2301,6 +2308,8 @@ def emit_pages(lines, el, name, eid, indent): lines.append(f'{indent}') inner = f'{indent}\t' + emit_title(lines, el, name, inner) + if el.get('pagesRepresentation'): lines.append(f'{inner}{el["pagesRepresentation"]}') @@ -2535,6 +2544,8 @@ def emit_command_bar(lines, el, name, eid, indent): lines.append(f'{indent}') inner = f'{indent}\t' + emit_title(lines, el, name, inner) + if el.get('autofill') is True: lines.append(f'{inner}true') diff --git a/.claude/skills/form-decompile/scripts/form-decompile.ps1 b/.claude/skills/form-decompile/scripts/form-decompile.ps1 index bc4c36cc..b82c98d6 100644 --- a/.claude/skills/form-decompile/scripts/form-decompile.ps1 +++ b/.claude/skills/form-decompile/scripts/form-decompile.ps1 @@ -1,4 +1,4 @@ -# form-decompile v0.14 — Decompile 1C managed Form.xml to JSON DSL (draft) +# form-decompile v0.16 — Decompile 1C managed Form.xml to JSON DSL (draft) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью. param( @@ -239,6 +239,8 @@ function Add-CommonProps { if ($null -ne $t) { $obj['title'] = $t } # formatted у LabelDecoration выводится компилятором из hyperlink — отдельный ключ не нужен (#16 хвост) } + $ttNode = $node.SelectSingleNode("lf:ToolTip", $ns) + if ($ttNode) { $tt = Get-LangText $ttNode; if ($null -ne $tt) { $obj['tooltip'] = $tt } } $ev = Get-Events $node $elName if ($ev) { $obj['events'] = $ev } } diff --git a/docs/form-dsl-spec.md b/docs/form-dsl-spec.md index e4b8820a..3d86de53 100644 --- a/docs/form-dsl-spec.md +++ b/docs/form-dsl-spec.md @@ -116,6 +116,7 @@ | `readOnly` | bool | `true` → `true` | | `events` | object | Обработчики событий: `{ "ИмяСобытия": "ИмяОбработчика" }` — тот же формат, что у событий формы (§3). Значение `null` → имя по конвенции (§4.2). См. §4.2 | | `titleLocation` | string | Расположение заголовка: `none`/`left`/`right`/`top`/`bottom`/`auto`. Эмитится при наличии (input, labelField, picField, table, calendar). У `check`/`radio` — особая семантика с умным дефолтом (см. их разделы) | +| `tooltip` | string/object | Всплывающая подсказка элемента (``). Строка → ru, объект `{ "ru": …, "en": … }` → мультиязычный (как `title`). Эмитится сразу после `title` | ### 4.1a. Общие layout-свойства diff --git a/tests/skills/cases/form-compile/input-fields.json b/tests/skills/cases/form-compile/input-fields.json index 1a7ecb3c..2190027a 100644 --- a/tests/skills/cases/form-compile/input-fields.json +++ b/tests/skills/cases/form-compile/input-fields.json @@ -16,7 +16,7 @@ "input": { "title": "Поля ввода", "elements": [ - { "input": "ОбычноеПоле", "path": "ОбычноеПоле", "title": "Обычное поле", "editMode": "EnterOnInput" }, + { "input": "ОбычноеПоле", "path": "ОбычноеПоле", "title": "Обычное поле", "tooltip": "Введите значение поля", "editMode": "EnterOnInput" }, { "labelField": "Ссылка", "path": "ОбычноеПоле", "titleLocation": "left", "hyperlink": true }, { "input": "МногострочноеПоле", "path": "МногострочноеПоле", "multiLine": true, "height": 5, "title": "Комментарий" }, { "input": "ПолеПароля", "path": "ПолеПароля", "passwordMode": true, "title": "Пароль" }, diff --git a/tests/skills/cases/form-compile/pages.json b/tests/skills/cases/form-compile/pages.json index aded9c10..8d1401f8 100644 --- a/tests/skills/cases/form-compile/pages.json +++ b/tests/skills/cases/form-compile/pages.json @@ -17,11 +17,11 @@ "title": "Мастер настройки", "properties": { "autoTitle": false }, "elements": [ - { "pages": "СтраницыМастера", "pagesRepresentation": "None", "children": [ + { "pages": "СтраницыМастера", "pagesRepresentation": "None", "tooltip": "Страницы мастера настройки", "children": [ { "page": "Шаг1", "title": "", "children": [ { "input": "Параметр1", "path": "Параметр1" } ]}, - { "page": "Шаг2", "title": "Результат", "children": [ + { "page": "Шаг2", "title": "Результат", "tooltip": "Шаг \"Результат\"", "children": [ { "input": "Итог", "path": "Итог", "readOnly": true } ]} ]}, diff --git a/tests/skills/cases/form-compile/snapshots/input-fields/DataProcessors/ПоляВвода/Forms/Форма/Ext/Form.xml b/tests/skills/cases/form-compile/snapshots/input-fields/DataProcessors/ПоляВвода/Forms/Форма/Ext/Form.xml index c8742959..2281d3f9 100644 --- a/tests/skills/cases/form-compile/snapshots/input-fields/DataProcessors/ПоляВвода/Forms/Форма/Ext/Form.xml +++ b/tests/skills/cases/form-compile/snapshots/input-fields/DataProcessors/ПоляВвода/Forms/Форма/Ext/Form.xml @@ -17,6 +17,12 @@ Обычное поле + + + ru + Введите значение поля + + EnterOnInput diff --git a/tests/skills/cases/form-compile/snapshots/pages/DataProcessors/Мастер/Forms/Форма/Ext/Form.xml b/tests/skills/cases/form-compile/snapshots/pages/DataProcessors/Мастер/Forms/Форма/Ext/Form.xml index 0ef9e502..96138f60 100644 --- a/tests/skills/cases/form-compile/snapshots/pages/DataProcessors/Мастер/Forms/Форма/Ext/Form.xml +++ b/tests/skills/cases/form-compile/snapshots/pages/DataProcessors/Мастер/Forms/Форма/Ext/Form.xml @@ -10,6 +10,12 @@ + + + ru + Страницы мастера настройки + + None @@ -30,6 +36,12 @@ Результат + + + ru + Шаг "Результат" + +