Send stickers, gifs, polls, media, document rights
This commit is contained in:
parent
4e3964ec8b
commit
37a1eaa37d
@ -1,5 +1,6 @@
|
|||||||
import Recorder from '../../../public/recorder.min';
|
import Recorder from '../../../public/recorder.min';
|
||||||
import { isTouchSupported } from "../../helpers/touchSupport";
|
import { isTouchSupported } from "../../helpers/touchSupport";
|
||||||
|
import appChatsManager from '../../lib/appManagers/appChatsManager';
|
||||||
import appDocsManager from "../../lib/appManagers/appDocsManager";
|
import appDocsManager from "../../lib/appManagers/appDocsManager";
|
||||||
import appImManager from "../../lib/appManagers/appImManager";
|
import appImManager from "../../lib/appManagers/appImManager";
|
||||||
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
|
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
|
||||||
@ -8,15 +9,19 @@ import apiManager from "../../lib/mtproto/mtprotoworker";
|
|||||||
//import Recorder from '../opus-recorder/dist/recorder.min';
|
//import Recorder from '../opus-recorder/dist/recorder.min';
|
||||||
import opusDecodeController from "../../lib/opusDecodeController";
|
import opusDecodeController from "../../lib/opusDecodeController";
|
||||||
import { RichTextProcessor } from "../../lib/richtextprocessor";
|
import { RichTextProcessor } from "../../lib/richtextprocessor";
|
||||||
|
import $rootScope from '../../lib/rootScope';
|
||||||
import { calcImageInBox, cancelEvent, getRichValue } from "../../lib/utils";
|
import { calcImageInBox, cancelEvent, getRichValue } from "../../lib/utils";
|
||||||
|
import ButtonMenu, { ButtonMenuItemOptions } from '../buttonMenu';
|
||||||
import emoticonsDropdown from "../emoticonsDropdown";
|
import emoticonsDropdown from "../emoticonsDropdown";
|
||||||
import { Layouter, RectPart } from "../groupedLayout";
|
import { Layouter, RectPart } from "../groupedLayout";
|
||||||
import PopupCreatePoll from "../popupCreatePoll";
|
import PopupCreatePoll from "../popupCreatePoll";
|
||||||
|
import { ripple } from '../ripple';
|
||||||
import Scrollable from "../scrollable";
|
import Scrollable from "../scrollable";
|
||||||
import { toast } from "../toast";
|
import { toast } from "../toast";
|
||||||
import { wrapDocument, wrapReply } from "../wrappers";
|
import { wrapDocument, wrapReply } from "../wrappers";
|
||||||
|
|
||||||
const RECORD_MIN_TIME = 500;
|
const RECORD_MIN_TIME = 500;
|
||||||
|
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
|
||||||
|
|
||||||
export class ChatInput {
|
export class ChatInput {
|
||||||
public pageEl = document.getElementById('page-chats') as HTMLDivElement;
|
public pageEl = document.getElementById('page-chats') as HTMLDivElement;
|
||||||
@ -32,12 +37,8 @@ export class ChatInput {
|
|||||||
private inputContainer = this.btnSend.parentElement.parentElement as HTMLDivElement;
|
private inputContainer = this.btnSend.parentElement.parentElement as HTMLDivElement;
|
||||||
private chatInput = this.inputContainer.parentElement as HTMLDivElement;
|
private chatInput = this.inputContainer.parentElement as HTMLDivElement;
|
||||||
|
|
||||||
public attachMenu: {
|
public attachMenu: HTMLButtonElement;
|
||||||
container?: HTMLButtonElement,
|
private attachMenuButtons: (ButtonMenuItemOptions & {verify: (peerID: number) => boolean})[];
|
||||||
media?: HTMLDivElement,
|
|
||||||
document?: HTMLDivElement,
|
|
||||||
poll?: HTMLDivElement
|
|
||||||
} = {};
|
|
||||||
|
|
||||||
public attachMediaPopUp: {
|
public attachMediaPopUp: {
|
||||||
container?: HTMLDivElement,
|
container?: HTMLDivElement,
|
||||||
@ -71,10 +72,49 @@ export class ChatInput {
|
|||||||
private scrollDiff = 0;
|
private scrollDiff = 0;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.attachMenu.container = document.getElementById('attach-file') as HTMLButtonElement;
|
this.attachMenu = document.getElementById('attach-file') as HTMLButtonElement;
|
||||||
this.attachMenu.media = this.attachMenu.container.querySelector('.menu-media') as HTMLDivElement;
|
|
||||||
this.attachMenu.document = this.attachMenu.container.querySelector('.menu-document') as HTMLDivElement;
|
this.attachMenuButtons = [{
|
||||||
this.attachMenu.poll = this.attachMenu.container.querySelector('.menu-poll') as HTMLDivElement;
|
icon: 'photo',
|
||||||
|
text: 'Photo or Video',
|
||||||
|
onClick: () => {
|
||||||
|
this.fileInput.setAttribute('accept', 'image/*, video/*');
|
||||||
|
willAttach.type = 'media';
|
||||||
|
this.fileInput.click();
|
||||||
|
},
|
||||||
|
verify: (peerID: number) => peerID > 0 || appChatsManager.hasRights(peerID, 'send', 'send_media')
|
||||||
|
}, {
|
||||||
|
icon: 'document',
|
||||||
|
text: 'Document',
|
||||||
|
onClick: () => {
|
||||||
|
this.fileInput.removeAttribute('accept');
|
||||||
|
willAttach.type = 'document';
|
||||||
|
this.fileInput.click();
|
||||||
|
},
|
||||||
|
verify: (peerID: number) => peerID > 0 || appChatsManager.hasRights(peerID, 'send', 'send_media')
|
||||||
|
}, {
|
||||||
|
icon: 'poll',
|
||||||
|
text: 'Poll',
|
||||||
|
onClick: () => {
|
||||||
|
new PopupCreatePoll().show();
|
||||||
|
},
|
||||||
|
verify: (peerID: number) => peerID < 0 && appChatsManager.hasRights(peerID, 'send', 'send_polls')
|
||||||
|
}];
|
||||||
|
|
||||||
|
/* this.attachMenu.addEventListener('mousedown', (e) => {
|
||||||
|
const hidden = this.attachMenu.querySelectorAll('.hide');
|
||||||
|
if(hidden.length == this.attachMenuButtons.length) {
|
||||||
|
toast(POSTING_MEDIA_NOT_ALLOWED);
|
||||||
|
cancelEvent(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}, {passive: false, capture: true}); */
|
||||||
|
|
||||||
|
const attachBtnMenu = ButtonMenu(this.attachMenuButtons);
|
||||||
|
attachBtnMenu.classList.add('top-left');
|
||||||
|
this.attachMenu.append(attachBtnMenu);
|
||||||
|
|
||||||
|
ripple(this.attachMenu);
|
||||||
|
|
||||||
this.attachMediaPopUp.container = this.pageEl.querySelector('.popup-send-photo') as HTMLDivElement;
|
this.attachMediaPopUp.container = this.pageEl.querySelector('.popup-send-photo') as HTMLDivElement;
|
||||||
this.attachMediaPopUp.titleEl = this.attachMediaPopUp.container.querySelector('.popup-title') as HTMLDivElement;
|
this.attachMediaPopUp.titleEl = this.attachMediaPopUp.container.querySelector('.popup-title') as HTMLDivElement;
|
||||||
@ -103,6 +143,19 @@ export class ChatInput {
|
|||||||
|
|
||||||
this.updateSendBtn();
|
this.updateSendBtn();
|
||||||
|
|
||||||
|
$rootScope.$on('peer_changed', (e) => {
|
||||||
|
const peerID = e.detail;
|
||||||
|
|
||||||
|
const visible = this.attachMenuButtons.filter(button => {
|
||||||
|
const good = button.verify(peerID);
|
||||||
|
button.element.classList.toggle('hide', !good);
|
||||||
|
return good;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.attachMenu.toggleAttribute('disabled', !visible.length);
|
||||||
|
this.updateSendBtn();
|
||||||
|
});
|
||||||
|
|
||||||
this.messageInput.addEventListener('keydown', (e: KeyboardEvent) => {
|
this.messageInput.addEventListener('keydown', (e: KeyboardEvent) => {
|
||||||
if(e.key == 'Enter' && !isTouchSupported) {
|
if(e.key == 'Enter' && !isTouchSupported) {
|
||||||
/* if(e.ctrlKey || e.metaKey) {
|
/* if(e.ctrlKey || e.metaKey) {
|
||||||
@ -429,24 +482,9 @@ export class ChatInput {
|
|||||||
attachFiles(Array.from(files));
|
attachFiles(Array.from(files));
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
this.attachMenu.media.addEventListener('click', () => {
|
|
||||||
this.fileInput.setAttribute('accept', 'image/*, video/*');
|
|
||||||
willAttach.type = 'media';
|
|
||||||
this.fileInput.click();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.attachMenu.document.addEventListener('click', () => {
|
|
||||||
this.fileInput.removeAttribute('accept');
|
|
||||||
willAttach.type = 'document';
|
|
||||||
this.fileInput.click();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.attachMenu.poll.addEventListener('click', () => {
|
|
||||||
new PopupCreatePoll().show();
|
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener('paste', (event) => {
|
document.addEventListener('paste', (event) => {
|
||||||
if(!appImManager.peerID || this.attachMediaPopUp.container.classList.contains('active')) {
|
const peerID = $rootScope.selectedPeerID;
|
||||||
|
if(!peerID || this.attachMediaPopUp.container.classList.contains('active') || (peerID < 0 && !appChatsManager.hasRights(peerID, 'send', 'send_media'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,6 +567,11 @@ export class ChatInput {
|
|||||||
this.sendMessage();
|
this.sendMessage();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if($rootScope.selectedPeerID < 0 && !appChatsManager.hasRights($rootScope.selectedPeerID, 'send', 'send_media')) {
|
||||||
|
toast(POSTING_MEDIA_NOT_ALLOWED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.chatInput.classList.add('is-locked');
|
this.chatInput.classList.add('is-locked');
|
||||||
this.recorder.start().then(() => {
|
this.recorder.start().then(() => {
|
||||||
this.recordCanceled = false;
|
this.recordCanceled = false;
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
import LazyLoadQueue, { LazyLoadQueueIntersector } from "../lazyLoadQueue";
|
|
||||||
import GifsTab from "./tabs/gifs";
|
|
||||||
import { findUpClassName, findUpTag, whichChild } from "../../lib/utils";
|
|
||||||
import { horizontalMenu } from "../horizontalMenu";
|
|
||||||
import animationIntersector from "../animationIntersector";
|
|
||||||
import appSidebarRight from "../sidebarRight";
|
|
||||||
import appImManager from "../../lib/appManagers/appImManager";
|
|
||||||
import Scrollable, { ScrollableX } from "../scrollable";
|
|
||||||
import EmojiTab from "./tabs/emoji";
|
|
||||||
import StickersTab from "./tabs/stickers";
|
|
||||||
import StickyIntersector from "../stickyIntersector";
|
|
||||||
import { MOUNT_CLASS_TO } from "../../lib/mtproto/mtproto_config";
|
|
||||||
import { isTouchSupported } from "../../helpers/touchSupport";
|
import { isTouchSupported } from "../../helpers/touchSupport";
|
||||||
|
import appChatsManager from "../../lib/appManagers/appChatsManager";
|
||||||
|
import appImManager from "../../lib/appManagers/appImManager";
|
||||||
|
import { MOUNT_CLASS_TO } from "../../lib/mtproto/mtproto_config";
|
||||||
|
import $rootScope from "../../lib/rootScope";
|
||||||
|
import { findUpClassName, findUpTag, whichChild } from "../../lib/utils";
|
||||||
|
import animationIntersector from "../animationIntersector";
|
||||||
|
import { horizontalMenu } from "../horizontalMenu";
|
||||||
|
import LazyLoadQueue, { LazyLoadQueueIntersector } from "../lazyLoadQueue";
|
||||||
|
import Scrollable, { ScrollableX } from "../scrollable";
|
||||||
|
import appSidebarRight from "../sidebarRight";
|
||||||
|
import StickyIntersector from "../stickyIntersector";
|
||||||
|
import EmojiTab from "./tabs/emoji";
|
||||||
|
import GifsTab from "./tabs/gifs";
|
||||||
|
import StickersTab from "./tabs/stickers";
|
||||||
|
|
||||||
export const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';
|
export const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';
|
||||||
|
|
||||||
@ -53,6 +55,8 @@ export class EmoticonsDropdown {
|
|||||||
onOpenAfter: []
|
onOpenAfter: []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private selectTab: ReturnType<typeof horizontalMenu>;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.element = document.getElementById('emoji-dropdown') as HTMLDivElement;
|
this.element = document.getElementById('emoji-dropdown') as HTMLDivElement;
|
||||||
|
|
||||||
@ -113,13 +117,7 @@ export class EmoticonsDropdown {
|
|||||||
|
|
||||||
this.container = this.element.querySelector('.emoji-container .tabs-container') as HTMLDivElement;
|
this.container = this.element.querySelector('.emoji-container .tabs-container') as HTMLDivElement;
|
||||||
this.tabsEl = this.element.querySelector('.emoji-tabs') as HTMLUListElement;
|
this.tabsEl = this.element.querySelector('.emoji-tabs') as HTMLUListElement;
|
||||||
horizontalMenu(this.tabsEl, this.container, (id) => {
|
this.selectTab = horizontalMenu(this.tabsEl, this.container, this.onSelectTabClick, () => {
|
||||||
animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP);
|
|
||||||
|
|
||||||
this.tabID = id;
|
|
||||||
this.searchButton.classList.toggle('hide', this.tabID == 0);
|
|
||||||
this.deleteBtn.classList.toggle('hide', this.tabID != 0);
|
|
||||||
}, () => {
|
|
||||||
const tab = this.tabs[this.tabID];
|
const tab = this.tabs[this.tabID];
|
||||||
if(tab.init) {
|
if(tab.init) {
|
||||||
tab.init();
|
tab.init();
|
||||||
@ -156,10 +154,45 @@ export class EmoticonsDropdown {
|
|||||||
//appSidebarRight.stickersTab.init();
|
//appSidebarRight.stickersTab.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
(this.tabsEl.firstElementChild.children[1] as HTMLLIElement).click(); // set emoji tab
|
(this.tabsEl.children[1] as HTMLLIElement).click(); // set emoji tab
|
||||||
this.tabs[0].init(); // onTransitionEnd не вызовется, т.к. это первая открытая вкладка
|
this.tabs[0].init(); // onTransitionEnd не вызовется, т.к. это первая открытая вкладка
|
||||||
|
|
||||||
|
$rootScope.$on('peer_changed', this.checkRights);
|
||||||
|
this.checkRights();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onSelectTabClick = (id: number) => {
|
||||||
|
if(this.tabID == id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP);
|
||||||
|
|
||||||
|
this.tabID = id;
|
||||||
|
this.searchButton.classList.toggle('hide', this.tabID == 0);
|
||||||
|
this.deleteBtn.classList.toggle('hide', this.tabID != 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
public checkRights = () => {
|
||||||
|
const peerID = $rootScope.selectedPeerID;
|
||||||
|
const children = this.tabsEl.children;
|
||||||
|
const tabsElements = Array.from(children) as HTMLElement[];
|
||||||
|
|
||||||
|
const canSendStickers = peerID > 0 || appChatsManager.hasRights(peerID, 'send', 'send_stickers');
|
||||||
|
tabsElements[2].toggleAttribute('disabled', !canSendStickers);
|
||||||
|
|
||||||
|
const canSendGifs = peerID > 0 || appChatsManager.hasRights(peerID, 'send', 'send_gifs');
|
||||||
|
tabsElements[3].toggleAttribute('disabled', !canSendGifs);
|
||||||
|
|
||||||
|
const active = this.tabsEl.querySelector('.active');
|
||||||
|
if(active && whichChild(active) != 1 && (!canSendStickers || !canSendGifs)) {
|
||||||
|
this.selectTab(0);
|
||||||
|
this.onSelectTabClick(0);
|
||||||
|
active.classList.remove('active');
|
||||||
|
children[1].classList.add('active');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public toggle = async(enable?: boolean) => {
|
public toggle = async(enable?: boolean) => {
|
||||||
//if(!this.element) return;
|
//if(!this.element) return;
|
||||||
const willBeActive = (!!this.element.style.display && enable === undefined) || enable;
|
const willBeActive = (!!this.element.style.display && enable === undefined) || enable;
|
||||||
@ -241,7 +274,7 @@ export class EmoticonsDropdown {
|
|||||||
//animationIntersector.checkAnimations(false, EMOTICONSSTICKERGROUP);
|
//animationIntersector.checkAnimations(false, EMOTICONSSTICKERGROUP);
|
||||||
};
|
};
|
||||||
|
|
||||||
public static menuOnClick = (menu: HTMLUListElement, scroll: Scrollable, menuScroll?: ScrollableX) => {
|
public static menuOnClick = (menu: HTMLElement, scroll: Scrollable, menuScroll?: ScrollableX) => {
|
||||||
let prevId = 0;
|
let prevId = 0;
|
||||||
let jumpedTo = -1;
|
let jumpedTo = -1;
|
||||||
|
|
||||||
@ -284,7 +317,7 @@ export class EmoticonsDropdown {
|
|||||||
|
|
||||||
menu.addEventListener('click', (e) => {
|
menu.addEventListener('click', (e) => {
|
||||||
let target = e.target as HTMLElement;
|
let target = e.target as HTMLElement;
|
||||||
target = findUpTag(target, 'LI');
|
target = findUpClassName(target, 'menu-horizontal-div-item');
|
||||||
|
|
||||||
if(!target) {
|
if(!target) {
|
||||||
return;
|
return;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { EmoticonsTab, EmoticonsDropdown } from "..";
|
import { EmoticonsDropdown, EmoticonsTab } from "..";
|
||||||
import Scrollable from "../../scrollable";
|
|
||||||
import Config from "../../../lib/config";
|
|
||||||
import { putPreloader } from "../../misc";
|
|
||||||
import appStateManager from "../../../lib/appManagers/appStateManager";
|
|
||||||
import { RichTextProcessor } from "../../../lib/richtextprocessor";
|
|
||||||
import appImManager from "../../../lib/appManagers/appImManager";
|
import appImManager from "../../../lib/appManagers/appImManager";
|
||||||
|
import appStateManager from "../../../lib/appManagers/appStateManager";
|
||||||
|
import Config from "../../../lib/config";
|
||||||
|
import { RichTextProcessor } from "../../../lib/richtextprocessor";
|
||||||
|
import { putPreloader } from "../../misc";
|
||||||
|
import Scrollable from "../../scrollable";
|
||||||
import StickyIntersector from "../../stickyIntersector";
|
import StickyIntersector from "../../stickyIntersector";
|
||||||
|
|
||||||
export default class EmojiTab implements EmoticonsTab {
|
export default class EmojiTab implements EmoticonsTab {
|
||||||
@ -80,7 +80,7 @@ export default class EmojiTab implements EmoticonsTab {
|
|||||||
}
|
}
|
||||||
//console.timeEnd('emojiParse');
|
//console.timeEnd('emojiParse');
|
||||||
|
|
||||||
const menu = this.content.previousElementSibling.firstElementChild as HTMLUListElement;
|
const menu = this.content.previousElementSibling as HTMLElement;
|
||||||
const emojiScroll = this.scroll = new Scrollable(this.content, 'EMOJI', null);
|
const emojiScroll = this.scroll = new Scrollable(this.content, 'EMOJI', null);
|
||||||
|
|
||||||
//emojiScroll.setVirtualContainer(emojiScroll.container);
|
//emojiScroll.setVirtualContainer(emojiScroll.container);
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
import emoticonsDropdown, { EmoticonsTab, EMOTICONSSTICKERGROUP, EmoticonsDropdown } from "..";
|
import emoticonsDropdown, { EmoticonsDropdown, EMOTICONSSTICKERGROUP, EmoticonsTab } from "..";
|
||||||
import { StickerSet } from "../../../layer";
|
|
||||||
import Scrollable, { ScrollableX } from "../../scrollable";
|
|
||||||
import { wrapSticker } from "../../wrappers";
|
|
||||||
import appStickersManager from "../../../lib/appManagers/appStickersManager";
|
|
||||||
import appDownloadManager from "../../../lib/appManagers/appDownloadManager";
|
|
||||||
import { readBlobAsText } from "../../../helpers/blob";
|
import { readBlobAsText } from "../../../helpers/blob";
|
||||||
|
import mediaSizes from "../../../helpers/mediaSizes";
|
||||||
|
import { StickerSet } from "../../../layer";
|
||||||
|
import appDocsManager, { MyDocument } from "../../../lib/appManagers/appDocsManager";
|
||||||
|
import appDownloadManager from "../../../lib/appManagers/appDownloadManager";
|
||||||
|
import appStickersManager from "../../../lib/appManagers/appStickersManager";
|
||||||
import lottieLoader from "../../../lib/lottieLoader";
|
import lottieLoader from "../../../lib/lottieLoader";
|
||||||
import { renderImageFromUrl, putPreloader } from "../../misc";
|
import apiManager from "../../../lib/mtproto/mtprotoworker";
|
||||||
import { RichTextProcessor } from "../../../lib/richtextprocessor";
|
import { RichTextProcessor } from "../../../lib/richtextprocessor";
|
||||||
import $rootScope from "../../../lib/rootScope";
|
import $rootScope from "../../../lib/rootScope";
|
||||||
import apiManager from "../../../lib/mtproto/mtprotoworker";
|
|
||||||
import StickyIntersector from "../../stickyIntersector";
|
|
||||||
import appDocsManager, {MyDocument} from "../../../lib/appManagers/appDocsManager";
|
|
||||||
import animationIntersector from "../../animationIntersector";
|
import animationIntersector from "../../animationIntersector";
|
||||||
import { LazyLoadQueueRepeat } from "../../lazyLoadQueue";
|
import { LazyLoadQueueRepeat } from "../../lazyLoadQueue";
|
||||||
import mediaSizes from "../../../helpers/mediaSizes";
|
import { putPreloader, renderImageFromUrl } from "../../misc";
|
||||||
|
import Scrollable, { ScrollableX } from "../../scrollable";
|
||||||
|
import StickyIntersector from "../../stickyIntersector";
|
||||||
|
import { wrapSticker } from "../../wrappers";
|
||||||
|
|
||||||
export default class StickersTab implements EmoticonsTab {
|
export default class StickersTab implements EmoticonsTab {
|
||||||
public content: HTMLElement;
|
public content: HTMLElement;
|
||||||
@ -29,7 +29,7 @@ export default class StickersTab implements EmoticonsTab {
|
|||||||
|
|
||||||
private scroll: Scrollable;
|
private scroll: Scrollable;
|
||||||
|
|
||||||
private menu: HTMLUListElement;
|
private menu: HTMLElement;
|
||||||
|
|
||||||
private mounted = false;
|
private mounted = false;
|
||||||
|
|
||||||
@ -110,18 +110,18 @@ export default class StickersTab implements EmoticonsTab {
|
|||||||
const categoryDiv = document.createElement('div');
|
const categoryDiv = document.createElement('div');
|
||||||
categoryDiv.classList.add('sticker-category');
|
categoryDiv.classList.add('sticker-category');
|
||||||
|
|
||||||
const li = document.createElement('li');
|
const button = document.createElement('button');
|
||||||
li.classList.add('btn-icon');
|
button.classList.add('btn-icon', 'menu-horizontal-div-item');
|
||||||
|
|
||||||
this.stickerSets[set.id] = {
|
this.stickerSets[set.id] = {
|
||||||
stickers: categoryDiv,
|
stickers: categoryDiv,
|
||||||
tab: li
|
tab: button
|
||||||
};
|
};
|
||||||
|
|
||||||
if(prepend) {
|
if(prepend) {
|
||||||
this.menu.insertBefore(li, this.menu.firstElementChild.nextSibling);
|
this.menu.insertBefore(button, this.menu.firstElementChild.nextSibling);
|
||||||
} else {
|
} else {
|
||||||
this.menu.append(li);
|
this.menu.append(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
//stickersScroll.append(categoryDiv);
|
//stickersScroll.append(categoryDiv);
|
||||||
@ -142,7 +142,7 @@ export default class StickersTab implements EmoticonsTab {
|
|||||||
//.then(JSON.parse)
|
//.then(JSON.parse)
|
||||||
.then(json => {
|
.then(json => {
|
||||||
lottieLoader.loadAnimationWorker({
|
lottieLoader.loadAnimationWorker({
|
||||||
container: li,
|
container: button,
|
||||||
loop: true,
|
loop: true,
|
||||||
autoplay: false,
|
autoplay: false,
|
||||||
animationData: json,
|
animationData: json,
|
||||||
@ -155,14 +155,14 @@ export default class StickersTab implements EmoticonsTab {
|
|||||||
const image = new Image();
|
const image = new Image();
|
||||||
promise.then(blob => {
|
promise.then(blob => {
|
||||||
renderImageFromUrl(image, URL.createObjectURL(blob), () => {
|
renderImageFromUrl(image, URL.createObjectURL(blob), () => {
|
||||||
li.append(image);
|
button.append(image);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if(stickerSet.documents[0]._ != 'documentEmpty') { // as thumb will be used first sticker
|
} else if(stickerSet.documents[0]._ != 'documentEmpty') { // as thumb will be used first sticker
|
||||||
wrapSticker({
|
wrapSticker({
|
||||||
doc: stickerSet.documents[0],
|
doc: stickerSet.documents[0],
|
||||||
div: li as any,
|
div: button as any,
|
||||||
group: EMOTICONSSTICKERGROUP
|
group: EMOTICONSSTICKERGROUP
|
||||||
}); // kostil
|
}); // kostil
|
||||||
}
|
}
|
||||||
@ -230,7 +230,7 @@ export default class StickersTab implements EmoticonsTab {
|
|||||||
this.recentDiv.classList.add('sticker-category');
|
this.recentDiv.classList.add('sticker-category');
|
||||||
|
|
||||||
let menuWrapper = this.content.previousElementSibling as HTMLDivElement;
|
let menuWrapper = this.content.previousElementSibling as HTMLDivElement;
|
||||||
this.menu = menuWrapper.firstElementChild.firstElementChild as HTMLUListElement;
|
this.menu = menuWrapper.firstElementChild as HTMLUListElement;
|
||||||
|
|
||||||
let menuScroll = new ScrollableX(menuWrapper);
|
let menuScroll = new ScrollableX(menuWrapper);
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ export function horizontalMenu(tabs: HTMLElement, content: HTMLElement, onClick?
|
|||||||
if(tabs) {
|
if(tabs) {
|
||||||
const useStripe = !tabs.classList.contains('no-stripe');
|
const useStripe = !tabs.classList.contains('no-stripe');
|
||||||
|
|
||||||
const tagName = 'LI';//tabs.firstElementChild.tagName;
|
const tagName = tabs.classList.contains('menu-horizontal-div') ? 'BUTTON' : 'LI';//tabs.firstElementChild.tagName;
|
||||||
tabs.addEventListener('click', function(e) {
|
tabs.addEventListener('click', function(e) {
|
||||||
let target = e.target as HTMLElement;
|
let target = e.target as HTMLElement;
|
||||||
|
|
||||||
|
@ -179,7 +179,9 @@ export default class PopupCreatePoll extends PopupElement {
|
|||||||
};
|
};
|
||||||
//poll.id = randomIDS;
|
//poll.id = randomIDS;
|
||||||
|
|
||||||
const inputMediaPoll = appPollsManager.getInputMediaPoll(poll, this.correctAnswers, this.quizSolutionInput ? this.quizSolutionInput.value : undefined);
|
const inputMediaPoll = appPollsManager.getInputMediaPoll(poll, this.correctAnswers, this.quizSolutionInput.value || undefined);
|
||||||
|
|
||||||
|
//console.log('Will try to create poll:', inputMediaPoll);
|
||||||
|
|
||||||
appMessagesManager.sendOther($rootScope.selectedPeerID, inputMediaPoll);
|
appMessagesManager.sendOther($rootScope.selectedPeerID, inputMediaPoll);
|
||||||
};
|
};
|
||||||
|
@ -513,13 +513,7 @@
|
|||||||
<div class="input-message-container">
|
<div class="input-message-container">
|
||||||
<div id="input-message" contenteditable="true" data-placeholder="Message"></div>
|
<div id="input-message" contenteditable="true" data-placeholder="Message"></div>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn-icon rp tgico-attach btn-menu-toggle" id="attach-file">
|
<button class="btn-icon tgico-attach btn-menu-toggle" id="attach-file"></button>
|
||||||
<div class="btn-menu top-left">
|
|
||||||
<div class="btn-menu-item menu-media tgico-photo rp">Photo or Video</div>
|
|
||||||
<div class="btn-menu-item menu-document tgico-document rp">Document</div>
|
|
||||||
<div class="btn-menu-item menu-poll tgico-poll rp">Poll</div>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
<div class="record-time"></div>
|
<div class="record-time"></div>
|
||||||
<input type="file" id="input-file" style="display: none;" multiple />
|
<input type="file" id="input-file" style="display: none;" multiple />
|
||||||
</div>
|
</div>
|
||||||
@ -537,27 +531,23 @@
|
|||||||
<div class="emoji-container">
|
<div class="emoji-container">
|
||||||
<div class="tabs-container">
|
<div class="tabs-container">
|
||||||
<div class="emoji-padding">
|
<div class="emoji-padding">
|
||||||
<nav class="menu-horizontal">
|
<nav class="menu-horizontal-div no-stripe">
|
||||||
<ul>
|
<button class="menu-horizontal-div-item active btn-icon tgico-recent rp"></button>
|
||||||
<li class="active btn-icon tgico-recent rp"></li>
|
<button class="menu-horizontal-div-item btn-icon tgico-smile rp"></button>
|
||||||
<li class="btn-icon tgico-smile rp"></li>
|
<button class="menu-horizontal-div-item btn-icon tgico-animals rp"></button>
|
||||||
<li class="btn-icon tgico-animals rp"></li>
|
<button class="menu-horizontal-div-item btn-icon tgico-eats rp"></button>
|
||||||
<li class="btn-icon tgico-eats rp"></li>
|
<button class="menu-horizontal-div-item btn-icon tgico-car rp"></button>
|
||||||
<li class="btn-icon tgico-car rp"></li>
|
<button class="menu-horizontal-div-item btn-icon tgico-sport rp"></button>
|
||||||
<li class="btn-icon tgico-sport rp"></li>
|
<button class="menu-horizontal-div-item btn-icon tgico-lamp rp"></button>
|
||||||
<li class="btn-icon tgico-lamp rp"></li>
|
<!-- <button class="menu-horizontal-div-item btn-icon tgico-info rp"></button> -->
|
||||||
<!-- <li class="btn-icon tgico-info rp"></li> -->
|
<button class="menu-horizontal-div-item btn-icon tgico-flag rp"></button>
|
||||||
<li class="btn-icon tgico-flag rp"></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="emoticons-content" id="content-emoji"></div>
|
<div class="emoticons-content" id="content-emoji"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stickers-padding">
|
<div class="stickers-padding">
|
||||||
<div class="menu-wrapper">
|
<div class="menu-wrapper">
|
||||||
<nav class="menu-horizontal">
|
<nav class="menu-horizontal-div no-stripe justify-start">
|
||||||
<ul class="justify-start">
|
<button class="menu-horizontal-div-item btn-icon tgico-recent active"></button>
|
||||||
<li class="btn-icon tgico-recent active"></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
<div class="emoticons-content" id="content-stickers"></div>
|
<div class="emoticons-content" id="content-stickers"></div>
|
||||||
@ -569,15 +559,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<nav class="emoji-tabs menu-horizontal no-stripe">
|
<div class="emoji-tabs menu-horizontal-div no-stripe">
|
||||||
<ul>
|
<button class="menu-horizontal-div-item emoji-tabs-search justify-self-start btn-icon tgico-search rp" data-tab="-1"></button>
|
||||||
<li class="emoji-tabs-search justify-self-start btn-icon tgico-search rp" data-tab="-1"></li>
|
<button class="menu-horizontal-div-item emoji-tabs-emoji btn-icon tgico-smile rp" data-tab="0"></button>
|
||||||
<li class="emoji-tabs-emoji btn-icon tgico-smile rp" data-tab="0"></li>
|
<button class="menu-horizontal-div-item emoji-tabs-stickers btn-icon tgico-stickers rp" data-tab="1"></button>
|
||||||
<li class="emoji-tabs-stickers btn-icon tgico-stickers rp" data-tab="1"></li>
|
<button class="menu-horizontal-div-item emoji-tabs-gifs btn-icon tgico-gifs rp" data-tab="2"></button>
|
||||||
<li class="emoji-tabs-gifs btn-icon tgico-gifs rp" data-tab="2"></li>
|
<button class="menu-horizontal-div-item emoji-tabs-delete justify-self-end btn-icon tgico-deleteleft rp" data-tab="-1"></button>
|
||||||
<li class="emoji-tabs-delete justify-self-end btn-icon tgico-deleteleft rp" data-tab="-1"></li>
|
</div>
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { InputChannel, InputChatPhoto, InputPeer, Updates } from "../../layer";
|
import { ChatBannedRights, InputChannel, InputChatPhoto, InputPeer, Updates } from "../../layer";
|
||||||
import apiManager from '../mtproto/mtprotoworker';
|
import apiManager from '../mtproto/mtprotoworker';
|
||||||
import { RichTextProcessor } from "../richtextprocessor";
|
import { RichTextProcessor } from "../richtextprocessor";
|
||||||
import $rootScope from "../rootScope";
|
import $rootScope from "../rootScope";
|
||||||
@ -151,7 +151,7 @@ export class AppChatsManager {
|
|||||||
return this.chats[id] || {_: 'chatEmpty', id: id, deleted: true, access_hash: this.channelAccess[id]};
|
return this.chats[id] || {_: 'chatEmpty', id: id, deleted: true, access_hash: this.channelAccess[id]};
|
||||||
}
|
}
|
||||||
|
|
||||||
public hasRights(id: number, action: ChatRights) {
|
public hasRights(id: number, action: ChatRights, flag?: keyof ChatBannedRights['pFlags']) {
|
||||||
const chat = this.getChat(id);
|
const chat = this.getChat(id);
|
||||||
if(chat._ == 'chatEmpty') return false;
|
if(chat._ == 'chatEmpty') return false;
|
||||||
|
|
||||||
@ -171,12 +171,16 @@ export class AppChatsManager {
|
|||||||
switch(action) {
|
switch(action) {
|
||||||
// good
|
// good
|
||||||
case 'send': {
|
case 'send': {
|
||||||
if(chat._ == 'channel' &&
|
if(flag && myFlags[flag]) {
|
||||||
!chat.pFlags.megagroup &&
|
|
||||||
!myFlags.post_messages) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(chat._ == 'channel') {
|
||||||
|
if((!chat.pFlags.megagroup && !myFlags.post_messages)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import type { StickerSet } from "../layer";
|
import type { StickerSet } from "../layer";
|
||||||
import type { MyDocument } from "./appManagers/appDocsManager";
|
import type { MyDocument } from "./appManagers/appDocsManager";
|
||||||
import type { Poll, PollResults } from "./appManagers/appPollsManager";
|
|
||||||
import type { AppMessagesManager, Dialog, MyDialogFilter } from "./appManagers/appMessagesManager";
|
import type { AppMessagesManager, Dialog, MyDialogFilter } from "./appManagers/appMessagesManager";
|
||||||
|
import type { Poll, PollResults } from "./appManagers/appPollsManager";
|
||||||
import { MOUNT_CLASS_TO } from "./mtproto/mtproto_config";
|
import { MOUNT_CLASS_TO } from "./mtproto/mtproto_config";
|
||||||
|
|
||||||
type BroadcastEvents = {
|
type BroadcastEvents = {
|
||||||
'user_update': number,
|
'user_update': number,
|
||||||
'user_auth': {dcID?: number, id: number},
|
'user_auth': {dcID?: number, id: number},
|
||||||
'peer_changed': number,
|
'peer_changed': number,
|
||||||
|
'peer_pinned_message': number,
|
||||||
|
|
||||||
'filter_delete': MyDialogFilter,
|
'filter_delete': MyDialogFilter,
|
||||||
'filter_update': MyDialogFilter,
|
'filter_update': MyDialogFilter,
|
||||||
@ -48,7 +49,6 @@ type BroadcastEvents = {
|
|||||||
//'contacts_update': any,
|
//'contacts_update': any,
|
||||||
'avatar_update': number,
|
'avatar_update': number,
|
||||||
'chat_full_update': number,
|
'chat_full_update': number,
|
||||||
'peer_pinned_message': number,
|
|
||||||
'poll_update': {poll: Poll, results: PollResults},
|
'poll_update': {poll: Poll, results: PollResults},
|
||||||
'chat_update': number,
|
'chat_update': number,
|
||||||
'stateSynchronized': void,
|
'stateSynchronized': void,
|
||||||
|
@ -342,7 +342,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-icon {
|
.btn-icon {
|
||||||
transition: .2s color, background-color .2s;
|
transition: .2s color, background-color .2s, .2s opacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
#btn-record-cancel, #btn-send {
|
#btn-record-cancel, #btn-send {
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
margin-left: -.5rem;
|
margin-left: -.5rem;
|
||||||
} */
|
} */
|
||||||
|
|
||||||
> .menu-horizontal {
|
> .menu-horizontal-div {
|
||||||
//font-weight: 500;
|
//font-weight: 500;
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
border: none;
|
border: none;
|
||||||
@ -52,9 +52,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.emoji-tabs {
|
.emoji-tabs {
|
||||||
ul {
|
justify-content: center;
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-search {
|
&-search {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -113,7 +111,7 @@
|
|||||||
|
|
||||||
.emoji-padding.active {
|
.emoji-padding.active {
|
||||||
@include respond-to(handhelds) {
|
@include respond-to(handhelds) {
|
||||||
.menu-horizontal li {
|
.menu-horizontal-div .menu-horizontal-div-item {
|
||||||
flex: unset;
|
flex: unset;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
@ -143,7 +141,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.emoji-padding, .stickers-padding {
|
.emoji-padding, .stickers-padding {
|
||||||
.menu-horizontal {
|
.menu-horizontal-div {
|
||||||
height: 48px;
|
height: 48px;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
@ -151,7 +149,7 @@
|
|||||||
box-shadow: 0px 1px 5px -1px rgba(0, 0, 0, 0.21);
|
box-shadow: 0px 1px 5px -1px rgba(0, 0, 0, 0.21);
|
||||||
z-index: 4;
|
z-index: 4;
|
||||||
|
|
||||||
li {
|
.menu-horizontal-div-item {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -248,12 +246,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-horizontal {
|
|
||||||
li {
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#content-stickers {
|
#content-stickers {
|
||||||
.scrollable {
|
.scrollable {
|
||||||
@ -261,12 +253,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-horizontal {
|
.menu-horizontal-div {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
box-shadow: 0px -2px 5px -1px rgba(0, 0, 0, .21);
|
box-shadow: 0px -2px 5px -1px rgba(0, 0, 0, .21);
|
||||||
|
|
||||||
li {
|
.menu-horizontal-div-item {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
margin: 0 12px;
|
margin: 0 12px;
|
||||||
width: 48px;
|
width: 48px;
|
||||||
@ -285,10 +277,10 @@
|
|||||||
box-shadow: 0px 1px 5px -1px rgba(0, 0, 0, .21);
|
box-shadow: 0px 1px 5px -1px rgba(0, 0, 0, .21);
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-horizontal {
|
.menu-horizontal-div {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
|
||||||
& li {
|
.menu-horizontal-div-item {
|
||||||
height: 48px;
|
height: 48px;
|
||||||
width: 48px;
|
width: 48px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@ -305,7 +297,7 @@
|
|||||||
//border-top: 1px solid $lightgrey;
|
//border-top: 1px solid $lightgrey;
|
||||||
}
|
}
|
||||||
|
|
||||||
li {
|
.menu-horizontal-div-item {
|
||||||
/* width: calc(100% / 7); */
|
/* width: calc(100% / 7); */
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
|
||||||
|
@ -1,5 +1,80 @@
|
|||||||
$slider-time: .25s;
|
$slider-time: .25s;
|
||||||
|
|
||||||
|
.menu-horizontal-div {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
color: $color-gray;
|
||||||
|
border-bottom: 1px solid $lightgrey;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&-item {
|
||||||
|
display: inline-block;
|
||||||
|
padding: .75rem 1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
//flex: 0 0 auto;
|
||||||
|
//overflow: hidden;
|
||||||
|
user-select: none;
|
||||||
|
// font-size: 1rem;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
position: relative;
|
||||||
|
border-top-left-radius: 6px;
|
||||||
|
border-top-right-radius: 6px;
|
||||||
|
|
||||||
|
html.no-touch & {
|
||||||
|
background-color: transparent;
|
||||||
|
transition: background-color .15s ease-in-out;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--color-gray-hover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> span {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: $color-blue;
|
||||||
|
|
||||||
|
i {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
position: absolute;
|
||||||
|
bottom: calc(-.625rem - 2px);
|
||||||
|
left: 0;
|
||||||
|
opacity: 0;
|
||||||
|
background-color: $color-blue;
|
||||||
|
height: .1875rem;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: .1875rem .1875rem 0 0;
|
||||||
|
pointer-events: none;
|
||||||
|
padding-right: .5rem;
|
||||||
|
margin-left: -.25rem;
|
||||||
|
box-sizing: content-box;
|
||||||
|
transform-origin: left;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
&.animate {
|
||||||
|
transition: transform $slider-time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.menu-horizontal {
|
.menu-horizontal {
|
||||||
color: $color-gray;
|
color: $color-gray;
|
||||||
border-bottom: 1px solid $lightgrey;
|
border-bottom: 1px solid $lightgrey;
|
||||||
|
@ -302,7 +302,7 @@ input, textarea {
|
|||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
line-height: 1.5rem;
|
line-height: 1.5rem;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
transition: background-color .15s ease-in-out;
|
transition: background-color .15s ease-in-out, opacity .15s ease-in-out;
|
||||||
color: $color-gray;
|
color: $color-gray;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
@ -323,6 +323,11 @@ input, textarea {
|
|||||||
html.no-touch &:hover {
|
html.no-touch &:hover {
|
||||||
background-color: var(--color-gray-hover);
|
background-color: var(--color-gray-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
pointer-events: none !important;
|
||||||
|
opacity: .25;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-icon:disabled {
|
.btn-icon:disabled {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user