Browse Source

Refactor legacy input fields

Added missed length restrictions on input fields
master
Eduard Kuzmenko 4 years ago
parent
commit
d1c9a25129
  1. 4
      src/components/inputField.ts
  2. 40
      src/components/sidebarLeft/tabs/editFolder.ts
  3. 57
      src/components/sidebarLeft/tabs/newChannel.ts
  4. 30
      src/components/sidebarLeft/tabs/newGroup.ts
  5. 36
      src/index.hbs
  6. 5
      src/lib/richtextprocessor.ts
  7. 72
      src/pages/pageSignUp.ts
  8. 1
      src/scss/partials/_input.scss
  9. 1
      src/scss/partials/_leftSidebar.scss
  10. 2
      src/scss/style.scss

4
src/components/inputField.ts

@ -54,6 +54,8 @@ class InputField { @@ -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 { @@ -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;

40
src/components/sidebarLeft/tabs/editFolder.ts

@ -9,6 +9,8 @@ import { SliderTab } from "../../slider"; @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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

57
src/components/sidebarLeft/tabs/newChannel.ts

@ -1,37 +1,64 @@ @@ -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 { @@ -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;
}
}

30
src/components/sidebarLeft/tabs/newGroup.ts

@ -4,6 +4,8 @@ import appChatsManager from "../../../lib/appManagers/appChatsManager"; @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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();
}

36
src/index.hbs

@ -109,17 +109,6 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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">

5
src/lib/richtextprocessor.ts

@ -4,7 +4,6 @@ import emojiRegExp from '../emoji/regex'; @@ -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 { @@ -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[],

72
src/pages/pageSignUp.ts

@ -1,15 +1,18 @@ @@ -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 @@ -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 @@ -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
});
const btnSignUp = Button('btn-primary');
btnSignUp.append('START MESSAGING');
inputWrapper.append(nameInputField.container, lastNameInputField.container, btnSignUp);
headerName.parentElement.append(inputWrapper);
if(!fieldName.value.length) {
fieldName.classList.add('error');
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;
}
if(!nameInputField.value.length) {
nameInputField.input.classList.add('error');
return false;
}
let name = fieldName.value;
let lastName = fieldLastName.value;
this.setAttribute('disabled', 'true');
const name = nameInputField.value.trim();
const lastName = lastNameInputField.value.trim();
let params = {
'phone_number': authCode.phone_number,
'phone_code_hash': authCode.phone_code_hash,
'first_name': name,
'last_name': lastName
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 @@ -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._) {

1
src/scss/partials/_input.scss

@ -61,6 +61,7 @@ @@ -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; */

1
src/scss/partials/_leftSidebar.scss

@ -547,6 +547,7 @@ @@ -547,6 +547,7 @@
p {
height: unset;
justify-content: start;
}
p:last-child {

2
src/scss/style.scss

@ -277,7 +277,7 @@ html { @@ -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…
Cancel
Save