Current Path : /var/www/www-root/data/www/monolith-realty.ru/bitrix/js/ui/mail/sender-editor/src/ |
Current File : /var/www/www-root/data/www/monolith-realty.ru/bitrix/js/ui/mail/sender-editor/src/alias-editor.js |
import { Layout } from 'ui.sidepanel.layout'; import { ajax, Dom, Event, Loc, Tag, Text } from 'main.core'; import { SmtpEditor } from './smtp-editor'; import { Button } from 'ui.buttons'; import './css/style.css'; import 'ui.forms'; import 'ui.layout-form'; import 'ui.sidepanel-content'; import 'ui.entity-selector'; import 'ui.icon-set.actions'; import 'ui.icon-set.main'; type Sender = { id: number, name: string, userId: number | null, isOwner: boolean, type: string, mailboxId: number | null, canEdit: boolean, editHref: string | null, avatar: string | null, userUrl: string | null, } type Options = { senderId: number, email: string, setSenderCallback?: Function, updateSenderList?: () => void, } const mailboxType = 'mailbox'; const senderType = 'sender'; const mailboxSenderType = 'mailboxSender'; const aliasType = 'alias'; const successSubmitMessage = 'mail-mailbox-config-success'; const deleteMessage = 'mail-mailbox-config-delete'; const aliasSliderUrl = 'mailAliasSlider'; export class AliasEditor { wasSenderUpdated: boolean = false; aliasCounter: number = 0; constructor(options: Options) { this.senderId = Number(options.senderId); this.email = options.email; this.setSender = options.setSenderCallback; this.updateSenderList = options.updateSenderList; this.#createContentContainer(); this.#createToolbarButtons(); } static openSlider(options: Options): void { const instance = new AliasEditor(options); const onSliderMessage = function(event) { const [sliderEvent] = event.getData(); if (!sliderEvent) { return; } const eventMessage = sliderEvent.getEventId(); const data = sliderEvent.getData(); const mailboxId = Number(sliderEvent.data.id); const slider = BX.SidePanel.Instance.getSlider(aliasSliderUrl); if (eventMessage === successSubmitMessage) { instance.wasSenderUpdated = true; instance.updateMainSenderName(mailboxId); if (slider) { slider.close(); } return; } if (eventMessage === deleteMessage) { instance.wasSenderUpdated = true; if (instance.id === Number(mailboxId)) { instance.setSender(); } if (slider) { slider.close(); } if (data && data.type !== senderType) { BX.SidePanel.Instance.postMessage(window, sliderEvent.getEventId(), sliderEvent.getData); } } }; BX.SidePanel.Instance.open(aliasSliderUrl, { width: 680, cacheable: false, contentCallback: () => { return Layout.createContent({ extensions: [ 'ui.mail.sender-editor', ], title: options.email, design: { section: false, margin: false, }, content(): Promise { return instance.loadSliderContent(); }, toolbar(): Array { return instance.getToolbarButtons(); }, buttons: () => {}, }); }, events: { onClose: () => { top.BX.Event.EventEmitter.unsubscribe('SidePanel.Slider:onMessage', onSliderMessage); if (instance.updateSenderList && instance.wasSenderUpdated) { instance.updateSenderList(); } }, }, }); top.BX.Event.EventEmitter.subscribe('SidePanel.Slider:onMessage', onSliderMessage); } getContentContainer(): HTMLElement { return this.contentContainer; } getToolbarButtons(): Array { const buttons = []; if (this.settingsButton) { buttons.push(this.settingsButton); } return buttons; } loadSliderContent(): Promise { return BX.ajax.runAction( 'main.api.mail.sender.getSenderTransitionalData', { data: { senderId: this.senderId }, }, ).then((response) => { const data = response.data; const senders = data.senders; this.id = Number(data.id); this.email = data.email; this.#addSenders(senders); const type = data.type || null; switch (type) { case mailboxType: this.settingsButton.bindEvent('click', () => { this.#openMailboxSettings(data.href); }); break; case senderType: this.settingsButton.bindEvent('click', () => { this.#openSmtpSettings(data.id); }); break; default: this.settingsButton.setDisabled(); break; } return this.getContentContainer(); }).catch(() => { this.settingsButton.setDisabled(); return this.getContentContainer(); }); } #createContentContainer(): void { this.senderList = Tag.render` <div class="mail-sender-list"></div> `; this.#createAddSenderContainer(); this.contentContainer = Tag.render` <div class="ui-form"> <div class="ui-slider-section"> <div class="ui-slider-content-box" style="margin-bottom: 0"> <div class="ui-slider-heading-4 sender-list-header">${Text.encode(Loc.getMessage('UI_MAIL_ALIAS_SLIDER_EMAIL_TITLE'))}</div> ${this.senderList} ${this.addSenderContainer} </div> </div> </div> `; } #createAddSenderContainer(): void { this.senderInput = Tag.render` <input type="text" class="ui-ctl-element" data-name="aliasName" placeholder="${Text.encode(Loc.getMessage('UI_MAIL_ALIAS_SLIDER_ADD_INPUT_PLACEHOLDER'))}"> `; this.senderInputContainer = Tag.render` <div class="add-sender-input-container" hidden> <div class="ui-ctl ui-ctl-textbox ui-ctl-default-light ui-ctl-sm ui-ctl-w100"> ${this.senderInput} </div> </div> `; Dom.append( this.#renderSubmitButton( () => { return this.#addAliasPromise(); }, this.senderInput, ), this.senderInputContainer, ); Dom.append( this.#renderCancelButton(() => { Dom.hide(this.senderInputContainer); Dom.show(this.senderAddButton); this.senderInput.value = null; }), this.senderInputContainer, ); this.senderAddButton = Tag.render` <div class="add-sender-button">${Text.encode(Loc.getMessage('UI_MAIL_ALIAS_SLIDER_ADD_BUTTON'))}</div> `; Event.bind(this.senderAddButton, 'click', () => { Dom.hide(this.senderAddButton); Dom.show(this.senderInputContainer); this.senderInput.focus(); }); this.addSenderContainer = Tag.render` <div class="add-sender-container"> ${this.senderInputContainer} ${this.senderAddButton} </div> `; } #addAliasPromise(): Promise { return new Promise((resolve) => { const hideInputContainer = () => { Dom.hide(this.senderInputContainer); Dom.show(this.senderAddButton); this.senderInput.value = null; resolve(); }; if (this.senderInput.value.trim().length === 0) { hideInputContainer(); return; } if (this.#hasNameInvalidCharacters(this.senderInput.value.trim())) { resolve(); return; } const name = this.senderInput.value; ajax.runAction( 'main.api.mail.sender.addAlias', { data: { name, email: this.email, }, }, ).then((response) => { const data = response.data; const newSenderId = data.senderId; if (this.setSender && data.senderId) { this.setSender(data.senderId, name, this.email); } this.wasSenderUpdated = true; this.senderId = newSenderId; const senderNode = this.#renderSenderItem({ id: newSenderId, name, isOwner: true, type: aliasType, canEdit: true, }); Dom.append(senderNode, this.senderList); this.aliasCounter++; hideInputContainer(); }).catch(() => { hideInputContainer(); }); }); } #createToolbarButtons(): void { this.settingsButton = new Button({ text: Loc.getMessage('UI_MAIL_ALIAS_SLIDER_MAIL_SETTINGS_BUTTON'), icon: Button.Icon.SETTING, color: Button.Color.LIGHT_BORDER, }); } #renderSenderItem(sender: Sender): HTMLElement { const itemContainer = Tag.render`<div class="sender-list-item"></div>`; const { root: nameContainer, textNode: nameTextContainer, } = this.#renderSenderNameContainer(sender.name); let handleShowEditInput = null; if (sender.canEdit) { const { nameEditContainer, editInput: nameEditInput, } = this.#renderSenderEditNode(sender, nameTextContainer); Dom.append(nameEditContainer, nameContainer); handleShowEditInput = () => { nameEditInput.value = nameContainer.innerText; Dom.hide(nameTextContainer); Dom.show(nameEditContainer); nameEditInput.focus(); }; Event.bind(nameTextContainer, 'click', handleShowEditInput); } Dom.append(nameContainer, itemContainer); Dom.append(this.#renderSenderExtraInfoContainer(sender), itemContainer); Dom.append(this.#renderSenderEditContainer(sender, itemContainer, handleShowEditInput), itemContainer); if ( (sender.type === senderType && this.id === Number(sender.id)) || (sender.type === mailboxSenderType && this.id === Number(sender.mailboxId)) ) { this.mainSenderNameNode = nameContainer.querySelector('.sender-item-name-text-container'); } return itemContainer; } #renderSenderNameContainer(senderName: string): { root: HTMLElement, textNode: HTMLElement} { const { root, textNode } = Tag.render` <div class="sender-item-name-container"> <div class="sender-item-name-text-container" ref="textNode"> ${Text.encode(senderName)} </div> </div> `; return { root, textNode }; } #renderSenderEditNode( sender: Sender, nameTextContainer: HTMLElement, ): {nameEditContainer: HTMLElement, editInput: HTMLElement} { const textContainer = nameTextContainer; const { root, editInput } = Tag.render` <div class="edit-sender-container-content" ref="editContent"> <div class="ui-ctl ui-ctl-textbox ui-ctl-default-light ui-ctl-sm ui-ctl-w100"> <input type="text" class="ui-ctl-element" ref="editInput" placeholder="${Loc.getMessage('UI_MAIL_ALIAS_SLIDER_ADD_INPUT_PLACEHOLDER')}"> </div> </div> `; const nameEditContainer = root; const submitPromise = () => { return new Promise((resolve) => { const hideEditContainer = () => { editInput.value = nameTextContainer.innerText; Dom.hide(nameEditContainer); Dom.show(textContainer); resolve(); }; if (editInput.value.length === 0 || editInput.value === nameTextContainer.innerText) { hideEditContainer(); return; } if (this.#hasNameInvalidCharacters(editInput.value)) { resolve(); return; } const senderNewName = editInput.value; ajax.runAction( 'main.api.mail.sender.updateSenderName', { data: { senderId: sender.id, name: senderNewName, }, }, ).then(() => { textContainer.innerText = senderNewName; if (this.setSender) { this.setSender(sender.id, senderNewName, this.email); } this.wasSenderUpdated = true; hideEditContainer(); }).catch(() => { hideEditContainer(); }); }); }; Dom.append(this.#renderSubmitButton(submitPromise, editInput), root); const cancelHandler = () => { Dom.hide(nameEditContainer); Dom.show(textContainer); editInput.value = null; }; Dom.append(this.#renderCancelButton(cancelHandler), root); Dom.hide(root); return { nameEditContainer, editInput }; } #renderSenderExtraInfoContainer(sender: Sender): HTMLElement { return Tag.render` <div class="sender-item-type-container">${Text.encode(this.#getExtraInfoText(sender))}</div> `; } #getExtraInfoText(sender: Sender): string { if ( (sender.type === senderType && this.id === Number(sender.id)) || (sender.type === mailboxSenderType && this.id === Number(sender.mailboxId)) ) { return Loc.getMessage('UI_MAIL_ALIAS_EDITOR_CURRENT_SENDER_NAME'); } if ([senderType, mailboxSenderType].includes(sender.type) && sender.isOwner) { return Loc.getMessage('UI_MAIL_ALIAS_EDITOR_ANOTHER_SENDER_NAME'); } if (sender.type === aliasType && sender.isOwner) { return Loc.getMessage('UI_MAIL_ALIAS_EDITOR_ADDITIONAL_SENDER_NAME'); } return ''; } #renderSenderEditContainer(sender: Sender, senderNode: HTMLElement, handleShowInput: null | () => void): HTMLElement { const senderEditContainer = Tag.render` <div class="sender-item-edit-container"></div> `; if (!sender.isOwner) { Dom.append(this.#renderUserInfoNode(sender.userUrl, sender.avatar), senderEditContainer); return senderEditContainer; } const senderNameEditButton = Tag.render` <div class="sender-item-btn ui-btn ui-btn-xs ui-icon-set --pencil-50"></div> `; Dom.append(senderNameEditButton, senderEditContainer); if (handleShowInput) { Event.bind(senderNameEditButton, 'click', handleShowInput); } if (sender.type === aliasType) { Dom.append(this.#renderDeleteButton(sender.id, senderNode), senderEditContainer); return senderEditContainer; } Dom.append(this.#renderSettingsButton(sender.type, sender.id, sender.editHref), senderEditContainer); return senderEditContainer; } #renderUserInfoNode(userUrl: string, avatar: string | null): HTMLElement { const { root, userAvatarContainer } = Tag.render` <div class="sender-item-owner-info"> ${Loc.getMessage('UI_MAIL_ALIAS_EDITOR_ANOTHER_USER_SENDER_NAME')} <a href="${Text.encode(userUrl)}" class="ui-icon ui-icon-common-user sender-item-owner-avatar" ref="userAvatarContainer"></a> </div> `; let avatarIcon = ''; if (avatar) { avatarIcon = Tag.render`<i style="background-image: url('${Text.encode(avatar)}')"></i>`; } else { avatarIcon = Tag.render`<div class="sender-item-owner-avatar-icon ui-icon-set --person"></div>`; } Dom.append(avatarIcon, userAvatarContainer); return root; } #renderDeleteButton(senderId: number, senderNode: HTMLElement): HTMLElement { const deleteButton = Tag.render` <div class="sender-item-btn ui-btn ui-btn-xs ui-icon-set --trash-bin" style="margin: 0"></div> `; Event.bind(deleteButton, 'click', () => { Dom.removeClass(deleteButton, ['ui-icon-set', '--trash-bin']); Dom.addClass(deleteButton, ['ui-btn-light', 'ui ui-btn-wait']); ajax.runAction( 'main.api.mail.sender.deleteSender', { data: { senderId, }, }, ).then(() => { senderNode.remove(); this.wasSenderUpdated = true; if (Number(senderId) === this.senderId) { this.setSender(); } this.aliasCounter--; this.#checkAliasCounter(); }).catch(() => { Dom.removeClass(deleteButton, 'ui-btn-wait'); }); }); return deleteButton; } #renderSettingsButton(type: string, senderId: number | string, editHref: string | null): HTMLElement { const editButton = Tag.render` <div class="sender-item-btn ui-btn ui-btn-xs ui-icon-set --settings-1" style="margin: 0"></div> `; if (type === mailboxSenderType) { Event.bind(editButton, 'click', () => { this.#openMailboxSettings(editHref); }); return editButton; } Event.bind(editButton, 'click', () => { this.#openSmtpSettings(senderId); }); return editButton; } #renderSubmitButton(submitPromise: Promise, targetElement: HTMLInputElement): HTMLElement { const submitButton = Tag.render` <div class="ui-btn ui-btn-xs ui-btn-primary ui-btn-icon-done" style="margin: 0"></div> `; Event.bind(submitButton, 'click', () => { Dom.addClass(submitButton, 'ui ui-btn-wait'); submitPromise() .then(() => { Dom.removeClass(submitButton, 'ui-btn-wait'); }) .catch(() => {}) ; }); Event.bind(targetElement, 'keypress', (event: KeyboardEvent) => { if (event.key === 'Enter') { submitButton.click(); } }); return submitButton; } #renderCancelButton(cancelHandler: () => void): HTMLElement { const cancelButton = Tag.render` <div class="sender-item-btn ui-btn ui-btn-xs ui-icon-set --cross-45" style="margin: 0"></div> `; Event.bind(cancelButton, 'click', cancelHandler); return cancelButton; } #addSenders(senders: Sender[] | null): void { if (!senders) { return; } senders.sort((a, b) => a.id - b.id); senders.forEach((sender: Sender) => { const senderNode = this.#renderSenderItem(sender); Dom.append(senderNode, this.senderList); this.aliasCounter++; }); } #openSmtpSettings(senderId: number | string): void { SmtpEditor.openSlider({ senderId: Number(senderId), setSenderCallback: (id: number | string, name: string, email: string) => { if (this.mainSenderNameNode) { this.mainSenderNameNode.innerText = name; } this.setSender(id, name, email); this.wasSenderUpdated = true; }, }); } #openMailboxSettings(href: string): void { BX.SidePanel.Instance.open(href); } #hasNameInvalidCharacters(name: string): boolean { // regex checks for characters other than letters of the alphabet, numbers, spaces // and special characters ("-", ".", "'", "(", ")", ",") const regexForInvalidCharacters = /[^\p{L}\p{N}\p{Zs}\-.'(),]+/ug; if (regexForInvalidCharacters.test(name)) { top.BX.UI.Notification.Center.notify({ content: Text.encode(Loc.getMessage('UI_MAIL_ALIAS_EDITOR_INVALID_SYMBOLS_NOTIFICATION')), }); return true; } return false; } updateMainSenderName(mailboxId: number): void { return BX.ajax.runAction( 'main.api.mail.sender.getSenderByMailboxId', { data: { mailboxId }, }, ) .then((response) => { const name = response.data?.name; if (!name || !this.mainSenderNameNode) { return; } this.mainSenderNameNode.innerText = name; }) .catch(() => {}) ; } #checkAliasCounter(): void { if (this.aliasCounter === 0) { const slider = BX.SidePanel.Instance.getSlider(aliasSliderUrl); if (slider) { slider.close(); } } } }