"use strict";

if (typeof window.administrators !== "function") {
  // Not initialized

  // Initialize of the class in global namespace
  window.administrators = class administrators {
    /**
     * Заблокировать функцию закрытия всплывающего окна?
     */
    static freeze = false;

    /**
     * Тело всплывающего окна (массив)
     */
    static body = {};

    /**
     * Инициализирован класс?
     */
    static initialized = false;

    /**
     * Управление кнопками (escape, enter...)
     *
     * Содержит функцию инициализирующую обработчики событий keydown для document
     * функция деинициализируется с document при закрытии окна
     */
    static buttons;

    /**
     * Ожидание зависимости: ядро
     *
     * @param {function} execute Функция, которая будет встроена в демпфер
     * @param {mixed} args Аргументы встраиваемой функции
     *
     * @return {void}
     */
    static core(execute, ...args) {
      if (typeof execute === "function") {
        // Получена функция

        // Инициализация интервала для ожидания загрузки зависимостей
        const interval = setInterval(() => {
          if (typeof core === "function") {
            // Инициализировано ядро

            // Деинициализация интервала для ожидания загрузки записимостей
            clearInterval(interval);

            // Запуск выполнения
            return execute(...args);
          }
        }, 100);

        // Инициализация деинициализации интервала для ожидания загрузки зависимостей спустя большой срок времени
        setTimeout(() => clearInterval(interval), 3000);
      }
    }

    /**
     * Ожидание зависимости: демпфер
     *
     * @param {function} execute Функция, которая будет встроена в демпфер
     * @param {number} timer Количество миллисекунд для демпфера
     * @param {mixed} args Аргументы встраиваемой функции
     *
     * @return {void}
     */
    static damper(execute, timer = 3000, ...args) {
      if (typeof execute === "function") {
        // Получена функция

        // Инициализация интервала для ожидания загрузки зависимостей
        const interval = setInterval(() => {
          if (typeof damper === "function") {
            // Инициализирован демпфер

            // Деинициализация интервала для ожидания загрузки записимостей
            clearInterval(interval);

            // Запуск выполнения
            return damper(() => execute(...args), timer);
          }
        }, 100);

        // Инициализация деинициализации интервала для ожидания загрузки зависимостей спустя большой срок времени
        setTimeout(() => clearInterval(interval), 3000);
      }
    }

    /**
     * Авторизация
     *
     * @param {function} execute Функция, которая будет встроена в демпфер
     * @param {mixed} args Аргументы встраиваемой функции
     *
     * @return {void}
     */
    static authorization(execute, ...args) {
      if (typeof execute === "function") {
        // Получена функция

        if (core.page === this.page) {
          // Пройдена проверка на страницу

          // Запуск выполнения
          return execute(...args);
        }
      }
    }

    /**
     * Обновить аккаунт (вызов демпфера)
     *
     * @param {HTMLElement} row Строка <div>
     * @param {HTMLElement} button Кнопка <button>
     * @param {HTMLElement} account_name_first Имя аккаунта <input>
     * @param {HTMLElement} account_name_second Фамилия аккаунта <input>
     * @param {HTMLElement} account_name_last Отчество аккаунта <input>
     * @param {HTMLElement} account_number SIM-номер аккаунта <input>
     * @param {HTMLElement} account_mail Почта аккаунта<input>
     * @param {HTMLElement} account_password Пароль аккаунта <input>
     * @param {HTMLElement} account_commentary Комментарий аккаунта <textarea>
     *
     * @return {void}
     */
    static _update(
      row,
      button,
      account_name_first,
      account_name_second,
      account_name_last,
      account_number,
      account_mail,
      account_password,
      account_commentary,
    ) {
      // Блокировка полей ввода
      account_name_first.setAttribute("readonly", true);
      account_name_second.setAttribute("readonly", true);
      account_name_last.setAttribute("readonly", true);
      account_number.setAttribute("readonly", true);
      account_mail.setAttribute("readonly", true);
      account_password.setAttribute("readonly", true);
      account_commentary.setAttribute("readonly", true);

      // Блокировка кнопки
      button.setAttribute("disabled", true);

      // Запуск выполнения
      this.__update(
        row,
        button,
        account_name_first,
        account_name_second,
        account_name_last,
        account_number,
        account_mail,
        account_password,
        account_commentary,
      );
    }

    /**
     * Обновить аккаунт (демпфер)
     *
     * @param {HTMLElement} row Строка <div>
     * @param {HTMLElement} button Кнопка <button>
     * @param {HTMLElement} account_name_first Имя аккаунта <input>
     * @param {HTMLElement} account_name_second Фамилия аккаунта <input>
     * @param {HTMLElement} account_name_last Отчество аккаунта <input>
     * @param {HTMLElement} account_number SIM-номер аккаунта <input>
     * @param {HTMLElement} account_mail Почта аккаунта<input>
     * @param {HTMLElement} account_password Пароль аккаунта <input>
     * @param {HTMLElement} account_commentary Комментарий аккаунта <textarea>
     *
     * @return {void}
     */
    static __update = damper(
      async (
        row,
        button,
        account_name_first,
        account_name_second,
        account_name_last,
        account_number,
        account_mail,
        account_password,
        account_commentary,
      ) => {
        // Инициализация функции разблокировки
        function unblock() {
          // Разблокировка полей ввода
          account_name_first.removeAttribute("readonly");
          account_name_second.removeAttribute("readonly");
          account_name_last.removeAttribute("readonly");
          account_number.removeAttribute("readonly");
          account_mail.removeAttribute("readonly");
          account_password.removeAttribute("readonly");
          account_commentary.removeAttribute("readonly");

          // Разблокировка кнопки
          button.removeAttribute("disabled");
        }

        // Инициализация идентификатора
        const id = row.getAttribute("id");

        // Запуск отсрочки разблокировки на случай, если сервер не отвечает
        const timeout = setTimeout(() => {
          this.errors(["Сервер не отвечает"]);
          unblock();
        }, 5000);

        // Запрос к серверу
        return await fetch(`/${id}/update`, {
          method: "POST",
          headers: {
            "Content-Type": "application/x-www-form-urlencoded",
          },
          body:
            `name_first=${account_name_first.value}&name_second=${account_name_second.value}&name_last=${account_name_last.value}&number=${account_number.mask.unmaskedValue}&mail=${account_mail.value}&password=${account_password.value}&commentary=${account_commentary.value}`,
        })
          .then((response) => response.json())
          .then((data) => {
            // Удаление отсрочки разблокировки
            clearTimeout(timeout);

            if (this.errors(data.errors)) {
              // Сгенерированы ошибки

              // Разблокировка полей ввода и кнопок
              unblock();
            } else {
              // Не сгенерированы ошибки (подразумевается их отсутствие)

              if (data.updated === true) {
                // Записаны данные

                // Инициализация буфера списка классов
                // const buffer = [...row.classList];

                // Инициализация статуса активной строки
                const selected = row.getAttribute("data-selected");

                // Реинициализация строки
                row.outerHTML = data.row;

                // Реинициализация строки (выражение странное, но правильное)
                row = document.getElementById(id);

                // Копирование классов из буфера классов удалённой строки
                // row.classList.add(...buffer);

                // Копирование статуса активной строки
                if (
                  typeof selected === "string" && selected === "true" &&
                  document.body.contains(document.getElementById("popup")) &&
                  !document.body.contains(
                    document.querySelector('[data-selected="true"]'),
                  )
                ) {
                  row.setAttribute("data-selected", "true");
                }
              }

              if (
                typeof data.clipboard !== "undefined" &&
                data.clipboard.length > 0
              ) {
                // Получены данные для записи в буфер обмена

                // Запись в буфер обмена (подразумеваются данные созданного аккаунта)
                navigator.clipboard.writeText(data.clipboard);
              }

              if (this.body.wrap instanceof HTMLElement) {
                // Найдено активное окно

                // Деинициализация быстрых действий по кнопкам
                document.removeEventListener("keydown", this.buttons);

                // Сброс блокировки
                this.freeze = false;

                // Деинициализация активного окна
                this.body.wrap.remove();

                // Удаление статуса активной строки
                row.removeAttribute("data-selected");
              }
            }
          });
      },
      300,
    );

    /**
     * Сгенерировать окно для редактированием аккаунта
     *
     * @param {HTMLElement} row Строка
     *
     * @return {void}
     */
    static update = damper(async (row) => {
      if (row instanceof HTMLElement) {
        // Получена строка

        // Инициализация идентификатора аккаунта
        const id = row.getAttribute("id");

        // Запрос к серверу
        return await fetch(`/${id}/fields`, {
          method: "POST",
          headers: {
            "Content-Type": "application/x-www-form-urlencoded",
          },
        })
          .then((response) => response.json())
          .then((data) => {
            // Инициализация буфера выбранных строк
            const buffer = [
              ...document.querySelectorAll('div[data-selected="true"]'),
            ];

            // Удаление статуса активной строки у остальных строк
            for (const element of buffer) {
              element.removeAttribute("data-selected");
            }

            // Инициализация статуса активной строки (обрабатываемой в данный момент)
            row.setAttribute("data-selected", "true");

            // Инициализация оболочки всплывающего окна
            this.body.wrap = document.createElement("div");
            this.body.wrap.setAttribute("id", "popup");

            // Инициализация оболочки всплывающего окна
            const popup = document.createElement("section");
            popup.classList.add("list", "extensive", "small");

            // Инициализация заголовка всплывающего окна
            const title = document.createElement("h3");
            title.innerText = id;

            // Инициализация оболочки с основной информацией
            const main = document.createElement("section");
            main.classList.add("main");

            // Инициализация колонки
            const account = document.createElement("div");
            account.classList.add("column");

            // Инициализация строки
            const account_name_first = document.createElement("div");
            account_name_first.classList.add("row", "merged");

            // Инициализация оболочки для строки
            const account_name_first_label = document.createElement("label");
            account_name_first_label.setAttribute("id", "account_first");

            // Инициализация заголовка для поля ввода
            const account_name_first_title = document.createElement("b");
            account_name_first_title.classList.add(
              "separated",
              "right",
              "unselectable",
            );
            account_name_first_title.innerText = "Имя:";

            // Инициализация поля ввода
            const account_name_first_input = document.createElement("input");
            account_name_first_input.classList.add("medium");
            account_name_first_input.setAttribute("type", "text");
            account_name_first_input.setAttribute("name", "first");
            account_name_first_input.setAttribute(
              "autocomplete",
              "given-name",
            );
            account_name_first_input.setAttribute("minlength", "0");
            account_name_first_input.setAttribute("maxlength", "100");
            account_name_first_input.setAttribute("title", "Имя аккаунта");
            account_name_first_input.setAttribute("placeholder", "Иван");
            account_name_first_input.value = data.name.first ?? "";

            // Инициализация строки
            const account_name_second = document.createElement("div");
            account_name_second.classList.add("row", "merged");

            // Инициализация оболочки для строки
            const account_name_second_label = document.createElement("label");
            account_name_second_label.setAttribute("id", "account_second");

            // Инициализация заголовка для поля ввода
            const account_name_second_title = document.createElement("b");
            account_name_second_title.classList.add(
              "separated",
              "right",
              "unselectable",
            );
            account_name_second_title.innerText = "Фамилия:";

            // Инициализация поля ввода
            const account_name_second_input = document.createElement("input");
            account_name_second_input.classList.add("medium");
            account_name_second_input.setAttribute(
              "autocomplete",
              "family-name",
            );
            account_name_second_input.setAttribute("name", "second");
            account_name_second_input.setAttribute("type", "text");
            account_name_second_input.setAttribute("minlength", "0");
            account_name_second_input.setAttribute("maxlength", "100");
            account_name_second_input.setAttribute(
              "title",
              "Фамилия аккаунта",
            );
            account_name_second_input.setAttribute("placeholder", "Иванов");
            account_name_second_input.value = data.name.second ?? "";

            // Инициализация строки
            const account_name_last = document.createElement("div");
            account_name_last.classList.add("row", "merged");

            // Инициализация оболочки для строки
            const account_name_last_label = document.createElement("label");
            account_name_last_label.setAttribute("id", "account_last");

            // Инициализация заголовка для поля ввода
            const account_name_last_title = document.createElement("b");
            account_name_last_title.classList.add(
              "separated",
              "right",
              "unselectable",
            );
            account_name_last_title.innerText = "Отчество:";

            // Инициализация поля ввода
            const account_name_last_input = document.createElement("input");
            account_name_last_input.classList.add("medium");
            account_name_last_input.setAttribute("name", "last");
            account_name_last_input.setAttribute(
              "autocomplete",
              "additional-name",
            );
            account_name_last_input.setAttribute("type", "text");
            account_name_last_input.setAttribute("minlength", "0");
            account_name_last_input.setAttribute("maxlength", "100");
            account_name_last_input.setAttribute(
              "title",
              "Отчество/Матчество аккаунта",
            );
            account_name_last_input.setAttribute("placeholder", "Иванович");
            account_name_last_input.value = data.name.last ?? "";

            // Инициализация строки
            const account_number = document.createElement("div");
            account_number.classList.add("row", "merged", "divided");

            // Инициализация оболочки для строки
            const account_number_label = document.createElement("label");
            account_number_label.setAttribute("id", "account_number");

            // Инициализация заголовка для поля ввода
            const account_number_title = document.createElement("b");
            account_number_title.classList.add(
              "separated",
              "right",
              "unselectable",
            );
            account_number_title.innerText = "SIM-номер:";

            // Инициализация поля ввода
            const account_number_input = document.createElement("input");
            account_number_input.classList.add("medium");
            account_number_input.setAttribute("name", "sim-number");
            account_number_input.setAttribute("autocomplete", "tel");
            account_number_input.setAttribute("type", "text");
            account_number_input.setAttribute("minlength", "18");
            account_number_input.setAttribute("maxlength", "18");
            account_number_input.setAttribute("title", "SIM-номер аккаунта");
            account_number_input.setAttribute(
              "placeholder",
              "+7 (000) 000-00-00",
            );
            account_number_input.value = data.number ?? "";

            // Инициализация строки
            const account_mail = document.createElement("div");
            account_mail.classList.add("row", "merged");

            // Инициализация оболочки для строки
            const account_mail_label = document.createElement("label");
            account_mail_label.setAttribute("id", "account_mail");

            // Инициализация заголовка для поля ввода
            const account_mail_title = document.createElement("b");
            account_mail_title.classList.add(
              "separated",
              "right",
              "unselectable",
            );
            account_mail_title.innerText = "Почта:";

            // Инициализация поля ввода
            const account_mail_input = document.createElement("input");
            account_mail_input.classList.add("medium");
            account_mail_input.setAttribute("name", "mail");
            account_mail_input.setAttribute("autocomplete", "email");
            account_mail_input.setAttribute("type", "text");
            account_mail_input.setAttribute("minlength", "3");
            account_mail_input.setAttribute("maxlength", "300");
            account_mail_input.setAttribute("title", "Почта аккаунта");
            account_mail_input.setAttribute("placeholder", "name@server");
            account_mail_input.value = data.mail ?? "";

            // Инициализация строки
            const account_password = document.createElement("div");
            account_password.classList.add("row", "merged");

            // Инициализация оболочки для строки
            const account_password_label = document.createElement("label");
            account_password_label.setAttribute("id", "account_password");

            // Инициализация заголовка для поля ввода
            const account_password_title = document.createElement("b");
            account_password_title.classList.add(
              "separated",
              "right",
              "unselectable",
            );
            account_password_title.innerText = "Пароль:";

            // Инициализация поля ввода
            const account_password_input = document.createElement("input");
            account_password_input.classList.add("medium");
            account_password_input.setAttribute("name", "password");
            account_password_input.setAttribute("required", "true");
            account_password_input.setAttribute(
              "title",
              "Не менее 8 символов",
            );
            account_password_input.setAttribute(
              "autocomplete",
              "new-password",
            );
            account_password_input.setAttribute("type", "password");
            account_password_input.setAttribute("minlength", "8");
            account_password_input.setAttribute("maxlength", "100");
            account_password_input.setAttribute("title", "Пароль аккаунта");
            account_password_input.setAttribute("placeholder", "*********");

            // Инициализация строки
            const account_commentary = document.createElement("div");
            account_commentary.classList.add("row", "endless");

            // Инициализация оболочки для строки
            const account_commentary_label = document.createElement("label");
            account_commentary_label.setAttribute("id", "account_commentary");

            // Инициализация поля ввода
            const account_commentary_textarea = document.createElement(
              "textarea",
            );
            account_commentary_textarea.setAttribute("maxlength", "800");
            account_commentary_textarea.setAttribute(
              "title",
              "Комментарий аккаунта",
            );
            account_commentary_textarea.setAttribute(
              "placeholder",
              "Дополнительная информация для администраторов",
            );
            account_commentary_textarea.value = data.commentary ?? "";

            // Инициализация строки
            const account_buttons = document.createElement("div");
            account_buttons.classList.add("row", "divided", "buttons");

            // Инициализация кнопки обновления
            const account_update_button = document.createElement("button");
            account_update_button.classList.add("grass", "stretched");
            account_update_button.innerText = "Сохранить";
            account_update_button.setAttribute(
              "onclick",
              `administrators._update(document.getElementById(${id}), this, ...this.parentElement.parentElement.parentElement.querySelectorAll(':is(input, textarea)'))`,
            );

            // Инициализация кнопки удаления
            const account_delete_button = document.createElement("button");
            account_delete_button.classList.add("clay");
            account_delete_button.innerText = "Удалить";
            account_delete_button.setAttribute(
              "onclick",
              `administrators._delete(document.getElementById(${id}), this, ...this.parentElement.parentElement.parentElement.querySelectorAll(':is(input, textarea)'))`,
            );

            // Инициализация окна с ошибками
            this.body.errors = document.createElement("section");
            this.body.errors.classList.add(
              "errors",
              "window",
              "list",
              "small",
              "hidden",
            );
            this.body.errors.setAttribute("data-errors", true);

            // Инициализация элемента-оболочки с ошибками для всплывающего окна
            const errors = document.createElement("section");
            errors.classList.add("body");

            // Инициализация элемента-списка ошибок
            const dl = document.createElement("dl");

            // Инициализация активного всплывающего окна
            const old = document.getElementById("popup");

            if (old instanceof HTMLElement) {
              // Найдено активное окно

              // Деинициализация быстрых действий по кнопкам
              document.removeEventListener("keydown", this.buttons);

              // Сброс блокировки
              this.freeze = false;

              // Удаление активного окна
              old.remove();
            }

            // Запись в документ
            popup.appendChild(title);

            account_name_first_label.appendChild(account_name_first_title);
            account_name_first_label.appendChild(account_name_first_input);
            account_name_first.appendChild(account_name_first_label);
            account.appendChild(account_name_first);

            account_name_second_label.appendChild(account_name_second_title);
            account_name_second_label.appendChild(account_name_second_input);
            account_name_second.appendChild(account_name_second_label);
            account.appendChild(account_name_second);

            account_name_last_label.appendChild(account_name_last_title);
            account_name_last_label.appendChild(account_name_last_input);
            account_name_last.appendChild(account_name_last_label);
            account.appendChild(account_name_last);

            account_number_label.appendChild(account_number_title);
            account_number_label.appendChild(account_number_input);
            account_number.appendChild(account_number_label);
            account.appendChild(account_number);

            account_mail_label.appendChild(account_mail_title);
            account_mail_label.appendChild(account_mail_input);
            account_mail.appendChild(account_mail_label);
            account.appendChild(account_mail);

            account_password_label.appendChild(account_password_title);
            account_password_label.appendChild(account_password_input);
            account_password.appendChild(account_password_label);
            account.appendChild(account_password);

            account_commentary_label.appendChild(account_commentary_textarea);
            account_commentary.appendChild(account_commentary_label);
            account.appendChild(account_commentary);

            account_buttons.appendChild(account_update_button);
            account_buttons.appendChild(account_delete_button);
            account.appendChild(account_buttons);

            main.appendChild(account);
            popup.appendChild(main);
            this.body.wrap.appendChild(popup);

            errors.appendChild(dl);
            this.body.errors.appendChild(errors);
            this.body.wrap.appendChild(this.body.errors);

            document.body.appendChild(this.body.wrap);

            // Инициалиация масок
            account_number_input.mask = IMask(account_number_input, {
              mask: "+{7} (000) 000-00-00",
            });

            // Инициализация переменных для окна с ошибками (12 - это значение gap из div#popup)
            function top(errors) {
              errors.style.setProperty(
                "transition",
                "0s",
              );
              errors.style.setProperty(
                "--top",
                popup.offsetTop + popup.offsetHeight + 12 + "px",
              );
              setTimeout(
                () => errors.style.removeProperty("transition"),
                100,
              );
            }
            top(this.body.errors);
            const resize = new ResizeObserver(() => top(this.body.errors));
            resize.observe(this.body.wrap);

            // Инициализация функции генерации пароля и записи в поле ввода и буфер обмена
            const generate = (e) => {
              // Блокировка выполнения при нажатии на поле для ввода
              if (e.target.tagName === "INPUT") return;

              // Инициализация поля ввода пароля
              const input = e.currentTarget.getElementsByTagName("input")[0];

              if (input instanceof HTMLElement) {
                // Найдено поле для ввода пароля

                // Инициализация буфера генерации пароля
                let password = "";

                // Инициализация используемых символов для генерируемого пароля
                const symbols =
                  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789------";

                // Генерация пароля
                for (let i = 0; i < Math.random() * 14 + 8; i++) {
                  password += symbols.charAt(
                    Math.floor(Math.random() * symbols.length),
                  );
                }

                // Запись пароля в поле для ввода пароля
                input.value = password;

                // Вызов функции инициализации генератора пароля
                input.dispatchEvent(new KeyboardEvent("keyup"));

                // Запиcь пароля в буфер обмена
                navigator.clipboard.writeText(password);

                // Фокусировка на поле для ввода пароля
                input.focus();
              }
            };

            // Инициализация функции инициализации генератора пароля
            const generator = (e) => {
              // Инициализация строки с полем для ввода пароля
              const row = e.currentTarget.parentElement.parentElement;

              if (row instanceof HTMLElement) {
                // Найдено поле для ввода пароля

                if (e.target.value.length === 0) {
                  // Не введён пароль

                  row.setAttribute("title", "Сгенерировать пароль");
                  row.setAttribute("data-interactive", "true");
                  row.addEventListener("click", generate);
                } else {
                  // Введён пароль

                  row.removeAttribute("title");
                  row.removeAttribute("data-interactive");
                  row.removeEventListener("click", generate);
                }
              }
            };

            // Инициализация вызова функции инициализации генератора пароля по события нажатия клавиши
            account_password_input.addEventListener("keyup", generator);

            // Вызов функции инициализации генератора пароля (первичный)
            account_password_input.dispatchEvent(new KeyboardEvent("keyup"));

            // Инициализация функции закрытия всплывающего окна
            const click = () => {
              // Блокировка
              if (this.freeze) return;

              // Удаление всплывающего окна
              this.body.wrap.remove();

              // Инициализация буфера выбранных строк
              const buffer = [
                ...document.querySelectorAll('div[data-selected="true"]'),
              ];

              // Удаление статуса активной строки у остальных строк
              for (const element of buffer) {
                element.removeAttribute("data-selected");
              }

              // Деинициализация быстрых действий по кнопкам
              document.removeEventListener("keydown", this.buttons);

              // Сброс блокировки
              this.freeze = false;
            };

            // Инициализация функции добавления функции закрытия всплывающего окна
            const enable = () =>
              this.body.wrap.addEventListener("click", click);

            // Инициализация функции удаления функции закрытия всплывающего окна
            const disable = () =>
              this.body.wrap.removeEventListener("click", click);

            // Первичная активация функции удаления всплывающего окна
            enable();

            // Инициализация блокировки удаления окна при взаимодействии с select-элементом
            for (const select of popup.getElementsByTagName("select")) {
              // Перебор всех select-элементов

              // Инициализация функции блокировки удаления окна по событию
              select.addEventListener("click", () => {
                // Блокировка удаления окна
                this.freeze = true;

                // Разблокировка удаления окна
                setTimeout(() => this.freeze = false, 100);
              });

              for (const option of select.getElementsByTagName("option")) {
                // Перебор всех option-элементов

                // Инициализация функции блокировки удаления окна по событию
                option.addEventListener("click", () => {
                  // Блокировка удаления окна
                  this.freeze = true;

                  // Разблокировка удаления окна
                  setTimeout(() => this.freeze = false, 100);
                });
              }
            }

            // Инициализация блокировки удаления окна при взаимодействии с textarea-элементом
            for (const textarea of popup.getElementsByTagName("textarea")) {
              // Перебор всех textarea-элементов

              // Обновлять позицию окна с ошибками при изменении размера textarea (там position: absolute)
              new MutationObserver(() => top(this.body.errors)).observe(
                textarea,
                {
                  attributes: true,
                  attributeFilter: ["style"],
                },
              );

              // Инициализация функции игнорирования блокировки для выбранных кнопок
              textarea.addEventListener("keydown", (e) => {
                if (e.keyCode === 27) {
                  // Нажата кнопка: "escape"

                  // Вызов глобальной функции управления кнопками
                  this.buttons(e, true);
                } else if (e.ctrlKey && e.keyCode === 13) {
                  // Нажаты кнопки: "control", "enter"

                  // Вызов глобальной функции управления кнопками
                  this.buttons(e, true);
                }
              });

              // Добавление функции блокировки удаления окна и клавиш по событиям
              textarea.addEventListener("focus", () => this.freeze = true);
              textarea.addEventListener("focusout", () => this.freeze = false);
            }

            // Инициализация функции управления кнопками
            this.buttons = (e, force = false) => {
              // Блокировка
              if (!force && this.freeze) return;

              if (e.keyCode === 27) {
                // Нажата кнопка: "escape"

                // Удаление окна
                click();
              } else if (event.keyCode === 13) {
                // Нажата кнопка: "enter"

                // Инициализация буфера с текущим статусом блокировки закрытия окна
                const freeze = this.freeze;

                // Блокировка закрытия окна (чтобы не вызвался click() через событие onclick)
                this.freeze = true;

                // Активация виртуальной кнопки "сохранить"
                account_update_button.click();

                // Возвращение статуса блокировки закрытия окна
                this.freeze = freeze;
              }
            };

            // Инициализация быстрых действий по кнопкам
            document.addEventListener("keydown", this.buttons);

            // Добавление функции удаления всплывающего окна по событиям
            popup.addEventListener("mouseenter", disable);
            popup.addEventListener("mouseleave", enable);

            // Фокусировка
            account_name_first_input.focus();
          });
      }
    }, 300);

    /**
     * Создать аккаунт (вызов демпфера)
     *
     * @param {HTMLElement} button Кнопка <button>
     * @param {HTMLElement} account_name_first Имя аккаунта <input>
     * @param {HTMLElement} account_name_second Фамилия аккаунта <input>
     * @param {HTMLElement} account_name_last Отчество аккаунта <input>
     * @param {HTMLElement} account_number SIM-номер аккаунта <input>
     * @param {HTMLElement} account_mail Почта аккаунта<input>
     * @param {HTMLElement} account_password Пароль аккаунта <input>
     * @param {HTMLElement} account_commentary Комментарий аккаунта <textarea>
     *
     * @return {void}
     */
    static _create(
      button,
      account_name_first,
      account_name_second,
      account_name_last,
      account_number,
      account_mail,
      account_password,
      account_commentary,
    ) {
      // Блокировка полей ввода
      account_name_first.setAttribute("readonly", true);
      account_name_second.setAttribute("readonly", true);
      account_name_last.setAttribute("readonly", true);
      account_number.setAttribute("readonly", true);
      account_mail.setAttribute("readonly", true);
      account_password.setAttribute("readonly", true);
      account_commentary.setAttribute("readonly", true);

      // Блокировка кнопки
      button.setAttribute("disabled", true);

      // Запуск выполнения
      this.__create(
        button,
        account_name_first,
        account_name_second,
        account_name_last,
        account_number,
        account_mail,
        account_password,
        account_commentary,
      );
    }

    /**
     * Создать аккаунт (демпфер)
     *
     * @param {HTMLElement} button Кнопка <button>
     * @param {HTMLElement} account_name_first Имя аккаунта <input>
     * @param {HTMLElement} account_name_second Фамилия аккаунта <input>
     * @param {HTMLElement} account_name_last Отчество аккаунта <input>
     * @param {HTMLElement} account_number SIM-номер аккаунта <input>
     * @param {HTMLElement} account_mail Почта аккаунта<input>
     * @param {HTMLElement} account_password Пароль аккаунта <input>
     * @param {HTMLElement} account_commentary Комментарий аккаунта <textarea>
     *
     * @return {void}
     */
    static __create = damper(
      async (
        button,
        account_name_first,
        account_name_second,
        account_name_last,
        account_number,
        account_mail,
        account_password,
        account_commentary,
      ) => {
        // Инициализация функции разблокировки
        function unblock() {
          // Разблокировка полей ввода
          account_name_first.removeAttribute("readonly");
          account_name_second.removeAttribute("readonly");
          account_name_last.removeAttribute("readonly");
          account_number.removeAttribute("readonly");
          account_mail.removeAttribute("readonly");
          account_password.removeAttribute("readonly");
          account_commentary.removeAttribute("readonly");

          // Разблокировка кнопки
          button.removeAttribute("disabled");
        }

        // Запуск отсрочки разблокировки на случай, если сервер не отвечает
        const timeout = setTimeout(() => {
          this.errors(["Сервер не отвечает"]);
          unblock();
        }, 5000);

        // Запрос к серверу
        return await fetch("/administrators/create", {
          method: "POST",
          headers: {
            "Content-Type": "application/x-www-form-urlencoded",
          },
          body:
            `name_first=${account_name_first.value}&name_second=${account_name_second.value}&name_last=${account_name_last.value}&number=${account_number.mask.unmaskedValue}&mail=${account_mail.value}&password=${account_password.value}&commentary=${account_commentary.value}`,
        })
          .then((response) => response.json())
          .then((data) => {
            // Удаление отсрочки разблокировки
            clearTimeout(timeout);

            if (this.errors(data.errors)) {
              // Сгенерированы ошибки

              // Разблокировка полей ввода и кнопок
              unblock();
            } else {
              // Не сгенерированы ошибки (подразумевается их отсутствие)

              if (data.clipboard.length > 0) {
                // Получены данные для записи в буфер обмена

                // Запись в буфер обмена (подразумеваются данные созданного аккаунта)
                navigator.clipboard.writeText(data.clipboard);
              }

              if (this.body.wrap instanceof HTMLElement) {
                // Найдено активное окно

                // Деинициализация быстрых действий по кнопкам
                document.removeEventListener("keydown", this.buttons);

                // Сброс блокировки
                this.freeze = false;

                // Деинициализация активного окна
                this.body.wrap.remove();
              }

              // Реинициализация строк
              this.reinit();
            }
          });
      },
      300,
    );

    /**
     * Сгенерировать окно с формой создания аккаунта
     *
     * @param {HTMLElement} row Строка
     *
     * @return {void}
     */
    static create = damper(() => {
      // Инициализация оболочки всплывающего окна
      this.body.wrap = document.createElement("div");
      this.body.wrap.setAttribute("id", "popup");

      // Инициализация оболочки всплывающего окна
      const popup = document.createElement("section");
      popup.classList.add("list", "extensive", "small");

      // Инициализация заголовка всплывающего окна
      const title = document.createElement("h3");
      title.classList.add("unselectable");
      title.innerText = "Создание администратора";

      // Инициализация оболочки с основной информацией
      const main = document.createElement("section");
      main.classList.add("main");

      // Инициализация колонки
      const account = document.createElement("div");
      account.classList.add("column");

      // Инициализация строки
      const account_name_first = document.createElement("div");
      account_name_first.classList.add("row", "merged");

      // Инициализация оболочки для строки
      const account_name_first_label = document.createElement("label");
      account_name_first_label.setAttribute("id", "account_first");

      // Инициализация заголовка для поля ввода
      const account_name_first_title = document.createElement("b");
      account_name_first_title.classList.add(
        "separated",
        "right",
        "unselectable",
      );
      account_name_first_title.innerText = "Имя:";

      // Инициализация поля ввода
      const account_name_first_input = document.createElement("input");
      account_name_first_input.classList.add("medium");
      account_name_first_input.setAttribute("type", "text");
      account_name_first_input.setAttribute("name", "first");
      account_name_first_input.setAttribute("autocomplete", "given-name");
      account_name_first_input.setAttribute("minlength", "0");
      account_name_first_input.setAttribute("maxlength", "100");
      account_name_first_input.setAttribute("title", "Имя аккаунта");
      account_name_first_input.setAttribute("placeholder", "Иван");

      // Инициализация строки
      const account_name_second = document.createElement("div");
      account_name_second.classList.add("row", "merged");

      // Инициализация оболочки для строки
      const account_name_second_label = document.createElement("label");
      account_name_second_label.setAttribute("id", "account_second");

      // Инициализация заголовка для поля ввода
      const account_name_second_title = document.createElement("b");
      account_name_second_title.classList.add(
        "separated",
        "right",
        "unselectable",
      );
      account_name_second_title.innerText = "Фамилия:";

      // Инициализация поля ввода
      const account_name_second_input = document.createElement("input");
      account_name_second_input.classList.add("medium");
      account_name_second_input.setAttribute("autocomplete", "family-name");
      account_name_second_input.setAttribute("name", "second");
      account_name_second_input.setAttribute("type", "text");
      account_name_second_input.setAttribute("minlength", "0");
      account_name_second_input.setAttribute("maxlength", "100");
      account_name_second_input.setAttribute("title", "Фамилия аккаунта");
      account_name_second_input.setAttribute("placeholder", "Иванов");

      // Инициализация строки
      const account_name_last = document.createElement("div");
      account_name_last.classList.add("row", "merged");

      // Инициализация оболочки для строки
      const account_name_last_label = document.createElement("label");
      account_name_last_label.setAttribute("id", "account_last");

      // Инициализация заголовка для поля ввода
      const account_name_last_title = document.createElement("b");
      account_name_last_title.classList.add(
        "separated",
        "right",
        "unselectable",
      );
      account_name_last_title.innerText = "Отчество:";

      // Инициализация поля ввода
      const account_name_last_input = document.createElement("input");
      account_name_last_input.classList.add("medium");
      account_name_last_input.setAttribute("name", "last");
      account_name_last_input.setAttribute("autocomplete", "additional-name");
      account_name_last_input.setAttribute("type", "text");
      account_name_last_input.setAttribute("minlength", "0");
      account_name_last_input.setAttribute("maxlength", "100");
      account_name_last_input.setAttribute(
        "title",
        "Отчество/Матчество аккаунта",
      );
      account_name_last_input.setAttribute("placeholder", "Иванович");

      // Инициализация строки
      const account_number = document.createElement("div");
      account_number.classList.add("row", "merged", "divided");

      // Инициализация оболочки для строки
      const account_number_label = document.createElement("label");
      account_number_label.setAttribute("id", "account_number");

      // Инициализация заголовка для поля ввода
      const account_number_title = document.createElement("b");
      account_number_title.classList.add("separated", "right", "unselectable");
      account_number_title.innerText = "SIM-номер:";

      // Инициализация поля ввода
      const account_number_input = document.createElement("input");
      account_number_input.classList.add("medium");
      account_number_input.setAttribute("name", "sim-number");
      account_number_input.setAttribute("autocomplete", "tel");
      account_number_input.setAttribute("type", "text");
      account_number_input.setAttribute("minlength", "18");
      account_number_input.setAttribute("maxlength", "18");
      account_number_input.setAttribute("title", "SIM-номер аккаунта");
      account_number_input.setAttribute("placeholder", "+7 (000) 000-00-00");

      // Инициализация строки
      const account_mail = document.createElement("div");
      account_mail.classList.add("row", "merged");

      // Инициализация оболочки для строки
      const account_mail_label = document.createElement("label");
      account_mail_label.setAttribute("id", "account_mail");

      // Инициализация заголовка для поля ввода
      const account_mail_title = document.createElement("b");
      account_mail_title.classList.add("separated", "right", "unselectable");
      account_mail_title.innerText = "Почта:";

      // Инициализация поля ввода
      const account_mail_input = document.createElement("input");
      account_mail_input.classList.add("medium");
      account_mail_input.setAttribute("name", "mail");
      account_mail_input.setAttribute("autocomplete", "email");
      account_mail_input.setAttribute("type", "text");
      account_mail_input.setAttribute("minlength", "3");
      account_mail_input.setAttribute("maxlength", "300");
      account_mail_input.setAttribute("title", "Почта аккаунта");
      account_mail_input.setAttribute("placeholder", "name@server");

      // Инициализация строки
      const account_password = document.createElement("div");
      account_password.classList.add("row", "merged");

      // Инициализация оболочки для строки
      const account_password_label = document.createElement("label");
      account_password_label.setAttribute("id", "account_password");

      // Инициализация заголовка для поля ввода
      const account_password_title = document.createElement("b");
      account_password_title.classList.add(
        "separated",
        "right",
        "unselectable",
      );
      account_password_title.innerText = "Пароль:";

      // Инициализация поля ввода
      const account_password_input = document.createElement("input");
      account_password_input.classList.add("medium");
      account_password_input.setAttribute("name", "password");
      account_password_input.setAttribute("required", "true");
      account_password_input.setAttribute("title", "Не менее 8 символов");
      account_password_input.setAttribute("autocomplete", "new-password");
      account_password_input.setAttribute("type", "password");
      account_password_input.setAttribute("minlength", "8");
      account_password_input.setAttribute("maxlength", "100");
      account_password_input.setAttribute("title", "Пароль аккаунта");
      account_password_input.setAttribute("placeholder", "*********");

      // Инициализация строки
      const account_commentary = document.createElement("div");
      account_commentary.classList.add("row", "endless");

      // Инициализация оболочки для строки
      const account_commentary_label = document.createElement("label");
      account_commentary_label.setAttribute("id", "account_commentary");

      // Инициализация поля ввода
      const account_commentary_textarea = document.createElement("textarea");
      account_commentary_textarea.classList.add("snow");
      account_commentary_textarea.setAttribute("maxlength", "800");
      account_commentary_textarea.setAttribute("title", "Комментарий аккаунта");
      account_commentary_textarea.setAttribute(
        "placeholder",
        "Дополнительная информация для администраторов",
      );

      // Инициализация строки
      const account_buttons = document.createElement("div");
      account_buttons.classList.add("row", "divided", "buttons");

      // Инициализация кнопки подтверждения
      const account_create_button = document.createElement("button");
      account_create_button.classList.add("grass", "stretched");
      account_create_button.innerText = "Создать";
      account_create_button.setAttribute(
        "onclick",
        `administrators._create(this, ...this.parentElement.parentElement.parentElement.querySelectorAll(':is(input, textarea)'))`,
      );

      // Инициализация окна с ошибками
      this.body.errors = document.createElement("section");
      this.body.errors.classList.add(
        "errors",
        "window",
        "list",
        "small",
        "hidden",
      );
      this.body.errors.setAttribute("data-errors", true);

      // Инициализация элемента-оболочки с ошибками для всплывающего окна
      const errors = document.createElement("section");
      errors.classList.add("body");

      // Инициализация элемента-списка ошибок
      const dl = document.createElement("dl");

      // Инициализация активного всплывающего окна
      const old = document.getElementById("popup");

      if (old instanceof HTMLElement) {
        // Найдено активное окно

        // Деинициализация быстрых действий по кнопкам
        document.removeEventListener("keydown", this.buttons);

        // Сброс блокировки
        this.freeze = false;

        // Удаление активного окна
        old.remove();
      }

      // Запись в документ
      popup.appendChild(title);

      account_name_first_label.appendChild(account_name_first_title);
      account_name_first_label.appendChild(account_name_first_input);
      account_name_first.appendChild(account_name_first_label);
      account.appendChild(account_name_first);

      account_name_second_label.appendChild(account_name_second_title);
      account_name_second_label.appendChild(account_name_second_input);
      account_name_second.appendChild(account_name_second_label);
      account.appendChild(account_name_second);

      account_name_last_label.appendChild(account_name_last_title);
      account_name_last_label.appendChild(account_name_last_input);
      account_name_last.appendChild(account_name_last_label);
      account.appendChild(account_name_last);

      account_number_label.appendChild(account_number_title);
      account_number_label.appendChild(account_number_input);
      account_number.appendChild(account_number_label);
      account.appendChild(account_number);

      account_mail_label.appendChild(account_mail_title);
      account_mail_label.appendChild(account_mail_input);
      account_mail.appendChild(account_mail_label);
      account.appendChild(account_mail);

      account_password_label.appendChild(account_password_title);
      account_password_label.appendChild(account_password_input);
      account_password.appendChild(account_password_label);
      account.appendChild(account_password);

      account_commentary_label.appendChild(account_commentary_textarea);
      account_commentary.appendChild(account_commentary_label);
      account.appendChild(account_commentary);

      account_buttons.appendChild(account_create_button);
      account.appendChild(account_buttons);

      main.appendChild(account);
      popup.appendChild(main);
      this.body.wrap.appendChild(popup);

      errors.appendChild(dl);
      this.body.errors.appendChild(errors);
      this.body.wrap.appendChild(this.body.errors);

      document.body.appendChild(this.body.wrap);

      // Инициалиация масок
      account_number_input.mask = IMask(account_number_input, {
        mask: "+{7} (000) 000-00-00",
      });

      // Инициализация переменных для окна с ошибками (12 - это значение gap из div#popup)
      function top(errors) {
        errors.style.setProperty(
          "transition",
          "0s",
        );
        errors.style.setProperty(
          "--top",
          popup.offsetTop + popup.offsetHeight + 12 + "px",
        );
        setTimeout(
          () => errors.style.removeProperty("transition"),
          100,
        );
      }
      top(this.body.errors);
      const resize = new ResizeObserver(() => top(this.body.errors));
      resize.observe(this.body.wrap);

      // Инициализация функции блокировки кнопки
      const block = () => {
        if (
          account_password_input.value.length > 6
        ) account_create_button.removeAttribute("disabled");
        else account_create_button.setAttribute("disabled", "true");
      };

      // Добавление функции блокировки кнопки по событиям
      account_password_input.addEventListener("keyup", block);

      // Первичная активация функции блокировки кнопки
      block();

      // Инициализация функции генерации пароля и записи в поле ввода и буфер обмена
      const generate = (e) => {
        // Блокировка выполнения при нажатии на поле для ввода
        if (e.target.tagName === "INPUT") return;

        // Инициализация поля ввода пароля
        const input = e.currentTarget.getElementsByTagName("input")[0];

        if (input instanceof HTMLElement) {
          // Найдено поле для ввода пароля

          // Инициализация буфера генерации пароля
          let password = "";

          // Инициализация используемых символов для генерируемого пароля
          const symbols =
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789------";

          // Генерация пароля
          for (let i = 0; i < Math.random() * 14 + 8; i++) {
            password += symbols.charAt(
              Math.floor(Math.random() * symbols.length),
            );
          }

          // Запись пароля в поле для ввода пароля
          input.value = password;

          // Вызов функции инициализации генератора пароля
          input.dispatchEvent(new KeyboardEvent("keyup"));

          // Запиcь пароля в буфер обмена
          navigator.clipboard.writeText(password);

          // Фокусировка на поле для ввода пароля
          input.focus();
        }
      };

      // Инициализация функции инициализации генератора пароля
      const generator = (e) => {
        // Инициализация строки с полем для ввода пароля
        const row = e.currentTarget.parentElement.parentElement;

        if (row instanceof HTMLElement) {
          // Найдено поле для ввода пароля

          if (e.target.value.length === 0) {
            // Не введён пароль

            row.setAttribute("title", "Сгенерировать пароль");
            row.setAttribute("data-interactive", "true");
            row.addEventListener("click", generate);
          } else {
            // Введён пароль

            row.removeAttribute("title");
            row.removeAttribute("data-interactive");
            row.removeEventListener("click", generate);
          }
        }
      };

      // Инициализация вызова функции инициализации генератора пароля по события нажатия клавиши
      account_password_input.addEventListener("keyup", generator);

      // Вызов функции инициализации генератора пароля (первичный)
      account_password_input.dispatchEvent(new KeyboardEvent("keyup"));

      // Инициализация функции закрытия всплывающего окна
      const click = () => {
        // Блокировка
        if (this.freeze) return;

        // Удаление всплывающего окна
        this.body.wrap.remove();

        // Удаление статуса активной строки
        row.removeAttribute("data-selected");

        // Деинициализация быстрых действий по кнопкам
        document.removeEventListener("keydown", this.buttons);

        // Сброс блокировки
        this.freeze = false;
      };

      // Инициализация функции добавления функции закрытия всплывающего окна
      const enable = () => this.body.wrap.addEventListener("click", click);

      // Инициализация функции удаления функции закрытия всплывающего окна
      const disable = () => this.body.wrap.removeEventListener("click", click);

      // Первичная активация функции удаления всплывающего окна
      enable();

      // Инициализация блокировки удаления окна при взаимодействии с select-элементом
      for (const select of popup.getElementsByTagName("select")) {
        // Перебор всех select-элементов

        // Инициализация функции блокировки удаления окна по событию
        select.addEventListener("click", () => {
          // Блокировка удаления окна
          this.freeze = true;

          // Разблокировка удаления окна
          setTimeout(() => this.freeze = false, 100);
        });

        for (const option of select.getElementsByTagName("option")) {
          // Перебор всех option-элементов

          // Инициализация функции блокировки удаления окна по событию
          option.addEventListener("click", () => {
            // Блокировка удаления окна
            this.freeze = true;

            // Разблокировка удаления окна
            setTimeout(() => this.freeze = false, 100);
          });
        }
      }

      // Инициализация блокировки удаления окна при взаимодействии с textarea-элементом
      for (const textarea of popup.getElementsByTagName("textarea")) {
        // Перебор всех textarea-элементов

        // Обновлять позицию окна с ошибками при изменении размера textarea (там position: absolute)
        new MutationObserver(() => top(this.body.errors)).observe(textarea, {
          attributes: true,
          attributeFilter: ["style"],
        });

        // Инициализация функции игнорирования блокировки для выбранных кнопок
        textarea.addEventListener("keydown", (e) => {
          if (e.keyCode === 27) {
            // Нажата кнопка: "escape"

            // Вызов глобальной функции управления кнопками
            this.buttons(e, true);
          } else if (e.ctrlKey && e.keyCode === 13) {
            // Нажаты кнопки: "control", "enter"

            // Вызов глобальной функции управления кнопками
            this.buttons(e, true);
          }
        });

        // Добавление функции блокировки удаления окна и клавиш по событиям
        textarea.addEventListener("focus", () => this.freeze = true);
        textarea.addEventListener("focusout", () => this.freeze = false);
      }

      // Инициализация функции управления кнопками
      this.buttons = (e, force = false) => {
        // Блокировка
        if (!force && this.freeze) return;

        if (e.keyCode === 27) {
          // Нажата кнопка: "escape"

          // Удаление окна
          click();
        } else if (event.keyCode === 13) {
          // Нажата кнопка: "enter"

          // Инициализация буфера с текущим статусом блокировки закрытия окна
          const freeze = this.freeze;

          // Блокировка закрытия окна (чтобы не вызвался click() через событие onclick)
          this.freeze = true;

          // Активация виртуальной кнопки "создать"
          account_create_button.click();

          // Возвращение статуса блокировки закрытия окна
          this.freeze = freeze;
        }
      };

      // Инициализация быстрых действий по кнопкам
      document.addEventListener("keydown", this.buttons);

      // Добавление функции удаления всплывающего окна по событиям
      popup.addEventListener("mouseenter", disable);
      popup.addEventListener("mouseleave", enable);

      // Фокусировка
      account_name_first_input.focus();
    }, 300);

    /**
     * Удалить аккаунт (вызов демпфера)
     *
     * @param {HTMLElement} row Строка <div>
     * @param {HTMLElement} button Кнопка <button>
     * @param {HTMLElement} account_name_first Имя аккаунта <input>
     * @param {HTMLElement} account_name_second Фамилия аккаунта <input>
     * @param {HTMLElement} account_name_last Отчество аккаунта <input>
     * @param {HTMLElement} account_number SIM-номер аккаунта <input>
     * @param {HTMLElement} account_mail Почта аккаунта<input>
     * @param {HTMLElement} account_password Пароль аккаунта <input>
     * @param {HTMLElement} account_commentary Комментарий аккаунта <textarea>
     *
     * @return {void}
     */
    static _delete(
      row,
      button,
      account_name_first,
      account_name_second,
      account_name_last,
      account_number,
      account_mail,
      account_password,
      account_commentary,
    ) {
      // Блокировка полей ввода
      account_name_first.setAttribute("readonly", true);
      account_name_second.setAttribute("readonly", true);
      account_name_last.setAttribute("readonly", true);
      account_number.setAttribute("readonly", true);
      account_mail.setAttribute("readonly", true);
      account_password.setAttribute("readonly", true);
      account_commentary.setAttribute("readonly", true);

      // Блокировка кнопки
      button.setAttribute("disabled", true);

      // Запуск выполнения
      this.__delete(
        row,
        button,
        account_name_first,
        account_name_second,
        account_name_last,
        account_number,
        account_mail,
        account_password,
        account_commentary,
      );
    }

    /**
     * Удалить аккаунт (демпфер)
     *
     * @param {HTMLElement} row Строка <div>
     * @param {HTMLElement} button Кнопка <button>
     * @param {HTMLElement} account_name_first Имя аккаунта <input>
     * @param {HTMLElement} account_name_second Фамилия аккаунта <input>
     * @param {HTMLElement} account_name_last Отчество аккаунта <input>
     * @param {HTMLElement} account_number SIM-номер аккаунта <input>
     * @param {HTMLElement} account_mail Почта аккаунта<input>
     * @param {HTMLElement} account_password Пароль аккаунта <input>
     * @param {HTMLElement} account_commentary Комментарий аккаунта <textarea>
     *
     * @return {void}
     */
    static __delete = damper(
      async (
        row,
        button,
        account_name_first,
        account_name_second,
        account_name_last,
        account_number,
        account_mail,
        account_password,
        account_commentary,
      ) => {
        // Инициализация функции разблокировки
        function unblock() {
          // Разблокировка полей ввода
          account_name_first.removeAttribute("readonly");
          account_name_second.removeAttribute("readonly");
          account_name_last.removeAttribute("readonly");
          account_number.removeAttribute("readonly");
          account_mail.removeAttribute("readonly");
          account_password.removeAttribute("readonly");
          account_commentary.removeAttribute("readonly");

          // Разблокировка кнопки
          button.removeAttribute("disabled");
        }

        // Инициализация идентификатора
        const id = row.getAttribute("id");

        // Запуск отсрочки разблокировки на случай, если сервер не отвечает
        const timeout = setTimeout(() => {
          this.errors(["Сервер не отвечает"]);
          unblock();
        }, 5000);

        // Запрос к серверу
        return await fetch(`/${id}/delete`, {
          method: "POST",
          headers: {
            "Content-Type": "application/x-www-form-urlencoded",
          },
        })
          .then((response) => response.json())
          .then((data) => {
            // Удаление отсрочки разблокировки
            clearTimeout(timeout);

            if (this.errors(data.errors)) {
              // Сгенерированы ошибки

              // Разблокировка полей ввода и кнопок
              unblock();
            } else {
              // Не сгенерированы ошибки (подразумевается их отсутствие)

              if (data.deleted === true) {
                // Удалены данные

                // Удаление строки
                row.remove();
              }

              if (this.body.wrap instanceof HTMLElement) {
                // Найдено активное окно

                // Деинициализация быстрых действий по кнопкам
                document.removeEventListener("keydown", this.buttons);

                // Сброс блокировки
                this.freeze = false;

                // Деинициализация активного окна
                this.body.wrap.remove();

                // Удаление статуса активной строки
                row.removeAttribute("data-selected");
              }
            }
          });
      },
      300,
    );

    /**
     * Переключить фильтр
     *
     * @param {string} name Название
     * @param {string|number|null} value Значение
     * @param {HTMLElement|null} button Кнопка
     *
     * @return {void}
     */
    static filter = damper(async (name, value, button) => {
      if (typeof name === "string") {
        // Получено название

        // Инициализация сериализованного пути к директории
        const path = `administrators_filter_${name}`;

        if (typeof value === "string" || typeof value === "number") {
          // Получено значение

          // Запись нового значения
          buffer.write(path, value);
        } else {
          // Не получено значение

          // Чтение текущего значения
          value = +(await buffer.read(path));

          // Инициализация значения по умолчанию
          if (isNaN(value)) value = 0;

          // Запись нового значения (инвертирование)
          buffer.write(path, ++value < 3 ? value : 0);

          if (button instanceof HTMLElement) {
            // Получена кнопка

            // Деинициализация классов статуса фильтра
            button.classList.remove("earth", "sand", "river");

            // Инициализация классов статуса фильтра
            if (value === 1) button.classList.add("sand");
            else if (value === 2) button.classList.add("river");
            else button.classList.add("earth");
          }
        }
      }
    }, 300);

    /**
     * Записать фильтр поиска
     *
     * @param {HTMLElement} input Строка поиска
     * @param {HTMLElement} button Кнопка отправки
     *
     * @return {void}
     */
    static search = (input, button) => {
      input.setAttribute("readonly", true);
      button.setAttribute("disabled", true);

      this._search(input, button);
    };

    /**
     * Записать фильтр поиска (системное)
     *
     * Используется как оболочка для большей временной задержки
     *
     * @param {HTMLElement} input Строка поиска
     * @param {HTMLElement} button Кнопка отправки
     *
     * @return {void}
     */
    static _search = damper((input, button) => {
      this.filter("search", input.value);
      this.reinit(() => {
        input.removeAttribute("readonly");
        button.removeAttribute("disabled");
      });
    }, 1000);

    /**
     * Инициализация страниц
     *
     * @param {number} amount Количество страниц для генерации
     * @param {number} iteration Номер итерации (системное)
     *
     * @return {void}
     */
    static async init(amount = 3, iteration = 0) {
      if (
        typeof amount === "number" && typeof iteration === "number" &&
        this.initialized === false
      ) {
        // Получены количество страниц и номер итерации

        // Инициализация страницы (написал administrators потому, что оптимизатор выдаёт ошибку, что this.read не найдено, хотя всё работает)
        await administrators.read(++iteration);

        // Проверка условий и отложенный запуск следующей итерации
        if (iteration < amount) setTimeout(this.init, 1500, amount, iteration);
        else this.initialized = true;
      }
    }

    /**
     * Реинициализация страниц
     *
     * @param {function} postprocessing Функция которая будет исполнена после реинициализации
     * @param {number} amount Количество страниц для генерации при инициализации
     *
     * @return {void}
     */
    static reinit = damper((postprocessing, amount = 3) => {
      if (typeof amount === "number") {
        // Получены количество страниц

        // Деинициализация cookie с номером страницы
        Cookies.remove("administrators_page", { path: "/" });

        // Инициализация оболочки
        const administrators = document.getElementById("administrators");

        if (administrators instanceof HTMLElement) {
          // Найдена оболочка

          // Инициализация буфера активного элемента
          const active = document.activeElement;

          // Инициализация буфера элементов
          const buffer = document.createElement("div");

          // Перенос элементов в буфер
          buffer.replaceChildren(...administrators.children);

          // Удаление комментариев с индексами страниц
          administrators.innerHTML = administrators.innerHTML.replace(
            /<!--(?!>)[\S\s]*?-->/g,
            "",
          );

          // Перенос элементов из буфера
          administrators.replaceChildren(...buffer.children);

          // Деинициализация страниц
          for (
            const element of administrators.querySelectorAll(
              ':scope > div[data-row="administrator"]',
            )
          ) element.remove();

          // Сброс статуса инициализированности
          this.initialized = false;

          // Инициализация страниц
          this.init(amount);

          // Возвращение фокуса на активный элемент
          active.focus();

          // Постобработка
          if (typeof postprocessing === "function") postprocessing();
        }
      }
    }, 2000);

    /**
     * Прочитать
     *
     * Читает список и модифицирует документ (записывает в общий список)
     *
     * @param {number} page Страница
     *
     * @return {object} {(bool) exist, (array) errors}
     */
    static read = damper(async (page) => {
      if (typeof core === "function" && typeof page !== "number") {
        // Не получена страница

        // Инициализация страницы (если не получена, то брать из cookie и прибавлять 1)
        page = Cookies.get(`administrators_page`) ?? 0;

        // Запись идентификатора следующей страницы
        ++page;
      }

      // Запрос к серверу
      return await fetch("/administrators/read", {
        method: "POST",
        headers: {
          "Content-Type": "application/x-www-form-urlencoded",
        },
        body: `page=${page}`,
      })
        .then((response) => response.text())
        .then((data) => {
          // Инициализация буфера для записи в документ
          const element = document.createElement("div");

          // Запись пустого элемента из буфера в документ
          document.getElementById("administrators").appendChild(element);

          // Запись в документ HTML-данных через буфер
          element.outerHTML = data;

          // Возврат (успех)
          return data;
        });
    }, 50);

    /**
     * Сгенерировать список (какой список?)
     *
     * @return {array|null} Массив HTML-элементов <option>
     */
    static async list() {
      // Запрос к серверу
      return await fetch(`/administrators/list`, {
        method: "POST",
        headers: {
          "Content-Type": "application/x-www-form-urlencoded",
        },
      })
        .then((response) => response.text())
        .then((data) => {
          if (data.length > 0) {
            // Получены данные

            return data;
          }

          return null;
        });
    }

    /**
     * Сгенерировать HTML-элемент со списком ошибок
     *
     * @param {object} registry Реестр ошибок
     * @param {bool} render Отобразить в окне с ошибками?
     * @param {bool} clean Очистить окно с ошибками перед добавлением?
     *
     * @return {bool} Сгенерированы ошибки?
     */
    static errors(registry, render = true, clean = true) {
      // Инициализация ссылки на HTML-элемент с ошибками
      const wrap = document.body.contains(this.body.errors)
        ? this.body.errors
        : document.querySelector('[data-errors="true"]');

      if (wrap instanceof HTMLElement && document.body.contains(wrap)) {
        // Найден HTML-элемент с ошибками

        // Перерасчёт высоты элемента
        function height() {
          wrap.classList.remove("hidden");
          wrap.classList.remove("animation");
          // Реинициализация переменной с данными о высоте HTML-элемента (16 - это padding-top + padding-bottom у div#popup > section.errors)
          wrap.style.setProperty(
            "--height",
            wrap.offsetHeight - 16 + "px",
          );
          wrap.classList.add("animation");
          wrap.classList.add("hidden");
        }

        // Инициализация элемента-списка ошибок
        const list = wrap.getElementsByTagName("dl")[0];

        // Удаление ошибок из прошлой генерации
        if (clean) list.innerHTML = null;

        for (const error in registry) {
          // Генерация HTML-элементов с текстами ошибок

          // Инициализация HTML-элемента текста ошибки
          const samp = document.createElement("samp");

          if (typeof registry[error] === "object") {
            // Категория ошибок

            // Проверка наличия ошибок
            if (registry[error].length === 0) continue;

            // Инициализация HTML-элемента-оболочки
            const wrap = document.createElement("dt");

            // Запись текста категории
            samp.innerText = error;

            // Запись HTML-элементов в список
            wrap.appendChild(samp);
            list.appendChild(wrap);

            // Реинициализация высоты
            height();

            // Обработка вложенных ошибок (вход в рекурсию)
            this.errors(registry[error], false);
          } else {
            // Текст ошибки (подразумевается)

            // Инициализация HTML-элемента
            const wrap = document.createElement("dd");

            // Запись текста ошибки
            samp.innerText = registry[error];

            // Запись HTML-элемента в список
            wrap.appendChild(samp);
            list.appendChild(wrap);

            // Реинициализация высоты
            height();
          }
        }

        if (render) {
          // Запрошена отрисовка

          if (
            list.childElementCount !== 0
          ) {
            // Найдены ошибки

            // Сброс анимации
            // УЛОВКА: таким образом не запускается анимация до взаимодействия с элементом (исправлял это в CSS, но не помню как)
            wrap.classList.add("animation");

            // Отображение
            wrap.classList.remove("hidden");
          } else {
            // Не найдены ошибки

            // Скрытие
            wrap.classList.add("hidden");
          }
        }

        return list.childElementCount === 0 ? false : true;
      }

      return false;
    }
  };
}

// Вызов события: "инициализировано"
document.dispatchEvent(
  new CustomEvent("administrators.initialized", {
    detail: { administrators: window.administrators },
  }),
);
