Расширенная настройка интерфейса

1. Общая информация

Для платёжной формы доступна опция расширенной кастомизации. В отличие от базовой настройки стилей, эта возможность позволяет полностью разработать собственный интерфейс для всех или отдельных этапов оплаты с сохранением базовой функциональности и безопасности платёжной системы.

Чтобы получить исходный HTML-файл, выгрузите его из интерфейса платёжной формы в браузере.

Ознакомиться с платёжной формой можно в разделе “Платёжная форма и виджет” — «Новая платёжная форма».

2. Файлы кастомизации и ограничения

Для изменения доступны:

  • HTML-файлы: с семантически правильной структурой, включая все необходимые секции (<!DOCTYPE html>, <html>, <head>, <body>) и полный контент страницы. Файлы должны быть самодостаточными и содержать всю разметку, а не только изменяемые части.
  • CSS-файлы: должны содержать полное описание стилей для всех элементов интерфейса, а не только переопределения отдельных правил. Рекомендуем добавлять свои стили в css-файл формы.
  • Шрифты: форматы woff2 и woff.
  • Изображения и иконки: форматы SVG (рекомендуется для иконок), PNG, JPEG (JPG).

Ограничения:

  • Добавление JavaScript недоступно.
  • Для кнопок методов оплаты недоступно изменение наименований и иконок.

Ориентировочная структура предоставляемых файлов:

  • html-файл — платёжная форма и форма ввода данных карты
  • css-файл — стили для платёжной формы и формы ввода данных карты (name.css)
  • fonts/ — папка с файлами шрифтов
  • img/ — папка с файлами изображений и иконок

3. Процесс передачи и пример архива

Подготовленные файлы кастомизации передайте вашему менеджеру.

При получении файлов мы проведём техническое ревью и предоставим обратную связь по результатам.

Пример структуры архива:

В приложенном архиве представлена папка js с файлом script.js для ознакомления и просмотра работы формы. Его редактирование и добавление новых скриптов недоступны.

custom_assistant.rar

4. Работа с postMessage

Если платёжная форма встроена на страницу магазина через iframe, родительская страница и iframe могут обмениваться сообщениями через механизм postMessage.

Механизм используется для:

  • автоматического изменения размеров iframe под размер виджета;
  • передачи CSS-класса для кастомизации виджета при подключённой расширенной настройке интерфейса и переданных стилях (см. разд. 1–3);
  • обмена статусами платёжного сценария между платёжной формой и родительской страницей магазина.

Обмен сообщениями происходит между родительской страницей магазина и iframe с платёжной формой. Для приёма сообщений на стороне магазина зарегистрируйте обработчик события message.

Поддерживаемые сообщения:

  • от платёжной формы → на страницу магазина:
    widgetSize — актуальные размеры виджета
    status — текущий статус платёжного сценария.
  • от страницы магазина → платёжную форму:
    bodyClass — CSS-класс для кастомизации виджета;
    request с m_val: "status" — запрос актуального статуса платёжного сценария.

Минимальный сценарий подключения:

  1. Встроить платёжную форму в страницу через iframe.
  2. Зарегистрировать обработчик window.addEventListener('message', ...).
  3. Обрабатывать сообщение widgetSize и менять размеры iframe.
  4. При необходимости обрабатывать сообщение status для получения текущего статуса платёжного сценария.
  5. При необходимости отправлять сообщение bodyClass для кастомизации виджета.
  6. При необходимости отправлять сообщение request с m_val: "status" для запроса актуального статуса платёжного сценария.

4.1. Получение размеров виджета (widgetSize)

Платёжная форма отправляет сообщение widgetSize, когда размер виджета изменяется. Это позволяет автоматически изменять размеры iframe на стороне магазина.

Формат сообщения:

{
  "m_type": "widgetSize",
  "width": 300,
  "height": 64
}

Где m_type — тип сообщения; width и height — ширина и высота виджета в пикселях. Рекомендуемый формат — число. Если виджет передаёт размеры строками, на стороне магазина их нужно привести к числу (см. пример ниже).

После получения сообщения необходимо:

  1. Убедиться, что сообщение пришло с соответствующим типом и структурой.
  2. Обновить размеры iframe.

Пример кода для родительского окна:

// ID iframe-элемента, в котором размещается форма
const ASSISTANT_WIDGET_ID = 'assistantWidget'

/**
 * Проверка, является ли сообщение валидным
 * @param {unknown} msg - Проверяемый объект
 * @returns {msg is { m_type: string } & Record<string, unknown>}
 */
function isValidMessage(msg) {
    return typeof msg?.m_type === 'string';
}

/**
 * Получает элемент виджета по ID
 * @returns {HTMLIFrameElement | null}
 */
function getAssistantWidget() {
    const widget = document.getElementById(ASSISTANT_WIDGET_ID);
    if (!widget) {
        console.warn(`Элемент с id "${ASSISTANT_WIDGET_ID}" не найден`);
    }
    return widget;
}

/**
 * Обработчик сообщений от виджета
 * @param {MessageEvent} event - Событие сообщения от window
 * @returns {void}
 */
function listener(event) {
    let msg;

    try {
        msg = JSON.parse(event.data);
    } catch (e) {
        return; // Невалидный JSON - игнорируем
    }

    if (!isValidMessage(msg)) {
        return; // Неверная структура сообщения - игнорируем
    }

    switch (msg.m_type) {
        case "widgetSize": {
            const width = Number(msg.width);
            const height = Number(msg.height);
            if (!Number.isFinite(width) || !Number.isFinite(height)) {
                console.warn('Неверный формат сообщения widgetSize:', msg);
                return;
            }

            const assistantWidget = getAssistantWidget();
            if (!assistantWidget) return;

            assistantWidget.style.height = `${height}px`;
            assistantWidget.style.width = `${width}px`;
            break;
        }

        default:
            console.debug(`Получено неизвестное сообщение: ${msg.m_type}`);
            break;
    }
}

// Подписка на сообщения
if (window.addEventListener) {
    window.addEventListener("message", listener, false);
} else {
    window.attachEvent("onmessage", listener);
}

Пример сообщения от платёжной формы:

{"m_type":"widgetSize","width":360,"height":740}

4.2. Передача CSS-класса (bodyClass)

Родительская страница может передать в платёжную форму CSS-класс для дополнительной кастомизации виджета. Функция доступна, если подключена расширенная настройка интерфейса и переданы стили (см. разд. 1–3).

Формат сообщения:

{
  "m_type": "bodyClass",
  "m_val": "class_name"
}

Где m_type — тип сообщения; m_val — имя CSS-класса.

Особенности обработки на стороне платёжной формы:

  1. Из значения m_val удаляются все недопустимые символы. Доступны только буквы, цифры, дефис - и нижнее подчёркивание _.
  2. Платёжная форма устанавливает CSS-класс для body виджета и применяет стили для этого класса (переданные в рамках расширенной настройки интерфейса). Если по значению m_val стили не найдены — отображается стандартный интерфейс платёжной формы.
  3. Отдельный ответ на сообщение bodyClass не отправляется.

Пример отправки класса (предполагается, что объявлена функция getAssistantWidget() из примера выше):

/**
 * Отправляет сообщение в виджет для установки CSS-класса для элемента body
 * @param {string} bodyClass - Название CSS-класса
 */
function setBodyClass(bodyClass) {
    if (!bodyClass || typeof bodyClass !== 'string') {
        console.warn('bodyClass должен быть непустой строкой');
        return;
    }

    const assistantWidget = getAssistantWidget();
    if (!assistantWidget) return;

    const data = {
        m_type: 'bodyClass',
        m_val: bodyClass
    };

    assistantWidget.contentWindow?.postMessage(data, "*");
}

Пример вызова:

setBodyClass('custom-theme-dark');

4.3. Обмен статусами платёжного сценария (status)

Платёжная форма может отправлять родительской странице сообщения о текущем статусе платёжного сценария. Это позволяет обновлять интерфейс магазина в зависимости от состояния оплаты: показывать ожидание, успешный результат, ошибку или истечение сессии.

Отправка текущего статуса

Платёжная форма отправляет сообщение status родительской странице:

  • при загрузке платёжной формы;
  • при изменении статуса платёжного сценария;
  • при истечении сессии;
  • в ответ на запрос актуального статуса от родительской страницы.

Формат сообщения:

{
  "m_type": "status",
  "status": "created"
}

Где m_type — тип сообщения; status — значение статуса платёжного сценария.

Значение поля status:

СтатусОписание
createdИнициализация платёжной формы. Платёжная операция ещё не запущена. Направляется в том числе при повторной инициализации формы после получения статуса failed или timeout.
inprogressПлатёжная операция находится в процессе проведения.
successПлатёжная операция успешно завершена.
failedПлатёжная операция завершена неуспешно.
timeoutИстёк срок действия сессии.

Пример сообщения от платёжной формы:

{"m_type":"status","status":"inprogress"}

После получения сообщения родительская страница может:

  1. Проверить источник сообщения.
  2. Определить, что сообщение относится к типу m_type: "status".
  3. Получить значение поля status.
  4. Обновить интерфейс магазина в зависимости от полученного статуса.

Пример обработки статуса (добавьте ветку в тот же обработчик listener из п. 4.1):

switch (msg.m_type) {
    case "status":
        if (typeof msg.status !== 'string') {
            console.warn('Неверный формат сообщения status:', msg);
            return;
        }

        // Обновить интерфейс магазина в зависимости от статуса:
        // created, inprogress, success, failed, timeout
        console.debug('Статус платёжного сценария:', msg.status);
        break;

    // остальные типы сообщений
}

Запрос актуального статуса

Родительская страница магазина может запросить у платёжной формы актуальный статус платёжного сценария — например, чтобы повторно синхронизировать интерфейс магазина с состоянием виджета.

Для запроса актуального статуса отправьте в iframe платёжной формы сообщение request с m_val: "status".

Формат сообщения:

{
  "m_type": "request",
  "m_val": "status"
}

Где m_type — тип сообщения; m_val — значение запроса. Для запроса актуального статуса принимает значение status.

При получении такого сообщения платёжная форма определяет текущий статус платёжного сценария и отправляет родительской странице ответ:

{"m_type":"status","status":"<значение_статуса>"}

Пример запроса статуса (предполагается, что объявлена функция getAssistantWidget() из примера в п. 4.1):

/**
 * Запрашивает у виджета актуальный статус платёжного сценария
 */
function requestStatus() {
    const assistantWidget = getAssistantWidget();
    if (!assistantWidget) return;

    const data = {
        m_type: 'request',
        m_val: 'status'
    };

    assistantWidget.contentWindow?.postMessage(data, "*");
}

Пример вызова:

requestStatus();