Refactor legacy input fields
Added missed length restrictions on input fields
This commit is contained in:
parent
4de230e114
commit
d1c9a25129
@ -54,6 +54,8 @@ class InputField {
|
||||
public container: HTMLElement;
|
||||
public input: HTMLElement;
|
||||
|
||||
//public onLengthChange: (length: number, isOverflow: boolean) => void;
|
||||
|
||||
constructor(private options: {
|
||||
placeholder?: string,
|
||||
label?: string,
|
||||
@ -116,6 +118,8 @@ class InputField {
|
||||
const isError = diff < 0;
|
||||
input.classList.toggle('error', isError);
|
||||
|
||||
//this.onLengthChange && this.onLengthChange(inputLength, isError);
|
||||
|
||||
if(isError || diff <= showLengthOn) {
|
||||
labelEl.innerText = label + ` (${maxLength - inputLength})`;
|
||||
if(!showingLength) showingLength = true;
|
||||
|
@ -9,6 +9,8 @@ import { SliderTab } from "../../slider";
|
||||
import { toast } from "../../toast";
|
||||
import appMessagesManager from "../../../lib/appManagers/appMessagesManager";
|
||||
import { attachClickEvent } from "../../../helpers/dom";
|
||||
import InputField from "../../inputField";
|
||||
import RichTextProcessor from "../../../lib/richtextprocessor";
|
||||
|
||||
const MAX_FOLDER_NAME_LENGTH = 12;
|
||||
|
||||
@ -22,7 +24,8 @@ export default class AppEditFolderTab implements SliderTab {
|
||||
private confirmBtn: HTMLElement;
|
||||
private menuBtn: HTMLElement;
|
||||
private deleteFolderBtn: HTMLElement;
|
||||
private nameInput: HTMLInputElement;
|
||||
private nameInput: HTMLElement;
|
||||
private nameInputField: InputField;
|
||||
|
||||
private include_peers: HTMLElement;
|
||||
private exclude_peers: HTMLElement;
|
||||
@ -44,7 +47,19 @@ export default class AppEditFolderTab implements SliderTab {
|
||||
this.confirmBtn = this.container.querySelector('.btn-confirm');
|
||||
this.menuBtn = this.container.querySelector('.btn-menu-toggle');
|
||||
this.deleteFolderBtn = this.menuBtn.querySelector('.menu-delete');
|
||||
this.nameInput = this.container.querySelector('#folder-name');
|
||||
|
||||
const inputWrapper = document.createElement('div');
|
||||
inputWrapper.classList.add('input-wrapper');
|
||||
|
||||
this.nameInputField = new InputField({
|
||||
label: 'Folder Name',
|
||||
maxLength: MAX_FOLDER_NAME_LENGTH
|
||||
});
|
||||
this.nameInput = this.nameInputField.input;
|
||||
|
||||
inputWrapper.append(this.nameInputField.container);
|
||||
|
||||
this.caption.parentElement.insertBefore(inputWrapper, this.caption.nextSibling);
|
||||
|
||||
this.include_peers = this.container.querySelector('.folder-list-included');
|
||||
this.exclude_peers = this.container.querySelector('.folder-list-excluded');
|
||||
@ -84,8 +99,12 @@ export default class AppEditFolderTab implements SliderTab {
|
||||
});
|
||||
|
||||
this.confirmBtn.addEventListener('click', () => {
|
||||
if(!this.nameInput.value.trim()) {
|
||||
this.nameInput.classList.add('error');
|
||||
if(this.nameInputField.input.classList.contains('error')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.nameInputField.value.trim()) {
|
||||
this.nameInputField.input.classList.add('error');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -122,14 +141,7 @@ export default class AppEditFolderTab implements SliderTab {
|
||||
});
|
||||
|
||||
this.nameInput.addEventListener('input', () => {
|
||||
if(this.nameInput.value.length > MAX_FOLDER_NAME_LENGTH) {
|
||||
this.nameInput.value = this.nameInput.value.slice(0, MAX_FOLDER_NAME_LENGTH);
|
||||
return;
|
||||
}
|
||||
|
||||
this.filter.title = this.nameInput.value;
|
||||
this.nameInput.classList.remove('error');
|
||||
|
||||
this.filter.title = this.nameInputField.value;
|
||||
this.editCheckForChange();
|
||||
});
|
||||
}
|
||||
@ -154,7 +166,7 @@ export default class AppEditFolderTab implements SliderTab {
|
||||
this.title.innerText = 'New Folder';
|
||||
this.menuBtn.classList.add('hide');
|
||||
this.confirmBtn.classList.remove('hide');
|
||||
this.nameInput.value = '';
|
||||
this.nameInputField.value = '';
|
||||
|
||||
for(const flag in this.flags) {
|
||||
// @ts-ignore
|
||||
@ -172,7 +184,7 @@ export default class AppEditFolderTab implements SliderTab {
|
||||
}
|
||||
|
||||
const filter = this.filter;
|
||||
this.nameInput.value = filter.title;
|
||||
this.nameInputField.value = RichTextProcessor.wrapEmojiText(filter.title);
|
||||
|
||||
for(const flag in this.flags) {
|
||||
// @ts-ignore
|
||||
|
@ -1,37 +1,64 @@
|
||||
import appSidebarLeft, { AppSidebarLeft } from "..";
|
||||
import { InputFile } from "../../../layer";
|
||||
import appChatsManager from "../../../lib/appManagers/appChatsManager";
|
||||
import Button from "../../button";
|
||||
import InputField from "../../inputField";
|
||||
import PopupAvatar from "../../popups/avatar";
|
||||
import { SliderTab } from "../../slider";
|
||||
|
||||
export default class AppNewChannelTab implements SliderTab {
|
||||
private container = document.querySelector('.new-channel-container') as HTMLDivElement;
|
||||
private canvas = this.container.querySelector('.avatar-edit-canvas') as HTMLCanvasElement;
|
||||
private channelNameInput = this.container.querySelector('.new-channel-name') as HTMLInputElement;
|
||||
private channelDescriptionInput = this.container.querySelector('.new-channel-description') as HTMLInputElement;
|
||||
private nextBtn = this.container.querySelector('.btn-corner') as HTMLButtonElement;
|
||||
private backBtn = this.container.querySelector('.sidebar-close-button') as HTMLButtonElement;
|
||||
private uploadAvatar: () => Promise<InputFile> = null;
|
||||
|
||||
private channelNameInputField: InputField;
|
||||
private channelDescriptionInputField: InputField;
|
||||
private nextBtn: HTMLButtonElement;
|
||||
|
||||
constructor() {
|
||||
const content = this.container.querySelector('.sidebar-content');
|
||||
|
||||
this.container.querySelector('.avatar-edit').addEventListener('click', () => {
|
||||
new PopupAvatar().open(this.canvas, (_upload) => {
|
||||
this.uploadAvatar = _upload;
|
||||
});
|
||||
});
|
||||
|
||||
this.channelNameInput.addEventListener('input', () => {
|
||||
let value = this.channelNameInput.value;
|
||||
if(value.length) {
|
||||
this.nextBtn.classList.add('is-visible');
|
||||
} else {
|
||||
this.nextBtn.classList.remove('is-visible');
|
||||
}
|
||||
const inputWrapper = document.createElement('div');
|
||||
inputWrapper.classList.add('input-wrapper');
|
||||
|
||||
this.channelNameInputField = new InputField({
|
||||
label: 'Channel Name',
|
||||
maxLength: 128
|
||||
});
|
||||
|
||||
this.channelDescriptionInputField = new InputField({
|
||||
label: 'Description (optional)',
|
||||
maxLength: 255
|
||||
});
|
||||
|
||||
inputWrapper.append(this.channelNameInputField.container, this.channelDescriptionInputField.container);
|
||||
|
||||
const onLengthChange = () => {
|
||||
this.nextBtn.classList.toggle('is-visible', !!this.channelNameInputField.value.length &&
|
||||
!this.channelNameInputField.input.classList.contains('error') &&
|
||||
!this.channelDescriptionInputField.input.classList.contains('error'));
|
||||
};
|
||||
|
||||
this.channelNameInputField.input.addEventListener('input', onLengthChange);
|
||||
this.channelDescriptionInputField.input.addEventListener('input', onLengthChange);
|
||||
|
||||
const caption = document.createElement('div');
|
||||
caption.classList.add('caption');
|
||||
caption.innerText = 'You can provide an optional description for your channel.';
|
||||
|
||||
this.nextBtn = Button('btn-corner btn-circle', {icon: 'next'});
|
||||
|
||||
content.append(inputWrapper, caption, this.nextBtn);
|
||||
|
||||
this.nextBtn.addEventListener('click', () => {
|
||||
let title = this.channelNameInput.value;
|
||||
let about = this.channelDescriptionInput.value;
|
||||
const title = this.channelNameInputField.value;
|
||||
const about = this.channelDescriptionInputField.value;
|
||||
|
||||
this.nextBtn.disabled = true;
|
||||
appChatsManager.createChannel(title, about).then((channelId) => {
|
||||
@ -52,8 +79,8 @@ export default class AppNewChannelTab implements SliderTab {
|
||||
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
|
||||
this.uploadAvatar = null;
|
||||
this.channelNameInput.value = '';
|
||||
this.channelDescriptionInput.value = '';
|
||||
this.channelNameInputField.value = '';
|
||||
this.channelDescriptionInputField.value = '';
|
||||
this.nextBtn.disabled = false;
|
||||
}
|
||||
}
|
@ -4,6 +4,8 @@ import appChatsManager from "../../../lib/appManagers/appChatsManager";
|
||||
import appDialogsManager from "../../../lib/appManagers/appDialogsManager";
|
||||
import appUsersManager from "../../../lib/appManagers/appUsersManager";
|
||||
import { SearchGroup } from "../../appSearch";
|
||||
import Button from "../../button";
|
||||
import InputField from "../../inputField";
|
||||
import PopupAvatar from "../../popups/avatar";
|
||||
import Scrollable from "../../scrollable";
|
||||
import { SliderTab } from "../../slider";
|
||||
@ -12,11 +14,11 @@ export default class AppNewGroupTab implements SliderTab {
|
||||
private container = document.querySelector('.new-group-container') as HTMLDivElement;
|
||||
private contentDiv = this.container.querySelector('.sidebar-content') as HTMLDivElement;
|
||||
private canvas = this.container.querySelector('.avatar-edit-canvas') as HTMLCanvasElement;
|
||||
private groupNameInput = this.container.querySelector('.new-group-name') as HTMLInputElement;
|
||||
private nextBtn = this.container.querySelector('.btn-corner') as HTMLButtonElement;
|
||||
private searchGroup = new SearchGroup(' ', 'contacts', true, 'new-group-members disable-hover', false);
|
||||
private uploadAvatar: () => Promise<InputFile> = null;
|
||||
private userIds: number[];
|
||||
private nextBtn: HTMLButtonElement;
|
||||
private groupNameInputField: InputField;
|
||||
|
||||
constructor() {
|
||||
this.container.querySelector('.avatar-edit').addEventListener('click', () => {
|
||||
@ -25,13 +27,25 @@ export default class AppNewGroupTab implements SliderTab {
|
||||
});
|
||||
});
|
||||
|
||||
this.groupNameInput.addEventListener('input', () => {
|
||||
const value = this.groupNameInput.value;
|
||||
this.nextBtn.classList.toggle('is-visible', !!value.length);
|
||||
const inputWrapper = document.createElement('div');
|
||||
inputWrapper.classList.add('input-wrapper');
|
||||
|
||||
this.groupNameInputField = new InputField({
|
||||
label: 'Group Name',
|
||||
maxLength: 128
|
||||
});
|
||||
|
||||
inputWrapper.append(this.groupNameInputField.container);
|
||||
|
||||
this.groupNameInputField.input.addEventListener('input', () => {
|
||||
const value = this.groupNameInputField.value;
|
||||
this.nextBtn.classList.toggle('is-visible', !!value.length && !this.groupNameInputField.input.classList.contains('error'));
|
||||
});
|
||||
|
||||
this.nextBtn = Button('btn-corner btn-circle', {icon: 'next'});
|
||||
|
||||
this.nextBtn.addEventListener('click', () => {
|
||||
const title = this.groupNameInput.value;
|
||||
const title = this.groupNameInputField.value;
|
||||
|
||||
this.nextBtn.disabled = true;
|
||||
appChatsManager.createChat(title, this.userIds).then((chatId) => {
|
||||
@ -51,7 +65,7 @@ export default class AppNewGroupTab implements SliderTab {
|
||||
|
||||
const scrollable = new Scrollable(chatsContainer);
|
||||
|
||||
this.contentDiv.append(chatsContainer);
|
||||
this.contentDiv.append(inputWrapper, chatsContainer, this.nextBtn);
|
||||
}
|
||||
|
||||
public onClose() {
|
||||
@ -65,7 +79,7 @@ export default class AppNewGroupTab implements SliderTab {
|
||||
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
|
||||
this.uploadAvatar = null;
|
||||
this.groupNameInput.value = '';
|
||||
this.groupNameInputField.value = '';
|
||||
this.nextBtn.disabled = false;
|
||||
this.searchGroup.clear();
|
||||
}
|
||||
|
@ -109,17 +109,6 @@
|
||||
</div>
|
||||
<h4 class="fullName">Your Name</h4>
|
||||
<p class="subtitle">Enter your name and add<br>a profile picture</p>
|
||||
<div class="input-wrapper">
|
||||
<div class="input-field">
|
||||
<input type="text" name="name" id="name" autocomplete="off" required />
|
||||
<label for="name">Name</label>
|
||||
</div>
|
||||
<div class="input-field">
|
||||
<input type="text" name="lastName" id="lastName" autocomplete="off" required />
|
||||
<label for="lastName">Last Name (optional)</label>
|
||||
</div>
|
||||
<button class="btn-primary rp" id="signUp">START MESSAGING</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -208,18 +197,6 @@
|
||||
<canvas class="avatar-edit-canvas"></canvas>
|
||||
<span class="tgico tgico-cameraadd"></span>
|
||||
</div>
|
||||
<div class="input-wrapper">
|
||||
<div class="input-field">
|
||||
<input type="text" name="name" class="new-channel-name" id="new-channel-name" autocomplete="xxDDqqOX" required="">
|
||||
<label for="new-channel-name">Channel Name</label>
|
||||
</div>
|
||||
<div class="input-field">
|
||||
<input type="text" name="description" class="new-channel-description" id="new-channel-description" autocomplete="aintsofunnow" required="">
|
||||
<label for="new-channel-description">Description (optional)</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="caption">You can provide an optional description for your channel.</div>
|
||||
<button class="btn-circle rp btn-corner tgico-next"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-slider-item addmembers-container">
|
||||
@ -241,13 +218,6 @@
|
||||
<canvas class="avatar-edit-canvas"></canvas>
|
||||
<span class="tgico tgico-cameraadd"></span>
|
||||
</div>
|
||||
<div class="input-wrapper">
|
||||
<div class="input-field">
|
||||
<input type="text" name="name" class="new-group-name" id="new-group-name" autocomplete="feellikeamonster2112" required="">
|
||||
<label for="new-group-name">Group Name</label>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-circle rp btn-corner tgico-next"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-slider-item settings-container">
|
||||
@ -336,12 +306,6 @@
|
||||
<div class="edit-folder scrollable scrollable-y">
|
||||
<div class="sticker-container"></div>
|
||||
<div class="caption">Choose chats and types of chats that will<br>appear and never appear in this folder.</div>
|
||||
<div class="input-wrapper">
|
||||
<div class="input-field">
|
||||
<input type="text" name="folder-name" class="folder-name" autocomplete="aintCCZsofunnowhHQ" id="folder-name" required="">
|
||||
<label for="folder-name">Folder Name</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="folder-list folder-list-included">
|
||||
<div class="sidebar-left-h2">Included chats</div>
|
||||
<div class="folder-categories">
|
||||
|
@ -4,7 +4,6 @@ import emojiRegExp from '../emoji/regex';
|
||||
import { encodeEmoji } from '../emoji';
|
||||
import { MOUNT_CLASS_TO } from './mtproto/mtproto_config';
|
||||
import { MessageEntity } from '../layer';
|
||||
import { copy } from '../helpers/object';
|
||||
import { encodeEntities } from '../helpers/string';
|
||||
import { isSafari } from '../helpers/userAgent';
|
||||
|
||||
@ -373,14 +372,14 @@ namespace RichTextProcessor {
|
||||
return currentEntities;
|
||||
}
|
||||
|
||||
export function wrapRichNestedText(text: string, nested: MessageEntity[], options: any) {
|
||||
/* export function wrapRichNestedText(text: string, nested: MessageEntity[], options: any) {
|
||||
if(nested === undefined) {
|
||||
return encodeEntities(text);
|
||||
}
|
||||
|
||||
options.hasNested = true;
|
||||
return wrapRichText(text, {entities: nested, nested: true});
|
||||
}
|
||||
} */
|
||||
|
||||
export function wrapRichText(text: string, options: Partial<{
|
||||
entities: MessageEntity[],
|
||||
|
@ -1,15 +1,18 @@
|
||||
import Button from '../components/button';
|
||||
import InputField from '../components/inputField';
|
||||
import { putPreloader } from '../components/misc';
|
||||
import PopupAvatar from '../components/popups/avatar';
|
||||
import appStateManager from '../lib/appManagers/appStateManager';
|
||||
//import apiManager from '../lib/mtproto/apiManager';
|
||||
import apiManager from '../lib/mtproto/mtprotoworker';
|
||||
import RichTextProcessor from '../lib/richtextprocessor';
|
||||
import { AuthState } from '../types';
|
||||
import Page from './page';
|
||||
import pageIm from './pageIm';
|
||||
|
||||
let authCode: AuthState.signUp['authCode'] = null;
|
||||
|
||||
let onFirstMount = () => import('../lib/appManagers/appProfileManager').then(imported => {
|
||||
const onFirstMount = () => import('../lib/appManagers/appProfileManager').then(imported => {
|
||||
const pageElement = page.pageEl;
|
||||
const avatarPreview = pageElement.querySelector('#canvas-avatar') as HTMLCanvasElement;
|
||||
const appProfileManager = imported.default;
|
||||
@ -23,19 +26,18 @@ let onFirstMount = () => import('../lib/appManagers/appProfileManager').then(imp
|
||||
|
||||
const headerName = pageElement.getElementsByClassName('fullName')[0] as HTMLHeadingElement;
|
||||
|
||||
let handleInput = function(this: typeof fieldName, e: Event) {
|
||||
let name = fieldName.value || '';
|
||||
let lastName = fieldLastName.value || '';
|
||||
const handleInput = (e: Event) => {
|
||||
const name = nameInputField.value || '';
|
||||
const lastName = lastNameInputField.value || '';
|
||||
|
||||
let fullName = name || lastName
|
||||
const fullName = name || lastName
|
||||
? (name + ' ' + lastName).trim()
|
||||
: 'Your Name';
|
||||
|
||||
if(headerName.innerText != fullName) headerName.innerText = fullName;
|
||||
this.classList.remove('error');
|
||||
if(headerName.innerHTML != fullName) headerName.innerHTML = RichTextProcessor.wrapEmojiText(fullName);
|
||||
};
|
||||
|
||||
let sendAvatar = () => new Promise((resolve, reject) => {
|
||||
let sendAvatar = () => new Promise<void>((resolve, reject) => {
|
||||
if(!uploadAvatar) {
|
||||
//console.log('User has not selected avatar');
|
||||
return resolve();
|
||||
@ -49,29 +51,49 @@ let onFirstMount = () => import('../lib/appManagers/appProfileManager').then(imp
|
||||
}, reject);
|
||||
});
|
||||
|
||||
const fieldName = document.getElementById('name') as HTMLInputElement;
|
||||
fieldName.addEventListener('input', handleInput);
|
||||
const inputWrapper = document.createElement('div');
|
||||
inputWrapper.classList.add('input-wrapper');
|
||||
|
||||
const fieldLastName = document.getElementById('lastName') as HTMLInputElement;
|
||||
fieldLastName.addEventListener('input', handleInput);
|
||||
const nameInputField = new InputField({
|
||||
label: 'Name',
|
||||
maxLength: 70
|
||||
});
|
||||
|
||||
const signUpButton = document.getElementById('signUp') as HTMLButtonElement;
|
||||
signUpButton.addEventListener('click', function(this: typeof signUpButton, e) {
|
||||
this.setAttribute('disabled', 'true');
|
||||
const lastNameInputField = new InputField({
|
||||
label: 'Last Name (optional)',
|
||||
maxLength: 64
|
||||
});
|
||||
|
||||
if(!fieldName.value.length) {
|
||||
fieldName.classList.add('error');
|
||||
const btnSignUp = Button('btn-primary');
|
||||
btnSignUp.append('START MESSAGING');
|
||||
|
||||
inputWrapper.append(nameInputField.container, lastNameInputField.container, btnSignUp);
|
||||
|
||||
headerName.parentElement.append(inputWrapper);
|
||||
|
||||
nameInputField.input.addEventListener('input', handleInput);
|
||||
lastNameInputField.input.addEventListener('input', handleInput);
|
||||
|
||||
btnSignUp.addEventListener('click', function(this: typeof btnSignUp, e) {
|
||||
if(nameInputField.input.classList.contains('error') || lastNameInputField.input.classList.contains('error')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let name = fieldName.value;
|
||||
let lastName = fieldLastName.value;
|
||||
if(!nameInputField.value.length) {
|
||||
nameInputField.input.classList.add('error');
|
||||
return false;
|
||||
}
|
||||
|
||||
let params = {
|
||||
'phone_number': authCode.phone_number,
|
||||
'phone_code_hash': authCode.phone_code_hash,
|
||||
'first_name': name,
|
||||
'last_name': lastName
|
||||
this.setAttribute('disabled', 'true');
|
||||
|
||||
const name = nameInputField.value.trim();
|
||||
const lastName = lastNameInputField.value.trim();
|
||||
|
||||
const params = {
|
||||
phone_number: authCode.phone_number,
|
||||
phone_code_hash: authCode.phone_code_hash,
|
||||
first_name: name,
|
||||
last_name: lastName
|
||||
};
|
||||
|
||||
//console.log('invoking auth.signUp with params:', params);
|
||||
@ -80,7 +102,7 @@ let onFirstMount = () => import('../lib/appManagers/appProfileManager').then(imp
|
||||
putPreloader(this);
|
||||
|
||||
apiManager.invokeApi('auth.signUp', params)
|
||||
.then((response: any) => {
|
||||
.then((response) => {
|
||||
//console.log('auth.signUp response:', response);
|
||||
|
||||
switch(response._) {
|
||||
|
@ -61,6 +61,7 @@
|
||||
transition: .2s border-color;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
text-align: left;
|
||||
//line-height: calc(54px - var(--border-width));
|
||||
/* overflow: hidden;
|
||||
white-space: nowrap; */
|
||||
|
@ -547,6 +547,7 @@
|
||||
|
||||
p {
|
||||
height: unset;
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
p:last-child {
|
||||
|
@ -277,7 +277,7 @@ html {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
text-rendering: optimizeSpeed;
|
||||
//text-rendering: optimizeSpeed;
|
||||
}
|
||||
|
||||
body {
|
||||
|
Loading…
x
Reference in New Issue
Block a user