mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-19 00:59:40 +03:00
feat(web-test): всплывающие (popup) группы — behavior, состояние, клик
Popup-группа надёжно отличается от сворачиваемой по DOM-маркеру панели
<base>#panel_div (+ #CloseBtn). В getFormState().groups она помечается
behavior:'popup', а её collapsed берётся из display панели (закрыта =
collapsed:true), не из инлайн-сиблинга (у popup содержимое в отдельном
слое, а не под mainGroup).
clickElement по заголовку popup и открывает, и закрывает — тот же
словарь {expand}/{toggle}, что и у сворачиваемых. После открытия
содержимое панели становится читаемым в getFormState (fields/
hyperlinks/texts). Тест 25-decoration-form покрывает popup; SKILL
дополнен. Полный регресс 29 passed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -146,7 +146,7 @@ Returns current form structure. This is the primary way to understand what's on
|
||||
|
||||
**navigation** — form navigation panel links (for objects with subordinate catalogs): `[{ name, active? }]`. Clickable via `clickElement()`. Only present when the form has a navigation panel (e.g. "Основное", "Объекты метаданных", "Подсистемы").
|
||||
|
||||
**groups** — collapsible form groups: `[{ name, title, collapsed }]`. `collapsed: true` means the group's content is hidden — part of the form is not shown until you expand it (common on settings pages like "Администрирование → Интернет-поддержка и сервисы"). Expand/collapse a group by its title with `clickElement`, same vocabulary as tree nodes: `{ expand: true }` opens (idempotent), `{ expand: false }` collapses, `{ toggle: true }` flips. Plain (non-collapsible) groups are not listed.
|
||||
**groups** — collapsible and pop-up form groups: `[{ name, title, collapsed, behavior? }]`. `collapsed: true` means the group's content is hidden — part of the form is not shown until you expand it (common on settings pages like "Администрирование → Интернет-поддержка и сервисы"). `behavior: 'popup'` marks a pop-up group (content shows in a floating panel); absent for ordinary collapsible groups. Expand/collapse (or open/close a pop-up) by the group title with `clickElement`, same vocabulary as tree nodes: `{ expand: true }` reveals (idempotent), `{ expand: false }` hides, `{ toggle: true }` flips. After expanding, the group's content becomes readable in the next `getFormState()` (its fields/hyperlinks/texts appear). Plain (non-collapsible) groups are not listed.
|
||||
```js
|
||||
const form = await getFormState();
|
||||
// form.groups = [{ name: "ГруппаНовости", title: "Новости", collapsed: true }, ...]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// web-test dom shared v1.6 — embedded JS function constants
|
||||
// web-test dom shared v1.7 — embedded JS function constants
|
||||
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
/**
|
||||
* Shared function strings embedded into page.evaluate() generators.
|
||||
@@ -675,26 +675,32 @@ function readForm(p) {
|
||||
if (iframeCount) result.iframes = iframeCount;
|
||||
|
||||
// Collapsible / popup groups — surface that part of the form is hidden + its state.
|
||||
// Идентификация раскрываемой группы: у неё есть заголовок <base>#title_text, и либо этот
|
||||
// заголовок — гиперссылка (.staticTextHyper: ControlRepresentation=TitleHyperlink / popup),
|
||||
// либо рядом есть кнопка-каретка <base>#titleBtn (ControlRepresentation=Picture). Обычные
|
||||
// (несворачиваемые) группы не имеют ни того, ни другого — их не показываем.
|
||||
// Состояние: DOM у 1С плоский (контент группы — сиблинги под mainGroup, не вложены), но при
|
||||
// глубинном обходе Form.xml ПЕРВЫЙ контент-сиблинг сразу за #title_div — всегда дочерний
|
||||
// элемент группы (свободные соседи идут после всех детей). Его display = состояние группы:
|
||||
// none → свёрнута, block → развёрнута. Переживает свободные элементы между группами.
|
||||
// Идентификация раскрываемой группы (есть заголовок <base>#title_text и один из признаков):
|
||||
// • заголовок — гиперссылка (.staticTextHyper: ControlRepresentation=TitleHyperlink);
|
||||
// • рядом кнопка-каретка <base>#titleBtn (ControlRepresentation=Picture);
|
||||
// • есть панель <base>#panel_div — это ВСПЛЫВАЮЩАЯ (popup) группа.
|
||||
// Обычные (несворачиваемые) группы не имеют ничего из этого — их не показываем.
|
||||
// Состояние:
|
||||
// • popup: display панели <base>#panel_div (none → закрыта);
|
||||
// • collapsible: DOM у 1С плоский (контент — сиблинги под mainGroup, не вложены), но при
|
||||
// глубинном обходе Form.xml ПЕРВЫЙ контент-сиблинг сразу за #title_div — всегда дочерний
|
||||
// элемент группы (свободные соседи идут после всех детей). Его display = состояние.
|
||||
const groups = [];
|
||||
document.querySelectorAll('[id^="' + p + '"][id$="#title_text"]').forEach(tt => {
|
||||
if (tt.offsetWidth === 0 && tt.offsetHeight === 0) return;
|
||||
const base = tt.id.slice(0, -('#title_text'.length));
|
||||
const panelDiv = document.getElementById(base + '#panel_div'); // popup-маркер
|
||||
const isHyper = tt.classList.contains('staticTextHyper');
|
||||
const hasBtn = !!document.getElementById(base + '#titleBtn');
|
||||
if (!isHyper && !hasBtn) return; // обычная (несворачиваемая) группа — пропускаем
|
||||
const title = nbsp(tt.innerText?.trim() || '');
|
||||
const g = { name: base.replace(p, ''), title };
|
||||
const titleDiv = document.getElementById(base + '#title_div');
|
||||
const contentSib = titleDiv?.nextElementSibling;
|
||||
if (contentSib) g.collapsed = getComputedStyle(contentSib).display === 'none';
|
||||
if (!isHyper && !hasBtn && !panelDiv) return; // обычная (несворачиваемая) группа
|
||||
const g = { name: base.replace(p, ''), title: nbsp(tt.innerText?.trim() || '') };
|
||||
if (panelDiv) {
|
||||
g.behavior = 'popup';
|
||||
g.collapsed = getComputedStyle(panelDiv).display === 'none';
|
||||
} else {
|
||||
const contentSib = document.getElementById(base + '#title_div')?.nextElementSibling;
|
||||
if (contentSib) g.collapsed = getComputedStyle(contentSib).display === 'none';
|
||||
}
|
||||
groups.push(g);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// web-test dom/forms v1.11 — form detection, content read, click-target/field-button resolution
|
||||
// web-test dom/forms v1.12 — form detection, content read, click-target/field-button resolution
|
||||
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
import { DETECT_FORM_FN, READ_FORM_FN, ROW_CLICK_POINT_FN } from './_shared.mjs';
|
||||
|
||||
@@ -105,23 +105,24 @@ export function findClickTargetScript(formNum, text, { tableName, gridSelector }
|
||||
});
|
||||
|
||||
// Сворачиваемые/всплывающие группы — заголовок как цель раскрытия/сворачивания.
|
||||
// Идентификация: <base>#title_text — гиперссылка (TitleHyperlink/popup) ЛИБО рядом есть
|
||||
// кнопка-каретка <base>#titleBtn (ControlRepresentation=Picture). Обычные группы пропускаем.
|
||||
// Мишень клика: #titleBtn (вариант «картинка») иначе сам заголовок-гиперссылка.
|
||||
// Состояние: первый контент-сиблинг за #title_div (display:none = свёрнута).
|
||||
// Идентификация: <base>#title_text и один из: гиперссылка (TitleHyperlink) ЛИБО кнопка-каретка
|
||||
// <base>#titleBtn (Picture) ЛИБО панель <base>#panel_div (popup). Обычные группы пропускаем.
|
||||
// Мишень клика: #titleBtn (вариант «картинка») иначе заголовок (у popup клик по заголовку
|
||||
// и открывает, и закрывает). Состояние: у popup — display панели, иначе — первый контент-
|
||||
// сиблинг за #title_div (display:none = свёрнута/закрыта).
|
||||
[...document.querySelectorAll('[id^="' + p + '"][id$="#title_text"]')]
|
||||
.filter(el => el.offsetWidth > 0 || el.offsetHeight > 0).forEach(el => {
|
||||
const base = el.id.slice(0, -('#title_text'.length));
|
||||
const btn = document.getElementById(base + '#titleBtn');
|
||||
const btnVisible = btn && (btn.offsetWidth > 0 || btn.offsetHeight > 0);
|
||||
if (!el.classList.contains('staticTextHyper') && !btnVisible) return; // обычная группа
|
||||
const panelDiv = document.getElementById(base + '#panel_div');
|
||||
if (!el.classList.contains('staticTextHyper') && !btnVisible && !panelDiv) return; // обычная группа
|
||||
const tgt = btnVisible ? btn : el;
|
||||
const r = tgt.getBoundingClientRect();
|
||||
const titleDiv = document.getElementById(base + '#title_div');
|
||||
const sib = titleDiv && titleDiv.nextElementSibling;
|
||||
const item = { id: '', kind: 'formGroup', name: norm(el.innerText) || base.replace(p, ''),
|
||||
label: base.replace(p, ''), x: Math.round(r.x + r.width / 2), y: Math.round(r.y + r.height / 2) };
|
||||
if (sib) item.collapsed = getComputedStyle(sib).display === 'none';
|
||||
const stateEl = panelDiv || (document.getElementById(base + '#title_div') || {}).nextElementSibling;
|
||||
if (stateEl) item.collapsed = getComputedStyle(stateEl).display === 'none';
|
||||
items.push(item);
|
||||
});
|
||||
|
||||
|
||||
@@ -70,4 +70,22 @@ export default async function({ navigateSection, openCommand, navigateLink, getF
|
||||
assert.equal(collapsedOf(r, 'ГруппаКартинкой'), false, 'B раскрыта тоглом');
|
||||
await closeForm();
|
||||
});
|
||||
|
||||
await step('popup: всплывающая группа — behavior, открытие показывает содержимое', async () => {
|
||||
const s = await navigateLink('Обработка.СтраницаНастроек');
|
||||
const pg = (s.groups || []).find(g => g.name === 'ГруппаВсплывающая');
|
||||
assert.ok(pg, 'всплывающая группа в groups[]');
|
||||
assert.equal(pg.behavior, 'popup', 'помечена behavior:popup (отличима от collapsible)');
|
||||
assert.equal(pg.collapsed, true, 'закрыта — collapsed:true');
|
||||
assert.ok(!(s.texts || []).some(t => /всплывающей/.test(t.value)), 'содержимое скрыто, пока закрыта');
|
||||
// Открыть → содержимое панели становится видно в состоянии формы.
|
||||
let r = await clickElement('Всплывающая группа', { expand: true });
|
||||
assert.equal((r.groups || []).find(g => g.name === 'ГруппаВсплывающая')?.collapsed, false, 'открыта');
|
||||
assert.ok((r.texts || []).some(t => /всплывающей/.test(t.value)), 'после открытия содержимое видно');
|
||||
r = await clickElement('Всплывающая группа', { expand: true });
|
||||
assert.equal(r.clicked.toggled, false, 'expand идемпотентен для popup');
|
||||
r = await clickElement('Всплывающая группа', { expand: false });
|
||||
assert.equal((r.groups || []).find(g => g.name === 'ГруппаВсплывающая')?.collapsed, true, 'закрыта обратно');
|
||||
await closeForm();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user