Two-factor:
Recovery email Fix enter shortcut on handhelds
This commit is contained in:
parent
c32a7cea12
commit
a6753d7325
38
src/components/codeInputField.ts
Normal file
38
src/components/codeInputField.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import InputField from "./inputField";
|
||||||
|
|
||||||
|
export default class CodeInputField extends InputField {
|
||||||
|
constructor(options: {
|
||||||
|
label?: string,
|
||||||
|
name?: string,
|
||||||
|
length: number,
|
||||||
|
onFill: (code: number) => void
|
||||||
|
}) {
|
||||||
|
super({
|
||||||
|
plainText: true,
|
||||||
|
...options
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = this.input as HTMLInputElement;
|
||||||
|
input.type = 'tel';
|
||||||
|
input.setAttribute('required', '');
|
||||||
|
input.autocomplete = 'off';
|
||||||
|
|
||||||
|
let lastLength = 0;
|
||||||
|
this.input.addEventListener('input', (e) => {
|
||||||
|
this.input.classList.remove('error');
|
||||||
|
this.label.innerText = options.label;
|
||||||
|
|
||||||
|
const value = this.value.replace(/\D/g, '').slice(0, options.length);
|
||||||
|
this.setValueSilently(value);
|
||||||
|
|
||||||
|
const length = this.value.length;
|
||||||
|
if(length === options.length) { // submit code
|
||||||
|
options.onFill(+this.value);
|
||||||
|
} else if(length === lastLength) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastLength = length;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -55,14 +55,14 @@ export function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGIma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function putPreloader(elem: Element, returnDiv = false) {
|
export function putPreloader(elem: Element, returnDiv = false): HTMLElement {
|
||||||
const html = `
|
const html = `
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="preloader-circular" viewBox="25 25 50 50">
|
<svg xmlns="http://www.w3.org/2000/svg" class="preloader-circular" viewBox="25 25 50 50">
|
||||||
<circle class="preloader-path" cx="50" cy="50" r="20" fill="none" stroke-miterlimit="10"/>
|
<circle class="preloader-path" cx="50" cy="50" r="20" fill="none" stroke-miterlimit="10"/>
|
||||||
</svg>`;
|
</svg>`;
|
||||||
|
|
||||||
if(returnDiv) {
|
if(returnDiv) {
|
||||||
let div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.classList.add('preloader');
|
div.classList.add('preloader');
|
||||||
div.innerHTML = html;
|
div.innerHTML = html;
|
||||||
|
|
||||||
@ -74,6 +74,7 @@ export function putPreloader(elem: Element, returnDiv = false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
elem.innerHTML += html;
|
elem.innerHTML += html;
|
||||||
|
return elem.lastElementChild as HTMLElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.putPreloader = putPreloader);
|
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.putPreloader = putPreloader);
|
||||||
|
@ -5,7 +5,7 @@ import Button from "../../../button";
|
|||||||
import SidebarSlider, { SliderSuperTab } from "../../../slider";
|
import SidebarSlider, { SliderSuperTab } from "../../../slider";
|
||||||
import { wrapSticker } from "../../../wrappers";
|
import { wrapSticker } from "../../../wrappers";
|
||||||
import InputField from "../../../inputField";
|
import InputField from "../../../inputField";
|
||||||
import { attachClickEvent, cancelEvent } from "../../../../helpers/dom";
|
import { attachClickEvent, cancelEvent, canFocus } from "../../../../helpers/dom";
|
||||||
import PopupConfirmAction from "../../../popups/confirmAction";
|
import PopupConfirmAction from "../../../popups/confirmAction";
|
||||||
import { putPreloader } from "../../../misc";
|
import { putPreloader } from "../../../misc";
|
||||||
import passwordManager from "../../../../lib/mtproto/passwordManager";
|
import passwordManager from "../../../../lib/mtproto/passwordManager";
|
||||||
@ -19,6 +19,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
|
|||||||
public plainPassword: string;
|
public plainPassword: string;
|
||||||
public newPassword: string;
|
public newPassword: string;
|
||||||
public hint: string;
|
public hint: string;
|
||||||
|
public isFirst = false;
|
||||||
|
|
||||||
constructor(slider: SidebarSlider) {
|
constructor(slider: SidebarSlider) {
|
||||||
super(slider, true);
|
super(slider, true);
|
||||||
@ -29,7 +30,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
|
|||||||
this.title.innerHTML = 'Recovery Email';
|
this.title.innerHTML = 'Recovery Email';
|
||||||
|
|
||||||
const section = new SettingSection({
|
const section = new SettingSection({
|
||||||
caption: ' ',
|
caption: '',
|
||||||
noDelimiter: true
|
noDelimiter: true
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -69,7 +70,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
|
|||||||
inputField.input.addEventListener('keypress', (e) => {
|
inputField.input.addEventListener('keypress', (e) => {
|
||||||
if(e.key === 'Enter') {
|
if(e.key === 'Enter') {
|
||||||
cancelEvent(e);
|
cancelEvent(e);
|
||||||
return btnContinue.click();
|
return onContinueClick();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -78,13 +79,13 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const btnContinue = Button('btn-primary btn-color-primary', {text: 'CONTINUE'});
|
const btnContinue = Button('btn-primary btn-color-primary', {text: 'CONTINUE'});
|
||||||
const btnSkip = Button('btn-primary btn-primary-transparent primary', {text: 'SKIP'});
|
const btnSkip = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'SKIP'});
|
||||||
|
|
||||||
const goNext = () => {
|
const goNext = () => {
|
||||||
new AppTwoStepVerificationSetTab(this.slider).open();
|
new AppTwoStepVerificationSetTab(this.slider).open();
|
||||||
};
|
};
|
||||||
|
|
||||||
attachClickEvent(btnContinue, (e) => {
|
const onContinueClick = () => {
|
||||||
const email = inputField.value.trim();
|
const email = inputField.value.trim();
|
||||||
const match = RichTextProcessor.matchEmail(email);
|
const match = RichTextProcessor.matchEmail(email);
|
||||||
if(!match || match[0].length !== email.length) {
|
if(!match || match[0].length !== email.length) {
|
||||||
@ -93,7 +94,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toggleButtons(true);
|
toggleButtons(true);
|
||||||
putPreloader(btnContinue);
|
const d = putPreloader(btnContinue);
|
||||||
|
|
||||||
passwordManager.updateSettings({
|
passwordManager.updateSettings({
|
||||||
hint: this.hint,
|
hint: this.hint,
|
||||||
@ -108,9 +109,6 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
|
|||||||
|
|
||||||
const tab = new AppTwoStepVerificationEmailConfirmationTab(this.slider);
|
const tab = new AppTwoStepVerificationEmailConfirmationTab(this.slider);
|
||||||
tab.state = this.state;
|
tab.state = this.state;
|
||||||
tab.newPassword = this.newPassword;
|
|
||||||
tab.plainPassword = this.plainPassword;
|
|
||||||
tab.hint = this.hint;
|
|
||||||
tab.email = email;
|
tab.email = email;
|
||||||
tab.length = symbols;
|
tab.length = symbols;
|
||||||
tab.open();
|
tab.open();
|
||||||
@ -119,8 +117,10 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toggleButtons(false);
|
toggleButtons(false);
|
||||||
|
d.remove();
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
|
attachClickEvent(btnContinue, onContinueClick);
|
||||||
|
|
||||||
const toggleButtons = (freeze: boolean) => {
|
const toggleButtons = (freeze: boolean) => {
|
||||||
if(freeze) {
|
if(freeze) {
|
||||||
@ -145,7 +145,8 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
|
|||||||
passwordManager.updateSettings({
|
passwordManager.updateSettings({
|
||||||
hint: this.hint,
|
hint: this.hint,
|
||||||
currentPassword: this.plainPassword,
|
currentPassword: this.plainPassword,
|
||||||
newPassword: this.newPassword
|
newPassword: this.newPassword,
|
||||||
|
email: ''
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
goNext();
|
goNext();
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
@ -169,6 +170,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onOpenAfterTimeout() {
|
onOpenAfterTimeout() {
|
||||||
|
if(!canFocus(this.isFirst)) return;
|
||||||
this.inputField.input.focus();
|
this.inputField.input.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,21 +4,19 @@ import appStickersManager from "../../../../lib/appManagers/appStickersManager";
|
|||||||
import Button from "../../../button";
|
import Button from "../../../button";
|
||||||
import SidebarSlider, { SliderSuperTab } from "../../../slider";
|
import SidebarSlider, { SliderSuperTab } from "../../../slider";
|
||||||
import { wrapSticker } from "../../../wrappers";
|
import { wrapSticker } from "../../../wrappers";
|
||||||
import InputField from "../../../inputField";
|
import { attachClickEvent, canFocus, toggleDisability } from "../../../../helpers/dom";
|
||||||
import { attachClickEvent } from "../../../../helpers/dom";
|
|
||||||
import PopupConfirmAction from "../../../popups/confirmAction";
|
|
||||||
import { putPreloader } from "../../../misc";
|
|
||||||
import passwordManager from "../../../../lib/mtproto/passwordManager";
|
import passwordManager from "../../../../lib/mtproto/passwordManager";
|
||||||
import AppTwoStepVerificationSetTab from "./passwordSet";
|
import AppTwoStepVerificationSetTab from "./passwordSet";
|
||||||
|
import CodeInputField from "../../../codeInputField";
|
||||||
|
import AppTwoStepVerificationEmailTab from "./email";
|
||||||
|
import { putPreloader } from "../../../misc";
|
||||||
|
|
||||||
export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSuperTab {
|
export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSuperTab {
|
||||||
public inputField: InputField;
|
public codeInputField: CodeInputField;
|
||||||
public state: AccountPassword;
|
public state: AccountPassword;
|
||||||
public plainPassword: string;
|
|
||||||
public newPassword: string;
|
|
||||||
public hint: string;
|
|
||||||
public email: string;
|
public email: string;
|
||||||
public length: number;
|
public length: number;
|
||||||
|
public isFirst = false;
|
||||||
|
|
||||||
constructor(slider: SidebarSlider) {
|
constructor(slider: SidebarSlider) {
|
||||||
super(slider, true);
|
super(slider, true);
|
||||||
@ -29,10 +27,12 @@ export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSu
|
|||||||
this.title.innerHTML = 'Recovery Email';
|
this.title.innerHTML = 'Recovery Email';
|
||||||
|
|
||||||
const section = new SettingSection({
|
const section = new SettingSection({
|
||||||
caption: ' ',
|
caption: 'Please enter code we\'ve just emailed at <b></b>',
|
||||||
noDelimiter: true
|
noDelimiter: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
(section.caption.lastElementChild as HTMLElement).innerText = this.email;
|
||||||
|
|
||||||
const emoji = '📬';
|
const emoji = '📬';
|
||||||
const doc = appStickersManager.getAnimatedEmojiSticker(emoji);
|
const doc = appStickersManager.getAnimatedEmojiSticker(emoji);
|
||||||
const stickerContainer = document.createElement('div');
|
const stickerContainer = document.createElement('div');
|
||||||
@ -60,54 +60,69 @@ export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSu
|
|||||||
const inputWrapper = document.createElement('div');
|
const inputWrapper = document.createElement('div');
|
||||||
inputWrapper.classList.add('input-wrapper');
|
inputWrapper.classList.add('input-wrapper');
|
||||||
|
|
||||||
const inputField = this.inputField = new InputField({
|
const inputField = this.codeInputField = new CodeInputField({
|
||||||
name: 'recovery-email-code',
|
name: 'recovery-email-code',
|
||||||
label: 'Code'
|
label: 'Code',
|
||||||
|
length: this.length,
|
||||||
|
onFill: (code) => {
|
||||||
|
freeze(true);
|
||||||
|
|
||||||
|
passwordManager.confirmPasswordEmail('' + code)
|
||||||
|
.then(value => {
|
||||||
|
if(!value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
goNext();
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
switch(err.type) {
|
||||||
|
case 'CODE_INVALID':
|
||||||
|
inputField.input.classList.add('error');
|
||||||
|
inputField.label.innerText = 'Invalid Code';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
console.error('confirm error', err);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeze(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const btnContinue = Button('btn-primary btn-color-primary', {text: 'CONTINUE'});
|
const btnChange = Button('btn-primary btn-primary-transparent primary', {text: 'CHANGE EMAIL'});
|
||||||
const btnSkip = Button('btn-primary btn-primary-transparent primary', {text: 'SKIP'});
|
const btnResend = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'RE-SEND CODE'});
|
||||||
|
|
||||||
const goNext = () => {
|
const goNext = () => {
|
||||||
new AppTwoStepVerificationSetTab(this.slider).open();
|
new AppTwoStepVerificationSetTab(this.slider).open();
|
||||||
};
|
};
|
||||||
|
|
||||||
attachClickEvent(btnContinue, (e) => {
|
const freeze = (disable: boolean) => {
|
||||||
|
toggleDisability([inputField.input, btnChange, btnResend], disable);
|
||||||
});
|
};
|
||||||
|
|
||||||
attachClickEvent(btnSkip, (e) => {
|
attachClickEvent(btnChange, (e) => {
|
||||||
const popup = new PopupConfirmAction('popup-skip-email', [{
|
freeze(true);
|
||||||
text: 'CANCEL',
|
passwordManager.cancelPasswordEmail().then(value => {
|
||||||
isCancel: true
|
this.slider.sliceTabsUntilTab(AppTwoStepVerificationEmailTab, this);
|
||||||
}, {
|
this.close();
|
||||||
text: 'SKIP',
|
}, () => {
|
||||||
callback: () => {
|
freeze(false);
|
||||||
//inputContent.classList.add('sidebar-left-section-disabled');
|
|
||||||
btnContinue.setAttribute('disabled', 'true');
|
|
||||||
btnSkip.setAttribute('disabled', 'true');
|
|
||||||
putPreloader(btnSkip);
|
|
||||||
passwordManager.updateSettings({
|
|
||||||
hint: this.hint,
|
|
||||||
currentPassword: this.plainPassword,
|
|
||||||
newPassword: this.newPassword
|
|
||||||
}).then(() => {
|
|
||||||
goNext();
|
|
||||||
}, (err) => {
|
|
||||||
btnContinue.removeAttribute('disabled');
|
|
||||||
btnSkip.removeAttribute('disabled');
|
|
||||||
});
|
|
||||||
},
|
|
||||||
isDanger: true,
|
|
||||||
}], {
|
|
||||||
title: 'Warning',
|
|
||||||
text: 'No, seriously.<br/><br/>If you forget your password, you will lose access to your Telegram account. There will be no way to restore it.'
|
|
||||||
});
|
});
|
||||||
|
|
||||||
popup.show();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
inputWrapper.append(inputField.container, btnContinue, btnSkip);
|
attachClickEvent(btnResend, (e) => {
|
||||||
|
freeze(true);
|
||||||
|
const d = putPreloader(btnResend);
|
||||||
|
passwordManager.resendPasswordEmail().then(value => {
|
||||||
|
d.remove();
|
||||||
|
freeze(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
inputWrapper.append(inputField.container, btnChange, btnResend);
|
||||||
|
|
||||||
inputContent.append(inputWrapper);
|
inputContent.append(inputWrapper);
|
||||||
|
|
||||||
@ -115,6 +130,7 @@ export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSu
|
|||||||
}
|
}
|
||||||
|
|
||||||
onOpenAfterTimeout() {
|
onOpenAfterTimeout() {
|
||||||
this.inputField.input.focus();
|
if(!canFocus(this.isFirst)) return;
|
||||||
|
this.codeInputField.input.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import AppTwoStepVerificationTab from ".";
|
import AppTwoStepVerificationTab from ".";
|
||||||
import { SettingSection } from "../..";
|
import { SettingSection } from "../..";
|
||||||
import { attachClickEvent, cancelEvent } from "../../../../helpers/dom";
|
import { attachClickEvent, cancelEvent, canFocus } from "../../../../helpers/dom";
|
||||||
|
import { isMobileSafari } from "../../../../helpers/userAgent";
|
||||||
import { AccountPassword } from "../../../../layer";
|
import { AccountPassword } from "../../../../layer";
|
||||||
import passwordManager from "../../../../lib/mtproto/passwordManager";
|
import passwordManager from "../../../../lib/mtproto/passwordManager";
|
||||||
import RichTextProcessor from "../../../../lib/richtextprocessor";
|
import RichTextProcessor from "../../../../lib/richtextprocessor";
|
||||||
@ -16,6 +17,7 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
|
|||||||
public state: AccountPassword;
|
public state: AccountPassword;
|
||||||
public passwordInputField: PasswordInputField;
|
public passwordInputField: PasswordInputField;
|
||||||
public plainPassword: string;
|
public plainPassword: string;
|
||||||
|
public isFirst = true;
|
||||||
|
|
||||||
constructor(slider: SidebarSlider) {
|
constructor(slider: SidebarSlider) {
|
||||||
super(slider, true);
|
super(slider, true);
|
||||||
@ -56,7 +58,7 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(e.key === 'Enter') {
|
if(e.key === 'Enter') {
|
||||||
return btnContinue.click();
|
return onContinueClick();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -69,6 +71,7 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let onContinueClick: (e?: Event) => void;
|
||||||
if(!isNew) {
|
if(!isNew) {
|
||||||
let getStateInterval: number;
|
let getStateInterval: number;
|
||||||
|
|
||||||
@ -123,12 +126,15 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
attachClickEvent(btnContinue, submit);
|
onContinueClick = submit;
|
||||||
|
|
||||||
getState();
|
getState();
|
||||||
} else {
|
} else {
|
||||||
attachClickEvent(btnContinue, (e) => {
|
onContinueClick = (e) => {
|
||||||
cancelEvent(e);
|
if(e) {
|
||||||
|
cancelEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
if(!verifyInput()) return;
|
if(!verifyInput()) return;
|
||||||
|
|
||||||
const tab = new AppTwoStepVerificationReEnterPasswordTab(this.slider);
|
const tab = new AppTwoStepVerificationReEnterPasswordTab(this.slider);
|
||||||
@ -136,11 +142,14 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
|
|||||||
tab.newPassword = passwordInputField.value;
|
tab.newPassword = passwordInputField.value;
|
||||||
tab.plainPassword = this.plainPassword;
|
tab.plainPassword = this.plainPassword;
|
||||||
tab.open();
|
tab.open();
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attachClickEvent(btnContinue, onContinueClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
onOpenAfterTimeout() {
|
onOpenAfterTimeout() {
|
||||||
|
if(!canFocus(this.isFirst)) return;
|
||||||
this.passwordInputField.input.focus();
|
this.passwordInputField.input.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import { wrapSticker } from "../../../wrappers";
|
|||||||
import InputField from "../../../inputField";
|
import InputField from "../../../inputField";
|
||||||
import AppTwoStepVerificationEmailTab from "./email";
|
import AppTwoStepVerificationEmailTab from "./email";
|
||||||
import { attachClickEvent, cancelEvent } from "../../../../helpers/dom";
|
import { attachClickEvent, cancelEvent } from "../../../../helpers/dom";
|
||||||
|
import { toast } from "../../../toast";
|
||||||
|
|
||||||
export default class AppTwoStepVerificationHintTab extends SliderSuperTab {
|
export default class AppTwoStepVerificationHintTab extends SliderSuperTab {
|
||||||
public inputField: InputField;
|
public inputField: InputField;
|
||||||
@ -23,7 +24,6 @@ export default class AppTwoStepVerificationHintTab extends SliderSuperTab {
|
|||||||
this.title.innerHTML = 'Password Hint';
|
this.title.innerHTML = 'Password Hint';
|
||||||
|
|
||||||
const section = new SettingSection({
|
const section = new SettingSection({
|
||||||
caption: ' ',
|
|
||||||
noDelimiter: true
|
noDelimiter: true
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -60,28 +60,37 @@ export default class AppTwoStepVerificationHintTab extends SliderSuperTab {
|
|||||||
inputField.input.addEventListener('keypress', (e) => {
|
inputField.input.addEventListener('keypress', (e) => {
|
||||||
if(e.key === 'Enter') {
|
if(e.key === 'Enter') {
|
||||||
cancelEvent(e);
|
cancelEvent(e);
|
||||||
return (inputField.value ? btnContinue : btnSkip).click();
|
return inputField.value ? onContinueClick() : onSkipClick();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const goNext = (e: Event, saveHint: boolean) => {
|
const goNext = (e?: Event, saveHint?: boolean) => {
|
||||||
cancelEvent(e);
|
if(e) {
|
||||||
|
cancelEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
const hint = saveHint ? inputField.value : undefined;
|
||||||
|
if(hint && this.newPassword === hint) {
|
||||||
|
toast('Hint must be different from your password');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const tab = new AppTwoStepVerificationEmailTab(this.slider);
|
const tab = new AppTwoStepVerificationEmailTab(this.slider);
|
||||||
tab.state = this.state;
|
tab.state = this.state;
|
||||||
tab.plainPassword = this.plainPassword;
|
tab.plainPassword = this.plainPassword;
|
||||||
tab.newPassword = this.newPassword;
|
tab.newPassword = this.newPassword;
|
||||||
if(saveHint) {
|
tab.hint = hint;
|
||||||
tab.hint = inputField.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
tab.open();
|
tab.open();
|
||||||
};
|
};
|
||||||
|
|
||||||
const btnContinue = Button('btn-primary btn-color-primary', {text: 'CONTINUE'});
|
const btnContinue = Button('btn-primary btn-color-primary', {text: 'CONTINUE'});
|
||||||
const btnSkip = Button('btn-primary btn-primary-transparent primary', {text: 'SKIP'});
|
const btnSkip = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'SKIP'});
|
||||||
|
|
||||||
attachClickEvent(btnContinue, (e) => goNext(e, true));
|
const onContinueClick = (e?: Event) => goNext(e, true);
|
||||||
attachClickEvent(btnSkip, (e) => goNext(e, false));
|
const onSkipClick = (e?: Event) => goNext(e, false);
|
||||||
|
attachClickEvent(btnContinue, onContinueClick);
|
||||||
|
attachClickEvent(btnSkip, onSkipClick);
|
||||||
|
|
||||||
inputWrapper.append(inputField.container, btnContinue, btnSkip);
|
inputWrapper.append(inputField.container, btnContinue, btnSkip);
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import PopupConfirmAction from "../../../popups/confirmAction";
|
|||||||
import SidebarSlider, { SliderSuperTab } from "../../../slider";
|
import SidebarSlider, { SliderSuperTab } from "../../../slider";
|
||||||
import { wrapSticker } from "../../../wrappers";
|
import { wrapSticker } from "../../../wrappers";
|
||||||
import AppSettingsTab from "../settings";
|
import AppSettingsTab from "../settings";
|
||||||
|
import AppTwoStepVerificationEmailTab from "./email";
|
||||||
import AppTwoStepVerificationEnterPasswordTab from "./enterPassword";
|
import AppTwoStepVerificationEnterPasswordTab from "./enterPassword";
|
||||||
|
|
||||||
export default class AppTwoStepVerificationTab extends SliderSuperTab {
|
export default class AppTwoStepVerificationTab extends SliderSuperTab {
|
||||||
@ -19,7 +20,7 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected init() {
|
protected init() {
|
||||||
this.container.classList.add('two-step-verification');
|
this.container.classList.add('two-step-verification', 'two-step-verification-main');
|
||||||
this.title.innerHTML = 'Two-Step Verification';
|
this.title.innerHTML = 'Two-Step Verification';
|
||||||
|
|
||||||
const section = new SettingSection({
|
const section = new SettingSection({
|
||||||
@ -55,7 +56,7 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab {
|
|||||||
|
|
||||||
const btnChangePassword = Button('btn-primary btn-transparent', {icon: 'edit', text: 'Change Password'});
|
const btnChangePassword = Button('btn-primary btn-transparent', {icon: 'edit', text: 'Change Password'});
|
||||||
const btnDisablePassword = Button('btn-primary btn-transparent', {icon: 'passwordoff', text: 'Turn Password Off'});
|
const btnDisablePassword = Button('btn-primary btn-transparent', {icon: 'passwordoff', text: 'Turn Password Off'});
|
||||||
const btnSetRecoveryEmail = Button('btn-primary btn-transparent', {icon: 'email', text: 'Set Recovery Email'});
|
const btnSetRecoveryEmail = Button('btn-primary btn-transparent', {icon: 'email', text: this.state.pFlags.has_recovery ? 'Change Recovery Email' : 'Set Recovery Email'});
|
||||||
|
|
||||||
attachClickEvent(btnChangePassword, () => {
|
attachClickEvent(btnChangePassword, () => {
|
||||||
const tab = new AppTwoStepVerificationEnterPasswordTab(this.slider);
|
const tab = new AppTwoStepVerificationEnterPasswordTab(this.slider);
|
||||||
@ -82,6 +83,16 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab {
|
|||||||
popup.show();
|
popup.show();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
attachClickEvent(btnSetRecoveryEmail, () => {
|
||||||
|
const tab = new AppTwoStepVerificationEmailTab(this.slider);
|
||||||
|
tab.state = this.state;
|
||||||
|
tab.hint = this.state.hint;
|
||||||
|
tab.plainPassword = this.plainPassword;
|
||||||
|
tab.newPassword = this.plainPassword;
|
||||||
|
tab.isFirst = true;
|
||||||
|
tab.open();
|
||||||
|
});
|
||||||
|
|
||||||
c.append(btnChangePassword, btnDisablePassword, btnSetRecoveryEmail);
|
c.append(btnChangePassword, btnDisablePassword, btnSetRecoveryEmail);
|
||||||
} else {
|
} else {
|
||||||
section.caption.innerHTML = 'You can set a password that will be required when you log in on a new device in addition to the code you get in the SMS.';
|
section.caption.innerHTML = 'You can set a password that will be required when you log in on a new device in addition to the code you get in the SMS.';
|
||||||
|
@ -31,8 +31,7 @@ export default class AppTwoStepVerificationSetTab extends SliderSuperTab {
|
|||||||
loop: true,
|
loop: true,
|
||||||
play: true,
|
play: true,
|
||||||
width: 160,
|
width: 160,
|
||||||
height: 160,
|
height: 160
|
||||||
emoji
|
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
// this.animation = player;
|
// this.animation = player;
|
||||||
});
|
});
|
||||||
|
@ -52,7 +52,7 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(e.key === 'Enter') {
|
if(e.key === 'Enter') {
|
||||||
return btnContinue.click();
|
return onContinueClick();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -65,8 +65,11 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
attachClickEvent(btnContinue, (e) => {
|
const onContinueClick = (e?: Event) => {
|
||||||
cancelEvent(e);
|
if(e) {
|
||||||
|
cancelEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
if(!verifyInput()) return;
|
if(!verifyInput()) return;
|
||||||
|
|
||||||
const tab = new AppTwoStepVerificationHintTab(this.slider);
|
const tab = new AppTwoStepVerificationHintTab(this.slider);
|
||||||
@ -74,7 +77,8 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
|
|||||||
tab.plainPassword = this.plainPassword;
|
tab.plainPassword = this.plainPassword;
|
||||||
tab.newPassword = this.newPassword;
|
tab.newPassword = this.newPassword;
|
||||||
tab.open();
|
tab.open();
|
||||||
});
|
};
|
||||||
|
attachClickEvent(btnContinue, onContinueClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
onOpenAfterTimeout() {
|
onOpenAfterTimeout() {
|
||||||
|
@ -7,6 +7,7 @@ import AppPrivacyPhoneNumberTab from "./privacy/phoneNumber";
|
|||||||
import AppTwoStepVerificationTab from "./2fa";
|
import AppTwoStepVerificationTab from "./2fa";
|
||||||
import passwordManager from "../../../lib/mtproto/passwordManager";
|
import passwordManager from "../../../lib/mtproto/passwordManager";
|
||||||
import AppTwoStepVerificationEnterPasswordTab from "./2fa/enterPassword";
|
import AppTwoStepVerificationEnterPasswordTab from "./2fa/enterPassword";
|
||||||
|
import AppTwoStepVerificationEmailConfirmationTab from "./2fa/emailConfirmation";
|
||||||
|
|
||||||
export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||||
constructor(slider: SidebarSlider) {
|
constructor(slider: SidebarSlider) {
|
||||||
@ -35,9 +36,15 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
|||||||
title: 'Two-Step Verification',
|
title: 'Two-Step Verification',
|
||||||
subtitle: 'Loading...',
|
subtitle: 'Loading...',
|
||||||
clickable: (e: Event) => {
|
clickable: (e: Event) => {
|
||||||
let tab: AppTwoStepVerificationTab | AppTwoStepVerificationEnterPasswordTab;
|
let tab: AppTwoStepVerificationTab | AppTwoStepVerificationEnterPasswordTab | AppTwoStepVerificationEmailConfirmationTab;
|
||||||
if(passwordState.pFlags.has_password) {
|
if(passwordState.pFlags.has_password) {
|
||||||
tab = new AppTwoStepVerificationEnterPasswordTab(this.slider);
|
tab = new AppTwoStepVerificationEnterPasswordTab(this.slider);
|
||||||
|
} else if(passwordState.email_unconfirmed_pattern) {
|
||||||
|
tab = new AppTwoStepVerificationEmailConfirmationTab(this.slider);
|
||||||
|
tab.email = passwordState.email_unconfirmed_pattern;
|
||||||
|
tab.length = 6;
|
||||||
|
tab.isFirst = true;
|
||||||
|
passwordManager.resendPasswordEmail();
|
||||||
} else {
|
} else {
|
||||||
tab = new AppTwoStepVerificationTab(this.slider);
|
tab = new AppTwoStepVerificationTab(this.slider);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { MessageEntity } from "../layer";
|
|||||||
import RichTextProcessor from "../lib/richtextprocessor";
|
import RichTextProcessor from "../lib/richtextprocessor";
|
||||||
import ListenerSetter from "./listenerSetter";
|
import ListenerSetter from "./listenerSetter";
|
||||||
import { isTouchSupported } from "./touchSupport";
|
import { isTouchSupported } from "./touchSupport";
|
||||||
import { isApple } from "./userAgent";
|
import { isApple, isMobileSafari } from "./userAgent";
|
||||||
import rootScope from "../lib/rootScope";
|
import rootScope from "../lib/rootScope";
|
||||||
import { MOUNT_CLASS_TO } from "../config/debug";
|
import { MOUNT_CLASS_TO } from "../config/debug";
|
||||||
import { doubleRaf } from "./schedulers";
|
import { doubleRaf } from "./schedulers";
|
||||||
@ -784,3 +784,15 @@ export function disableTransition(elements: HTMLElement[]) {
|
|||||||
elements.forEach(el => el.classList.remove('no-transition'));
|
elements.forEach(el => el.classList.remove('no-transition'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toggleDisability(elements: HTMLElement[], disable: boolean) {
|
||||||
|
if(disable) {
|
||||||
|
elements.forEach(el => el.setAttribute('disabled', 'true'));
|
||||||
|
} else {
|
||||||
|
elements.forEach(el => el.removeAttribute('disabled'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canFocus(isFirstInput: boolean) {
|
||||||
|
return !isMobileSafari || !isFirstInput;
|
||||||
|
}
|
||||||
|
@ -181,7 +181,7 @@ export class AppDialogsManager {
|
|||||||
public doms: {[peerId: number]: DialogDom} = {};
|
public doms: {[peerId: number]: DialogDom} = {};
|
||||||
|
|
||||||
public chatsContainer = document.getElementById('chatlist-container') as HTMLDivElement;
|
public chatsContainer = document.getElementById('chatlist-container') as HTMLDivElement;
|
||||||
private chatsPreloader: HTMLDivElement;
|
private chatsPreloader: HTMLElement;
|
||||||
|
|
||||||
public loadDialogsPromise: Promise<any>;
|
public loadDialogsPromise: Promise<any>;
|
||||||
|
|
||||||
|
@ -80,6 +80,18 @@ export class PasswordManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public confirmPasswordEmail(code: string) {
|
||||||
|
return apiManager.invokeApi('account.confirmPasswordEmail', {code});
|
||||||
|
}
|
||||||
|
|
||||||
|
public resendPasswordEmail() {
|
||||||
|
return apiManager.invokeApi('account.resendPasswordEmail');
|
||||||
|
}
|
||||||
|
|
||||||
|
public cancelPasswordEmail() {
|
||||||
|
return apiManager.invokeApi('account.cancelPasswordEmail');
|
||||||
|
}
|
||||||
|
|
||||||
/* public requestRecovery(options: any = {}) {
|
/* public requestRecovery(options: any = {}) {
|
||||||
return apiManager.invokeApi('auth.requestPasswordRecovery', {}, options);
|
return apiManager.invokeApi('auth.requestPasswordRecovery', {}, options);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import mediaSizes from '../helpers/mediaSizes';
|
import mediaSizes from '../helpers/mediaSizes';
|
||||||
import { AuthSentCode, AuthSentCodeType } from '../layer';
|
import { AuthSentCode, AuthSentCodeType, AuthSignIn } from '../layer';
|
||||||
import appStateManager from '../lib/appManagers/appStateManager';
|
import appStateManager from '../lib/appManagers/appStateManager';
|
||||||
import apiManager from '../lib/mtproto/mtprotoworker';
|
import apiManager from '../lib/mtproto/mtprotoworker';
|
||||||
import Page from './page';
|
import Page from './page';
|
||||||
@ -7,8 +7,8 @@ import pageIm from './pageIm';
|
|||||||
import pagePassword from './pagePassword';
|
import pagePassword from './pagePassword';
|
||||||
import pageSignIn from './pageSignIn';
|
import pageSignIn from './pageSignIn';
|
||||||
import pageSignUp from './pageSignUp';
|
import pageSignUp from './pageSignUp';
|
||||||
import InputField from '../components/inputField';
|
|
||||||
import TrackingMonkey from '../components/monkeys/tracking';
|
import TrackingMonkey from '../components/monkeys/tracking';
|
||||||
|
import CodeInputField from '../components/codeInputField';
|
||||||
|
|
||||||
let authCode: AuthSentCode.authSentCode = null;
|
let authCode: AuthSentCode.authSentCode = null;
|
||||||
|
|
||||||
@ -17,24 +17,21 @@ let sentTypeElement: HTMLParagraphElement = null;
|
|||||||
let codeInput: HTMLInputElement;
|
let codeInput: HTMLInputElement;
|
||||||
|
|
||||||
let onFirstMount = (): Promise<any> => {
|
let onFirstMount = (): Promise<any> => {
|
||||||
let lastLength = 0;
|
|
||||||
|
|
||||||
const CODELENGTH = (authCode.type as AuthSentCodeType.authSentCodeTypeApp).length;
|
const CODELENGTH = (authCode.type as AuthSentCodeType.authSentCodeTypeApp).length;
|
||||||
|
|
||||||
const codeInputField = new InputField({
|
const codeInputField = new CodeInputField({
|
||||||
label: 'Code',
|
label: 'Code',
|
||||||
name: 'code',
|
name: 'code',
|
||||||
plainText: true
|
length: CODELENGTH,
|
||||||
|
onFill: (code) => {
|
||||||
|
submitCode('' + code);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
codeInput = codeInputField.input as HTMLInputElement;
|
codeInput = codeInputField.input as HTMLInputElement;
|
||||||
codeInput.type = 'tel';
|
|
||||||
codeInput.setAttribute('required', '');
|
|
||||||
codeInput.autocomplete = 'off';
|
|
||||||
|
|
||||||
page.pageEl.querySelector('.input-wrapper').append(codeInputField.container);
|
page.pageEl.querySelector('.input-wrapper').append(codeInputField.container);
|
||||||
|
|
||||||
const codeInputLabel = codeInput.nextElementSibling as HTMLLabelElement;
|
|
||||||
const editButton = page.pageEl.querySelector('.phone-edit') as HTMLElement;
|
const editButton = page.pageEl.querySelector('.phone-edit') as HTMLElement;
|
||||||
|
|
||||||
editButton.addEventListener('click', function() {
|
editButton.addEventListener('click', function() {
|
||||||
@ -50,7 +47,7 @@ let onFirstMount = (): Promise<any> => {
|
|||||||
const submitCode = (code: string) => {
|
const submitCode = (code: string) => {
|
||||||
codeInput.setAttribute('disabled', 'true');
|
codeInput.setAttribute('disabled', 'true');
|
||||||
|
|
||||||
const params = {
|
const params: AuthSignIn = {
|
||||||
phone_number: authCode.phone_number,
|
phone_number: authCode.phone_number,
|
||||||
phone_code_hash: authCode.phone_code_hash,
|
phone_code_hash: authCode.phone_code_hash,
|
||||||
phone_code: code
|
phone_code: code
|
||||||
@ -92,15 +89,15 @@ let onFirstMount = (): Promise<any> => {
|
|||||||
break;
|
break;
|
||||||
case 'PHONE_CODE_EXPIRED':
|
case 'PHONE_CODE_EXPIRED':
|
||||||
codeInput.classList.add('error');
|
codeInput.classList.add('error');
|
||||||
codeInputLabel.innerText = 'Code expired';
|
codeInputField.label.innerText = 'Code expired';
|
||||||
break;
|
break;
|
||||||
case 'PHONE_CODE_EMPTY':
|
case 'PHONE_CODE_EMPTY':
|
||||||
case 'PHONE_CODE_INVALID':
|
case 'PHONE_CODE_INVALID':
|
||||||
codeInput.classList.add('error');
|
codeInput.classList.add('error');
|
||||||
codeInputLabel.innerText = 'Invalid Code';
|
codeInputField.label.innerText = 'Invalid Code';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
codeInputLabel.innerText = err.type;
|
codeInputField.label.innerText = err.type;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,25 +105,6 @@ let onFirstMount = (): Promise<any> => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
codeInput.addEventListener('input', function(this: typeof codeInput, e) {
|
|
||||||
this.classList.remove('error');
|
|
||||||
codeInputLabel.innerText = 'Code';
|
|
||||||
|
|
||||||
this.value = this.value.replace(/\D/g, '');
|
|
||||||
if(this.value.length > CODELENGTH) {
|
|
||||||
this.value = this.value.slice(0, CODELENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
const length = this.value.length;
|
|
||||||
if(length === CODELENGTH) { // submit code
|
|
||||||
submitCode(this.value);
|
|
||||||
} else if(length === lastLength) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastLength = length;
|
|
||||||
});
|
|
||||||
|
|
||||||
const imageDiv = page.pageEl.querySelector('.auth-image') as HTMLDivElement;
|
const imageDiv = page.pageEl.querySelector('.auth-image') as HTMLDivElement;
|
||||||
const size = mediaSizes.isMobile ? 100 : 166;
|
const size = mediaSizes.isMobile ? 100 : 166;
|
||||||
const monkey = new TrackingMonkey(codeInputField, size);
|
const monkey = new TrackingMonkey(codeInputField, size);
|
||||||
|
@ -264,6 +264,10 @@
|
|||||||
|
|
||||||
@include hover-background-effect();
|
@include hover-background-effect();
|
||||||
|
|
||||||
|
&.danger {
|
||||||
|
@include hover-background-effect(red);
|
||||||
|
}
|
||||||
|
|
||||||
// * tgico
|
// * tgico
|
||||||
&:before {
|
&:before {
|
||||||
color: #707579;
|
color: #707579;
|
||||||
|
@ -913,8 +913,14 @@
|
|||||||
margin-bottom: 1.125rem;
|
margin-bottom: 1.125rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary + .btn-primary {
|
&-main {
|
||||||
margin-top: .125rem !important;
|
.btn-primary + .btn-primary {
|
||||||
|
margin-top: .125rem !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
margin-top: .5rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-sticker-wrapper {
|
.media-sticker-wrapper {
|
||||||
@ -935,12 +941,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-hint, &-email {
|
|
||||||
.btn-primary + .btn-primary {
|
|
||||||
margin-top: .5rem !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-hint {
|
&-hint {
|
||||||
.media-sticker-wrapper {
|
.media-sticker-wrapper {
|
||||||
width: 160px;
|
width: 160px;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user