680 lines
24 KiB
JavaScript
680 lines
24 KiB
JavaScript
|
"use strict";
|
|||
|
|
|||
|
/**
|
|||
|
* Бегущая строка
|
|||
|
*
|
|||
|
* @description
|
|||
|
* Простой, но мощный класс для создания бегущих строк. Поддерживает
|
|||
|
* перемещение мышью и прокрутку колесом, полностью настраивается очень гибок
|
|||
|
* для настроек в CSS и подразумевается, что отлично индексируется поисковыми роботами.
|
|||
|
* Имеет свой препроцессор, благодаря которому можно создавать бегущие строки
|
|||
|
* без программирования - с помощью HTML-аттрибутов, а так же возможность
|
|||
|
* изменять параметры (data-hotline-* аттрибуты) на лету. Есть возможность вызывать
|
|||
|
* события при выбранных действиях для того, чтобы пользователь имел возможность
|
|||
|
* дорабатывать функционал без изучения и изменения моего кода
|
|||
|
*
|
|||
|
* @example
|
|||
|
* сonst hotline = new hotline();
|
|||
|
* hotline.step = '-5';
|
|||
|
* hotline.start();
|
|||
|
*
|
|||
|
* @todo
|
|||
|
* 1. Бесконечный режим - элементы не удаляются если видны на экране (будут дубликаты)
|
|||
|
*
|
|||
|
* @copyright WTFPL
|
|||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|||
|
*/
|
|||
|
class hotline {
|
|||
|
// Идентификатор
|
|||
|
#id = 0;
|
|||
|
|
|||
|
// Оболочка (instanceof HTMLElement)
|
|||
|
#shell = document.getElementById("hotline");
|
|||
|
|
|||
|
// Инстанция горячей строки
|
|||
|
#instance = null;
|
|||
|
|
|||
|
// Перемещение
|
|||
|
#transfer = true;
|
|||
|
|
|||
|
// Движение
|
|||
|
#move = true;
|
|||
|
|
|||
|
// Наблюдатель
|
|||
|
#observer = null;
|
|||
|
|
|||
|
// Наблюдатель
|
|||
|
#block = new Set(["events"]);
|
|||
|
|
|||
|
// Настраиваемые параметры
|
|||
|
transfer = null;
|
|||
|
move = null;
|
|||
|
delay = 10;
|
|||
|
step = 1;
|
|||
|
hover = true;
|
|||
|
movable = true;
|
|||
|
sticky = false;
|
|||
|
wheel = false;
|
|||
|
delta = null;
|
|||
|
vertical = false;
|
|||
|
observe = false;
|
|||
|
events = new Map([
|
|||
|
["start", false],
|
|||
|
["stop", false],
|
|||
|
["move", false],
|
|||
|
["move.block", false],
|
|||
|
["move.unblock", false],
|
|||
|
["offset", false],
|
|||
|
["transfer.start", true],
|
|||
|
["transfer.end", true],
|
|||
|
["onmousemove", false]
|
|||
|
]);
|
|||
|
|
|||
|
constructor(id, shell) {
|
|||
|
// Запись идентификатора
|
|||
|
if (typeof id === "string" || typeof id === "number") this.#id = id;
|
|||
|
|
|||
|
// Запись оболочки
|
|||
|
if (shell instanceof HTMLElement) this.#shell = shell;
|
|||
|
}
|
|||
|
|
|||
|
start() {
|
|||
|
if (this.#instance === null) {
|
|||
|
// Нет запущенной инстанции бегущей строки
|
|||
|
|
|||
|
// Инициализация ссылки на ядро
|
|||
|
const _this = this;
|
|||
|
|
|||
|
// Запуск движения
|
|||
|
this.#instance = setInterval(function () {
|
|||
|
if (_this.#shell.childElementCount > 1) {
|
|||
|
// Найдено содержимое бегущей строки (2 и более)
|
|||
|
|
|||
|
// Инициализация буфера для временных данных
|
|||
|
let buffer;
|
|||
|
|
|||
|
// Инициализация данных первого элемента в строке
|
|||
|
const first = {
|
|||
|
element: (buffer = _this.#shell.firstElementChild),
|
|||
|
coords: buffer.getBoundingClientRect()
|
|||
|
};
|
|||
|
|
|||
|
if (_this.vertical) {
|
|||
|
// Вертикальная бегущая строка
|
|||
|
|
|||
|
// Инициализация сдвига у первого элемента (движение)
|
|||
|
first.offset = isNaN(
|
|||
|
(buffer = parseFloat(first.element.style.marginTop))
|
|||
|
)
|
|||
|
? 0
|
|||
|
: buffer;
|
|||
|
|
|||
|
// Инициализация отступа до второго элемента у первого элемента (разделение)
|
|||
|
first.separator = isNaN(
|
|||
|
(buffer = parseFloat(
|
|||
|
getComputedStyle(first.element).marginBottom
|
|||
|
))
|
|||
|
)
|
|||
|
? 0
|
|||
|
: buffer;
|
|||
|
|
|||
|
// Инициализация крайнего с конца ребра первого элемента в строке
|
|||
|
first.end = first.coords.y + first.coords.height + first.separator;
|
|||
|
} else {
|
|||
|
// Горизонтальная бегущая строка
|
|||
|
|
|||
|
// Инициализация отступа у первого элемента (движение)
|
|||
|
first.offset = isNaN(
|
|||
|
(buffer = parseFloat(first.element.style.marginLeft))
|
|||
|
)
|
|||
|
? 0
|
|||
|
: buffer;
|
|||
|
|
|||
|
// Инициализация отступа до второго элемента у первого элемента (разделение)
|
|||
|
first.separator = isNaN(
|
|||
|
(buffer = parseFloat(getComputedStyle(first.element).marginRight))
|
|||
|
)
|
|||
|
? 0
|
|||
|
: buffer;
|
|||
|
|
|||
|
// Инициализация крайнего с конца ребра первого элемента в строке
|
|||
|
first.end = first.coords.x + first.coords.width + first.separator;
|
|||
|
}
|
|||
|
|
|||
|
if (
|
|||
|
(_this.vertical &&
|
|||
|
Math.round(first.end) < _this.#shell.offsetTop) ||
|
|||
|
(!_this.vertical && Math.round(first.end) < _this.#shell.offsetLeft)
|
|||
|
) {
|
|||
|
// Элемент (вместе с отступом до второго элемента) вышел из области видимости (строки)
|
|||
|
|
|||
|
if (
|
|||
|
(_this.transfer === null && _this.#transfer) ||
|
|||
|
_this.transfer === true
|
|||
|
) {
|
|||
|
// Перенос разрешен
|
|||
|
|
|||
|
if (_this.vertical) {
|
|||
|
// Вертикальная бегущая строка
|
|||
|
|
|||
|
// Удаление отступов (движения)
|
|||
|
first.element.style.marginTop = null;
|
|||
|
} else {
|
|||
|
// Горизонтальная бегущая строка
|
|||
|
|
|||
|
// Удаление отступов (движения)
|
|||
|
first.element.style.marginLeft = null;
|
|||
|
}
|
|||
|
|
|||
|
// Копирование первого элемента в конец строки
|
|||
|
_this.#shell.appendChild(first.element);
|
|||
|
|
|||
|
if (_this.events.get("transfer.end")) {
|
|||
|
// Запрошен вызов события: "перемещение в конец"
|
|||
|
|
|||
|
// Вызов события: "перемещение в конец"
|
|||
|
document.dispatchEvent(
|
|||
|
new CustomEvent(`hotline.${_this.#id}.transfer.end`, {
|
|||
|
detail: {
|
|||
|
element: first.element,
|
|||
|
offset: -(
|
|||
|
(_this.vertical
|
|||
|
? first.coords.height
|
|||
|
: first.coords.width) + first.separator
|
|||
|
)
|
|||
|
}
|
|||
|
})
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
} else if (
|
|||
|
(_this.vertical &&
|
|||
|
Math.round(first.coords.y) > _this.#shell.offsetTop) ||
|
|||
|
(!_this.vertical &&
|
|||
|
Math.round(first.coords.x) > _this.#shell.offsetLeft)
|
|||
|
) {
|
|||
|
// Передняя (движущая) граница первого элемента вышла из области видимости
|
|||
|
|
|||
|
if (
|
|||
|
(_this.transfer === null && _this.#transfer) ||
|
|||
|
_this.transfer === true
|
|||
|
) {
|
|||
|
// Перенос разрешен
|
|||
|
|
|||
|
// Инициализация отступа у последнего элемента (разделение)
|
|||
|
const separator =
|
|||
|
(buffer = isNaN(
|
|||
|
(buffer = parseFloat(
|
|||
|
getComputedStyle(_this.#shell.lastElementChild)[
|
|||
|
_this.vertical ? "marginBottom" : "marginRight"
|
|||
|
]
|
|||
|
))
|
|||
|
)
|
|||
|
? 0
|
|||
|
: buffer) === 0
|
|||
|
? first.separator
|
|||
|
: buffer;
|
|||
|
|
|||
|
// Инициализация координат первого элемента в строке
|
|||
|
const coords = _this.#shell.lastElementChild.getBoundingClientRect();
|
|||
|
|
|||
|
if (_this.vertical) {
|
|||
|
// Вертикальная бегущая строка
|
|||
|
|
|||
|
// Удаление отступов (движения)
|
|||
|
_this.#shell.lastElementChild.style.marginTop =
|
|||
|
-coords.height - separator + "px";
|
|||
|
} else {
|
|||
|
// Горизонтальная бегущая строка
|
|||
|
|
|||
|
// Удаление отступов (движения)
|
|||
|
_this.#shell.lastElementChild.style.marginLeft =
|
|||
|
-coords.width - separator + "px";
|
|||
|
}
|
|||
|
|
|||
|
// Копирование последнего элемента в начало строки
|
|||
|
_this.#shell.insertBefore(
|
|||
|
_this.#shell.lastElementChild,
|
|||
|
first.element
|
|||
|
);
|
|||
|
|
|||
|
// Удаление отступов у второго элемента в строке (движения)
|
|||
|
_this.#shell.children[1].style[
|
|||
|
_this.vertical ? "marginTop" : "marginLeft"
|
|||
|
] = null;
|
|||
|
|
|||
|
if (_this.events.get("transfer.start")) {
|
|||
|
// Запрошен вызов события: "перемещение в начало"
|
|||
|
|
|||
|
// Вызов события: "перемещение в начало"
|
|||
|
document.dispatchEvent(
|
|||
|
new CustomEvent(`hotline.${_this.#id}.transfer.start`, {
|
|||
|
detail: {
|
|||
|
element: _this.#shell.lastElementChild,
|
|||
|
offset:
|
|||
|
(_this.vertical ? coords.height : coords.width) +
|
|||
|
separator
|
|||
|
}
|
|||
|
})
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
// Элемент в области видимости
|
|||
|
|
|||
|
if ((_this.move === null && _this.#move) || _this.move === true) {
|
|||
|
// Движение разрешено
|
|||
|
|
|||
|
// Запись новых координат сдвига
|
|||
|
const offset = first.offset + _this.step;
|
|||
|
|
|||
|
// Запись сдвига (движение)
|
|||
|
_this.offset(offset);
|
|||
|
|
|||
|
if (_this.events.get("move")) {
|
|||
|
// Запрошен вызов события: "движение"
|
|||
|
|
|||
|
// Вызов события: "движение"
|
|||
|
document.dispatchEvent(
|
|||
|
new CustomEvent(`hotline.${_this.#id}.move`, {
|
|||
|
detail: {
|
|||
|
from: first.offset,
|
|||
|
to: offset
|
|||
|
}
|
|||
|
})
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}, _this.delay);
|
|||
|
|
|||
|
if (this.hover) {
|
|||
|
// Запрошена возможность останавливать бегущую строку
|
|||
|
|
|||
|
// Инициализация сдвига
|
|||
|
let offset = 0;
|
|||
|
|
|||
|
// Инициализация слушателя события при перемещении элемента в бегущей строке
|
|||
|
const listener = function (e) {
|
|||
|
// Увеличение сдвига
|
|||
|
offset += e.detail.offset ?? 0;
|
|||
|
};
|
|||
|
|
|||
|
// Инициализация обработчика наведения курсора (остановка движения)
|
|||
|
this.#shell.onmouseover = function (e) {
|
|||
|
// Курсор наведён на бегущую строку
|
|||
|
|
|||
|
// Блокировка движения
|
|||
|
_this.#move = false;
|
|||
|
|
|||
|
if (_this.events.get("move.block")) {
|
|||
|
// Запрошен вызов события: "блокировка движения"
|
|||
|
|
|||
|
// Вызов события: "блокировка движения"
|
|||
|
document.dispatchEvent(
|
|||
|
new CustomEvent(`hotline.${_this.#id}.move.block`)
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
if (_this.movable) {
|
|||
|
// Запрошена возможность двигать бегущую строку
|
|||
|
|
|||
|
_this.#shell.onmousedown = function (onmousedown) {
|
|||
|
// Курсор активирован
|
|||
|
|
|||
|
// Инициализация слушателей события перемещения элемента в бегущей строке
|
|||
|
document.addEventListener(
|
|||
|
`hotline.${_this.#id}.transfer.start`,
|
|||
|
listener
|
|||
|
);
|
|||
|
document.addEventListener(
|
|||
|
`hotline.${_this.#id}.transfer.end`,
|
|||
|
listener
|
|||
|
);
|
|||
|
|
|||
|
// Инициализация буфера для временных данных
|
|||
|
let buffer;
|
|||
|
|
|||
|
// Инициализация данных первого элемента в строке
|
|||
|
const first = {
|
|||
|
offset: isNaN(
|
|||
|
(buffer = parseFloat(
|
|||
|
_this.vertical
|
|||
|
? _this.#shell.firstElementChild.style.marginTop
|
|||
|
: _this.#shell.firstElementChild.style.marginLeft
|
|||
|
))
|
|||
|
)
|
|||
|
? 0
|
|||
|
: buffer
|
|||
|
};
|
|||
|
|
|||
|
document.onmousemove = function (onmousemove) {
|
|||
|
// Курсор движется
|
|||
|
|
|||
|
if (_this.vertical) {
|
|||
|
// Вертикальная бегущая строка
|
|||
|
|
|||
|
// Инициализация буфера местоположения
|
|||
|
const from = _this.#shell.firstElementChild.style.marginTop;
|
|||
|
const to =
|
|||
|
onmousemove.pageY -
|
|||
|
(onmousedown.pageY + offset - first.offset);
|
|||
|
|
|||
|
// Движение
|
|||
|
_this.#shell.firstElementChild.style.marginTop = to + "px";
|
|||
|
|
|||
|
if (_this.events.get("onmousemove")) {
|
|||
|
// Запрошен вызов события: "перемещение мышью"
|
|||
|
|
|||
|
// Вызов события: "перемещение мышью"
|
|||
|
document.dispatchEvent(
|
|||
|
new CustomEvent(`hotline.${_this.#id}.onmousemove`, {
|
|||
|
detail: { from, to }
|
|||
|
})
|
|||
|
);
|
|||
|
}
|
|||
|
} else {
|
|||
|
// Горизонтальная бегущая строка
|
|||
|
|
|||
|
// Инициализация буфера местоположения
|
|||
|
const from = _this.#shell.firstElementChild.style.marginLeft;
|
|||
|
const to =
|
|||
|
onmousemove.pageX -
|
|||
|
(onmousedown.pageX + offset - first.offset);
|
|||
|
|
|||
|
// Движение
|
|||
|
_this.#shell.firstElementChild.style.marginLeft = to + "px";
|
|||
|
|
|||
|
if (_this.events.get("onmousemove")) {
|
|||
|
// Запрошен вызов события: "перемещение мышью"
|
|||
|
|
|||
|
// Вызов события: "перемещение мышью"
|
|||
|
document.dispatchEvent(
|
|||
|
new CustomEvent(`hotline.${_this.#id}.onmousemove`, {
|
|||
|
detail: { from, to }
|
|||
|
})
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Запись курсора
|
|||
|
_this.#shell.style.cursor = "grabbing";
|
|||
|
};
|
|||
|
};
|
|||
|
|
|||
|
// Перещапись событий браузера (чтобы не дёргалось)
|
|||
|
_this.#shell.ondragstart = null;
|
|||
|
|
|||
|
_this.#shell.onmouseup = function () {
|
|||
|
// Курсор деактивирован
|
|||
|
|
|||
|
// Остановка обработки движения
|
|||
|
document.onmousemove = null;
|
|||
|
|
|||
|
// Сброс сдвига
|
|||
|
offset = 0;
|
|||
|
|
|||
|
document.removeEventListener(
|
|||
|
`hotline.${_this.#id}.transfer.start`,
|
|||
|
listener
|
|||
|
);
|
|||
|
document.removeEventListener(
|
|||
|
`hotline.${_this.#id}.transfer.end`,
|
|||
|
listener
|
|||
|
);
|
|||
|
|
|||
|
// Восстановление курсора
|
|||
|
_this.#shell.style.cursor = null;
|
|||
|
};
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
// Инициализация обработчика отведения курсора (остановка движения)
|
|||
|
this.#shell.onmouseleave = function (onmouseleave) {
|
|||
|
// Курсор отведён от бегущей строки
|
|||
|
|
|||
|
if (!_this.sticky) {
|
|||
|
// Отключено прилипание
|
|||
|
|
|||
|
// Остановка обработки движения
|
|||
|
document.onmousemove = null;
|
|||
|
|
|||
|
document.removeEventListener(
|
|||
|
`hotline.${_this.#id}.transfer.start`,
|
|||
|
listener
|
|||
|
);
|
|||
|
document.removeEventListener(
|
|||
|
`hotline.${_this.#id}.transfer.end`,
|
|||
|
listener
|
|||
|
);
|
|||
|
|
|||
|
// Восстановление курсора
|
|||
|
_this.#shell.style.cursor = null;
|
|||
|
}
|
|||
|
|
|||
|
// Сброс сдвига
|
|||
|
offset = 0;
|
|||
|
|
|||
|
// Разблокировка движения
|
|||
|
_this.#move = true;
|
|||
|
|
|||
|
if (_this.events.get("move.unblock")) {
|
|||
|
// Запрошен вызов события: "разблокировка движения"
|
|||
|
|
|||
|
// Вызов события: "разблокировка движения"
|
|||
|
document.dispatchEvent(
|
|||
|
new CustomEvent(`hotline.${_this.#id}.move.unblock`)
|
|||
|
);
|
|||
|
}
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
if (this.wheel) {
|
|||
|
// Запрошена возможность прокручивать колесом мыши
|
|||
|
|
|||
|
// Инициализация обработчика наведения курсора (остановка движения)
|
|||
|
this.#shell.onwheel = function (e) {
|
|||
|
// Курсор наведён на бегущую
|
|||
|
|
|||
|
// Инициализация буфера для временных данных
|
|||
|
let buffer;
|
|||
|
|
|||
|
// Перемещение
|
|||
|
_this.offset(
|
|||
|
(isNaN(
|
|||
|
(buffer = parseFloat(
|
|||
|
_this.#shell.firstElementChild.style[
|
|||
|
_this.vertical ? "marginTop" : "marginLeft"
|
|||
|
]
|
|||
|
))
|
|||
|
)
|
|||
|
? 0
|
|||
|
: buffer) +
|
|||
|
(_this.delta === null
|
|||
|
? e.wheelDelta
|
|||
|
: e.wheelDelta > 0
|
|||
|
? _this.delta
|
|||
|
: -_this.delta)
|
|||
|
);
|
|||
|
};
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (this.observe) {
|
|||
|
// Запрошено наблюдение за изменениями аттрибутов элемента бегущей строки
|
|||
|
|
|||
|
if (this.#observer === null) {
|
|||
|
// Отсутствует наблюдатель
|
|||
|
|
|||
|
// Инициализация ссылки на ядро
|
|||
|
const _this = this;
|
|||
|
|
|||
|
// Инициализация наблюдателя
|
|||
|
this.#observer = new MutationObserver(function (mutations) {
|
|||
|
for (const mutation of mutations) {
|
|||
|
if (mutation.type === "attributes") {
|
|||
|
// Запись параметра в инстанцию бегущей строки
|
|||
|
_this.configure(mutation.attributeName);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Перезапуск бегущей строки
|
|||
|
_this.restart();
|
|||
|
});
|
|||
|
|
|||
|
// Активация наблюдения
|
|||
|
this.#observer.observe(this.#shell, {
|
|||
|
attributes: true
|
|||
|
});
|
|||
|
}
|
|||
|
} else if (this.#observer instanceof MutationObserver) {
|
|||
|
// Запрошено отключение наблюдения
|
|||
|
|
|||
|
// Деактивация наблюдения
|
|||
|
this.#observer.disconnect();
|
|||
|
|
|||
|
// Удаление наблюдателя
|
|||
|
this.#observer = null;
|
|||
|
}
|
|||
|
|
|||
|
if (this.events.get("start")) {
|
|||
|
// Запрошен вызов события: "запуск"
|
|||
|
|
|||
|
// Вызов события: "запуск"
|
|||
|
document.dispatchEvent(new CustomEvent(`hotline.${this.#id}.start`));
|
|||
|
}
|
|||
|
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
stop() {
|
|||
|
// Остановка бегущей строки
|
|||
|
clearInterval(this.#instance);
|
|||
|
|
|||
|
// Удаление инстанции интервала
|
|||
|
this.#instance = null;
|
|||
|
|
|||
|
if (this.events.get("stop")) {
|
|||
|
// Запрошен вызов события: "остановка"
|
|||
|
|
|||
|
// Вызов события: "остановка"
|
|||
|
document.dispatchEvent(new CustomEvent(`hotline.${this.#id}.stop`));
|
|||
|
}
|
|||
|
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
restart() {
|
|||
|
// Остановка бегущей строки
|
|||
|
this.stop();
|
|||
|
|
|||
|
// Запуск бегущей строки
|
|||
|
this.start();
|
|||
|
}
|
|||
|
|
|||
|
configure(attribute) {
|
|||
|
// Инициализация названия параметра
|
|||
|
const parameter = (/^data-hotline-(\w+)$/.exec(attribute) ?? [, null])[1];
|
|||
|
|
|||
|
if (typeof parameter === "string") {
|
|||
|
// Параметр найден
|
|||
|
|
|||
|
// Проверка на разрешение изменения
|
|||
|
if (this.#block.has(parameter)) return;
|
|||
|
|
|||
|
// Инициализация значения параметра
|
|||
|
const value = this.#shell.getAttribute(attribute);
|
|||
|
|
|||
|
// Инициализация буфера для временных данных
|
|||
|
let buffer;
|
|||
|
|
|||
|
// Запись параметра
|
|||
|
this[parameter] = isNaN((buffer = parseFloat(value)))
|
|||
|
? value === "true"
|
|||
|
? true
|
|||
|
: value === "false"
|
|||
|
? false
|
|||
|
: value
|
|||
|
: buffer;
|
|||
|
}
|
|||
|
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
offset(value) {
|
|||
|
// Запись отступа
|
|||
|
this.#shell.firstElementChild.style[
|
|||
|
this.vertical ? "marginTop" : "marginLeft"
|
|||
|
] = value + "px";
|
|||
|
|
|||
|
if (this.events.get("offset")) {
|
|||
|
// Запрошен вызов события: "сдвиг"
|
|||
|
|
|||
|
// Вызов события: "сдвиг"
|
|||
|
document.dispatchEvent(
|
|||
|
new CustomEvent(`hotline.${this.#id}.offset`, {
|
|||
|
detail: {
|
|||
|
to: value
|
|||
|
}
|
|||
|
})
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
static preprocessing(event = false) {
|
|||
|
// Инициализация счётчиков инстанций горячей строки
|
|||
|
const success = new Set();
|
|||
|
let error = 0;
|
|||
|
|
|||
|
for (const element of document.querySelectorAll('*[data-hotline="true"]')) {
|
|||
|
// Перебор элементов для инициализации бегущих строк
|
|||
|
|
|||
|
if (typeof element.id === "string") {
|
|||
|
// Найден идентификатор
|
|||
|
|
|||
|
// Инициализация инстанции бегущей строки
|
|||
|
const hotline = new this(element.id, element);
|
|||
|
|
|||
|
for (const attribute of element.getAttributeNames()) {
|
|||
|
// Перебор аттрибутов
|
|||
|
|
|||
|
// Запись параметра в инстанцию бегущей строки
|
|||
|
hotline.configure(attribute);
|
|||
|
}
|
|||
|
|
|||
|
// Запуск бегущей строки
|
|||
|
hotline.start();
|
|||
|
|
|||
|
// Запись инстанции бегущей строки в элемент
|
|||
|
element.hotline = hotline;
|
|||
|
|
|||
|
// Запись в счётчик успешных инициализаций
|
|||
|
success.add(hotline);
|
|||
|
} else ++error;
|
|||
|
}
|
|||
|
|
|||
|
if (event) {
|
|||
|
// Запрошен вызов события: "предварительная подготовка"
|
|||
|
|
|||
|
// Вызов события: "предварительная подготовка"
|
|||
|
document.dispatchEvent(
|
|||
|
new CustomEvent(`hotline.preprocessed`, {
|
|||
|
detail: {
|
|||
|
success,
|
|||
|
error
|
|||
|
}
|
|||
|
})
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
document.dispatchEvent(
|
|||
|
new CustomEvent("hotline.loaded", {
|
|||
|
detail: { hotline }
|
|||
|
})
|
|||
|
);
|