support fro unique aliases, https://github.com/tinode/chat/issues/446
This commit is contained in:
+4
-1
@@ -144,4 +144,7 @@ export const WAKE_UP_TICK = 1000;
|
||||
export const MIN_SWIPE_DISTANCE = REM_SIZE * 3;
|
||||
|
||||
// Self-topic avatar as an SVG icon encoded as data URI
|
||||
export const SELF_AVATAR_URI = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB2aWV3Qm94PSIwIDAgMTcgMTciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0zLjU2MiAxdjE1LjQ1OWw0LjY4Ni0zLjI3IDQuNzUyIDMuMjZ2LTE1LjQ0OWgtOS40Mzh6TTEyIDE0LjU1MWwtMy43NTYtMi41NzgtMy42ODEgMi41Njh2LTEyLjU0MWg3LjQzN3YxMi41NTF6IiBmaWxsPSIjMzMzMzMzIiAvPgo8L3N2Zz4=' // eslint-disable-line max-len
|
||||
export const SELF_AVATAR_URI = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZpZXdCb3g9IjAgMCAxNyAxNyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMy41NjIgMXYxNS40NTlsNC42ODYtMy4yNyA0Ljc1MiAzLjI2di0xNS40NDloLTkuNDM4ek0xMiAxNC41NTFsLTMuNzU2LTIuNTc4LTMuNjgxIDIuNTY4di0xMi41NDFoNy40Mzd2MTIuNTUxeiIgZmlsbD0iIzU1NTU1NSIgLz48L3N2Zz4=' // eslint-disable-line max-len
|
||||
|
||||
// Toast display duration, milliseconds.
|
||||
export const TOAST_DURATION = 3_000;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1685,5 +1685,54 @@
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_editing_placeholder": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias (optional)",
|
||||
"description": "Placeholder for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias:",
|
||||
"description": "Label for user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_already_taken": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(already taken)",
|
||||
"description": "Error message for alias already taken",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_invalid": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(invalid)",
|
||||
"description": "Error message for invalid alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias_edit": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias",
|
||||
"description": "Label for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"select_country": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Select country",
|
||||
"description": "Placeholder for the country selector",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"text_copied": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Copied to clipboard",
|
||||
"description": "Notification that text has been copied to clipboard",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1685,5 +1685,54 @@
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_editing_placeholder": {
|
||||
"translation": "Alias (optional)",
|
||||
"defaultMessage": "Alias (optional)",
|
||||
"description": "Placeholder for editing user or topic alias",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias": {
|
||||
"translation": "Alias:",
|
||||
"defaultMessage": "Alias:",
|
||||
"description": "Label for user or topic alias",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_already_taken": {
|
||||
"translation": "(already taken)",
|
||||
"defaultMessage": "(already taken)",
|
||||
"description": "Error message for alias already taken",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_invalid": {
|
||||
"translation": "(invalid)",
|
||||
"defaultMessage": "(invalid)",
|
||||
"description": "Error message for invalid alias",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias_edit": {
|
||||
"translation": "Alias",
|
||||
"defaultMessage": "Alias",
|
||||
"description": "Label for editing user or topic alias",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"select_country": {
|
||||
"translation": "Select country",
|
||||
"defaultMessage": "Select country",
|
||||
"description": "Placeholder for the country selector",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"text_copied": {
|
||||
"translation": "Copied to clipboard",
|
||||
"defaultMessage": "Copied to clipboard",
|
||||
"description": "Notification that text has been copied to clipboard",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1685,5 +1685,54 @@
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_editing_placeholder": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias (optional)",
|
||||
"description": "Placeholder for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias:",
|
||||
"description": "Label for user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_already_taken": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(already taken)",
|
||||
"description": "Error message for alias already taken",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_invalid": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(invalid)",
|
||||
"description": "Error message for invalid alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias_edit": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias",
|
||||
"description": "Label for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"select_country": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Select country",
|
||||
"description": "Placeholder for the country selector",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"text_copied": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Copied to clipboard",
|
||||
"description": "Notification that text has been copied to clipboard",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,18 @@
|
||||
"defaultMessage": "Report Conversation",
|
||||
"description": "Flat button [Report Group]"
|
||||
},
|
||||
"alias_already_taken": {
|
||||
"defaultMessage": "(already taken)",
|
||||
"description": "Error message for alias already taken"
|
||||
},
|
||||
"alias_editing_placeholder": {
|
||||
"defaultMessage": "Alias (optional)",
|
||||
"description": "Placeholder for editing user or topic alias"
|
||||
},
|
||||
"alias_invalid": {
|
||||
"defaultMessage": "(invalid)",
|
||||
"description": "Error message for invalid alias"
|
||||
},
|
||||
"already_in_call": {
|
||||
"defaultMessage": "You already in an ongoing call!",
|
||||
"description": "Error message when the user tried to accept a new call without finishing pervious one"
|
||||
@@ -370,6 +382,14 @@
|
||||
"defaultMessage": "Invalid security token",
|
||||
"description": "Error message when resetting password."
|
||||
},
|
||||
"label_alias": {
|
||||
"defaultMessage": "Alias:",
|
||||
"description": "Label for user or topic alias"
|
||||
},
|
||||
"label_alias_edit": {
|
||||
"defaultMessage": "Alias",
|
||||
"description": "Label for editing user or topic alias"
|
||||
},
|
||||
"label_client": {
|
||||
"defaultMessage": "Client:",
|
||||
"description": "Label for a client version"
|
||||
@@ -824,6 +844,10 @@
|
||||
"defaultMessage": "List like alice@example.com, +17025550003...",
|
||||
"description": "Placeholder in contacts search field"
|
||||
},
|
||||
"select_country": {
|
||||
"defaultMessage": "Select country",
|
||||
"description": "Placeholder for the country selector"
|
||||
},
|
||||
"self_topic_comment": {
|
||||
},
|
||||
"self_topic_name": {
|
||||
@@ -896,6 +920,10 @@
|
||||
"defaultMessage": "No tags defined. Add some.",
|
||||
"description": ""
|
||||
},
|
||||
"text_copied": {
|
||||
"defaultMessage": "Copied to clipboard",
|
||||
"description": "Notification that text has been copied to clipboard"
|
||||
},
|
||||
"title_all_contacts": {
|
||||
"defaultMessage": "All Contacts",
|
||||
"description": "Section title [All Contacts]"
|
||||
|
||||
@@ -1685,5 +1685,54 @@
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_editing_placeholder": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias (optional)",
|
||||
"description": "Placeholder for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias:",
|
||||
"description": "Label for user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_already_taken": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(already taken)",
|
||||
"description": "Error message for alias already taken",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_invalid": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(invalid)",
|
||||
"description": "Error message for invalid alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias_edit": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias",
|
||||
"description": "Label for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"select_country": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Select country",
|
||||
"description": "Placeholder for the country selector",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"text_copied": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Copied to clipboard",
|
||||
"description": "Notification that text has been copied to clipboard",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1685,5 +1685,54 @@
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_editing_placeholder": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias (optional)",
|
||||
"description": "Placeholder for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias:",
|
||||
"description": "Label for user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_already_taken": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(already taken)",
|
||||
"description": "Error message for alias already taken",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_invalid": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(invalid)",
|
||||
"description": "Error message for invalid alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias_edit": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias",
|
||||
"description": "Label for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"select_country": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Select country",
|
||||
"description": "Placeholder for the country selector",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"text_copied": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Copied to clipboard",
|
||||
"description": "Notification that text has been copied to clipboard",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1685,5 +1685,54 @@
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_editing_placeholder": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias (optional)",
|
||||
"description": "Placeholder for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias:",
|
||||
"description": "Label for user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_already_taken": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(already taken)",
|
||||
"description": "Error message for alias already taken",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_invalid": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(invalid)",
|
||||
"description": "Error message for invalid alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias_edit": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias",
|
||||
"description": "Label for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"select_country": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Select country",
|
||||
"description": "Placeholder for the country selector",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"text_copied": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Copied to clipboard",
|
||||
"description": "Notification that text has been copied to clipboard",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1685,5 +1685,54 @@
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_editing_placeholder": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias (optional)",
|
||||
"description": "Placeholder for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias:",
|
||||
"description": "Label for user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_already_taken": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(already taken)",
|
||||
"description": "Error message for alias already taken",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_invalid": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(invalid)",
|
||||
"description": "Error message for invalid alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias_edit": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias",
|
||||
"description": "Label for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"select_country": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Select country",
|
||||
"description": "Placeholder for the country selector",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"text_copied": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Copied to clipboard",
|
||||
"description": "Notification that text has been copied to clipboard",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1685,5 +1685,54 @@
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_editing_placeholder": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias (optional)",
|
||||
"description": "Placeholder for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias:",
|
||||
"description": "Label for user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_already_taken": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(already taken)",
|
||||
"description": "Error message for alias already taken",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_invalid": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(invalid)",
|
||||
"description": "Error message for invalid alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias_edit": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias",
|
||||
"description": "Label for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"select_country": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Select country",
|
||||
"description": "Placeholder for the country selector",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"text_copied": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Copied to clipboard",
|
||||
"description": "Notification that text has been copied to clipboard",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1685,5 +1685,54 @@
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_editing_placeholder": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias (optional)",
|
||||
"description": "Placeholder for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias:",
|
||||
"description": "Label for user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_already_taken": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(already taken)",
|
||||
"description": "Error message for alias already taken",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_invalid": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(invalid)",
|
||||
"description": "Error message for invalid alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias_edit": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias",
|
||||
"description": "Label for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"select_country": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Select country",
|
||||
"description": "Placeholder for the country selector",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"text_copied": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Copied to clipboard",
|
||||
"description": "Notification that text has been copied to clipboard",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1685,5 +1685,54 @@
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_editing_placeholder": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias (optional)",
|
||||
"description": "Placeholder for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias:",
|
||||
"description": "Label for user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_already_taken": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(already taken)",
|
||||
"description": "Error message for alias already taken",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_invalid": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(invalid)",
|
||||
"description": "Error message for invalid alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias_edit": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias",
|
||||
"description": "Label for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"select_country": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Select country",
|
||||
"description": "Placeholder for the country selector",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"text_copied": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Copied to clipboard",
|
||||
"description": "Notification that text has been copied to clipboard",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1685,5 +1685,54 @@
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_editing_placeholder": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias (optional)",
|
||||
"description": "Placeholder for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias:",
|
||||
"description": "Label for user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_already_taken": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(already taken)",
|
||||
"description": "Error message for alias already taken",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"alias_invalid": {
|
||||
"translation": "",
|
||||
"defaultMessage": "(invalid)",
|
||||
"description": "Error message for invalid alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_alias_edit": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Alias",
|
||||
"description": "Label for editing user or topic alias",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"select_country": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Select country",
|
||||
"description": "Placeholder for the country selector",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"text_copied": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Copied to clipboard",
|
||||
"description": "Notification that text has been copied to clipboard",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -89,7 +89,7 @@ export function arrayEqual(a, b) {
|
||||
export function asPhone(val) {
|
||||
val = val.trim();
|
||||
if (/^(?:\+?(\d{1,3}))?[- (.]*(\d{3})[- ).]*(\d{3})[- .]*(\d{2})[- .]*(\d{2})?$/.test(val)) {
|
||||
return val.replace(/[- ().]*/, '');
|
||||
return val.replaceAll(/[- ().]*/g, '');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -97,7 +97,7 @@ export function asPhone(val) {
|
||||
// Checks (loosely) if the given string is an email. If so returns the email.
|
||||
export function asEmail(val) {
|
||||
val = val.trim();
|
||||
if (/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/.test(val)) {
|
||||
if (/^[a-z0-9_.+-]+@[a-z0-9-]+(\.[a-z0-9-]+)+$/i.test(val)) {
|
||||
return val;
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -39,6 +39,8 @@ test('arrayEqual', () => {
|
||||
|
||||
test('asEmail', () => {
|
||||
expect(asEmail('test@example.com')).toBe('test@example.com');
|
||||
expect(asEmail('test@mail.example.com')).toBe('test@mail.example.com');
|
||||
expect(asEmail('test@e-mail.example.com')).toBe('test@e-mail.example.com');
|
||||
expect(asEmail(' test@example.com ')).toBe('test@example.com');
|
||||
expect(asEmail('test.email+alex@leetcode.com')).toBe('test.email+alex@leetcode.com');
|
||||
expect(asEmail('test.email@sub.example.com')).toBe('test.email@sub.example.com');
|
||||
@@ -50,6 +52,8 @@ test('asEmail', () => {
|
||||
expect(asEmail('invalid-email@example..com')).toBeNull();
|
||||
expect(asEmail('invalid-email@.example.com')).toBeNull();
|
||||
expect(asEmail('invalid-email@example.com.')).toBeNull();
|
||||
expect(asEmail('invalid-email@@example.com.')).toBeNull();
|
||||
expect(asEmail('invalid/email@example.com.')).toBeNull();
|
||||
});
|
||||
|
||||
test('isUrlRelative', () => {
|
||||
|
||||
@@ -24,7 +24,8 @@ export default class AccountSettingsView extends React.Component {
|
||||
description: _clip(me.public ? me.public.note : undefined, MAX_TOPIC_DESCRIPTION_LENGTH),
|
||||
avatar: makeImageUrl(me.public ? me.public.photo : null),
|
||||
credentials: me.getCredentials() || [],
|
||||
credEdit: undefined
|
||||
credEdit: undefined,
|
||||
alias: ((me.tags() || []).find(tag => tag.startsWith('alias:')) || '').substring(6),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -123,6 +124,12 @@ export default class AccountSettingsView extends React.Component {
|
||||
description="Label for user address (ID)" /></label>
|
||||
<tt>{this.props.myUserId}</tt>
|
||||
</div>
|
||||
{this.state.alias ?
|
||||
<div className="group">
|
||||
<label className="small"><FormattedMessage id="label_alias" defaultMessage="Alias:"
|
||||
description="Label for user or topic alias" /></label>
|
||||
<tt>@{this.state.alias}</tt>
|
||||
</div> : null}
|
||||
<div className="group">
|
||||
<BadgeList trustedBadges={this.props.trustedBadges} />
|
||||
</div>
|
||||
|
||||
+39
-8
@@ -16,7 +16,8 @@ import ShowQRCode from '../widgets/show-qrcode.jsx';
|
||||
import TopicCommonView from './topic-common-view.jsx';
|
||||
import TopicSecurity from '../widgets/topic-security.jsx';
|
||||
|
||||
import { MAX_TITLE_LENGTH, MAX_TOPIC_DESCRIPTION_LENGTH, NO_ACCESS_MODE } from '../config.js';
|
||||
import { MAX_TITLE_LENGTH, MAX_TOPIC_DESCRIPTION_LENGTH,
|
||||
NO_ACCESS_MODE, TOAST_DURATION } from '../config.js';
|
||||
|
||||
import { makeImageUrl } from '../lib/blob-helpers.js';
|
||||
import { theCard, clipStr } from '../lib/utils.js';
|
||||
@@ -82,6 +83,11 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Scan QR Code',
|
||||
description: 'Title for scanning QR code'
|
||||
},
|
||||
text_copied: {
|
||||
id: 'text_copied',
|
||||
defaultMessage: 'Copied to clipboard',
|
||||
description: 'Notification that text has been copied to clipboard'
|
||||
}
|
||||
});
|
||||
|
||||
class InfoView extends React.Component {
|
||||
@@ -127,8 +133,8 @@ class InfoView extends React.Component {
|
||||
this.handleUnarchive = this.handleUnarchive.bind(this);
|
||||
this.handlePermissionsChanged = this.handlePermissionsChanged.bind(this);
|
||||
this.handleLaunchPermissionsEditor = this.handleLaunchPermissionsEditor.bind(this);
|
||||
this.handleCopyID = this.handleCopyID.bind(this);
|
||||
this.handleShowQRCode = this.handleShowQRCode.bind(this);
|
||||
this.handleCopyToClipboard = this.handleCopyToClipboard.bind(this);
|
||||
this.handleShowAddMembers = this.handleShowAddMembers.bind(this);
|
||||
this.handleMemberUpdateRequest = this.handleMemberUpdateRequest.bind(this);
|
||||
this.handleMemberSelected = this.handleMemberSelected.bind(this);
|
||||
@@ -384,16 +390,20 @@ class InfoView extends React.Component {
|
||||
this.props.onNavigate(`perm/${which}`);
|
||||
}
|
||||
|
||||
handleCopyID(e) {
|
||||
e.preventDefault();
|
||||
navigator.clipboard.writeText(this.props.myUserId);
|
||||
}
|
||||
|
||||
handleShowQRCode(e) {
|
||||
e.preventDefault();
|
||||
this.props.onNavigate('qrcode');
|
||||
}
|
||||
|
||||
handleCopyToClipboard(e, text) {
|
||||
e.preventDefault();
|
||||
navigator.clipboard.writeText(text).then(_ => {
|
||||
this.setState({toast: this.props.intl.formatMessage(messages.text_copied)});
|
||||
setTimeout(_ => { this.setState({toast: ''}); }, TOAST_DURATION);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
handleShowAddMembers(e) {
|
||||
e.preventDefault();
|
||||
this.props.onInitFind();
|
||||
@@ -463,8 +473,12 @@ class InfoView extends React.Component {
|
||||
const panelTitle = formatMessage((view == 'perm' ? messages['perm_' + args[0]] : messages[view])
|
||||
|| messages['info']);
|
||||
|
||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||
const alias = topic && topic.alias();
|
||||
|
||||
return (
|
||||
<div id="info-view">
|
||||
<div className={`toast${this.state.toast ? ' show' : ''}`}>{this.state.toast}</div>
|
||||
<div className="caption-panel" id="info-caption-panel">
|
||||
<div className="panel-title" id="info-title">{panelTitle}</div>
|
||||
<div>
|
||||
@@ -581,6 +595,7 @@ class InfoView extends React.Component {
|
||||
: null
|
||||
}
|
||||
{!this.state.isSelf ?
|
||||
<>
|
||||
<div className="panel-form-row">
|
||||
<div>
|
||||
<label className="small"><FormattedMessage id="label_user_id" defaultMessage="ID:"
|
||||
@@ -588,7 +603,7 @@ class InfoView extends React.Component {
|
||||
<tt>{this.state.address}</tt>
|
||||
</div>
|
||||
<div style={{marginLeft: 'auto'}}>
|
||||
<a href="#" onClick={this.handleCopyID}>
|
||||
<a href="#" onClick={e => {this.handleCopyToClipboard(e, this.state.address);}}>
|
||||
<i className="material-icons">content_copy</i>
|
||||
</a>
|
||||
<a href="#" onClick={this.handleShowQRCode}>
|
||||
@@ -596,6 +611,22 @@ class InfoView extends React.Component {
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{alias ?
|
||||
<div className="panel-form-row">
|
||||
<div>
|
||||
<label className="small"><FormattedMessage id="label_alias" defaultMessage="Alias:"
|
||||
description="Label for user or topic alias" /></label>
|
||||
<tt>{alias}</tt>
|
||||
</div>
|
||||
<div style={{marginLeft: 'auto'}}>
|
||||
<a href="#" onClick={e => {this.handleCopyToClipboard(e, alias);}}>
|
||||
<i className="material-icons">content_copy</i>
|
||||
</a>
|
||||
<i className="material-icons" style={{opacity: 0}}>qr_code</i>
|
||||
</div>
|
||||
</div>
|
||||
: null}
|
||||
</>
|
||||
: null
|
||||
}
|
||||
{this.state.trustedBadges.length > 0 ?
|
||||
|
||||
@@ -10,7 +10,7 @@ import NewTopicGroup from '../widgets/new-topic-group.jsx';
|
||||
import SearchContacts from '../widgets/search-contacts.jsx';
|
||||
|
||||
import HashNavigation from '../lib/navigation.js';
|
||||
import { theCard } from '../lib/utils.js';
|
||||
import { asEmail, asPhone, theCard } from '../lib/utils.js';
|
||||
|
||||
const messages = defineMessages({
|
||||
search_for_contacts: {
|
||||
@@ -57,6 +57,24 @@ class NewTopicView extends React.Component {
|
||||
}
|
||||
|
||||
handleSearchContacts(query) {
|
||||
query = query.trim();
|
||||
if (!query) {
|
||||
query = Tinode.DEL_CHAR;
|
||||
} else if (!/[\s,:]/.test(query)) {
|
||||
// No colons, spaces or commas. Try as email or phone.
|
||||
// If not email or phone, treat as alias.
|
||||
const email = asEmail(query);
|
||||
if (email) {
|
||||
query = `email:${email}`;
|
||||
} else {
|
||||
const tel = asPhone(query);
|
||||
if (tel) {
|
||||
query = `tel:${tel}`;
|
||||
} else {
|
||||
query = `alias:${query}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.props.onSearchContacts(query);
|
||||
this.setState({searchQuery: Tinode.isNullValue(query) ? null : query});
|
||||
}
|
||||
@@ -125,7 +143,7 @@ class NewTopicView extends React.Component {
|
||||
contacts={this.props.searchResults}
|
||||
myUserId={this.props.myUserId}
|
||||
emptyListMessage={no_contacts_placeholder}
|
||||
showSelfTopic={true}
|
||||
showSelfTopic={!this.state.searchQuery}
|
||||
showOnline={false}
|
||||
showUnread={false}
|
||||
showContextMenu={false}
|
||||
|
||||
@@ -89,6 +89,11 @@ const messages = defineMessages({
|
||||
id: 'password_reset_success',
|
||||
defaultMessage: 'Password reset successfully',
|
||||
description: 'Notification message that the password was successfully reset.'
|
||||
},
|
||||
select_country: {
|
||||
id: 'select_country',
|
||||
defaultMessage: 'Select country',
|
||||
description: 'Placeholder for the country selector'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1763,7 +1768,7 @@ class TinodeWeb extends React.Component {
|
||||
}
|
||||
|
||||
handleShowCountrySelector(code, dial, selectedCallback) {
|
||||
this.handleShowAlert("Select country",
|
||||
this.handleShowAlert(this.props.intl.formatMessage(messages.select_country),
|
||||
<Suspense fallback={<div><FormattedMessage id="loading_note" defaultMessage="Loading..."
|
||||
description="Message shown when component is loading"/></div>}>
|
||||
<PhoneCountrySelector
|
||||
@@ -1773,7 +1778,7 @@ class TinodeWeb extends React.Component {
|
||||
selectedCallback(c, d);
|
||||
}} />
|
||||
</Suspense>,
|
||||
null, null, _ => {}, "Cancel");
|
||||
null, null, _ => {}, null);
|
||||
}
|
||||
|
||||
handleStartVideoCall() {
|
||||
|
||||
@@ -12,7 +12,8 @@ export default class InPlaceEdit extends React.Component {
|
||||
this.state = {
|
||||
active: props.active,
|
||||
initialValue: props.value || '',
|
||||
value: props.value || ''
|
||||
value: props.value || '',
|
||||
valid: true
|
||||
};
|
||||
|
||||
this.handeTextChange = this.handeTextChange.bind(this);
|
||||
@@ -36,6 +37,18 @@ export default class InPlaceEdit extends React.Component {
|
||||
|
||||
handeTextChange(e) {
|
||||
this.setState({value: e.target.value || ''});
|
||||
if (this.props.validator) {
|
||||
Promise.resolve(this.props.validator(e.target.value))
|
||||
.then(valid => {
|
||||
this.setState({valid: valid});
|
||||
})
|
||||
.catch(err => {
|
||||
// If it's interrupted, then the err is undefined. Ignore it.
|
||||
if (err) {
|
||||
this.setState({valid: false});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyDown(e) {
|
||||
@@ -66,7 +79,7 @@ export default class InPlaceEdit extends React.Component {
|
||||
return;
|
||||
}
|
||||
this.setState({active: false});
|
||||
if ((value || this.props.value) && (value !== this.props.value)) {
|
||||
if ((value || this.props.value) && (value !== this.props.value) && this.state.valid) {
|
||||
this.props.onFinished(value);
|
||||
}
|
||||
}
|
||||
@@ -91,7 +104,9 @@ export default class InPlaceEdit extends React.Component {
|
||||
}
|
||||
|
||||
return (<span className={spanClass} onClick={this.handleStartEditing}>
|
||||
{this.props.iconLeft && <i className="material-icons light-gray">{this.props.iconLeft}</i>}
|
||||
<span>{spanText}</span>
|
||||
{this.props.iconRight && <i className="material-icons light-gray">{this.props.iconRight}</i>}
|
||||
</span>);
|
||||
}
|
||||
|
||||
@@ -104,12 +119,18 @@ export default class InPlaceEdit extends React.Component {
|
||||
if (this.props.multiline > 1) {
|
||||
element = 'textarea';
|
||||
attr.rows = this.props.multiline;
|
||||
attr.className = 'inplace-edit';
|
||||
attr.className = 'in-place-edit';
|
||||
} else {
|
||||
element = 'input';
|
||||
attr.type = this.props.type || 'text';
|
||||
attr.className = 'in-place-edit' + (this.props.iconLeft ? ' with-icon-left'
|
||||
: this.props.iconRight ? ' with-icon-right' : '');
|
||||
if (this.props.maxLength) {
|
||||
attr.maxLength=this.props.maxLength;
|
||||
}
|
||||
}
|
||||
attr.value = this.state.value;
|
||||
attr.className += this.state.valid ? '' : ' invalid';
|
||||
attr.ref = this.selfRef;
|
||||
attr.onChange = this.handeTextChange;
|
||||
attr.onKeyDown = this.handleKeyDown;
|
||||
@@ -119,7 +140,19 @@ export default class InPlaceEdit extends React.Component {
|
||||
attr.required = this.props.required ? 'required' : '';
|
||||
attr.autoComplete = this.props.autoComplete;
|
||||
attr.autoFocus = true;
|
||||
if (this.props.spellCheck !== undefined) {
|
||||
attr.spellCheck = this.props.spellCheck ? 'true' : 'false';
|
||||
}
|
||||
|
||||
if (this.props.iconLeft || this.props.iconRight) {
|
||||
return (
|
||||
<>
|
||||
{this.props.iconLeft && <i className="material-icons light-gray">{this.props.iconLeft}</i>}
|
||||
{React.createElement(element, attr, null)}
|
||||
{this.props.iconRight && <i className="material-icons light-gray">{this.props.iconRight}</i>}
|
||||
</>
|
||||
);
|
||||
}
|
||||
return React.createElement(element, attr, null);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Widget for editing topic description.
|
||||
|
||||
import React from 'react';
|
||||
import { FormattedMessage, injectIntl } from 'react-intl';
|
||||
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
|
||||
|
||||
import { Tinode } from 'tinode-sdk';
|
||||
|
||||
@@ -15,6 +15,22 @@ import { AVATAR_SIZE, MAX_AVATAR_BYTES, MAX_EXTERN_ATTACHMENT_SIZE, MAX_TITLE_LE
|
||||
import { imageScaled, blobToBase64, makeImageUrl } from '../lib/blob-helpers.js';
|
||||
import { arrayEqual, theCard } from '../lib/utils.js';
|
||||
|
||||
const messages = defineMessages({
|
||||
alias_invalid: {
|
||||
id: 'alias_invalid',
|
||||
defaultMessage: '(invalid)',
|
||||
description: 'Error message for invalid alias'
|
||||
},
|
||||
alias_already_taken: {
|
||||
id: 'alias_already_taken',
|
||||
defaultMessage: '(already taken)',
|
||||
description: 'Error message for alias already taken'
|
||||
},
|
||||
});
|
||||
|
||||
const ALIAS_REGEX = /^[a-z0-9_\-]{4,24}$/;
|
||||
const ALIAS_AVAILABILITY_CHECK_DELAY = 1000; // milliseconds
|
||||
|
||||
class TopicDescEdit extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -34,10 +50,13 @@ class TopicDescEdit extends React.Component {
|
||||
avatar: makeImageUrl(topic.public ? topic.public.photo : null),
|
||||
tags: topic.tags() || [],
|
||||
newAvatar: null,
|
||||
newAvatarMime: null
|
||||
newAvatarMime: null,
|
||||
aliasError: ''
|
||||
};
|
||||
|
||||
this.previousOnTags = null;
|
||||
this.aliasCheckTimer = null;
|
||||
this.aliasCheckPromise = null;
|
||||
|
||||
this.tnNewTags = this.tnNewTags.bind(this);
|
||||
this.handleFullNameUpdate = this.handleFullNameUpdate.bind(this);
|
||||
@@ -46,8 +65,10 @@ class TopicDescEdit extends React.Component {
|
||||
this.handleAvatarCropCancel = this.handleAvatarCropCancel.bind(this);
|
||||
this.uploadAvatar = this.uploadAvatar.bind(this);
|
||||
this.handlePrivateUpdate = this.handlePrivateUpdate.bind(this);
|
||||
this.handleAliasUpdate = this.handleAliasUpdate.bind(this);
|
||||
this.handleDescriptionUpdate = this.handleDescriptionUpdate.bind(this);
|
||||
this.handleTagsUpdated = this.handleTagsUpdated.bind(this);
|
||||
this.validateAlias = this.validateAlias.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -145,6 +166,60 @@ class TopicDescEdit extends React.Component {
|
||||
this.setState({newAvatar: null, newAvatarMime: null});
|
||||
}
|
||||
|
||||
handleAliasUpdate(alias) {
|
||||
alias = alias.trim() || '';
|
||||
const tags = this.state.tags.filter(t => !t.startsWith('alias:'));
|
||||
if (alias) {
|
||||
tags.push('alias:' + alias.toLowerCase());
|
||||
}
|
||||
this.handleTagsUpdated(tags);
|
||||
}
|
||||
|
||||
validateAlias(alias) {
|
||||
// Reset pending delayed check.
|
||||
if (this.aliasCheckTimer) {
|
||||
this.aliasCheckPromise.reject(null);
|
||||
clearTimeout(this.aliasCheckTimer);
|
||||
this.aliasCheckTimer = null;
|
||||
}
|
||||
|
||||
if (!alias) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const valid = ALIAS_REGEX.test(alias);
|
||||
if (!valid) {
|
||||
this.setState({aliasError: this.props.intl.formatMessage(messages.alias_invalid)});
|
||||
return false;
|
||||
}
|
||||
this.setState({aliasError: ''});
|
||||
|
||||
// Setup a delayed check for alias availability.
|
||||
this.aliasCheckPromise = {};
|
||||
const validationPromise = new Promise((resolve, reject) => {
|
||||
this.aliasCheckPromise.resolve = resolve;
|
||||
this.aliasCheckPromise.reject = reject;
|
||||
});
|
||||
this.aliasCheckTimer = setTimeout(_ => {
|
||||
this.aliasCheckTimer = null;
|
||||
const fnd = this.props.tinode.getFndTopic();
|
||||
fnd.subscribe()
|
||||
.then(_ => fnd.setMeta({desc: {public: `alias:${alias}`}}))
|
||||
.then(_ => fnd.getMeta(fnd.startMetaQuery().withTags().build()))
|
||||
.then(meta => {
|
||||
const taken = Array.isArray(meta.tags);
|
||||
this.setState({aliasError: taken ?
|
||||
this.props.intl.formatMessage(messages.alias_already_taken) : ''});
|
||||
this.aliasCheckPromise.resolve(!taken)
|
||||
})
|
||||
.catch(err => {
|
||||
this.aliasCheckPromise.reject(err);
|
||||
this.setState({aliasError: err.message});
|
||||
});
|
||||
}, ALIAS_AVAILABILITY_CHECK_DELAY);
|
||||
return validationPromise;
|
||||
}
|
||||
|
||||
handleTagsUpdated(tags) {
|
||||
// Check if tags have actually changed.
|
||||
if (arrayEqual(this.state.tags.slice(0), tags.slice(0))) {
|
||||
@@ -166,6 +241,11 @@ class TopicDescEdit extends React.Component {
|
||||
}
|
||||
|
||||
const editable = this.state.isMe || (this.state.owner && !this.state.isSelf);
|
||||
let alias = this.state.tags && this.state.tags.find(t => t.startsWith('alias:'));
|
||||
if (alias) {
|
||||
// Remove 'alias:' prefix.
|
||||
alias = alias.substring(6);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -212,6 +292,7 @@ class TopicDescEdit extends React.Component {
|
||||
readOnly={!editable}
|
||||
value={this.state.fullName}
|
||||
required={true}
|
||||
maxLength={32}
|
||||
onFinished={this.handleFullNameUpdate} />
|
||||
}</FormattedMessage>
|
||||
</div>
|
||||
@@ -235,6 +316,30 @@ class TopicDescEdit extends React.Component {
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
{editable || alias ?
|
||||
<div className="group">
|
||||
<div><label className={'small ' + (this.state.aliasError ? 'invalid' : '')}>
|
||||
<FormattedMessage id="label_alias_edit" defaultMessage="Alias"
|
||||
description="Label for editing user or topic alias" /> {this.state.aliasError}
|
||||
</label></div>
|
||||
<div>
|
||||
<FormattedMessage id="alias_editing_placeholder"
|
||||
defaultMessage="Alias (optional)"
|
||||
description="Placeholder for editing user or topic alias">{
|
||||
(private_placeholder) => <InPlaceEdit
|
||||
placeholder={private_placeholder}
|
||||
readOnly={!editable}
|
||||
value={alias}
|
||||
validator={this.validateAlias}
|
||||
iconLeft='alternate_email'
|
||||
maxLength={24}
|
||||
spellCheck={false}
|
||||
onFinished={this.handleAliasUpdate} />
|
||||
}</FormattedMessage>
|
||||
</div>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
{editable || this.state.description ?
|
||||
<div className="group">
|
||||
<div><label className="small">
|
||||
|
||||
@@ -67,10 +67,11 @@ export default class VisiblePassword extends React.PureComponent {
|
||||
render() {
|
||||
return (
|
||||
<div tabIndex="-1" className="group-focus" onBlur={this.handleEditingFinished}>
|
||||
<input className="with-visibility"
|
||||
<input className="with-icon-right"
|
||||
type={this.state.visible ? 'text' : 'password'}
|
||||
value={this.state.value}
|
||||
placeholder={this.props.placeholder}
|
||||
maxLength={32}
|
||||
required={this.props.required ? 'required' : ''}
|
||||
autoFocus={this.props.autoFocus ? 'autoFocus' : ''}
|
||||
autoComplete={this.props.autoComplete}
|
||||
|
||||
Reference in New Issue
Block a user