Skip to content

Commit

Permalink
Disable auto-capitalization for lowercase only input fields
Browse files Browse the repository at this point in the history
There are a few fields where we don't use input type="email" but
shouldn't be capitalized. This includes some email fields,
domain names, and social handles to name a few.
As such, mobile devices automatically capitalize these fields.

Close #7403
  • Loading branch information
hrb-hub committed Oct 22, 2024
1 parent 873d562 commit 0922a96
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 20 deletions.
9 changes: 9 additions & 0 deletions src/common/gui/base/TextField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export type TextFieldAttrs = {
label: TranslationKey | lazy<string>
value: string
autocompleteAs?: Autocomplete
autocapitalize?: Autocapitalize
type?: TextFieldType
hasPopup?: AriaPopupType
helpLabel?: lazy<Children> | null
Expand Down Expand Up @@ -66,6 +67,12 @@ export const enum Autocomplete {
ccExp = "cc-exp",
}

// relevant subset of possible values for the autocapitalize html field
// https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autocapitalize
export const enum Autocapitalize {
none = "none",
}

export const inputLineHeight: number = size.font_size_base + 8
const inputMarginTop = size.font_size_small + size.hpad_small + 3

Expand Down Expand Up @@ -234,6 +241,7 @@ export class TextField implements ClassComponent<TextFieldAttrs> {
autofillGuard.concat([
m("input.input" + (a.alignRight ? ".right" : ""), {
autocomplete: a.autocompleteAs ?? "",
autocapitalize: a.autocapitalize,
type: a.type,
min: a.min,
max: a.max,
Expand Down Expand Up @@ -311,6 +319,7 @@ export class TextField implements ClassComponent<TextFieldAttrs> {
return m("textarea.input-area.text-pre", {
"aria-label": lang.getMaybeLazy(a.label),
disabled: a.disabled,
autocapitalize: a.autocapitalize,
class: getOperatingClasses(a.disabled) + " text",
oncreate: (vnode) => {
this.domInput = vnode.dom as HTMLInputElement
Expand Down
10 changes: 8 additions & 2 deletions src/common/settings/SelectMailAddressForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Icon } from "../gui/base/Icon.js"
import { locator } from "../api/main/CommonLocator.js"
import { assertMainOrNode } from "../api/common/Env.js"
import { px, size } from "../gui/size.js"
import { Autocomplete, inputLineHeight, TextField } from "../gui/base/TextField.js"
import { Autocapitalize, Autocomplete, inputLineHeight, TextField } from "../gui/base/TextField.js"
import { attachDropdown, DropdownButtonAttrs } from "../gui/base/Dropdown.js"
import { IconButton, IconButtonAttrs } from "../gui/base/IconButton.js"
import { ButtonSize } from "../gui/base/ButtonSize.js"
Expand Down Expand Up @@ -76,6 +76,7 @@ export class SelectMailAddressForm implements Component<SelectMailAddressFormAtt
value: this.username,
alignRight: true,
autocompleteAs: Autocomplete.newPassword,
autocapitalize: Autocapitalize.none,
helpLabel: () => this.addressHelpLabel(),
fontSize: px(size.font_size_smaller),
oninput: (value) => {
Expand Down Expand Up @@ -199,7 +200,12 @@ export class SelectMailAddressForm implements Component<SelectMailAddressFormAtt
let result: ValidationResult
try {
const available = await locator.mailAddressFacade.isMailAddressAvailable(cleanMailAddress)
result = available ? { isValid: true, errorId: null } : { isValid: false, errorId: attrs.mailAddressNAError ?? "mailAddressNA_msg" }
result = available
? { isValid: true, errorId: null }
: {
isValid: false,
errorId: attrs.mailAddressNAError ?? "mailAddressNA_msg",
}
} catch (e) {
if (e instanceof AccessDeactivatedError) {
result = { isValid: false, errorId: "mailAddressDelay_msg" }
Expand Down
10 changes: 4 additions & 6 deletions src/mail-app/contacts/ContactAggregateEditor.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
import { TextFieldAttrs, TextFieldType } from "../../common/gui/base/TextField.js"
import { TextField } from "../../common/gui/base/TextField.js"
import { TranslationKey, TranslationText } from "../../common/misc/LanguageViewModel"
import { lang } from "../../common/misc/LanguageViewModel"
import { Autocapitalize, TextField, TextFieldType } from "../../common/gui/base/TextField.js"
import { lang, TranslationKey, TranslationText } from "../../common/misc/LanguageViewModel"
import m, { Children, Component, Vnode, VnodeDOM } from "mithril"
import { Icons } from "../../common/gui/base/icons/Icons"
import { animations, height, opacity } from "../../common/gui/animation/Animations"
import { attachDropdown } from "../../common/gui/base/Dropdown.js"
import { IconButton } from "../../common/gui/base/IconButton.js"
import { BootIcons } from "../../common/gui/base/icons/BootIcons.js"
import { ButtonSize } from "../../common/gui/base/ButtonSize.js"
import { lazy } from "@tutao/tutanota-utils"
import type { TranslationKeyType } from "../../common/misc/TranslationKey.js"

export type AggregateEditorAttrs<AggregateType> = {
value: string
Expand All @@ -25,6 +21,7 @@ export type AggregateEditorAttrs<AggregateType> = {
helpLabel: TranslationText
typeLabels: ReadonlyArray<[AggregateType, TranslationKey]>
onTypeSelected: (arg0: AggregateType) => unknown
autocapitalizeTextField?: Autocapitalize
}

export class ContactAggregateEditor implements Component<AggregateEditorAttrs<any>> {
Expand All @@ -51,6 +48,7 @@ export class ContactAggregateEditor implements Component<AggregateEditorAttrs<an
value: attrs.value,
label: () => attrs.label,
type: attrs.fieldType,
autocapitalize: attrs.autocapitalizeTextField,
helpLabel: () => helpLabel(),
injectionsRight: () => this._moreButtonFor(attrs),
oninput: (value) => attrs.onUpdate(value),
Expand Down
23 changes: 20 additions & 3 deletions src/mail-app/contacts/ContactEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ import {
} from "./view/ContactGuiUtils"
import { parseBirthday } from "../../common/misc/DateParser"
import type { TextFieldAttrs } from "../../common/gui/base/TextField.js"
import { Autocomplete, TextField, TextFieldType } from "../../common/gui/base/TextField.js"
import { Autocapitalize, Autocomplete, TextField, TextFieldType } from "../../common/gui/base/TextField.js"
import { EntityClient } from "../../common/api/common/EntityClient"
import { timestampToGeneratedId } from "../../common/api/common/utils/EntityUtils"
import { AggregateEditorAttrs, ContactAggregateEditor } from "./ContactAggregateEditor"
Expand Down Expand Up @@ -174,7 +174,14 @@ export class ContactEditor {
this.messengerHandles.push(this.newMessengerHandler())
this.pronouns = this.contact.pronouns.map((pronoun) => [pronoun, id(pronoun)])
this.pronouns.push(this.newPronoun())
this.customDates = this.contact.customDate.map((date) => [{ ...date, date: formatContactDate(date.dateIso), isValid: true }, id(date)])
this.customDates = this.contact.customDate.map((date) => [
{
...date,
date: formatContactDate(date.dateIso),
isValid: true,
},
id(date),
])
this.customDates.push(this.newCustomDate())

this.hasInvalidBirthday = false
Expand Down Expand Up @@ -505,6 +512,7 @@ export class ContactEditor {
fieldType: TextFieldType.Text,
label: getContactSocialTypeLabel(downcast<ContactSocialType>(socialId.type), socialId.customTypeName),
helpLabel: "emptyString_msg",
autocapitalizeTextField: Autocapitalize.none,
cancelAction: () => {
findAndRemove(this.socialIds, (t) => t[1] === id)
},
Expand All @@ -527,6 +535,7 @@ export class ContactEditor {
fieldType: TextFieldType.Text,
label: getContactCustomWebsiteTypeToLabel(downcast<ContactWebsiteType>(website.type), website.customTypeName),
helpLabel: "emptyString_msg",
autocapitalizeTextField: Autocapitalize.none,
cancelAction: () => {
findAndRemove(this.websites, (t) => t[1] === id)
},
Expand Down Expand Up @@ -571,6 +580,7 @@ export class ContactEditor {
fieldType: TextFieldType.Text,
label: getContactMessengerHandleTypeToLabel(downcast<ContactMessengerHandleType>(messengerHandle.type), messengerHandle.customTypeName),
helpLabel: "emptyString_msg",
autocapitalizeTextField: Autocapitalize.none,
cancelAction: () => {
findAndRemove(this.messengerHandles, (t) => t[1] === id)
},
Expand All @@ -593,6 +603,7 @@ export class ContactEditor {
fieldType: TextFieldType.Text,
label: pronouns.language,
helpLabel: "emptyString_msg",
autocapitalizeTextField: Autocapitalize.none,
cancelAction: () => {
findAndRemove(this.pronouns, (t) => t[1] === id)
},
Expand Down Expand Up @@ -822,7 +833,13 @@ export class ContactEditor {
return timestampToGeneratedId(Date.now())
}

private onTypeSelected<K, T extends { type: K; customTypeName: string }>(isCustom: boolean, key: K, aggregate: T): void {
private onTypeSelected<
K,
T extends {
type: K
customTypeName: string
},
>(isCustom: boolean, key: K, aggregate: T): void {
if (isCustom) {
setTimeout(() => {
Dialog.showTextInputDialog({
Expand Down
8 changes: 6 additions & 2 deletions src/mail-app/settings/AddInboxRuleDialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { createInboxRule } from "../../common/api/entities/tutanota/TypeRefs.js"
import type { MailboxDetail } from "../../common/mailFunctionality/MailboxModel.js"
import stream from "mithril/stream"
import { DropDownSelector } from "../../common/gui/base/DropDownSelector.js"
import { TextField } from "../../common/gui/base/TextField.js"
import { Autocapitalize, TextField } from "../../common/gui/base/TextField.js"
import { neverNull } from "@tutao/tutanota-utils"
import { LockedError } from "../../common/api/common/error/RestError"
import { showNotAvailableForFreeDialog } from "../../common/misc/SubscriptionDialogs"
Expand All @@ -29,7 +29,10 @@ import type { IndentedFolder } from "../../common/api/common/mail/FolderSystem.j

assertMainOrNode()

export type InboxRuleTemplate = Pick<InboxRule, "type" | "value"> & { _id?: InboxRule["_id"]; targetFolder?: InboxRule["targetFolder"] }
export type InboxRuleTemplate = Pick<InboxRule, "type" | "value"> & {
_id?: InboxRule["_id"]
targetFolder?: InboxRule["targetFolder"]
}

export async function show(mailBoxDetail: MailboxDetail, ruleOrTemplate: InboxRuleTemplate) {
if (locator.logins.getUserController().isFreeAccount()) {
Expand All @@ -56,6 +59,7 @@ export async function show(mailBoxDetail: MailboxDetail, ruleOrTemplate: InboxRu
}),
m(TextField, {
label: "inboxRuleValue_label",
autocapitalize: Autocapitalize.none,
value: inboxRuleValue(),
oninput: inboxRuleValue,
helpLabel: () =>
Expand Down
6 changes: 3 additions & 3 deletions src/mail-app/settings/AddSpamRuleDialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ import type { TranslationKey } from "../../common/misc/LanguageViewModel"
import { lang } from "../../common/misc/LanguageViewModel"
import { isDomainOrTopLevelDomain, isMailAddress } from "../../common/misc/FormatValidator"
import { getSpamRuleField, getSpamRuleType, SpamRuleFieldType, SpamRuleType, TUTA_MAIL_ADDRESS_DOMAINS } from "../../common/api/common/TutanotaConstants"
import { contains, neverNull, objectEntries } from "@tutao/tutanota-utils"
import { contains, objectEntries } from "@tutao/tutanota-utils"
import { Dialog } from "../../common/gui/base/Dialog"
import type { EmailSenderListElement } from "../../common/api/entities/sys/TypeRefs.js"
import { CustomerInfoTypeRef, CustomerTypeRef } from "../../common/api/entities/sys/TypeRefs.js"
import stream from "mithril/stream"
import type { SelectorItemList } from "../../common/gui/base/DropDownSelector.js"
import { DropDownSelector } from "../../common/gui/base/DropDownSelector.js"
import { TextField } from "../../common/gui/base/TextField.js"
import { Autocapitalize, TextField } from "../../common/gui/base/TextField.js"
import { locator } from "../../common/api/main/CommonLocator"
import { assertMainOrNode } from "../../common/api/common/Env"
import { isOfflineError } from "../../common/api/common/utils/ErrorUtils.js"
Expand All @@ -37,6 +36,7 @@ export function showAddSpamRuleDialog(existingSpamRuleOrTemplate: EmailSenderLis
}),
m(TextField, {
label: "emailSenderPlaceholder_label",
autocapitalize: Autocapitalize.none,
value: valueFieldValue(),
oninput: valueFieldValue,
helpLabel: () =>
Expand Down
6 changes: 3 additions & 3 deletions src/mail-app/settings/TemplateEditor.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import m, { Children, Component, Vnode } from "mithril"
import { TextField } from "../../common/gui/base/TextField.js"
import { Autocapitalize, TextField } from "../../common/gui/base/TextField.js"
import type { DialogHeaderBarAttrs } from "../../common/gui/base/DialogHeaderBar"
import type { ButtonAttrs } from "../../common/gui/base/Button.js"
import { Button, ButtonType } from "../../common/gui/base/Button.js"
import { ButtonType } from "../../common/gui/base/Button.js"
import { Dialog } from "../../common/gui/base/Dialog"
import { Icons } from "../../common/gui/base/icons/Icons"
import { createDropdown, DropdownButtonAttrs } from "../../common/gui/base/Dropdown.js"
Expand Down Expand Up @@ -95,6 +94,7 @@ class TemplateEditor implements Component<TemplateEditorAttrs> {
}),
m(TextField, {
label: "shortcut_label",
autocapitalize: Autocapitalize.none,
value: this.model.tag(),
oninput: this.model.tag,
}),
Expand Down
3 changes: 2 additions & 1 deletion src/mail-app/settings/emaildomain/EnterDomainPage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import m, { Children, Vnode, VnodeDOM } from "mithril"
import { TextField } from "../../../common/gui/base/TextField.js"
import { Autocapitalize, TextField } from "../../../common/gui/base/TextField.js"
import { isDomainName } from "../../../common/misc/FormatValidator"
import { Dialog } from "../../../common/gui/base/Dialog"
import type { AddDomainData } from "./AddDomainWizard"
Expand All @@ -26,6 +26,7 @@ export class EnterDomainPage implements WizardPageN<AddDomainData> {
m(".mt", lang.get("enterDomainGetReady_msg")),
m(TextField, {
label: "customDomain_label",
autocapitalize: Autocapitalize.none,
value: vnode.attrs.data.domain(),
oninput: vnode.attrs.data.domain,
helpLabel: () => {
Expand Down

0 comments on commit 0922a96

Please sign in to comment.