diff --git a/src/components/dotRenderer.ts b/src/components/dotRenderer.ts index b2f23d219..e3d5b29a7 100644 --- a/src/components/dotRenderer.ts +++ b/src/components/dotRenderer.ts @@ -36,7 +36,7 @@ export default class DotRenderer implements AnimationItemWrapper { const dpr = this.dpr = window.devicePixelRatio; canvas.width = width * dpr; canvas.height = height * dpr; - canvas.style.cssText = `position: absolute; width: 100%; height: 100%; z-index: 1;`; + canvas.classList.add('canvas-thumbnail', 'canvas-dots'); this.paused = true; this.autoplay = true; diff --git a/src/components/monkeys/password.ts b/src/components/monkeys/password.ts index 038a67ce2..6c315676c 100644 --- a/src/components/monkeys/password.ts +++ b/src/components/monkeys/password.ts @@ -42,8 +42,8 @@ export default class PasswordMonkey { } }); - this.passwordInputField.onVisibilityClickAdditional = () => { - if(this.passwordInputField.passwordVisible) { + this.passwordInputField.helpers.onVisibilityClickAdditional = () => { + if(this.passwordInputField.helpers.passwordVisible) { this.animation.setDirection(1); this.animation.curFrame = 0; this.needFrame = 16; diff --git a/src/components/passwordInputField.ts b/src/components/passwordInputField.ts index aadeba965..4d59af71d 100644 --- a/src/components/passwordInputField.ts +++ b/src/components/passwordInputField.ts @@ -4,34 +4,20 @@ * https://github.com/morethanwords/tweb/blob/master/LICENSE */ -// import { IS_MOBILE_SAFARI, IS_SAFARI } from "../environment/userAgent"; import cancelEvent from '../helpers/dom/cancelEvent'; import InputField, {InputFieldOptions} from './inputField'; -export default class PasswordInputField extends InputField { +export class PasswordInputHelpers { public passwordVisible = false; public toggleVisible: HTMLElement; public onVisibilityClickAdditional: () => void; - constructor(options: InputFieldOptions = {}) { - super({ - plainText: true, - ...options - }); - - const input = this.input as HTMLInputElement; + constructor(public container: HTMLElement, public input: HTMLInputElement) { input.type = 'password'; input.setAttribute('required', ''); input.name = 'notsearch_password'; input.autocomplete = 'off'; - /* if(IS_SAFARI && !IS_MOBILE_SAFARI) { - input.setAttribute('readonly', ''); - input.addEventListener('focus', () => { - input.removeAttribute('readonly'); - }, {once: true}); - } */ - // * https://stackoverflow.com/a/35949954/6758968 const stealthy = document.createElement('input'); stealthy.classList.add('stealthy'); @@ -40,11 +26,18 @@ export default class PasswordInputField extends InputField { input.parentElement.prepend(stealthy); input.parentElement.insertBefore(stealthy.cloneNode(), input.nextSibling); + /* if(IS_SAFARI && !IS_MOBILE_SAFARI) { + input.setAttribute('readonly', ''); + input.addEventListener('focus', () => { + input.removeAttribute('readonly'); + }, {once: true}); + } */ + const toggleVisible = this.toggleVisible = document.createElement('span'); toggleVisible.classList.add('toggle-visible', 'tgico'); - this.container.classList.add('input-field-password'); - this.container.append(toggleVisible); + container.classList.add('input-field-password'); + container.append(toggleVisible); toggleVisible.addEventListener('click', this.onVisibilityClick); toggleVisible.addEventListener('touchend', this.onVisibilityClick); @@ -59,3 +52,16 @@ export default class PasswordInputField extends InputField { this.onVisibilityClickAdditional && this.onVisibilityClickAdditional(); }; } + +export default class PasswordInputField extends InputField { + public helpers: PasswordInputHelpers; + + constructor(options: InputFieldOptions = {}) { + super({ + plainText: true, + ...options + }); + + this.helpers = new PasswordInputHelpers(this.container, this.input as HTMLInputElement); + } +} diff --git a/src/components/popups/payment.ts b/src/components/popups/payment.ts index 6a519e358..7898411fa 100644 --- a/src/components/popups/payment.ts +++ b/src/components/popups/payment.ts @@ -782,7 +782,7 @@ export default class PopupPayment extends PopupElement { if(paymentResult._ === 'payments.paymentResult') { onConfirmed(); } else { - popupPaymentVerification = new PopupPaymentVerification(paymentResult.url); + popupPaymentVerification = new PopupPaymentVerification(paymentResult.url, !mediaInvoice.extended_media); popupPaymentVerification.addEventListener('finish', () => { popupPaymentVerification = undefined; diff --git a/src/components/popups/paymentCard.ts b/src/components/popups/paymentCard.ts index 899f28d89..891398bf9 100644 --- a/src/components/popups/paymentCard.ts +++ b/src/components/popups/paymentCard.ts @@ -14,7 +14,6 @@ import {renderImageFromUrlPromise} from '../../helpers/dom/renderImageFromUrl'; import noop from '../../helpers/noop'; import {PaymentsPaymentForm} from '../../layer'; import {LangPackKey, _i18n} from '../../lib/langPack'; -import {TelegramWebviewEvent} from '../../types'; import CheckboxField from '../checkboxField'; import confirmationPopup from '../confirmationPopup'; import CountryInputField from '../countryInputField'; @@ -23,6 +22,7 @@ import Row from '../row'; import {SettingSection} from '../sidebarLeft'; import {getPaymentBrandIconPath, PaymentButton, PaymentsCredentialsToken} from './payment'; import {createVerificationIframe} from './paymentVerification'; +import {PasswordInputHelpers} from '../passwordInputField'; export type PaymentCardDetails = { cardNumber: string; @@ -335,15 +335,34 @@ export default class PopupPaymentCard extends PopupElement<{ validateMethod: validateCardExpiry }); + // handle autocomplete: 01/2345 -> 01/45 + expireInputField.input.addEventListener('input', () => { + let value = expireInputField.value; + if(value.length < 5) { + return; + } + + const splitted = value.split('/'); + if(splitted[1].length !== 4) { + return; + } + + value = [splitted[0], splitted[1].slice(2)].join('/'); + expireInputField.setValueSilently(value); + }, {capture: true}); + const cvcInputField = new InputFieldCorrected({ labelText: 'CVC', plainText: true, inputMode: 'numeric', autocomplete: 'cc-csc', + name: 'cvc', formatMethod: () => cardFormattingPatterns.cardCvc(cardInputField.value) // validateMethod: (...args) => _5AH3.a.cardCvc(cardInputField.value)(...args) }); + const passwordHelpers = new PasswordInputHelpers(cvcInputField.container, cvcInputField.input as HTMLInputElement); + const switchFocusOrder: (InputFieldCorrected | InputField)[] = [ cardInputField, expireInputField, @@ -391,11 +410,14 @@ export default class PopupPaymentCard extends PopupElement<{ inputFieldsRow.classList.add('input-fields-row'); inputFieldsRow.append(expireInputField.container, cvcInputField.container); - cardSection.content.append(...[ + const form = document.createElement('form'); + form.append(...[ cardInputField.container, inputFieldsRow, nameInputField?.container - ].filter(Boolean)); + ].filter(Boolean)) + + cardSection.content.append(form); let billingSection: SettingSection; // let saveCheckboxField: CheckboxField; diff --git a/src/components/popups/paymentVerification.ts b/src/components/popups/paymentVerification.ts index d23e8e8a1..d9c649e53 100644 --- a/src/components/popups/paymentVerification.ts +++ b/src/components/popups/paymentVerification.ts @@ -37,7 +37,7 @@ export function createVerificationIframe(url: string, callback: TelegramWebviewE export default class PopupPaymentVerification extends PopupElement<{ finish: () => void }> { - constructor(private url: string) { + constructor(private url: string, private openPathAfter?: boolean) { super('popup-payment popup-payment-verification', { closable: true, overlayClosable: true, @@ -56,7 +56,9 @@ export default class PopupPaymentVerification extends PopupElement<{ this.dispatchEvent('finish'); this.hide(); - appImManager.openUrl('https://t.me' + event.eventData.path_full); + if(this.openPathAfter) { + appImManager.openUrl('https://t.me' + event.eventData.path_full); + } }); this.body.append(iframe); diff --git a/src/helpers/dom/placeCaretAtEnd.ts b/src/helpers/dom/placeCaretAtEnd.ts index a55525b7e..42a601df6 100644 --- a/src/helpers/dom/placeCaretAtEnd.ts +++ b/src/helpers/dom/placeCaretAtEnd.ts @@ -12,7 +12,7 @@ import IS_TOUCH_SUPPORTED from '../../environment/touchSupport'; export default function placeCaretAtEnd(el: HTMLElement, ignoreTouchCheck = false, focus = true) { - if(IS_TOUCH_SUPPORTED && (!ignoreTouchCheck || document.activeElement !== el)) { + if(IS_TOUCH_SUPPORTED && (!ignoreTouchCheck || (document.activeElement.tagName !== 'INPUT' && !(document.activeElement as HTMLElement).isContentEditable))) { return; } diff --git a/src/scss/partials/_chatBubble.scss b/src/scss/partials/_chatBubble.scss index c77163178..82c10a397 100644 --- a/src/scss/partials/_chatBubble.scss +++ b/src/scss/partials/_chatBubble.scss @@ -622,6 +622,14 @@ $bubble-beside-button-width: 38px; .thumbnail { position: absolute; } + + .canvas-thumbnail { + border-radius: inherit; + } + + .canvas-dots { + z-index: 1; + } &.emoji-big { --emoji-size: 1rem; @@ -2884,8 +2892,12 @@ $bubble-beside-button-width: 38px; .reply-markup { width: 100%; + .bubble:not(.is-group-last) & { + margin-bottom: $bubble-margin; + } + &-row { - margin-top: .3125rem; + margin-top: .1875rem; overflow: hidden; min-height: 2.5rem; display: flex; diff --git a/src/scss/partials/_input.scss b/src/scss/partials/_input.scss index 50eec289e..f50e464d7 100644 --- a/src/scss/partials/_input.scss +++ b/src/scss/partials/_input.scss @@ -415,7 +415,7 @@ input:focus, button:focus { .input-field-input { padding-right: 2.5rem; max-height: var(--height); - + &[type="password"] { font-size: 2.25rem; padding-left: calc(.875rem - var(--border-width)); diff --git a/src/scss/partials/popups/_payment.scss b/src/scss/partials/popups/_payment.scss index c0ce8914a..f25862fbb 100644 --- a/src/scss/partials/popups/_payment.scss +++ b/src/scss/partials/popups/_payment.scss @@ -42,13 +42,17 @@ .input-field { --height: 3rem; - margin: 1.25rem .5rem 0; + margin: .75rem .5rem 0; &-input { --padding: .75rem; } } + .input-fields-row .input-field { + margin-top: 1.25rem; + } + .sidebar-left-section { padding: 0 !important;