Добавить кнопку и собственное окно
Добавить полезное окно с действием, выбрав правильное поведение закрытия.
Сделаем небольшую панель: пользователь задаёт максимальное число строк, нажимает «Обновить список» и видит имена выделенных объектов. Панель не изменяет проект. Она показывает, как хранить состояние между открытиями и освобождать обработчики при закрытии.
Нужно уметь установить минимальный плагин.
Пример рассчитан на текущий Release BDEngine и использует editorAPI и стандартный DOM.
Задача интерфейса
Скачать полный плагин window.js. Установите файл и перезапустите редактор. В меню дока появится «Панель выделения».
Параметр «Максимум строк» принимает целое число от 1 до 50. Это ограничение примера, оно не ограничивает количество объектов в проекте. При пустом выделении панель покажет ноль объектов. Имена выводятся как текст: название объекта не выполняется как HTML.
Список обновляется при открытии окна и по кнопке. Изменение выделения при открытой панели само по себе не запускает обновление. Значение параметра сохраняется в переменной плагина до перезагрузки редактора, а не записывается в файл проекта.
Где разместить кнопку
Для панели, которую открывают по необходимости, подходит меню дока:
editorAPI.addButtonDockMenu( 'icon-list', 'Панель выделения', openPanel);openPanel - функция плагина. Метод возвращает DOM-элемент ссылки; если потребуется
убрать именно эту кнопку, сохраните результат и вызовите у него remove().
Удаление кнопки не закрывает уже созданное окно.
Для часто используемого действия есть addButtonTool(icon, handler, right, sound).
Он размещает кнопку в полосе инструментов. Пункты импорта и экспорта добавляются
отдельными методами. Параметры и возвращаемые значения:
выбрать кнопку.
Кнопка регистрируется один раз после bde:started. Обработчик события ставится
при выполнении файла плагина:
window.addEventListener('bde:started', () => { // Создание кнопки и начального состояния плагина.}, {once: true});В этот момент интерфейс уже создан. Это не обещание, что последний проект успел восстановиться: читать выделение следует в ответ на действие пользователя.
Обычное или модальное окно
Нашей панели подходит обычное окно: пользователь может менять выделение и возвращаться к списку.
createWindow сразу создаёт и открывает окно:
const panel = editorAPI.createWindow( 'Панель выделения', 'bde.docs.window.panel', 'icon-list', 460, 340, 300, 240, cleanup);После иконки передаются желаемые ширина и высота, минимальные ширина и высота, затем
обработчик закрытия крестиком. Размеры задаются в пикселях. Используйте собственный
постоянный name_id: редактор связывает с ним сохранённую геометрию окна.
В panel.container находится DOM-контейнер содержимого. focus() выводит уже открытое
окно на передний план и восстанавливает его, если оно было свёрнуто.
createModalWindow(title) подходит для временного выбора, который перекрывает работу
с редактором. Модальное окно создаётся скрытым: его открывают через showModal(),
закрывают через hideModal(), а содержимое добавляют в container. Скрытие сохраняет
DOM и обработчики. Если выберете такой вариант, создайте модальное окно один раз
и переиспользуйте его, вместо создания нового при каждом нажатии.
Содержимое и обработчики
Панель использует обычные элементы form, input, button и ul.
Ключевая часть обновления списка:
const selected = editorAPI.getSelectedObjects();list.replaceChildren();for (const object of selected.slice(0, maxRows)) { const row = document.createElement('li'); row.textContent = object.name || 'Объект без имени'; list.append(row);}getSelectedObjects() возвращает текущие объекты сцены, а не копии их данных.
Здесь мы только читаем name. Перед вызовом проверяем параметр через Number.isInteger
и границы диапазона; одного input.min недостаточно для проверки значений в коде.
При отправке формы вызываем event.preventDefault(), чтобы браузер не перезагружал страницу.
События keydown и keyup внутри формы останавливаем через stopPropagation(),
чтобы ввод в поле не передавался обработчикам клавиатуры редактора.
Обработчики формы привязаны с общим AbortController:
const events = new AbortController();form.addEventListener('submit', handler, {signal: events.signal});// При закрытии:events.abort();Не вставляйте введённые пользователем значения в innerHTML.
Для текста используйте textContent, для значения поля - value.
Повторное открытие и очистка
Плагин хранит одну ссылку на окно. Пока она существует, повторное нажатие вызывает
focus(). При закрытии обработчики отключаются, а ссылка сбрасывается.
Есть существенное различие между двумя способами закрытия обычного окна:
- Крестик окна вызывает переданный
closeFunc, затемclose(). - Прямой вызов
panel.close()сам по себе не вызываетcloseFunc.
Поэтому своя кнопка закрытия выполняет оба действия:
cleanup();current.close();close() удаляет DOM окна после анимации. Закрытое окно повторно не открывают:
при следующем нажатии создаётся новое. Параметр maxRows остаётся снаружи окна,
поэтому сохраняется между открытиями.
Если в инструменте появятся setInterval, подписки на window или другие внешние ресурсы,
их тоже нужно освобождать в собственном cleanup. Сам факт удаления DOM этого не делает.
closeFunc не является обработчиком выгрузки всего плагина.
Подробнее: проверить жизненный цикл.
Проверить действие и состояние
- Откройте панель без выделения. Должны появиться ноль объектов и пустой список.
- Выделите несколько объектов и нажмите «Обновить список». Проверьте имена и счётчик.
- Укажите максимум 1. В списке останется одна строка, общий счётчик выделения не изменится.
- Попробуйте пустое поле, 0, 51 и дробное число. Некорректное значение не должно примениться.
- Не закрывая окно, нажмите его пункт в доке ещё раз. Должно активироваться то же окно.
- Закройте его крестиком, затем откройте снова. Повторите со своей кнопкой «Закрыть». В обоих случаях значение параметра должно сохраниться, а одно нажатие формы - дать одно обновление.
Это проверки в самом редакторе. Сверка кода и проверка JavaScript не заменяют проверку фокуса, сворачивания и размеров окна на нужном устройстве.