New input field:
Support emoji Support RTL Support cyrillic
This commit is contained in:
parent
b8e3ce1e4d
commit
a885492a09
@ -11,7 +11,7 @@ import apiManager from "../../lib/mtproto/mtprotoworker";
|
|||||||
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 $rootScope from '../../lib/rootScope';
|
||||||
import { cancelEvent, findUpClassName, getRichValue } from "../../helpers/dom";
|
import { cancelEvent, findUpClassName, getRichValue, isInputEmpty, serializeNodes } from "../../helpers/dom";
|
||||||
import ButtonMenu, { ButtonMenuItemOptions } from '../buttonMenu';
|
import ButtonMenu, { ButtonMenuItemOptions } from '../buttonMenu';
|
||||||
import emoticonsDropdown from "../emoticonsDropdown";
|
import emoticonsDropdown from "../emoticonsDropdown";
|
||||||
import PopupCreatePoll from "../popupCreatePoll";
|
import PopupCreatePoll from "../popupCreatePoll";
|
||||||
@ -21,7 +21,7 @@ import { ripple } from '../ripple';
|
|||||||
import Scrollable from "../scrollable";
|
import Scrollable from "../scrollable";
|
||||||
import { toast } from "../toast";
|
import { toast } from "../toast";
|
||||||
import { wrapReply } from "../wrappers";
|
import { wrapReply } from "../wrappers";
|
||||||
import { checkRTL } from '../../helpers/string';
|
import InputField from '../inputField';
|
||||||
|
|
||||||
const RECORD_MIN_TIME = 500;
|
const RECORD_MIN_TIME = 500;
|
||||||
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
|
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
|
||||||
@ -30,7 +30,7 @@ type ChatInputHelperType = 'edit' | 'webpage' | 'forward' | 'reply';
|
|||||||
|
|
||||||
export class ChatInput {
|
export class ChatInput {
|
||||||
public pageEl = document.getElementById('page-chats') as HTMLDivElement;
|
public pageEl = document.getElementById('page-chats') as HTMLDivElement;
|
||||||
public messageInput = document.getElementById('input-message') as HTMLDivElement/* HTMLInputElement */;
|
public messageInput: HTMLDivElement/* HTMLInputElement */;
|
||||||
public fileInput = document.getElementById('input-file') as HTMLInputElement;
|
public fileInput = document.getElementById('input-file') as HTMLInputElement;
|
||||||
public inputMessageContainer = document.getElementsByClassName('input-message-container')[0] as HTMLDivElement;
|
public inputMessageContainer = document.getElementsByClassName('input-message-container')[0] as HTMLDivElement;
|
||||||
public inputScroll = new Scrollable(this.inputMessageContainer);
|
public inputScroll = new Scrollable(this.inputMessageContainer);
|
||||||
@ -73,6 +73,15 @@ export class ChatInput {
|
|||||||
private helperFunc: () => void;
|
private helperFunc: () => void;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
const messageInputField = InputField({
|
||||||
|
placeholder: 'Message',
|
||||||
|
name: 'message'
|
||||||
|
});
|
||||||
|
|
||||||
|
messageInputField.input.className = '';
|
||||||
|
this.inputScroll.container.append(messageInputField.input);
|
||||||
|
this.messageInput = messageInputField.input;
|
||||||
|
|
||||||
this.attachMenu = document.getElementById('attach-file') as HTMLButtonElement;
|
this.attachMenu = document.getElementById('attach-file') as HTMLButtonElement;
|
||||||
|
|
||||||
let willAttachType: 'document' | 'media';
|
let willAttachType: 'document' | 'media';
|
||||||
@ -183,8 +192,6 @@ export class ChatInput {
|
|||||||
|
|
||||||
this.messageInput.addEventListener('input', (e) => {
|
this.messageInput.addEventListener('input', (e) => {
|
||||||
//console.log('messageInput input', this.messageInput.innerText, this.serializeNodes(Array.from(this.messageInput.childNodes)));
|
//console.log('messageInput input', this.messageInput.innerText, this.serializeNodes(Array.from(this.messageInput.childNodes)));
|
||||||
this.setDirection();
|
|
||||||
|
|
||||||
const value = this.messageInput.innerText;
|
const value = this.messageInput.innerText;
|
||||||
|
|
||||||
const entities = RichTextProcessor.parseEntities(value);
|
const entities = RichTextProcessor.parseEntities(value);
|
||||||
@ -217,7 +224,7 @@ export class ChatInput {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!value.trim() && !this.serializeNodes(Array.from(this.messageInput.childNodes)).trim()) {
|
if(!value.trim() && !serializeNodes(Array.from(this.messageInput.childNodes)).trim()) {
|
||||||
this.messageInput.innerHTML = '';
|
this.messageInput.innerHTML = '';
|
||||||
|
|
||||||
appMessagesManager.setTyping($rootScope.selectedPeerID, 'sendMessageCancelAction');
|
appMessagesManager.setTyping($rootScope.selectedPeerID, 'sendMessageCancelAction');
|
||||||
@ -232,7 +239,7 @@ export class ChatInput {
|
|||||||
this.updateSendBtn();
|
this.updateSendBtn();
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!RichTextProcessor.emojiSupported) {
|
/* if(!RichTextProcessor.emojiSupported) {
|
||||||
this.messageInput.addEventListener('copy', (e) => {
|
this.messageInput.addEventListener('copy', (e) => {
|
||||||
const selection = document.getSelection();
|
const selection = document.getSelection();
|
||||||
|
|
||||||
@ -243,7 +250,7 @@ export class ChatInput {
|
|||||||
|
|
||||||
let selectedNodes = Array.from(ancestorContainer.childNodes).slice(range.startOffset, range.endOffset);
|
let selectedNodes = Array.from(ancestorContainer.childNodes).slice(range.startOffset, range.endOffset);
|
||||||
if(selectedNodes.length) {
|
if(selectedNodes.length) {
|
||||||
str = this.serializeNodes(selectedNodes);
|
str = serializeNodes(selectedNodes);
|
||||||
} else {
|
} else {
|
||||||
str = selection.toString();
|
str = selection.toString();
|
||||||
}
|
}
|
||||||
@ -257,30 +264,7 @@ export class ChatInput {
|
|||||||
event.clipboardData.setData('text/plain', str);
|
event.clipboardData.setData('text/plain', str);
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
});
|
});
|
||||||
}
|
} */
|
||||||
|
|
||||||
this.messageInput.addEventListener('paste', (e) => {
|
|
||||||
//console.log('messageInput paste');
|
|
||||||
|
|
||||||
e.preventDefault();
|
|
||||||
// @ts-ignore
|
|
||||||
let text = (e.originalEvent || e).clipboardData.getData('text/plain');
|
|
||||||
|
|
||||||
let entities = RichTextProcessor.parseEntities(text);
|
|
||||||
//console.log('messageInput paste', text, entities);
|
|
||||||
entities = entities.filter(e => e._ == 'messageEntityEmoji' || e._ == 'messageEntityLinebreak');
|
|
||||||
//text = RichTextProcessor.wrapEmojiText(text);
|
|
||||||
text = RichTextProcessor.wrapRichText(text, {entities, noLinks: true});
|
|
||||||
|
|
||||||
// console.log('messageInput paste after', text);
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
//let html = (e.originalEvent || e).clipboardData.getData('text/html');
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
//console.log('paste text', text, );
|
|
||||||
window.document.execCommand('insertHTML', false, text);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.fileInput.addEventListener('change', (e) => {
|
this.fileInput.addEventListener('change', (e) => {
|
||||||
let files = (e.target as HTMLInputElement & EventTarget).files;
|
let files = (e.target as HTMLInputElement & EventTarget).files;
|
||||||
@ -292,7 +276,7 @@ export class ChatInput {
|
|||||||
this.fileInput.value = '';
|
this.fileInput.value = '';
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
document.addEventListener('paste', (event) => {
|
document.addEventListener('paste', (e) => {
|
||||||
const peerID = $rootScope.selectedPeerID;
|
const peerID = $rootScope.selectedPeerID;
|
||||||
if(!peerID || $rootScope.overlayIsActive || (peerID < 0 && !appChatsManager.hasRights(peerID, 'send', 'send_media'))) {
|
if(!peerID || $rootScope.overlayIsActive || (peerID < 0 && !appChatsManager.hasRights(peerID, 'send', 'send_media'))) {
|
||||||
return;
|
return;
|
||||||
@ -301,13 +285,15 @@ export class ChatInput {
|
|||||||
//console.log('document paste');
|
//console.log('document paste');
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
|
const items = (e.clipboardData || e.originalEvent.clipboardData).items;
|
||||||
//console.log('item', event.clipboardData.getData());
|
//console.log('item', event.clipboardData.getData());
|
||||||
|
let foundFile = false;
|
||||||
for(let i = 0; i < items.length; ++i) {
|
for(let i = 0; i < items.length; ++i) {
|
||||||
if(items[i].kind == 'file') {
|
if(items[i].kind == 'file') {
|
||||||
event.preventDefault()
|
e.preventDefault()
|
||||||
event.cancelBubble = true;
|
e.cancelBubble = true;
|
||||||
event.stopPropagation();
|
e.stopPropagation();
|
||||||
|
foundFile = true;
|
||||||
|
|
||||||
let file = items[i].getAsFile();
|
let file = items[i].getAsFile();
|
||||||
//console.log(items[i], file);
|
//console.log(items[i], file);
|
||||||
@ -541,10 +527,8 @@ export class ChatInput {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private isInputEmpty() {
|
public isInputEmpty() {
|
||||||
let value = this.messageInput.innerText;
|
return isInputEmpty(this.messageInput);
|
||||||
|
|
||||||
return !value.trim() && !this.serializeNodes(Array.from(this.messageInput.childNodes)).trim();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateSendBtn() {
|
public updateSendBtn() {
|
||||||
@ -556,18 +540,6 @@ export class ChatInput {
|
|||||||
this.btnSend.classList.toggle('send', icon == 'send');
|
this.btnSend.classList.toggle('send', icon == 'send');
|
||||||
this.btnSend.classList.toggle('record', icon == 'record');
|
this.btnSend.classList.toggle('record', icon == 'record');
|
||||||
}
|
}
|
||||||
|
|
||||||
public serializeNodes(nodes: Node[]): string {
|
|
||||||
return nodes.reduce((str, child: any) => {
|
|
||||||
//console.log('childNode', str, child, typeof(child), typeof(child) === 'string', child.innerText);
|
|
||||||
|
|
||||||
if(typeof(child) === 'object' && child.textContent) return str += child.textContent;
|
|
||||||
if(child.innerText) return str += child.innerText;
|
|
||||||
if(child.tagName == 'IMG' && child.classList && child.classList.contains('emoji')) return str += child.getAttribute('alt');
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}, '');
|
|
||||||
};
|
|
||||||
|
|
||||||
public onMessageSent(clearInput = true, clearReply?: boolean) {
|
public onMessageSent(clearInput = true, clearReply?: boolean) {
|
||||||
let dialog = appMessagesManager.getDialogByPeerID(appImManager.peerID)[0];
|
let dialog = appMessagesManager.getDialogByPeerID(appImManager.peerID)[0];
|
||||||
@ -587,17 +559,6 @@ export class ChatInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.updateSendBtn();
|
this.updateSendBtn();
|
||||||
this.setDirection();
|
|
||||||
}
|
|
||||||
|
|
||||||
public setDirection() {
|
|
||||||
const char = this.messageInput.innerText[0];
|
|
||||||
let direction = 'ltr';
|
|
||||||
if(char && checkRTL(char)) {
|
|
||||||
direction = 'rtl';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.messageInput.style.direction = direction;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public sendMessage() {
|
public sendMessage() {
|
||||||
@ -708,7 +669,6 @@ export class ChatInput {
|
|||||||
this.editMsgID = 0;
|
this.editMsgID = 0;
|
||||||
this.helperType = this.helperFunc = undefined;
|
this.helperType = this.helperFunc = undefined;
|
||||||
this.chatInput.parentElement.classList.remove('is-helper-active');
|
this.chatInput.parentElement.classList.remove('is-helper-active');
|
||||||
this.setDirection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public setTopInfo(type: ChatInputHelperType, callerFunc: () => void, title = '', subtitle = '', input?: string, message?: any) {
|
public setTopInfo(type: ChatInputHelperType, callerFunc: () => void, title = '', subtitle = '', input?: string, message?: any) {
|
||||||
@ -735,7 +695,6 @@ export class ChatInput {
|
|||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.updateSendBtn();
|
this.updateSendBtn();
|
||||||
this.setDirection();
|
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,33 +1,119 @@
|
|||||||
const InputField = (placeholder: string, label: string, name: string, maxLength?: number, showLengthOn: number = maxLength ? maxLength / 3 : 0) => {
|
import { getRichValue, isInputEmpty } from "../helpers/dom";
|
||||||
|
import { checkRTL } from "../helpers/string";
|
||||||
|
import RichTextProcessor from "../lib/richtextprocessor";
|
||||||
|
|
||||||
|
let init = () => {
|
||||||
|
document.addEventListener('paste', (e) => {
|
||||||
|
if(!(e.target as HTMLElement).hasAttribute('contenteditable') && !(e.target as HTMLElement).parentElement.hasAttribute('contenteditable')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//console.log('document paste');
|
||||||
|
|
||||||
|
//console.log('messageInput paste');
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
// @ts-ignore
|
||||||
|
let text = (e.originalEvent || e).clipboardData.getData('text/plain');
|
||||||
|
|
||||||
|
let entities = RichTextProcessor.parseEntities(text);
|
||||||
|
//console.log('messageInput paste', text, entities);
|
||||||
|
entities = entities.filter(e => e._ == 'messageEntityEmoji' || e._ == 'messageEntityLinebreak');
|
||||||
|
//text = RichTextProcessor.wrapEmojiText(text);
|
||||||
|
text = RichTextProcessor.wrapRichText(text, {entities, noLinks: true});
|
||||||
|
|
||||||
|
// console.log('messageInput paste after', text);
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
//let html = (e.originalEvent || e).clipboardData.getData('text/html');
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
//console.log('paste text', text, );
|
||||||
|
window.document.execCommand('insertHTML', false, text);
|
||||||
|
});
|
||||||
|
|
||||||
|
init = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const InputField = (options: {
|
||||||
|
placeholder?: string,
|
||||||
|
label?: string,
|
||||||
|
name: string,
|
||||||
|
maxLength?: number,
|
||||||
|
showLengthOn?: number,
|
||||||
|
plainText?: true
|
||||||
|
}) => {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.classList.add('input-field');
|
div.classList.add('input-field');
|
||||||
|
|
||||||
div.innerHTML = `
|
if(options.maxLength) {
|
||||||
<input type="text" name="${name}" id="input-${name}" placeholder="${placeholder}" autocomplete="off" required="">
|
options.showLengthOn = Math.round(options.maxLength / 3);
|
||||||
<label for="input-${name}">${label}</label>
|
}
|
||||||
`;
|
|
||||||
|
|
||||||
|
const {placeholder, label, maxLength, showLengthOn, name, plainText} = options;
|
||||||
|
|
||||||
|
if(!plainText) {
|
||||||
|
if(init) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
div.innerHTML = `
|
||||||
|
<div id="input-${name}" ${placeholder ? `data-placeholder="${placeholder}"` : ''} contenteditable="true" class="input-field-input"></div>
|
||||||
|
${label ? `<label for="input-${name}">${label}</label>` : ''}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const input = div.firstElementChild as HTMLElement;
|
||||||
|
const observer = new MutationObserver((mutationsList, observer) => {
|
||||||
|
const isEmpty = isInputEmpty(input);
|
||||||
|
console.log('input', isEmpty);
|
||||||
|
|
||||||
|
const char = input.innerText[0];
|
||||||
|
let direction = 'ltr';
|
||||||
|
if(char && checkRTL(char)) {
|
||||||
|
direction = 'rtl';
|
||||||
|
}
|
||||||
|
|
||||||
|
input.style.direction = direction;
|
||||||
|
|
||||||
|
if(processInput) {
|
||||||
|
processInput();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ! childList for paste first symbol
|
||||||
|
observer.observe(input, {characterData: true, childList: true, subtree: true});
|
||||||
|
} else {
|
||||||
|
div.innerHTML = `
|
||||||
|
<input type="text" name="${name}" id="input-${name}" ${placeholder ? `placeholder="${placeholder}"` : ''} autocomplete="off" required="" class="input-field-input">
|
||||||
|
${label ? `<label for="input-${name}">${label}</label>` : ''}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
let processInput: () => void;
|
||||||
if(maxLength) {
|
if(maxLength) {
|
||||||
const input = div.firstElementChild as HTMLInputElement;
|
const input = div.firstElementChild as HTMLInputElement;
|
||||||
const labelEl = div.lastElementChild as HTMLLabelElement;
|
const labelEl = div.lastElementChild as HTMLLabelElement;
|
||||||
let showingLength = false;
|
let showingLength = false;
|
||||||
input.addEventListener('input', (e) => {
|
|
||||||
|
processInput = () => {
|
||||||
const wasError = input.classList.contains('error');
|
const wasError = input.classList.contains('error');
|
||||||
const diff = maxLength - input.value.length;
|
const inputLength = plainText ? input.value.length : getRichValue(input).length;
|
||||||
|
const diff = maxLength - inputLength;
|
||||||
const isError = diff < 0;
|
const isError = diff < 0;
|
||||||
input.classList.toggle('error', isError);
|
input.classList.toggle('error', isError);
|
||||||
|
|
||||||
if(isError || diff <= showLengthOn) {
|
if(isError || diff <= showLengthOn) {
|
||||||
labelEl.innerText = label + ` (${maxLength - input.value.length})`;
|
labelEl.innerText = label + ` (${maxLength - inputLength})`;
|
||||||
if(!showingLength) showingLength = true;
|
if(!showingLength) showingLength = true;
|
||||||
} else if((wasError && !isError) || showingLength) {
|
} else if((wasError && !isError) || showingLength) {
|
||||||
labelEl.innerText = label;
|
labelEl.innerText = label;
|
||||||
showingLength = false;
|
showingLength = false;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
input.addEventListener('input', processInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
return div;
|
return {container: div, input: div.firstElementChild as HTMLInputElement};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default InputField;
|
export default InputField;
|
@ -2,7 +2,7 @@ import appMessagesManager from "../lib/appManagers/appMessagesManager";
|
|||||||
import appPeersManager from "../lib/appManagers/appPeersManager";
|
import appPeersManager from "../lib/appManagers/appPeersManager";
|
||||||
import appPollsManager, { Poll } from "../lib/appManagers/appPollsManager";
|
import appPollsManager, { Poll } from "../lib/appManagers/appPollsManager";
|
||||||
import $rootScope from "../lib/rootScope";
|
import $rootScope from "../lib/rootScope";
|
||||||
import { findUpTag, whichChild } from "../helpers/dom";
|
import { cancelEvent, findUpTag, getRichValue, isInputEmpty, whichChild } from "../helpers/dom";
|
||||||
import CheckboxField from "./checkbox";
|
import CheckboxField from "./checkbox";
|
||||||
import InputField from "./inputField";
|
import InputField from "./inputField";
|
||||||
import { PopupElement } from "./popup";
|
import { PopupElement } from "./popup";
|
||||||
@ -32,10 +32,15 @@ export default class PopupCreatePoll extends PopupElement {
|
|||||||
|
|
||||||
this.title.innerText = 'New Poll';
|
this.title.innerText = 'New Poll';
|
||||||
|
|
||||||
const questionField = InputField('Ask a Question', 'Ask a Question', 'question', MAX_LENGTH_QUESTION);
|
const questionField = InputField({
|
||||||
this.questionInput = questionField.firstElementChild as HTMLInputElement;
|
placeholder: 'Ask a Question',
|
||||||
|
label: 'Ask a Question',
|
||||||
|
name: 'question',
|
||||||
|
maxLength: MAX_LENGTH_QUESTION
|
||||||
|
});
|
||||||
|
this.questionInput = questionField.input;
|
||||||
|
|
||||||
this.header.append(questionField);
|
this.header.append(questionField.container);
|
||||||
|
|
||||||
const hr = document.createElement('hr');
|
const hr = document.createElement('hr');
|
||||||
const d = document.createElement('div');
|
const d = document.createElement('div');
|
||||||
@ -93,14 +98,19 @@ export default class PopupCreatePoll extends PopupElement {
|
|||||||
const quizSolutionContainer = document.createElement('div');
|
const quizSolutionContainer = document.createElement('div');
|
||||||
quizSolutionContainer.classList.add('poll-create-questions');
|
quizSolutionContainer.classList.add('poll-create-questions');
|
||||||
|
|
||||||
const quizSolutionField = InputField('Add a Comment (Optional)', 'Add a Comment (Optional)', 'solution', MAX_LENGTH_SOLUTION);
|
const quizSolutionField = InputField({
|
||||||
this.quizSolutionInput = quizSolutionField.firstElementChild as HTMLInputElement;
|
placeholder: 'Add a Comment (Optional)',
|
||||||
|
label: 'Add a Comment (Optional)',
|
||||||
|
name: 'solution',
|
||||||
|
maxLength: MAX_LENGTH_SOLUTION
|
||||||
|
});
|
||||||
|
this.quizSolutionInput = quizSolutionField.input;
|
||||||
|
|
||||||
const quizSolutionSubtitle = document.createElement('div');
|
const quizSolutionSubtitle = document.createElement('div');
|
||||||
quizSolutionSubtitle.classList.add('subtitle');
|
quizSolutionSubtitle.classList.add('subtitle');
|
||||||
quizSolutionSubtitle.innerText = 'Users will see this comment after choosing a wrong answer, good for educational purposes.';
|
quizSolutionSubtitle.innerText = 'Users will see this comment after choosing a wrong answer, good for educational purposes.';
|
||||||
|
|
||||||
quizSolutionContainer.append(quizSolutionField, quizSolutionSubtitle);
|
quizSolutionContainer.append(quizSolutionField.container, quizSolutionSubtitle);
|
||||||
|
|
||||||
quizElements.push(quizHr, quizSolutionCaption, quizSolutionContainer);
|
quizElements.push(quizHr, quizSolutionCaption, quizSolutionContainer);
|
||||||
quizElements.forEach(el => el.classList.add('hide'));
|
quizElements.forEach(el => el.classList.add('hide'));
|
||||||
@ -120,15 +130,15 @@ export default class PopupCreatePoll extends PopupElement {
|
|||||||
|
|
||||||
private getFilledAnswers() {
|
private getFilledAnswers() {
|
||||||
const answers = Array.from(this.questions.children).map((el, idx) => {
|
const answers = Array.from(this.questions.children).map((el, idx) => {
|
||||||
const input = el.querySelector('input[type="text"]') as HTMLInputElement;
|
const input = el.querySelector('.input-field-input');
|
||||||
return input.value;
|
return getRichValue(input);
|
||||||
}).filter(v => !!v.trim());
|
}).filter(v => !!v.trim());
|
||||||
|
|
||||||
return answers;
|
return answers;
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmitClick = (e: MouseEvent) => {
|
onSubmitClick = (e: MouseEvent) => {
|
||||||
const question = this.questionInput.value.trim();
|
const question = getRichValue(this.questionInput);
|
||||||
|
|
||||||
if(!question) {
|
if(!question) {
|
||||||
toast('Please enter a question.');
|
toast('Please enter a question.');
|
||||||
@ -158,7 +168,7 @@ export default class PopupCreatePoll extends PopupElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const quizSolution = this.quizSolutionInput.value.trim() || undefined;
|
const quizSolution = getRichValue(this.quizSolutionInput) || undefined;
|
||||||
if(quizSolution?.length > MAX_LENGTH_SOLUTION) {
|
if(quizSolution?.length > MAX_LENGTH_SOLUTION) {
|
||||||
toast('Explanation is too long.');
|
toast('Explanation is too long.');
|
||||||
return;
|
return;
|
||||||
@ -210,14 +220,15 @@ export default class PopupCreatePoll extends PopupElement {
|
|||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
|
|
||||||
const radioLabel = findUpTag(target, 'LABEL');
|
const radioLabel = findUpTag(target, 'LABEL');
|
||||||
if(target.value.length) {
|
const isEmpty = isInputEmpty(target);
|
||||||
|
if(!isEmpty) {
|
||||||
target.parentElement.classList.add('is-filled');
|
target.parentElement.classList.add('is-filled');
|
||||||
radioLabel.classList.remove('hidden-widget');
|
radioLabel.classList.remove('hidden-widget');
|
||||||
radioLabel.firstElementChild.removeAttribute('disabled');
|
radioLabel.firstElementChild.removeAttribute('disabled');
|
||||||
}
|
}
|
||||||
|
|
||||||
const isLast = !radioLabel.nextElementSibling;
|
const isLast = !radioLabel.nextElementSibling;
|
||||||
if(isLast && target.value.length && this.questions.childElementCount < 10) {
|
if(isLast && !isEmpty && this.questions.childElementCount < 10) {
|
||||||
this.appendMoreField();
|
this.appendMoreField();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -235,11 +246,17 @@ export default class PopupCreatePoll extends PopupElement {
|
|||||||
private appendMoreField() {
|
private appendMoreField() {
|
||||||
const tempID = this.tempID++;
|
const tempID = this.tempID++;
|
||||||
const idx = this.questions.childElementCount + 1;
|
const idx = this.questions.childElementCount + 1;
|
||||||
const questionField = InputField('Add an Option', 'Option ' + idx, 'question-' + tempID, MAX_LENGTH_OPTION);
|
const questionField = InputField({
|
||||||
(questionField.firstElementChild as HTMLInputElement).addEventListener('input', this.onInput);
|
placeholder: 'Add an Option',
|
||||||
|
label: 'Option ' + idx,
|
||||||
|
name: 'question-' + tempID,
|
||||||
|
maxLength: MAX_LENGTH_OPTION
|
||||||
|
});
|
||||||
|
questionField.input.addEventListener('input', this.onInput);
|
||||||
|
|
||||||
const radioField = RadioField('', 'question');
|
const radioField = RadioField('', 'question');
|
||||||
radioField.main.append(questionField);
|
radioField.main.append(questionField.container);
|
||||||
|
radioField.main.addEventListener('click', cancelEvent);
|
||||||
radioField.label.classList.add('hidden-widget');
|
radioField.label.classList.add('hidden-widget');
|
||||||
radioField.input.disabled = true;
|
radioField.input.disabled = true;
|
||||||
if(!this.quizCheckboxField.input.checked) {
|
if(!this.quizCheckboxField.input.checked) {
|
||||||
@ -255,7 +272,7 @@ export default class PopupCreatePoll extends PopupElement {
|
|||||||
|
|
||||||
const deleteBtn = document.createElement('span');
|
const deleteBtn = document.createElement('span');
|
||||||
deleteBtn.classList.add('btn-icon', 'tgico-close');
|
deleteBtn.classList.add('btn-icon', 'tgico-close');
|
||||||
questionField.append(deleteBtn);
|
questionField.container.append(deleteBtn);
|
||||||
|
|
||||||
deleteBtn.addEventListener('click', this.onDeleteClick, {once: true});
|
deleteBtn.addEventListener('click', this.onDeleteClick, {once: true});
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { isTouchSupported } from "../helpers/touchSupport";
|
import { isTouchSupported } from "../helpers/touchSupport";
|
||||||
import appImManager from "../lib/appManagers/appImManager";
|
import appImManager from "../lib/appManagers/appImManager";
|
||||||
import appMessagesManager from "../lib/appManagers/appMessagesManager";
|
import appMessagesManager from "../lib/appManagers/appMessagesManager";
|
||||||
import { calcImageInBox } from "../helpers/dom";
|
import { calcImageInBox, getRichValue } from "../helpers/dom";
|
||||||
import { Layouter, RectPart } from "./groupedLayout";
|
import { Layouter, RectPart } from "./groupedLayout";
|
||||||
import InputField from "./inputField";
|
import InputField from "./inputField";
|
||||||
import { PopupElement } from "./popup";
|
import { PopupElement } from "./popup";
|
||||||
@ -53,9 +53,15 @@ export default class PopupNewMedia extends PopupElement {
|
|||||||
const scrollable = new Scrollable(null);
|
const scrollable = new Scrollable(null);
|
||||||
scrollable.container.append(this.mediaContainer);
|
scrollable.container.append(this.mediaContainer);
|
||||||
|
|
||||||
const inputField = InputField('Add a caption...', 'Caption', 'photo-caption', MAX_LENGTH_CAPTION, 80);
|
const inputField = InputField({
|
||||||
this.input = inputField.firstElementChild as HTMLInputElement;
|
placeholder: 'Add a caption...',
|
||||||
this.container.append(scrollable.container, inputField);
|
label: 'Caption',
|
||||||
|
name: 'photo-caption',
|
||||||
|
maxLength: MAX_LENGTH_CAPTION,
|
||||||
|
showLengthOn: 80
|
||||||
|
});
|
||||||
|
this.input = inputField.input;
|
||||||
|
this.container.append(scrollable.container, inputField.container);
|
||||||
|
|
||||||
this.attachFiles(files);
|
this.attachFiles(files);
|
||||||
}
|
}
|
||||||
@ -72,7 +78,7 @@ export default class PopupNewMedia extends PopupElement {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public send = () => {
|
public send = () => {
|
||||||
let caption = this.input.value.trim();
|
let caption = getRichValue(this.input);
|
||||||
if(caption.length > MAX_LENGTH_CAPTION) {
|
if(caption.length > MAX_LENGTH_CAPTION) {
|
||||||
toast('Caption is too long.');
|
toast('Caption is too long.');
|
||||||
return;
|
return;
|
||||||
|
@ -158,7 +158,7 @@ export default class Scrollable extends ScrollableBase {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
public checkForTriggers() {
|
public checkForTriggers = () => {
|
||||||
if(this.scrollLocked || (!this.onScrolledTop && !this.onScrolledBottom)) return;
|
if(this.scrollLocked || (!this.onScrolledTop && !this.onScrolledBottom)) return;
|
||||||
|
|
||||||
const container = this.container;
|
const container = this.container;
|
||||||
@ -179,7 +179,7 @@ export default class Scrollable extends ScrollableBase {
|
|||||||
if(this.onScrolledBottom && (maxScrollTop - scrollTop) <= this.onScrollOffset) {
|
if(this.onScrolledBottom && (maxScrollTop - scrollTop) <= this.onScrollOffset) {
|
||||||
this.onScrolledBottom();
|
this.onScrolledBottom();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
public prepend(element: HTMLElement) {
|
public prepend(element: HTMLElement) {
|
||||||
(this.splitUp || this.container).prepend(element);
|
(this.splitUp || this.container).prepend(element);
|
||||||
|
@ -19,7 +19,7 @@ export default class AppArchivedTab implements SliderTab {
|
|||||||
appDialogsManager.setListClickListener(this.chatList, null, true);
|
appDialogsManager.setListClickListener(this.chatList, null, true);
|
||||||
|
|
||||||
window.addEventListener('resize', () => {
|
window.addEventListener('resize', () => {
|
||||||
setTimeout(appDialogsManager.onChatsScroll, 0);
|
setTimeout(appDialogsManager.scroll.checkForTriggers, 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
import appSidebarLeft from "..";
|
import appSidebarLeft from "..";
|
||||||
|
import { getRichValue } from "../../../helpers/dom";
|
||||||
import { InputFile } from "../../../layer";
|
import { InputFile } from "../../../layer";
|
||||||
import appProfileManager from "../../../lib/appManagers/appProfileManager";
|
import appProfileManager from "../../../lib/appManagers/appProfileManager";
|
||||||
import appUsersManager from "../../../lib/appManagers/appUsersManager";
|
import appUsersManager from "../../../lib/appManagers/appUsersManager";
|
||||||
import apiManager from "../../../lib/mtproto/mtprotoworker";
|
import apiManager from "../../../lib/mtproto/mtprotoworker";
|
||||||
|
import RichTextProcessor from "../../../lib/richtextprocessor";
|
||||||
import $rootScope from "../../../lib/rootScope";
|
import $rootScope from "../../../lib/rootScope";
|
||||||
|
import AvatarElement from "../../avatar";
|
||||||
|
import InputField from "../../inputField";
|
||||||
import PopupAvatar from "../../popupAvatar";
|
import PopupAvatar from "../../popupAvatar";
|
||||||
import Scrollable from "../../scrollable";
|
import Scrollable from "../../scrollable";
|
||||||
import { SliderTab } from "../../slider";
|
import { SliderTab } from "../../slider";
|
||||||
@ -11,21 +15,21 @@ import { SliderTab } from "../../slider";
|
|||||||
// TODO: аватарка не поменяется в этой вкладке после изменения почему-то (если поставить в другом клиенте, и потом тут проверить, для этого ещё вышел в чатлист)
|
// TODO: аватарка не поменяется в этой вкладке после изменения почему-то (если поставить в другом клиенте, и потом тут проверить, для этого ещё вышел в чатлист)
|
||||||
|
|
||||||
export default class AppEditProfileTab implements SliderTab {
|
export default class AppEditProfileTab implements SliderTab {
|
||||||
private container = document.querySelector('.edit-profile-container') as HTMLDivElement;
|
private container: HTMLElement;
|
||||||
private scrollWrapper = this.container.querySelector('.scroll-wrapper') as HTMLDivElement;
|
private scrollWrapper: HTMLElement;
|
||||||
private nextBtn = this.container.querySelector('.btn-corner') as HTMLButtonElement;
|
private nextBtn: HTMLButtonElement;
|
||||||
private canvas = this.container.querySelector('.avatar-edit-canvas') as HTMLCanvasElement;
|
private canvas: HTMLCanvasElement;
|
||||||
private uploadAvatar: () => Promise<InputFile> = null;
|
private uploadAvatar: () => Promise<InputFile> = null;
|
||||||
|
|
||||||
private firstNameInput = this.container.querySelector('.firstname') as HTMLInputElement;
|
private firstNameInput: HTMLInputElement;
|
||||||
private lastNameInput = this.container.querySelector('.lastname') as HTMLInputElement;
|
private lastNameInput: HTMLInputElement;
|
||||||
private bioInput = this.container.querySelector('.bio') as HTMLInputElement;
|
private bioInput: HTMLInputElement;
|
||||||
private userNameInput = this.container.querySelector('.username') as HTMLInputElement;
|
private userNameInput: HTMLInputElement;
|
||||||
|
|
||||||
private avatarElem = document.createElement('avatar-element');
|
private avatarElem: AvatarElement;
|
||||||
|
|
||||||
private profileUrlContainer = this.container.querySelector('.profile-url-container') as HTMLDivElement;
|
private profileUrlContainer: HTMLDivElement;
|
||||||
private profileUrlAnchor = this.profileUrlContainer.lastElementChild as HTMLAnchorElement;
|
private profileUrlAnchor: HTMLAnchorElement;
|
||||||
|
|
||||||
private originalValues = {
|
private originalValues = {
|
||||||
firstName: '',
|
firstName: '',
|
||||||
@ -34,8 +38,20 @@ export default class AppEditProfileTab implements SliderTab {
|
|||||||
bio: ''
|
bio: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor() {
|
public init() {
|
||||||
this.container.querySelector('.avatar-edit').addEventListener('click', () => {
|
this.container = document.querySelector('.edit-profile-container');
|
||||||
|
this.scrollWrapper = this.container.querySelector('.scroll-wrapper');
|
||||||
|
this.nextBtn = this.container.querySelector('.btn-corner');
|
||||||
|
this.canvas = this.container.querySelector('.avatar-edit-canvas');
|
||||||
|
|
||||||
|
this.avatarElem = document.createElement('avatar-element') as AvatarElement;
|
||||||
|
this.avatarElem.classList.add('avatar-placeholder');
|
||||||
|
|
||||||
|
this.profileUrlContainer = this.container.querySelector('.profile-url-container');
|
||||||
|
this.profileUrlAnchor = this.profileUrlContainer.lastElementChild as HTMLAnchorElement;
|
||||||
|
|
||||||
|
const avatarEdit = this.container.querySelector('.avatar-edit');
|
||||||
|
avatarEdit.addEventListener('click', () => {
|
||||||
new PopupAvatar().open(this.canvas, (_upload) => {
|
new PopupAvatar().open(this.canvas, (_upload) => {
|
||||||
this.uploadAvatar = _upload;
|
this.uploadAvatar = _upload;
|
||||||
this.handleChange();
|
this.handleChange();
|
||||||
@ -43,13 +59,56 @@ export default class AppEditProfileTab implements SliderTab {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.avatarElem.classList.add('avatar-placeholder');
|
{
|
||||||
|
const inputWrapper = document.createElement('div');
|
||||||
|
inputWrapper.classList.add('input-wrapper');
|
||||||
|
|
||||||
|
const firstNameInputField = InputField({
|
||||||
|
label: 'Name',
|
||||||
|
name: 'first-name',
|
||||||
|
maxLength: 70
|
||||||
|
});
|
||||||
|
const lastNameInputField = InputField({
|
||||||
|
label: 'Last Name',
|
||||||
|
name: 'last-name',
|
||||||
|
maxLength: 64
|
||||||
|
});
|
||||||
|
const bioInputField = InputField({
|
||||||
|
label: 'Bio (optional)',
|
||||||
|
name: 'bio',
|
||||||
|
maxLength: 70
|
||||||
|
});
|
||||||
|
|
||||||
|
this.firstNameInput = firstNameInputField.input;
|
||||||
|
this.lastNameInput = lastNameInputField.input;
|
||||||
|
this.bioInput = bioInputField.input;
|
||||||
|
|
||||||
|
inputWrapper.append(firstNameInputField.container, lastNameInputField.container, bioInputField.container);
|
||||||
|
avatarEdit.parentElement.insertBefore(inputWrapper, avatarEdit.nextElementSibling);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const inputWrapper = document.createElement('div');
|
||||||
|
inputWrapper.classList.add('input-wrapper');
|
||||||
|
|
||||||
|
const userNameInputField = InputField({
|
||||||
|
label: 'Username (optional)',
|
||||||
|
name: 'username',
|
||||||
|
plainText: true
|
||||||
|
});
|
||||||
|
this.userNameInput = userNameInputField.input;
|
||||||
|
|
||||||
|
inputWrapper.append(userNameInputField.container);
|
||||||
|
|
||||||
|
const caption = this.profileUrlContainer.parentElement;
|
||||||
|
caption.parentElement.insertBefore(inputWrapper, caption);
|
||||||
|
}
|
||||||
|
|
||||||
let userNameLabel = this.userNameInput.nextElementSibling as HTMLLabelElement;
|
let userNameLabel = this.userNameInput.nextElementSibling as HTMLLabelElement;
|
||||||
|
|
||||||
this.firstNameInput.addEventListener('input', () => this.handleChange());
|
this.firstNameInput.addEventListener('input', this.handleChange);
|
||||||
this.lastNameInput.addEventListener('input', () => this.handleChange());
|
this.lastNameInput.addEventListener('input', this.handleChange);
|
||||||
this.bioInput.addEventListener('input', () => this.handleChange());
|
this.bioInput.addEventListener('input', this.handleChange);
|
||||||
this.userNameInput.addEventListener('input', () => {
|
this.userNameInput.addEventListener('input', () => {
|
||||||
let value = this.userNameInput.value;
|
let value = this.userNameInput.value;
|
||||||
|
|
||||||
@ -110,8 +169,7 @@ export default class AppEditProfileTab implements SliderTab {
|
|||||||
|
|
||||||
let promises: Promise<any>[] = [];
|
let promises: Promise<any>[] = [];
|
||||||
|
|
||||||
|
promises.push(appProfileManager.updateProfile(getRichValue(this.firstNameInput), getRichValue(this.lastNameInput), getRichValue(this.bioInput)).then(() => {
|
||||||
promises.push(appProfileManager.updateProfile(this.firstNameInput.value, this.lastNameInput.value, this.bioInput.value).then(() => {
|
|
||||||
appSidebarLeft.selectTab(0);
|
appSidebarLeft.selectTab(0);
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
console.error('updateProfile error:', err);
|
console.error('updateProfile error:', err);
|
||||||
@ -127,10 +185,8 @@ export default class AppEditProfileTab implements SliderTab {
|
|||||||
promises.push(appProfileManager.updateUsername(this.userNameInput.value));
|
promises.push(appProfileManager.updateUsername(this.userNameInput.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise.race(promises).then(() => {
|
Promise.race(promises).finally(() => {
|
||||||
this.nextBtn.disabled = false;
|
this.nextBtn.removeAttribute('disabled');
|
||||||
}, () => {
|
|
||||||
this.nextBtn.disabled = false;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -138,17 +194,34 @@ export default class AppEditProfileTab implements SliderTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public fillElements() {
|
public fillElements() {
|
||||||
let user = appUsersManager.getSelf();
|
if(this.init) {
|
||||||
this.firstNameInput.value = this.originalValues.firstName = user.first_name ?? '';
|
this.init();
|
||||||
this.lastNameInput.value = this.originalValues.lastName = user.last_name ?? '';
|
this.init = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = appUsersManager.getSelf();
|
||||||
|
|
||||||
|
Object.assign(this.originalValues, {
|
||||||
|
firstName: user.first_name,
|
||||||
|
lastName: user.last_name,
|
||||||
|
userName: user.username
|
||||||
|
});
|
||||||
|
|
||||||
|
this.firstNameInput.innerHTML = user.rFirstName;
|
||||||
|
this.lastNameInput.innerHTML = RichTextProcessor.wrapRichText(user.last_name, {noLinks: true, noLinebreaks: true});
|
||||||
this.userNameInput.value = this.originalValues.userName = user.username ?? '';
|
this.userNameInput.value = this.originalValues.userName = user.username ?? '';
|
||||||
|
|
||||||
|
this.firstNameInput.classList.remove('error');
|
||||||
|
this.lastNameInput.classList.remove('error');
|
||||||
|
this.bioInput.classList.remove('error');
|
||||||
|
|
||||||
this.userNameInput.classList.remove('valid', 'error');
|
this.userNameInput.classList.remove('valid', 'error');
|
||||||
this.userNameInput.nextElementSibling.innerHTML = 'Username (optional)';
|
this.userNameInput.nextElementSibling.innerHTML = 'Username (optional)';
|
||||||
|
|
||||||
appProfileManager.getProfile(user.id).then(userFull => {
|
appProfileManager.getProfile(user.id, true).then(userFull => {
|
||||||
if(userFull.rAbout) {
|
if(userFull.rAbout) {
|
||||||
this.bioInput.value = this.originalValues.bio = userFull.rAbout;
|
this.originalValues.bio = userFull.about;
|
||||||
|
this.bioInput.innerHTML = userFull.rAbout;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -168,10 +241,10 @@ export default class AppEditProfileTab implements SliderTab {
|
|||||||
|
|
||||||
private isChanged() {
|
private isChanged() {
|
||||||
return !!this.uploadAvatar
|
return !!this.uploadAvatar
|
||||||
|| this.firstNameInput.value != this.originalValues.firstName
|
|| (!this.firstNameInput.classList.contains('error') && getRichValue(this.firstNameInput) != this.originalValues.firstName)
|
||||||
|| this.lastNameInput.value != this.originalValues.lastName
|
|| (!this.lastNameInput.classList.contains('error') && getRichValue(this.lastNameInput) != this.originalValues.lastName)
|
||||||
|| (this.userNameInput.value != this.originalValues.userName && !this.userNameInput.classList.contains('error'))
|
|| (!this.bioInput.classList.contains('error') && getRichValue(this.bioInput) != this.originalValues.bio)
|
||||||
|| this.bioInput.value != this.originalValues.bio;
|
|| (this.userNameInput.value != this.originalValues.userName && !this.userNameInput.classList.contains('error'));
|
||||||
}
|
}
|
||||||
|
|
||||||
private setProfileUrl() {
|
private setProfileUrl() {
|
||||||
@ -185,13 +258,13 @@ export default class AppEditProfileTab implements SliderTab {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleChange() {
|
private handleChange = () => {
|
||||||
if(this.isChanged()) {
|
if(this.isChanged()) {
|
||||||
this.nextBtn.classList.add('is-visible');
|
this.nextBtn.classList.add('is-visible');
|
||||||
} else {
|
} else {
|
||||||
this.nextBtn.classList.remove('is-visible');
|
this.nextBtn.classList.remove('is-visible');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
onCloseAfterTimeout() {
|
onCloseAfterTimeout() {
|
||||||
this.nextBtn.classList.remove('is-visible');
|
this.nextBtn.classList.remove('is-visible');
|
||||||
|
@ -127,6 +127,28 @@ export function getRichElementValue(node: any, lines: string[], line: string[],
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isInputEmpty(element: HTMLElement) {
|
||||||
|
if(element.hasAttribute('contenteditable') || element.tagName != 'INPUT') {
|
||||||
|
const value = element.innerText;
|
||||||
|
|
||||||
|
return !value.trim() && !serializeNodes(Array.from(element.childNodes)).trim();
|
||||||
|
} else {
|
||||||
|
return !(element as HTMLInputElement).value.trim().length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function serializeNodes(nodes: Node[]): string {
|
||||||
|
return nodes.reduce((str, child: any) => {
|
||||||
|
//console.log('childNode', str, child, typeof(child), typeof(child) === 'string', child.innerText);
|
||||||
|
|
||||||
|
if(typeof(child) === 'object' && child.textContent) return str += child.textContent;
|
||||||
|
if(child.innerText) return str += child.innerText;
|
||||||
|
if(child.tagName == 'IMG' && child.classList && child.classList.contains('emoji')) return str += child.getAttribute('alt');
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}, '');
|
||||||
|
}
|
||||||
|
|
||||||
/* if (Config.Modes.animations &&
|
/* if (Config.Modes.animations &&
|
||||||
typeof window.requestAnimationFrame == 'function') {
|
typeof window.requestAnimationFrame == 'function') {
|
||||||
window.onAnimationFrameCallback = function (cb) {
|
window.onAnimationFrameCallback = function (cb) {
|
||||||
|
@ -168,7 +168,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="transition-item sidebar-search" id="search-container"></div>
|
<div class="transition-item sidebar-search" id="search-container"></div>
|
||||||
<button class="btn-primary btn-circle btn-icon rp btn-corner tgico-newchat_filled btn-menu-toggle" id="new-menu">
|
<button class="btn-circle rp btn-corner tgico-newchat_filled btn-menu-toggle" id="new-menu">
|
||||||
<div class="btn-menu top-left">
|
<div class="btn-menu top-left">
|
||||||
<div class="btn-menu-item menu-channel tgico-newchannel rp">New Channel</div>
|
<div class="btn-menu-item menu-channel tgico-newchannel rp">New Channel</div>
|
||||||
<div class="btn-menu-item menu-group tgico-newgroup rp">New Group</div>
|
<div class="btn-menu-item menu-group tgico-newgroup rp">New Group</div>
|
||||||
@ -219,7 +219,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="caption">You can provide an optional description for your channel.</div>
|
<div class="caption">You can provide an optional description for your channel.</div>
|
||||||
<button class="btn-primary btn-circle btn-icon rp btn-corner tgico-next"></button>
|
<button class="btn-circle rp btn-corner tgico-next"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sidebar-slider-item addmembers-container">
|
<div class="sidebar-slider-item addmembers-container">
|
||||||
@ -228,7 +228,7 @@
|
|||||||
<div class="sidebar-header__title">Add Members</div>
|
<div class="sidebar-header__title">Add Members</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sidebar-content">
|
<div class="sidebar-content">
|
||||||
<button class="btn-primary btn-circle btn-icon rp btn-corner tgico-next"></button>
|
<button class="btn-circle rp btn-corner tgico-next"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sidebar-slider-item new-group-container">
|
<div class="sidebar-slider-item new-group-container">
|
||||||
@ -247,7 +247,7 @@
|
|||||||
<label for="new-group-name">Group Name</label>
|
<label for="new-group-name">Group Name</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn-primary btn-circle btn-icon rp btn-corner tgico-next"></button>
|
<button class="btn-circle rp btn-corner tgico-next"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sidebar-slider-item settings-container">
|
<div class="sidebar-slider-item settings-container">
|
||||||
@ -287,34 +287,14 @@
|
|||||||
<canvas class="avatar-edit-canvas"></canvas>
|
<canvas class="avatar-edit-canvas"></canvas>
|
||||||
<span class="tgico tgico-cameraadd"></span>
|
<span class="tgico tgico-cameraadd"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-wrapper">
|
|
||||||
<div class="input-field">
|
|
||||||
<input type="text" name="name" class="firstname" autocomplete="xxDDqqOXJXC" id="settings-name" required="">
|
|
||||||
<label for="settings-name">Name</label>
|
|
||||||
</div>
|
|
||||||
<div class="input-field">
|
|
||||||
<input type="text" name="lastname" class="lastname" autocomplete="aintsofunnowzXCFF" id="settings-lastname" required="">
|
|
||||||
<label for="settings-lastname">Last Name</label>
|
|
||||||
</div>
|
|
||||||
<div class="input-field">
|
|
||||||
<input type="text" name="bio" class="bio" autocomplete="aintsofunnowhHQ" id="settings-bio" required="">
|
|
||||||
<label for="settings-bio">Bio (optional)</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="caption">Any details such as age, occupation or city. Example:<br>23 y.o. designer from San Francisco.</div>
|
<div class="caption">Any details such as age, occupation or city. Example:<br>23 y.o. designer from San Francisco.</div>
|
||||||
<hr/>
|
<hr/>
|
||||||
<div class="sidebar-left-h2">Username</div>
|
<div class="sidebar-left-h2">Username</div>
|
||||||
<div class="input-wrapper">
|
|
||||||
<div class="input-field">
|
|
||||||
<input type="text" name="username" class="username" autocomplete="xxDDqqOXffEER" id="settings-username" required="">
|
|
||||||
<label for="settings-username">Username (optional)</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="caption">You can choose a username on Telegram. If you do, other people will be able to find you by this username and contact you without knowing your phone number.<br><br>You can use a-z, 0-9 and underscores. Minimum length is 5 characters.<br><br><div class="profile-url-container">This link opens a chat with you:
|
<div class="caption">You can choose a username on Telegram. If you do, other people will be able to find you by this username and contact you without knowing your phone number.<br><br>You can use a-z, 0-9 and underscores. Minimum length is 5 characters.<br><br><div class="profile-url-container">This link opens a chat with you:
|
||||||
<br><a class="profile-url" href="#" target="_blank"></a></div>
|
<br><a class="profile-url" href="#" target="_blank"></a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn-primary btn-circle btn-icon rp btn-corner tgico-check"></button>
|
<button class="btn-circle rp btn-corner tgico-check"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sidebar-slider-item chat-folders-container">
|
<div class="sidebar-slider-item chat-folders-container">
|
||||||
@ -447,9 +427,7 @@
|
|||||||
<div class="new-message-wrapper">
|
<div class="new-message-wrapper">
|
||||||
<button class="btn-icon rp tgico toggle-emoticons" id="toggle-emoticons"></button>
|
<button class="btn-icon rp tgico toggle-emoticons" id="toggle-emoticons"></button>
|
||||||
<!-- <textarea type="text" id="input-message" placeholder="Message" contenteditable="true"></textarea> -->
|
<!-- <textarea type="text" id="input-message" placeholder="Message" contenteditable="true"></textarea> -->
|
||||||
<div class="input-message-container">
|
<div class="input-message-container"></div>
|
||||||
<div id="input-message" contenteditable="true" data-placeholder="Message"></div>
|
|
||||||
</div>
|
|
||||||
<button class="btn-icon tgico-attach btn-menu-toggle" id="attach-file"></button>
|
<button class="btn-icon tgico-attach btn-menu-toggle" id="attach-file"></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 />
|
||||||
|
@ -68,7 +68,7 @@ export class AppChatsManager {
|
|||||||
public chats: {[id: number]: Channel | Chat | any} = {};
|
public chats: {[id: number]: Channel | Chat | any} = {};
|
||||||
//public usernames: any = {};
|
//public usernames: any = {};
|
||||||
//public channelAccess: any = {};
|
//public channelAccess: any = {};
|
||||||
public megagroups: {[id: number]: true} = {};
|
//public megagroups: {[id: number]: true} = {};
|
||||||
public cachedPhotoLocations: {[id: number]: any} = {};
|
public cachedPhotoLocations: {[id: number]: any} = {};
|
||||||
|
|
||||||
public megagroupOnlines: {[id: number]: {timestamp: number, onlines: number}} = {};
|
public megagroupOnlines: {[id: number]: {timestamp: number, onlines: number}} = {};
|
||||||
@ -253,13 +253,13 @@ export class AppChatsManager {
|
|||||||
this.channelAccess[id] = accessHash;
|
this.channelAccess[id] = accessHash;
|
||||||
} */
|
} */
|
||||||
|
|
||||||
public saveIsMegagroup(id: number) {
|
/* public saveIsMegagroup(id: number) {
|
||||||
this.megagroups[id] = true;
|
this.megagroups[id] = true;
|
||||||
}
|
} */
|
||||||
|
|
||||||
public isChannel(id: number) {
|
public isChannel(id: number) {
|
||||||
if(id < 0) id = -id;
|
if(id < 0) id = -id;
|
||||||
let chat = this.chats[id];
|
const chat = this.chats[id];
|
||||||
if(chat && (chat._ == 'channel' || chat._ == 'channelForbidden')/* || this.channelAccess[id] */) {
|
if(chat && (chat._ == 'channel' || chat._ == 'channelForbidden')/* || this.channelAccess[id] */) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -267,11 +267,11 @@ export class AppChatsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public isMegagroup(id: number) {
|
public isMegagroup(id: number) {
|
||||||
if(this.megagroups[id]) {
|
/* if(this.megagroups[id]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
} */
|
||||||
|
|
||||||
let chat = this.chats[id];
|
const chat = this.chats[id];
|
||||||
if(chat && chat._ == 'channel' && chat.pFlags.megagroup) {
|
if(chat && chat._ == 'channel' && chat.pFlags.megagroup) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -242,7 +242,7 @@ export class AppUsersManager {
|
|||||||
|
|
||||||
const fullName = user.first_name + ' ' + (user.last_name || '');
|
const fullName = user.first_name + ' ' + (user.last_name || '');
|
||||||
if(user.first_name) {
|
if(user.first_name) {
|
||||||
user.rFirstName = RichTextProcessor.wrapRichText(user.first_name, {noLinks: true, noLinebreaks: true})
|
user.rFirstName = RichTextProcessor.wrapRichText(user.first_name, {noLinks: true, noLinebreaks: true});
|
||||||
user.rFullName = user.last_name ? RichTextProcessor.wrapRichText(fullName, {noLinks: true, noLinebreaks: true}) : user.rFirstName;
|
user.rFullName = user.last_name ? RichTextProcessor.wrapRichText(fullName, {noLinks: true, noLinebreaks: true}) : user.rFirstName;
|
||||||
} else {
|
} else {
|
||||||
user.rFirstName = RichTextProcessor.wrapRichText(user.last_name, {noLinks: true, noLinebreaks: true}) || user.rPhone || 'user_first_name_deleted';
|
user.rFirstName = RichTextProcessor.wrapRichText(user.last_name, {noLinks: true, noLinebreaks: true}) || user.rPhone || 'user_first_name_deleted';
|
||||||
|
@ -809,15 +809,15 @@ namespace RichTextProcessor {
|
|||||||
let first = '', last = '';
|
let first = '', last = '';
|
||||||
|
|
||||||
const firstNode = childNodes[0];
|
const firstNode = childNodes[0];
|
||||||
if('length' in firstNode) first = (firstNode as any).textContent.charAt(0).toUpperCase();
|
if('length' in firstNode) first = (firstNode as any).textContent.trim().charAt(0).toUpperCase();
|
||||||
else first = (firstNode as HTMLElement).outerHTML;
|
else first = (firstNode as HTMLElement).outerHTML;
|
||||||
|
|
||||||
if(onlyFirst) return first;
|
if(onlyFirst) return first;
|
||||||
|
|
||||||
if(str.indexOf(' ') !== -1) {
|
if(str.indexOf(' ') !== -1) {
|
||||||
const lastNode = childNodes[childNodes.length - 1];
|
const lastNode = childNodes[childNodes.length - 1];
|
||||||
if(lastNode == firstNode) last = lastNode.textContent.split(' ').pop().charAt(0).toUpperCase();
|
if(lastNode == firstNode) last = lastNode.textContent.split(' ').pop().trim().charAt(0).toUpperCase();
|
||||||
else if('length' in lastNode) last = (lastNode as any).textContent.charAt(0).toUpperCase();
|
else if('length' in lastNode) last = (lastNode as any).textContent.trim().charAt(0).toUpperCase();
|
||||||
else last = (lastNode as HTMLElement).outerHTML;
|
else last = (lastNode as HTMLElement).outerHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,18 @@
|
|||||||
transform: translate3d(0, var(--translateY), 0);
|
transform: translate3d(0, var(--translateY), 0);
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
background-color: $color-blue;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
&.is-visible {
|
&.is-visible {
|
||||||
--translateY: 0;
|
--translateY: 0;
|
||||||
@ -49,7 +61,12 @@
|
|||||||
|
|
||||||
body.animation-level-0 & {
|
body.animation-level-0 & {
|
||||||
transition: none !important;
|
transition: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 1 !important;
|
||||||
|
pointer-events: all !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-menu {
|
.btn-menu {
|
||||||
@ -238,7 +255,7 @@
|
|||||||
cursor: pointer !important;
|
cursor: pointer !important;
|
||||||
pointer-events: all !important;
|
pointer-events: all !important;
|
||||||
|
|
||||||
&:not(.btn-primary).menu-open {
|
&:not(.btn-primary):not(.btn-corner).menu-open {
|
||||||
background-color: var(--color-gray-hover);
|
background-color: var(--color-gray-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,7 +290,6 @@ $chat-helper-size: 39px;
|
|||||||
resize: none;
|
resize: none;
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
cursor: text;
|
|
||||||
|
|
||||||
@media only screen and (max-height: 30rem) {
|
@media only screen and (max-height: 30rem) {
|
||||||
max-height: unquote('max(39px, calc(100vh - 10rem))');
|
max-height: unquote('max(39px, calc(100vh - 10rem))');
|
||||||
@ -303,13 +302,6 @@ $chat-helper-size: 39px;
|
|||||||
/* span.emoji {
|
/* span.emoji {
|
||||||
font-size: .95rem;
|
font-size: .95rem;
|
||||||
} */
|
} */
|
||||||
|
|
||||||
//[contenteditable=true]:empty:before {
|
|
||||||
&:empty:before {
|
|
||||||
content: attr(data-placeholder);
|
|
||||||
color: #a2acb4;
|
|
||||||
display: block; /* For Firefox By Ariel Flesler */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle-emoticons {
|
.toggle-emoticons {
|
||||||
@ -967,7 +959,6 @@ $chat-helper-size: 39px;
|
|||||||
box-shadow: 0 1px 2px 0 rgba(16, 35, 47, .07);
|
box-shadow: 0 1px 2px 0 rgba(16, 35, 47, .07);
|
||||||
min-height: $chat-input-size;
|
min-height: $chat-input-size;
|
||||||
max-height: 30rem;
|
max-height: 30rem;
|
||||||
caret-color: $button-primary-background;
|
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
|
155
src/scss/partials/_input.scss
Normal file
155
src/scss/partials/_input.scss
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
.input-wrapper {
|
||||||
|
width: 360px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-field {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.arrow-down {
|
||||||
|
position: absolute;
|
||||||
|
content: " ";
|
||||||
|
top: 50%;
|
||||||
|
bottom: 0;
|
||||||
|
right: 21px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
|
||||||
|
border: solid #707579;
|
||||||
|
border-radius: 1px;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 5px;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
margin-top: -9px;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
-webkit-transform: rotate(45deg);
|
||||||
|
transition: .2s all;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
position: absolute;
|
||||||
|
color: $placeholder-color;
|
||||||
|
left: 1rem;
|
||||||
|
right: auto;
|
||||||
|
z-index: 2;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
background-color: #fff;
|
||||||
|
transition: .2s all, .1s opacity;
|
||||||
|
display: inline-block;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, &-input {
|
||||||
|
--border-width: 1px;
|
||||||
|
--border-width-top: 2px;
|
||||||
|
border: var(--border-width) solid #DADCE0;
|
||||||
|
border-radius: $border-radius-medium;
|
||||||
|
//padding: 0 1rem;
|
||||||
|
padding: calc(1rem - var(--border-width-top)) calc(1rem - var(--border-width));
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 54px;
|
||||||
|
transition: .2s border-color;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
//line-height: calc(54px - var(--border-width));
|
||||||
|
/* overflow: hidden;
|
||||||
|
white-space: nowrap; */
|
||||||
|
|
||||||
|
html.no-touch & {
|
||||||
|
&:hover:not(:focus):not(.error):not(.valid) {
|
||||||
|
border-color: var(--color-gray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include respond-to(handhelds) {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
/* font-weight: 500; */
|
||||||
|
|
||||||
|
/* &:hover {
|
||||||
|
border-color: #000;
|
||||||
|
} */
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
--border-width: 2px;
|
||||||
|
--border-width-top: 3px;
|
||||||
|
border-color: $button-primary-background;
|
||||||
|
//padding: 0 calc(1rem - 1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
background-color: #fff;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.error {
|
||||||
|
border-color: $color-error;
|
||||||
|
|
||||||
|
& + label {
|
||||||
|
color: $color-error!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.valid {
|
||||||
|
border-color: #26962F;
|
||||||
|
|
||||||
|
& + label {
|
||||||
|
color: #26962F !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* &.error, &.valid {
|
||||||
|
transition: .2s border-width;
|
||||||
|
} */
|
||||||
|
|
||||||
|
&:focus ~ .arrow-down {
|
||||||
|
margin-top: -4px;
|
||||||
|
transform: rotate(225deg);
|
||||||
|
-webkit-transform: rotate(225deg);
|
||||||
|
border-color: $button-primary-background;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus + label {
|
||||||
|
color: $button-primary-background;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus + label, &:valid + label, &:not(:empty) + label, &:disabled + label {
|
||||||
|
top: -.5rem;
|
||||||
|
transform: none;
|
||||||
|
padding: 0 5px;
|
||||||
|
left: .75rem;
|
||||||
|
font-size: 0.75rem!important;
|
||||||
|
//color: #666;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-wrapper > * + * {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
|
||||||
|
color: #909192;
|
||||||
|
opacity: 1; /* Firefox */
|
||||||
|
}
|
||||||
|
|
||||||
|
:-ms-input-placeholder { /* Internet Explorer 10-11 */
|
||||||
|
color: #a2acb4;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-ms-input-placeholder { /* Microsoft Edge */
|
||||||
|
color: #a2acb4;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus, button:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
@ -9,7 +9,7 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
&[contenteditable="true"] {
|
&[contenteditable] {
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
|
@ -25,9 +25,8 @@
|
|||||||
.btn-icon {
|
.btn-icon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: .5rem;
|
right: .5rem;
|
||||||
top: 50%;
|
top: .5rem;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
transform: translateY(-50%);
|
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: opacity .2s ease;
|
transition: opacity .2s ease;
|
||||||
}
|
}
|
||||||
@ -47,7 +46,7 @@
|
|||||||
.poll-create-questions {
|
.poll-create-questions {
|
||||||
padding: 0px 1.25rem 2.03125rem;
|
padding: 0px 1.25rem 2.03125rem;
|
||||||
|
|
||||||
.input-field input {
|
.input-field-input {
|
||||||
padding-right: 3.25rem;
|
padding-right: 3.25rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,4 +64,8 @@
|
|||||||
font-size: .875rem;
|
font-size: .875rem;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
width: 94px;
|
||||||
|
}
|
||||||
}
|
}
|
@ -132,27 +132,22 @@
|
|||||||
margin-top: 25px;
|
margin-top: 25px;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
|
||||||
&::placeholder {
|
&-input {
|
||||||
color: #a2acb4;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
//height: 54px;
|
//height: 54px;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
border-radius: $border-radius-medium;
|
border-radius: $border-radius-medium;
|
||||||
|
|
||||||
|
&:not(:focus):empty + label {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
opacity: 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-create-poll.popup-new-media .btn-primary {
|
|
||||||
width: 94px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popup-new-media.popup-send-photo {
|
.popup-new-media.popup-send-photo {
|
||||||
.popup-header {
|
.popup-header {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -102,6 +102,7 @@ $messages-container-width: 728px;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@import "partials/ico";
|
@import "partials/ico";
|
||||||
|
@import "partials/input";
|
||||||
@import "partials/button";
|
@import "partials/button";
|
||||||
@import "partials/checkbox";
|
@import "partials/checkbox";
|
||||||
@import "partials/chatlist";
|
@import "partials/chatlist";
|
||||||
@ -294,7 +295,7 @@ h4 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input, [contenteditable] {
|
||||||
caret-color: $button-primary-background;
|
caret-color: $button-primary-background;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,140 +443,6 @@ hr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-wrapper {
|
|
||||||
width: 360px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-field {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.arrow-down {
|
|
||||||
position: absolute;
|
|
||||||
content: " ";
|
|
||||||
top: 50%;
|
|
||||||
bottom: 0;
|
|
||||||
right: 21px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
height: 0;
|
|
||||||
width: 0;
|
|
||||||
|
|
||||||
border: solid #707579;
|
|
||||||
border-radius: 1px;
|
|
||||||
border-width: 0 2px 2px 0;
|
|
||||||
display: inline-block;
|
|
||||||
padding: 5px;
|
|
||||||
vertical-align: middle;
|
|
||||||
|
|
||||||
z-index: 2;
|
|
||||||
|
|
||||||
margin-top: -9px;
|
|
||||||
transform: rotate(45deg);
|
|
||||||
-webkit-transform: rotate(45deg);
|
|
||||||
transition: .2s all;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
position: absolute;
|
|
||||||
color: $placeholder-color;
|
|
||||||
left: 1rem;
|
|
||||||
right: auto;
|
|
||||||
z-index: 2;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
background-color: #fff;
|
|
||||||
transition: .2s all, .1s opacity;
|
|
||||||
display: inline-block;
|
|
||||||
cursor: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
--border-width: 1px;
|
|
||||||
border: var(--border-width) solid #DADCE0;
|
|
||||||
border-radius: $border-radius-medium;
|
|
||||||
//padding: 0 1rem;
|
|
||||||
padding: 0 calc(1rem - var(--border-width));
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: 100%;
|
|
||||||
height: 54px;
|
|
||||||
transition: .2s border-color;
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
|
|
||||||
html.no-touch & {
|
|
||||||
&:hover:not(:focus):not(.error):not(.valid) {
|
|
||||||
border-color: var(--color-gray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include respond-to(handhelds) {
|
|
||||||
height: 50px;
|
|
||||||
}
|
|
||||||
/* font-weight: 500; */
|
|
||||||
|
|
||||||
/* &:hover {
|
|
||||||
border-color: #000;
|
|
||||||
} */
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
--border-width: 2px;
|
|
||||||
border-color: $button-primary-background;
|
|
||||||
//padding: 0 calc(1rem - 1px);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:disabled {
|
|
||||||
background-color: #fff;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.error {
|
|
||||||
border-color: $color-error;
|
|
||||||
|
|
||||||
& + label {
|
|
||||||
color: $color-error!important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.valid {
|
|
||||||
border-color: #26962F;
|
|
||||||
|
|
||||||
& + label {
|
|
||||||
color: #26962F !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* &.error, &.valid {
|
|
||||||
transition: .2s border-width;
|
|
||||||
} */
|
|
||||||
|
|
||||||
&:focus ~ .arrow-down {
|
|
||||||
margin-top: -4px;
|
|
||||||
transform: rotate(225deg);
|
|
||||||
-webkit-transform: rotate(225deg);
|
|
||||||
border-color: $button-primary-background;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus + label {
|
|
||||||
color: $button-primary-background;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus + label, &:valid + label, &:disabled + label {
|
|
||||||
top: -.5rem;
|
|
||||||
transform: none;
|
|
||||||
padding: 0 5px;
|
|
||||||
left: .75rem;
|
|
||||||
font-size: 0.75rem!important;
|
|
||||||
//color: #666;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-wrapper > * + * {
|
|
||||||
margin-top: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select-wrapper {
|
.select-wrapper {
|
||||||
max-height: 23.5rem;
|
max-height: 23.5rem;
|
||||||
/* height: auto; */
|
/* height: auto; */
|
||||||
@ -640,23 +507,6 @@ hr {
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
|
|
||||||
color: #909192;
|
|
||||||
opacity: 1; /* Firefox */
|
|
||||||
}
|
|
||||||
|
|
||||||
:-ms-input-placeholder { /* Internet Explorer 10-11 */
|
|
||||||
color: #a2acb4;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-ms-input-placeholder { /* Microsoft Edge */
|
|
||||||
color: #a2acb4;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:focus, button:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this dimensions will be used for monkey business
|
// this dimensions will be used for monkey business
|
||||||
.auth-image {
|
.auth-image {
|
||||||
width: 166px;
|
width: 166px;
|
||||||
@ -787,8 +637,19 @@ img.emoji {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[contenteditable=true] {
|
[contenteditable] {
|
||||||
user-select: text;
|
user-select: text;
|
||||||
|
outline: none;
|
||||||
|
cursor: text;
|
||||||
|
|
||||||
|
&[data-placeholder] {
|
||||||
|
&:empty:before {
|
||||||
|
content: attr(data-placeholder);
|
||||||
|
color: #a2acb4;
|
||||||
|
display: block; /* For Firefox By Ariel Flesler */
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sticky_sentinel {
|
.sticky_sentinel {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user