Модуль создаёт глобальную функцию sendNotification, которую можно вызывать как из виджета код, так и из клиентского сценария посредством обращения к window.sendNotification. На входе функция принимает:
- notification_type - код уведомления из таблицы типов уведомления модуля;
- text - текст уведомления;
- details - детали уведомления. Будут отображены при клике на кнопку "Подробнее". Если на входе подавать пустую строку или undefined - кнопки "Подробнее" не будет;
- time - время (в секундах), по истечению которого уведомление будет удалено со страницы. Если на входе подавать 0, то уведомление будет отображено, до тех пор пока пользователь сам его не закроет.
Подробнее о реализации
В модуле реализован виджет в расширении корневой компонент. Корневой компонент позволяет создать виджет, код которого будет исполняться на всех страницах при загрузке системы. Это позволяет нам, единожды создав функцию, использовать её на всех виджетах и формах.
Внутри корневого компонента добавляем 3 виджет кода на форму с следующим содержимым:
1. CSS стили блоков - которые бесстыдно подсмотрены в стандартных уведомлениях ELMA365.
Код:
<style>
#notify-container>*+*,
#toast-container>*+* {
margin-top: 7px;
}
.notify-div {
width: 60%;
max-width: 900px;
position: relative;
overflow: hidden;
border-radius: 3px;
box-shadow: 0 0 12px #999;
margin: 0 auto;
padding: 0;
cursor: pointer;
font-size: 16px;
line-height: 24px;
pointer-events: all;
}
.notify-div:hover {
box-shadow: 0 0 12px #000;
}
.notify-row {
display: flex;
flex-wrap: revert;
padding: 3.5px;
margin-left: -4px;
margin-right: -4px;
box-sizing: border-box;
}
.notify-icon {
height: 20px;
width: 20px;
background-repeat: no-repeat;
margin-left: 16px;
}
.notify-text-div {
flex: 1 0 75%;
max-width: none;
display: flex;
flex-direction: column;
justify-content: center;
}
.notify-text {
font-weight: 700;
color: #1f1f1f;
display: flex;
}
a.details-button:hover {
text-decoration: none;
}
.show-details .notify-details {
display: block !important;
}
</style>
2. HTML разметка уведомлений.
Подтягиваем из настроек модуля типы уведомлении и формируем для каждого из них шаблон, хранящийся на странице браузера, но скрытый от глаз пользователя.
Код:
<% const notify_types = Context.data.notify_type; %>
<% if (notify_types && notify_types.length > 0) { %>
<div id="notify-template" style="display: none;">
<% for (let i = 0; i < notify_types.length; ++i) { %>
<% const notify_type = notify_types[i]; %>
<div class="notify-div <%- notify_type.code %>-div"
style="display: block; border: 1px solid <%- notify_type.border_color %>; background-color: <%- notify_type.bg_color %>;">
<div class="notify-row">
<div class="notify-icon">
<i class="elma-icons md-18" style="color: <%- notify_type.border_color %>;"><%- notify_type.icon_code %></i>
</div>
<div class="col-9 notify-text-div">
<div class="notify-text">
<p style="margin: 0 3px 0 0;"></p>
<a class="details-button" style="color: <%- notify_type.border_color %>;" onclick="show_details(this)">Подробнее... </a>
</div>
</div>
<div class="col-3 text-right" style="flex: 0 0 20px;">
<button class="md-18 btn btn-default btn-style-icon elma-icons" style="height: 20px; width: 20px; padding: 0;"
onclick="remove_notify(this)"> system_close </button>
</div>
</div>
<textarea class="notify-details" readonly="" style="background: #ffffff; display: none;"></textarea>
</div>
<% } %>
</div>
<% } %>
3. Скрипты
Код:
<div class="overlay-container" id="notify-overlay">
<div id="notify-container" class="toast-top-center toast-container"></div>
</div>
<script>
//Перемещаем в блок body контейнер для наших всплывающих уведомлений
document.querySelector("body").appendChild(document.querySelector("#notify-overlay"));
//Записываем в глобальную переменную sendNotification нашу функцию
window.sendNotification = function ( notify_type, text, details, time = 0 ) {
// Ищем на странице шаблон поданного уведомления
const template = document.querySelector("#notify-template ." + notify_type + "-div");
if (!template){
return;
}
// Ищем на странице контейнер для всплывающего уведомления
const target_container = document.querySelector("#toast-container") ?? document.querySelector("#notify-container");
// Копируем шаблон уведомления
const notify = template.cloneNode(true);
notify.querySelector(".notify-text p").innerText = text ?? notify_type; // Указываем заголовок уведомления
if (details) {
notify.querySelector(".notify-details").innerText = details ?? ''; // Указываем детали уведомления
} else {
notify.querySelector(".details-button").remove();
}
// Вставляем уведомление в контейнер для уведомления
target_container.prepend(notify);
// Автоудаление уведомления
if (time > 0) {
setTimeout(() => {
notify.remove();
}, time * 1000);
}
}
// Кнопка для удаления уведомления со страницы
function remove_notify( element ) {
element.closest('.notify-div').remove();
}
// Кнопка для отображения деталей уведомления
function show_details( element ) {
notify = element.closest('.notify-div');
if (notify.classList.contains('show-details')){
notify.classList.remove('show-details');
element.innerText = 'Подробнее...';
} else {
notify.classList.add('show-details');
element.innerText = 'Скрыть...';
}
}
</script>
</script>
Использование:
Теперь мы можем вызывать глобальную функцию напрямую из TypeScript, предварительно подключив window
Код:
declare const window: any;
window.sendNotification('error', 'Текст ошибки', 'Подробности', 0);
Однако!
Корневой компонент инициализируется при первой загрузке страницы. При перезагрузке страницы или например при открытие в новой вкладке, может возникнуть ситуация, что корневой компонент не успеет загрузиться, например если отправлять уведомления из функции onInit. Поэтому создадим функцию на TypeScript для ожидания загрузки корневого компонента.
Код:
declare const console: any;
declare const window: any;
/**
* Отправляет всплывающее уведомления на форму
* @param {string} notification_type Тип уведомления
* @param {string} text Текст уведомления
* @param {string | undefined} details Подробности
* @param {Number} time Количество секунд до автоматического скрытия уведомления. Если передать 0, то уведомления не будет автоматически скрываться
*/
async function sendNotification(notification_type: string, text: string, details: string | undefined = undefined, time: Number = 0): Promise<void> {
if (!window.sendNotification) {
window.setTimeout(() => {
try {
window.sendNotification(notification_type, text, details, time);
} catch {
// Глобальная функция sendNotification не найдена
console.error("Корневой компонент шаблоны уведомлений не найдет ")
}
}, 1000);
return;
}
window.sendNotification(notification_type, text, details, time);
}
async function onInit(): Promise<void> {
// Отправляем уведомление на страницу
sendNotification("success", "Успех");
sendNotification("info", "Информация", undefined, 5);
sendNotification("warning", "Предупреждение", "Подробности предупреждения");
sendNotification("error", "Ошибка", "Текст ошибки", 0);
}
Файл модуля во вложении