support fro unique aliases, https://github.com/tinode/chat/issues/446
This commit is contained in:
+83
-9
@@ -68,6 +68,10 @@ label.large {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
label.invalid {
|
||||
color: #D32F2F;
|
||||
}
|
||||
|
||||
img.avatar {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -242,22 +246,23 @@ textarea::placeholder {
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
input[type="text"].with-visibility,
|
||||
input[type="password"].with-visibility {
|
||||
input[type="text"].with-icon-right,
|
||||
input[type="password"].with-icon-right {
|
||||
margin-right:-2rem;
|
||||
padding-right:2rem;
|
||||
}
|
||||
|
||||
input[type="text"].with-icon-left,
|
||||
input[type="password"].with-icon-left {
|
||||
margin-left:-1.45rem;
|
||||
padding-left:1.75rem;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: none;
|
||||
padding-top: 0.45rem;
|
||||
}
|
||||
|
||||
textarea.inplace-edit {
|
||||
height: unset;
|
||||
font-size: unset;
|
||||
}
|
||||
|
||||
/* END of input and buttons */
|
||||
|
||||
/* BEGIN scrollbar styling. */
|
||||
@@ -634,6 +639,7 @@ div.trusted-badge {
|
||||
}
|
||||
|
||||
#info-view {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 0;
|
||||
@@ -679,7 +685,7 @@ div.trusted-badge {
|
||||
}
|
||||
|
||||
/* BEGIN InPlaceEdit styles */
|
||||
.in-place-edit {
|
||||
span.in-place-edit, div.in-place-edit {
|
||||
display: inline-block;
|
||||
font-family: inherit;
|
||||
font-size: 1rem;
|
||||
@@ -691,9 +697,12 @@ div.trusted-badge {
|
||||
}
|
||||
|
||||
.in-place-edit.short {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-size: 1.1rem;
|
||||
height: 2.5rem;
|
||||
line-height: 2.25;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.in-place-edit.disabled {
|
||||
@@ -711,11 +720,29 @@ div.trusted-badge {
|
||||
}
|
||||
|
||||
.in-place-edit.short span {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow-x: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.in-place-edit .material-icons {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.material-icons.invalid {
|
||||
color: #c66;
|
||||
}
|
||||
|
||||
textarea.in-place-edit {
|
||||
height: unset;
|
||||
font-size: unset;
|
||||
}
|
||||
|
||||
input.in-place-edit.invalid {
|
||||
color: #c66;
|
||||
}
|
||||
|
||||
/* END of InPlaceEdit styles */
|
||||
|
||||
table.permission-editor {
|
||||
@@ -3248,6 +3275,53 @@ ul.phone-country-selector span.country {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
div.toast {
|
||||
visibility: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
min-width: 10rem;
|
||||
padding: 0.5rem 1rem;
|
||||
height: 3rem;
|
||||
z-index: 3;
|
||||
font-weight: lighter;
|
||||
color: #eee;
|
||||
background-color: #333;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 1px 2px 0.3rem gray;
|
||||
bottom: 2rem;
|
||||
left: 50%;
|
||||
translate: -50%;
|
||||
}
|
||||
|
||||
div.toast.show {
|
||||
visibility: visible;
|
||||
animation: fadein 0.5s, fadeout 0.5s 2.5s;
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
from {
|
||||
bottom: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
bottom: 2rem;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeout {
|
||||
from {
|
||||
bottom: 2rem;
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
bottom: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Very wide monitor.
|
||||
*/
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Generated
+3419
-844
File diff suppressed because it is too large
Load Diff
+4
-2
@@ -18,7 +18,8 @@
|
||||
"i18n:obsolete": "node scripts/i18n.js obsolete",
|
||||
"vers": "node scripts/gen-version.js",
|
||||
"extract": "formatjs extract \"src/**/*.{js,jsx}\" --out-file src/i18n/ex/base-en.json --id-interpolation-pattern '[sha512:contenthash:base64:6]'",
|
||||
"compile": "formatjs compile"
|
||||
"compile": "formatjs compile",
|
||||
"test": "jest"
|
||||
},
|
||||
"browserslist": "> 0.5%, last 2 versions, Firefox ESR, not dead",
|
||||
"files": [
|
||||
@@ -84,8 +85,9 @@
|
||||
"babel-plugin-formatjs": "^10.5.3",
|
||||
"browserslist": "^4.21.10",
|
||||
"copy-webpack-plugin": "^12.0.0",
|
||||
"cssnano": "^6.0.1",
|
||||
"cssnano": "^7.0.6",
|
||||
"glob": "^11.0.0",
|
||||
"jest": "^29.7.0",
|
||||
"postcss": "^8.4.27",
|
||||
"postcss-cli": "^11.0.0",
|
||||
"webpack": "^5.88.2",
|
||||
|
||||
+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}
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
{"version":3,"file":"316.prod.js","mappings":"8KASA,MAAMA,UAA6BC,IAAAA,cACjCC,WAAAA,CAAYC,GACVC,MAAMD,GAENE,KAAKC,UAAY,GACjB,MAAM,kBAAEC,GAAsBJ,EAAMK,KACpCC,EAAeC,SAAQC,IACPA,EAAGC,KAAKC,MAAM,KACtBH,SAAQI,IACZT,KAAKC,UAAUS,KAAK,CAClBH,KAAME,EAAKE,OACXC,KAAMN,EAAGM,KACTC,MAAMC,EAAAA,EAAAA,IAAUR,EAAGM,MACnBG,KAAMb,EAAkBI,EAAGM,KAAM,CAACI,KAAM,YACxC,GACF,IAGJhB,KAAKC,UAAUgB,MAAK,CAACC,EAAGC,IAAMD,EAAEH,KAAKK,cAAcD,EAAEJ,OACvD,CAEAM,iBAAAA,GACMrB,KAAKsB,aACPtB,KAAKsB,YAAYC,eAAe,CAACC,MAAO,SAAUC,OAAQ,WAE9D,CAEAC,MAAAA,GACE,MAAMzB,EAAY,GACZ0B,EAAW3B,KAAKF,MAAM6B,UAAY,KAYxC,OAXA3B,KAAKC,UAAUI,SAAQ,CAACuB,EAAGC,KACzB,MAAMC,EAASF,EAAEhB,MAAQe,EAAW,YAAc,GAClD1B,EAAUS,KAAKd,IAAAA,cAAA,MAAImC,UAAWD,EAAOE,IAAKH,EACxCI,IAAKA,IAAYL,EAAEhB,MAAQe,IAAW3B,KAAKsB,YAAcW,EAAG,EAC5DC,QAASC,GAAKnC,KAAKF,MAAMsC,SAASR,EAAEhB,KAAMgB,EAAErB,OAC5CX,IAAAA,cAAA,QAAMmC,UAAU,gBAAgBH,EAAEf,MAClCjB,IAAAA,cAAA,QAAMmC,UAAU,WAAU,IAAOH,EAAEb,MACnCnB,IAAAA,cAAA,QAAMmC,UAAU,aAAY,KAAQH,EAAErB,OAClC,IAINX,IAAAA,cAAA,OAAKmC,UAAU,mBAAmBD,MAAO,CAACO,OAAQ,UAChDzC,IAAAA,cAAA,MAAImC,UAAU,0BACX9B,GAIT,EAGF,WAAeqC,EAAAA,EAAAA,YAAW3C,E","sources":["webpack://tinode-webapp/./src/widgets/phone-country-selector.jsx"],"sourcesContent":["// Selector for country dialing code.\n\nimport React from 'react';\nimport { injectIntl } from 'react-intl';\n\nimport * as dcodes from '../dcodes.json';\n\nimport { flagEmoji } from '../lib/strformat';\n\nclass PhoneCountrySelector extends React.PureComponent {\n constructor(props) {\n super(props);\n\n this.countries = [];\n const { formatDisplayName } = props.intl;\n dcodes.default.forEach(dc => {\n const parts = dc.dial.split(',');\n parts.forEach(part => {\n this.countries.push({\n dial: part.trim(),\n code: dc.code,\n flag: flagEmoji(dc.code),\n name: formatDisplayName(dc.code, {type: 'region'})\n });\n });\n });\n\n this.countries.sort((a, b) => a.name.localeCompare(b.name));\n }\n\n componentDidMount() {\n if (this.selectedRef) {\n this.selectedRef.scrollIntoView({block: 'center', inline: 'nearest'});\n }\n }\n\n render() {\n const countries = [];\n const selected = this.props.selected || 'US';\n this.countries.forEach((c, idx) => {\n const style = (c.code == selected ? 'selected ' : '');\n countries.push(<li className={style} key={idx}\n ref={ref => {if (c.code == selected) {this.selectedRef = ref}}}\n onClick={_ => this.props.onSubmit(c.code, c.dial)}>\n <span className=\"country-flag\">{c.flag}</span>\n <span className=\"country\"> {c.name}</span>\n <span className=\"dial-code\"> +{c.dial}</span>\n </li>);\n });\n\n return (\n <div className=\"scrollable-panel\" style={{height: '30rem'}}>\n <ul className=\"phone-country-selector\">\n {countries}\n </ul>\n </div>\n );\n }\n}\n\nexport default injectIntl(PhoneCountrySelector);\n"],"names":["PhoneCountrySelector","React","constructor","props","super","this","countries","formatDisplayName","intl","dcodes","forEach","dc","dial","split","part","push","trim","code","flag","flagEmoji","name","type","sort","a","b","localeCompare","componentDidMount","selectedRef","scrollIntoView","block","inline","render","selected","c","idx","style","className","key","ref","onClick","_","onSubmit","height","injectIntl"],"sourceRoot":""}
|
||||
{"version":3,"file":"316.prod.js","mappings":"qkNASA,MAAMA,UAA6BC,IAAAA,cACjCC,WAAAA,CAAYC,GACVC,MAAMD,GAENE,KAAKC,UAAY,GACjB,MAAM,kBAAEC,GAAsBJ,EAAMK,KACpCC,EAAeC,SAAQC,IACPA,EAAGC,KAAKC,MAAM,KACtBH,SAAQI,IACZT,KAAKC,UAAUS,KAAK,CAClBH,KAAME,EAAKE,OACXC,KAAMN,EAAGM,KACTC,MAAMC,EAAAA,EAAAA,IAAUR,EAAGM,MACnBG,KAAMb,EAAkBI,EAAGM,KAAM,CAACI,KAAM,YACxC,GACF,IAGJhB,KAAKC,UAAUgB,MAAK,CAACC,EAAGC,IAAMD,EAAEH,KAAKK,cAAcD,EAAEJ,OACvD,CAEAM,iBAAAA,GACMrB,KAAKsB,aACPtB,KAAKsB,YAAYC,eAAe,CAACC,MAAO,SAAUC,OAAQ,WAE9D,CAEAC,MAAAA,GACE,MAAMzB,EAAY,GACZ0B,EAAW3B,KAAKF,MAAM6B,UAAY,KAYxC,OAXA3B,KAAKC,UAAUI,SAAQ,CAACuB,EAAGC,KACzB,MAAMC,EAASF,EAAEhB,MAAQe,EAAW,YAAc,GAClD1B,EAAUS,KAAKd,IAAAA,cAAA,MAAImC,UAAWD,EAAOE,IAAKH,EACxCI,IAAKA,IAAYL,EAAEhB,MAAQe,IAAW3B,KAAKsB,YAAcW,EAAG,EAC5DC,QAASC,GAAKnC,KAAKF,MAAMsC,SAASR,EAAEhB,KAAMgB,EAAErB,OAC5CX,IAAAA,cAAA,QAAMmC,UAAU,gBAAgBH,EAAEf,MAClCjB,IAAAA,cAAA,QAAMmC,UAAU,WAAU,IAAOH,EAAEb,MACnCnB,IAAAA,cAAA,QAAMmC,UAAU,aAAY,KAAQH,EAAErB,OAClC,IAINX,IAAAA,cAAA,OAAKmC,UAAU,mBAAmBD,MAAO,CAACO,OAAQ,UAChDzC,IAAAA,cAAA,MAAImC,UAAU,0BACX9B,GAIT,EAGF,WAAeqC,EAAAA,EAAAA,YAAW3C,E","sources":["webpack://tinode-webapp/./src/widgets/phone-country-selector.jsx"],"sourcesContent":["// Selector for country dialing code.\n\nimport React from 'react';\nimport { injectIntl } from 'react-intl';\n\nimport * as dcodes from '../dcodes.json';\n\nimport { flagEmoji } from '../lib/strformat';\n\nclass PhoneCountrySelector extends React.PureComponent {\n constructor(props) {\n super(props);\n\n this.countries = [];\n const { formatDisplayName } = props.intl;\n dcodes.default.forEach(dc => {\n const parts = dc.dial.split(',');\n parts.forEach(part => {\n this.countries.push({\n dial: part.trim(),\n code: dc.code,\n flag: flagEmoji(dc.code),\n name: formatDisplayName(dc.code, {type: 'region'})\n });\n });\n });\n\n this.countries.sort((a, b) => a.name.localeCompare(b.name));\n }\n\n componentDidMount() {\n if (this.selectedRef) {\n this.selectedRef.scrollIntoView({block: 'center', inline: 'nearest'});\n }\n }\n\n render() {\n const countries = [];\n const selected = this.props.selected || 'US';\n this.countries.forEach((c, idx) => {\n const style = (c.code == selected ? 'selected ' : '');\n countries.push(<li className={style} key={idx}\n ref={ref => {if (c.code == selected) {this.selectedRef = ref}}}\n onClick={_ => this.props.onSubmit(c.code, c.dial)}>\n <span className=\"country-flag\">{c.flag}</span>\n <span className=\"country\"> {c.name}</span>\n <span className=\"dial-code\"> +{c.dial}</span>\n </li>);\n });\n\n return (\n <div className=\"scrollable-panel\" style={{height: '30rem'}}>\n <ul className=\"phone-country-selector\">\n {countries}\n </ul>\n </div>\n );\n }\n}\n\nexport default injectIntl(PhoneCountrySelector);\n"],"names":["PhoneCountrySelector","React","constructor","props","super","this","countries","formatDisplayName","intl","dcodes","forEach","dc","dial","split","part","push","trim","code","flag","flagEmoji","name","type","sort","a","b","localeCompare","componentDidMount","selectedRef","scrollIntoView","block","inline","render","selected","c","idx","style","className","key","ref","onClick","_","onSubmit","height","injectIntl"],"sourceRoot":""}
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+5057
-4823
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
{"version":3,"file":"src_widgets_phone-country-selector_jsx.dev.js","mappings":";;;;;;;;;;;;;;;;AAE0B;AACc;AAEC;AAEI;AAE7C,MAAMI,oBAAoB,SAASJ,4DAAmB,CAAC;EACrDM,WAAWA,CAACC,KAAK,EAAE;IACjB,KAAK,CAACA,KAAK,CAAC;IAEZ,IAAI,CAACC,SAAS,GAAG,EAAE;IACnB,MAAM;MAAEC;IAAkB,CAAC,GAAGF,KAAK,CAACG,IAAI;IACxCR,yCAAc,CAACU,OAAO,CAACC,EAAE,IAAI;MAC3B,MAAMC,KAAK,GAAGD,EAAE,CAACE,IAAI,CAACC,KAAK,CAAC,GAAG,CAAC;MAChCF,KAAK,CAACF,OAAO,CAACK,IAAI,IAAI;QACpB,IAAI,CAACT,SAAS,CAACU,IAAI,CAAC;UAClBH,IAAI,EAAEE,IAAI,CAACE,IAAI,CAAC,CAAC;UACjBC,IAAI,EAAEP,EAAE,CAACO,IAAI;UACbC,IAAI,EAAElB,yDAAS,CAACU,EAAE,CAACO,IAAI,CAAC;UACxBE,IAAI,EAAEb,iBAAiB,CAACI,EAAE,CAACO,IAAI,EAAE;YAACG,IAAI,EAAE;UAAQ,CAAC;QACnD,CAAC,CAAC;MACJ,CAAC,CAAC;IACJ,CAAC,CAAC;IAEF,IAAI,CAACf,SAAS,CAACgB,IAAI,CAAC,CAACC,CAAC,EAAEC,CAAC,KAAKD,CAAC,CAACH,IAAI,CAACK,aAAa,CAACD,CAAC,CAACJ,IAAI,CAAC,CAAC;EAC7D;EAEAM,iBAAiBA,CAAA,EAAG;IAClB,IAAI,IAAI,CAACC,WAAW,EAAE;MACpB,IAAI,CAACA,WAAW,CAACC,cAAc,CAAC;QAACC,KAAK,EAAE,QAAQ;QAAEC,MAAM,EAAE;MAAS,CAAC,CAAC;IACvE;EACF;EAEAC,MAAMA,CAAA,EAAG;IACP,MAAMzB,SAAS,GAAG,EAAE;IACpB,MAAM0B,QAAQ,GAAG,IAAI,CAAC3B,KAAK,CAAC2B,QAAQ,IAAI,IAAI;IAC5C,IAAI,CAAC1B,SAAS,CAACI,OAAO,CAAC,CAACuB,CAAC,EAAEC,GAAG,KAAK;MACjC,MAAMC,KAAK,GAAIF,CAAC,CAACf,IAAI,IAAIc,QAAQ,GAAG,WAAW,GAAG,EAAG;MACrD1B,SAAS,CAACU,IAAI,CAAClB,0DAAA;QAAIuC,SAAS,EAAEF,KAAM;QAACG,GAAG,EAAEJ,GAAI;QAC5CK,GAAG,EAAEA,GAAG,IAAI;UAAC,IAAIN,CAAC,CAACf,IAAI,IAAIc,QAAQ,EAAE;YAAC,IAAI,CAACL,WAAW,GAAGY,GAAG;UAAA;QAAC,CAAE;QAC/DC,OAAO,EAAEC,CAAC,IAAI,IAAI,CAACpC,KAAK,CAACqC,QAAQ,CAACT,CAAC,CAACf,IAAI,EAAEe,CAAC,CAACpB,IAAI;MAAE,GAClDf,0DAAA;QAAMuC,SAAS,EAAC;MAAc,GAAEJ,CAAC,CAACd,IAAW,CAAC,EAC9CrB,0DAAA;QAAMuC,SAAS,EAAC;MAAS,GAAC,MAAM,EAACJ,CAAC,CAACb,IAAW,CAAC,EAC/CtB,0DAAA;QAAMuC,SAAS,EAAC;MAAW,GAAC,OAAO,EAACJ,CAAC,CAACpB,IAAW,CAC/C,CAAC,CAAC;IACR,CAAC,CAAC;IAEF,OACEf,0DAAA;MAAKuC,SAAS,EAAC,kBAAkB;MAACF,KAAK,EAAE;QAACQ,MAAM,EAAE;MAAO;IAAE,GACzD7C,0DAAA;MAAIuC,SAAS,EAAC;IAAwB,GACnC/B,SACC,CACD,CAAC;EAEV;AACF;AAEA,+DAAeP,sDAAU,CAACG,oBAAoB,CAAC","sources":["webpack://tinode-webapp/./src/widgets/phone-country-selector.jsx"],"sourcesContent":["// Selector for country dialing code.\n\nimport React from 'react';\nimport { injectIntl } from 'react-intl';\n\nimport * as dcodes from '../dcodes.json';\n\nimport { flagEmoji } from '../lib/strformat';\n\nclass PhoneCountrySelector extends React.PureComponent {\n constructor(props) {\n super(props);\n\n this.countries = [];\n const { formatDisplayName } = props.intl;\n dcodes.default.forEach(dc => {\n const parts = dc.dial.split(',');\n parts.forEach(part => {\n this.countries.push({\n dial: part.trim(),\n code: dc.code,\n flag: flagEmoji(dc.code),\n name: formatDisplayName(dc.code, {type: 'region'})\n });\n });\n });\n\n this.countries.sort((a, b) => a.name.localeCompare(b.name));\n }\n\n componentDidMount() {\n if (this.selectedRef) {\n this.selectedRef.scrollIntoView({block: 'center', inline: 'nearest'});\n }\n }\n\n render() {\n const countries = [];\n const selected = this.props.selected || 'US';\n this.countries.forEach((c, idx) => {\n const style = (c.code == selected ? 'selected ' : '');\n countries.push(<li className={style} key={idx}\n ref={ref => {if (c.code == selected) {this.selectedRef = ref}}}\n onClick={_ => this.props.onSubmit(c.code, c.dial)}>\n <span className=\"country-flag\">{c.flag}</span>\n <span className=\"country\"> {c.name}</span>\n <span className=\"dial-code\"> +{c.dial}</span>\n </li>);\n });\n\n return (\n <div className=\"scrollable-panel\" style={{height: '30rem'}}>\n <ul className=\"phone-country-selector\">\n {countries}\n </ul>\n </div>\n );\n }\n}\n\nexport default injectIntl(PhoneCountrySelector);\n"],"names":["React","injectIntl","dcodes","flagEmoji","PhoneCountrySelector","PureComponent","constructor","props","countries","formatDisplayName","intl","default","forEach","dc","parts","dial","split","part","push","trim","code","flag","name","type","sort","a","b","localeCompare","componentDidMount","selectedRef","scrollIntoView","block","inline","render","selected","c","idx","style","createElement","className","key","ref","onClick","_","onSubmit","height"],"sourceRoot":""}
|
||||
{"version":3,"file":"src_widgets_phone-country-selector_jsx.dev.js","mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAE0B;AACc;AAEC;AAEI;AAE7C,MAAMI,oBAAoB,SAASJ,4DAAmB,CAAC;EACrDM,WAAWA,CAACC,KAAK,EAAE;IACjB,KAAK,CAACA,KAAK,CAAC;IAEZ,IAAI,CAACC,SAAS,GAAG,EAAE;IACnB,MAAM;MAAEC;IAAkB,CAAC,GAAGF,KAAK,CAACG,IAAI;IACxCR,yCAAc,CAACU,OAAO,CAACC,EAAE,IAAI;MAC3B,MAAMC,KAAK,GAAGD,EAAE,CAACE,IAAI,CAACC,KAAK,CAAC,GAAG,CAAC;MAChCF,KAAK,CAACF,OAAO,CAACK,IAAI,IAAI;QACpB,IAAI,CAACT,SAAS,CAACU,IAAI,CAAC;UAClBH,IAAI,EAAEE,IAAI,CAACE,IAAI,CAAC,CAAC;UACjBC,IAAI,EAAEP,EAAE,CAACO,IAAI;UACbC,IAAI,EAAElB,yDAAS,CAACU,EAAE,CAACO,IAAI,CAAC;UACxBE,IAAI,EAAEb,iBAAiB,CAACI,EAAE,CAACO,IAAI,EAAE;YAACG,IAAI,EAAE;UAAQ,CAAC;QACnD,CAAC,CAAC;MACJ,CAAC,CAAC;IACJ,CAAC,CAAC;IAEF,IAAI,CAACf,SAAS,CAACgB,IAAI,CAAC,CAACC,CAAC,EAAEC,CAAC,KAAKD,CAAC,CAACH,IAAI,CAACK,aAAa,CAACD,CAAC,CAACJ,IAAI,CAAC,CAAC;EAC7D;EAEAM,iBAAiBA,CAAA,EAAG;IAClB,IAAI,IAAI,CAACC,WAAW,EAAE;MACpB,IAAI,CAACA,WAAW,CAACC,cAAc,CAAC;QAACC,KAAK,EAAE,QAAQ;QAAEC,MAAM,EAAE;MAAS,CAAC,CAAC;IACvE;EACF;EAEAC,MAAMA,CAAA,EAAG;IACP,MAAMzB,SAAS,GAAG,EAAE;IACpB,MAAM0B,QAAQ,GAAG,IAAI,CAAC3B,KAAK,CAAC2B,QAAQ,IAAI,IAAI;IAC5C,IAAI,CAAC1B,SAAS,CAACI,OAAO,CAAC,CAACuB,CAAC,EAAEC,GAAG,KAAK;MACjC,MAAMC,KAAK,GAAIF,CAAC,CAACf,IAAI,IAAIc,QAAQ,GAAG,WAAW,GAAG,EAAG;MACrD1B,SAAS,CAACU,IAAI,CAAClB,0DAAA;QAAIuC,SAAS,EAAEF,KAAM;QAACG,GAAG,EAAEJ,GAAI;QAC5CK,GAAG,EAAEA,GAAG,IAAI;UAAC,IAAIN,CAAC,CAACf,IAAI,IAAIc,QAAQ,EAAE;YAAC,IAAI,CAACL,WAAW,GAAGY,GAAG;UAAA;QAAC,CAAE;QAC/DC,OAAO,EAAEC,CAAC,IAAI,IAAI,CAACpC,KAAK,CAACqC,QAAQ,CAACT,CAAC,CAACf,IAAI,EAAEe,CAAC,CAACpB,IAAI;MAAE,GAClDf,0DAAA;QAAMuC,SAAS,EAAC;MAAc,GAAEJ,CAAC,CAACd,IAAW,CAAC,EAC9CrB,0DAAA;QAAMuC,SAAS,EAAC;MAAS,GAAC,MAAM,EAACJ,CAAC,CAACb,IAAW,CAAC,EAC/CtB,0DAAA;QAAMuC,SAAS,EAAC;MAAW,GAAC,OAAO,EAACJ,CAAC,CAACpB,IAAW,CAC/C,CAAC,CAAC;IACR,CAAC,CAAC;IAEF,OACEf,0DAAA;MAAKuC,SAAS,EAAC,kBAAkB;MAACF,KAAK,EAAE;QAACQ,MAAM,EAAE;MAAO;IAAE,GACzD7C,0DAAA;MAAIuC,SAAS,EAAC;IAAwB,GACnC/B,SACC,CACD,CAAC;EAEV;AACF;AAEA,+DAAeP,sDAAU,CAACG,oBAAoB,CAAC","sources":["webpack://tinode-webapp/./src/widgets/phone-country-selector.jsx"],"sourcesContent":["// Selector for country dialing code.\n\nimport React from 'react';\nimport { injectIntl } from 'react-intl';\n\nimport * as dcodes from '../dcodes.json';\n\nimport { flagEmoji } from '../lib/strformat';\n\nclass PhoneCountrySelector extends React.PureComponent {\n constructor(props) {\n super(props);\n\n this.countries = [];\n const { formatDisplayName } = props.intl;\n dcodes.default.forEach(dc => {\n const parts = dc.dial.split(',');\n parts.forEach(part => {\n this.countries.push({\n dial: part.trim(),\n code: dc.code,\n flag: flagEmoji(dc.code),\n name: formatDisplayName(dc.code, {type: 'region'})\n });\n });\n });\n\n this.countries.sort((a, b) => a.name.localeCompare(b.name));\n }\n\n componentDidMount() {\n if (this.selectedRef) {\n this.selectedRef.scrollIntoView({block: 'center', inline: 'nearest'});\n }\n }\n\n render() {\n const countries = [];\n const selected = this.props.selected || 'US';\n this.countries.forEach((c, idx) => {\n const style = (c.code == selected ? 'selected ' : '');\n countries.push(<li className={style} key={idx}\n ref={ref => {if (c.code == selected) {this.selectedRef = ref}}}\n onClick={_ => this.props.onSubmit(c.code, c.dial)}>\n <span className=\"country-flag\">{c.flag}</span>\n <span className=\"country\"> {c.name}</span>\n <span className=\"dial-code\"> +{c.dial}</span>\n </li>);\n });\n\n return (\n <div className=\"scrollable-panel\" style={{height: '30rem'}}>\n <ul className=\"phone-country-selector\">\n {countries}\n </ul>\n </div>\n );\n }\n}\n\nexport default injectIntl(PhoneCountrySelector);\n"],"names":["React","injectIntl","dcodes","flagEmoji","PhoneCountrySelector","PureComponent","constructor","props","countries","formatDisplayName","intl","default","forEach","dc","parts","dial","split","part","push","trim","code","flag","name","type","sort","a","b","localeCompare","componentDidMount","selectedRef","scrollIntoView","block","inline","render","selected","c","idx","style","createElement","className","key","ref","onClick","_","onSubmit","height"],"sourceRoot":""}
|
||||
@@ -4473,6 +4473,13 @@ class Topic {
|
||||
aux(key) {
|
||||
return this._aux[key];
|
||||
}
|
||||
alias() {
|
||||
let alias = this._tags && this._tags.find(t => t.startsWith('alias:'));
|
||||
if (alias) {
|
||||
alias = alias.substring(6);
|
||||
}
|
||||
return alias;
|
||||
}
|
||||
subscriber(uid) {
|
||||
return this._users[uid];
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+66
-21
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -3073,6 +3073,322 @@ exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
|
||||
}
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./node_modules/int64-buffer/int64-buffer.js":
|
||||
/*!***************************************************!*\
|
||||
!*** ./node_modules/int64-buffer/int64-buffer.js ***!
|
||||
\***************************************************/
|
||||
/***/ (function(__unused_webpack_module, exports) {
|
||||
|
||||
// int64-buffer.js
|
||||
|
||||
/*jshint -W018 */ // Confusing use of '!'.
|
||||
/*jshint -W030 */ // Expected an assignment or function call and instead saw an expression.
|
||||
/*jshint -W093 */ // Did you mean to return a conditional instead of an assignment?
|
||||
|
||||
var Uint64BE, Int64BE, Uint64LE, Int64LE;
|
||||
|
||||
!function(exports) {
|
||||
// constants
|
||||
|
||||
var UNDEFINED = "undefined";
|
||||
var BUFFER = (UNDEFINED !== typeof Buffer) && Buffer;
|
||||
var UINT8ARRAY = (UNDEFINED !== typeof Uint8Array) && Uint8Array;
|
||||
var ARRAYBUFFER = (UNDEFINED !== typeof ArrayBuffer) && ArrayBuffer;
|
||||
var ZERO = [0, 0, 0, 0, 0, 0, 0, 0];
|
||||
var isArray = Array.isArray || _isArray;
|
||||
var BIT32 = 4294967296;
|
||||
var BIT24 = 16777216;
|
||||
|
||||
// storage class
|
||||
|
||||
var storage; // Array;
|
||||
|
||||
// generate classes
|
||||
|
||||
Uint64BE = factory("Uint64BE", true, true);
|
||||
Int64BE = factory("Int64BE", true, false);
|
||||
Uint64LE = factory("Uint64LE", false, true);
|
||||
Int64LE = factory("Int64LE", false, false);
|
||||
|
||||
// class factory
|
||||
|
||||
function factory(name, bigendian, unsigned) {
|
||||
var posH = bigendian ? 0 : 4;
|
||||
var posL = bigendian ? 4 : 0;
|
||||
var pos0 = bigendian ? 0 : 3;
|
||||
var pos1 = bigendian ? 1 : 2;
|
||||
var pos2 = bigendian ? 2 : 1;
|
||||
var pos3 = bigendian ? 3 : 0;
|
||||
var fromPositive = bigendian ? fromPositiveBE : fromPositiveLE;
|
||||
var fromNegative = bigendian ? fromNegativeBE : fromNegativeLE;
|
||||
var proto = Int64.prototype;
|
||||
var isName = "is" + name;
|
||||
var _isInt64 = "_" + isName;
|
||||
|
||||
// properties
|
||||
proto.buffer = void 0;
|
||||
proto.offset = 0;
|
||||
proto[_isInt64] = true;
|
||||
|
||||
// methods
|
||||
proto.toNumber = toNumber;
|
||||
proto.toString = toString;
|
||||
proto.toJSON = toNumber;
|
||||
proto.toArray = toArray;
|
||||
|
||||
// add .toBuffer() method only when Buffer available
|
||||
if (BUFFER) proto.toBuffer = toBuffer;
|
||||
|
||||
// add .toArrayBuffer() method only when Uint8Array available
|
||||
if (UINT8ARRAY) proto.toArrayBuffer = toArrayBuffer;
|
||||
|
||||
// isUint64BE, isInt64BE
|
||||
Int64[isName] = isInt64;
|
||||
|
||||
// CommonJS
|
||||
exports[name] = Int64;
|
||||
|
||||
return Int64;
|
||||
|
||||
// constructor
|
||||
function Int64(buffer, offset, value, raddix) {
|
||||
if (!(this instanceof Int64)) return new Int64(buffer, offset, value, raddix);
|
||||
return init(this, buffer, offset, value, raddix);
|
||||
}
|
||||
|
||||
// isUint64BE, isInt64BE
|
||||
function isInt64(b) {
|
||||
return !!(b && b[_isInt64]);
|
||||
}
|
||||
|
||||
// initializer
|
||||
function init(that, buffer, offset, value, raddix) {
|
||||
if (UINT8ARRAY && ARRAYBUFFER) {
|
||||
if (buffer instanceof ARRAYBUFFER) buffer = new UINT8ARRAY(buffer);
|
||||
if (value instanceof ARRAYBUFFER) value = new UINT8ARRAY(value);
|
||||
}
|
||||
|
||||
// Int64BE() style
|
||||
if (!buffer && !offset && !value && !storage) {
|
||||
// shortcut to initialize with zero
|
||||
that.buffer = newArray(ZERO, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Int64BE(value, raddix) style
|
||||
if (!isValidBuffer(buffer, offset)) {
|
||||
var _storage = storage || Array;
|
||||
raddix = offset;
|
||||
value = buffer;
|
||||
offset = 0;
|
||||
buffer = (storage === BUFFER) ? BUFFER.alloc(8) : new _storage(8);
|
||||
}
|
||||
|
||||
that.buffer = buffer;
|
||||
that.offset = offset |= 0;
|
||||
|
||||
// Int64BE(buffer, offset) style
|
||||
if (UNDEFINED === typeof value) return;
|
||||
|
||||
// Int64BE(buffer, offset, value, raddix) style
|
||||
if ("string" === typeof value) {
|
||||
fromString(buffer, offset, value, raddix || 10);
|
||||
} else if (isValidBuffer(value, raddix)) {
|
||||
fromArray(buffer, offset, value, raddix);
|
||||
} else if ("number" === typeof raddix) {
|
||||
writeInt32(buffer, offset + posH, value); // high
|
||||
writeInt32(buffer, offset + posL, raddix); // low
|
||||
} else if (value > 0) {
|
||||
fromPositive(buffer, offset, value); // positive
|
||||
} else if (value < 0) {
|
||||
fromNegative(buffer, offset, value); // negative
|
||||
} else {
|
||||
fromArray(buffer, offset, ZERO, 0); // zero, NaN and others
|
||||
}
|
||||
}
|
||||
|
||||
function fromString(buffer, offset, str, raddix) {
|
||||
var pos = 0;
|
||||
var len = str.length;
|
||||
var high = 0;
|
||||
var low = 0;
|
||||
if (str[0] === "-") pos++;
|
||||
var sign = pos;
|
||||
while (pos < len) {
|
||||
var chr = parseInt(str[pos++], raddix);
|
||||
if (!(chr >= 0)) break; // NaN
|
||||
low = low * raddix + chr;
|
||||
high = high * raddix + Math.floor(low / BIT32);
|
||||
low %= BIT32;
|
||||
}
|
||||
if (sign) {
|
||||
high = ~high;
|
||||
if (low) {
|
||||
low = BIT32 - low;
|
||||
} else {
|
||||
high++;
|
||||
}
|
||||
}
|
||||
writeInt32(buffer, offset + posH, high);
|
||||
writeInt32(buffer, offset + posL, low);
|
||||
}
|
||||
|
||||
function toNumber() {
|
||||
var buffer = this.buffer;
|
||||
var offset = this.offset;
|
||||
var high = readInt32(buffer, offset + posH);
|
||||
var low = readInt32(buffer, offset + posL);
|
||||
if (!unsigned) high |= 0; // a trick to get signed
|
||||
return high ? (high * BIT32 + low) : low;
|
||||
}
|
||||
|
||||
function toString(radix) {
|
||||
var buffer = this.buffer;
|
||||
var offset = this.offset;
|
||||
var high = readInt32(buffer, offset + posH);
|
||||
var low = readInt32(buffer, offset + posL);
|
||||
var str = "";
|
||||
var sign = !unsigned && (high & 0x80000000);
|
||||
if (sign) {
|
||||
high = ~high;
|
||||
low = BIT32 - low;
|
||||
}
|
||||
radix = radix || 10;
|
||||
while (1) {
|
||||
var mod = (high % radix) * BIT32 + low;
|
||||
high = Math.floor(high / radix);
|
||||
low = Math.floor(mod / radix);
|
||||
str = (mod % radix).toString(radix) + str;
|
||||
if (!high && !low) break;
|
||||
}
|
||||
if (sign) {
|
||||
str = "-" + str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function writeInt32(buffer, offset, value) {
|
||||
buffer[offset + pos3] = value & 255;
|
||||
value = value >> 8;
|
||||
buffer[offset + pos2] = value & 255;
|
||||
value = value >> 8;
|
||||
buffer[offset + pos1] = value & 255;
|
||||
value = value >> 8;
|
||||
buffer[offset + pos0] = value & 255;
|
||||
}
|
||||
|
||||
function readInt32(buffer, offset) {
|
||||
return (buffer[offset + pos0] * BIT24) +
|
||||
(buffer[offset + pos1] << 16) +
|
||||
(buffer[offset + pos2] << 8) +
|
||||
buffer[offset + pos3];
|
||||
}
|
||||
}
|
||||
|
||||
function toArray(raw) {
|
||||
var buffer = this.buffer;
|
||||
var offset = this.offset;
|
||||
storage = null; // Array
|
||||
|
||||
if (raw !== false && isArray(buffer)) {
|
||||
return (buffer.length === 8) ? buffer : buffer.slice(offset, offset + 8);
|
||||
}
|
||||
|
||||
return newArray(buffer, offset);
|
||||
}
|
||||
|
||||
function toBuffer(raw) {
|
||||
var buffer = this.buffer;
|
||||
var offset = this.offset;
|
||||
storage = BUFFER;
|
||||
|
||||
if (raw !== false && BUFFER.isBuffer(buffer)) {
|
||||
return (buffer.length === 8) ? buffer : buffer.slice(offset, offset + 8);
|
||||
}
|
||||
|
||||
// Buffer.from(arraybuffer) available since Node v4.5.0
|
||||
// https://nodejs.org/en/blog/release/v4.5.0/
|
||||
return BUFFER.from(toArrayBuffer.call(this, raw));
|
||||
}
|
||||
|
||||
function toArrayBuffer(raw) {
|
||||
var buffer = this.buffer;
|
||||
var offset = this.offset;
|
||||
var arrbuf = buffer.buffer;
|
||||
storage = UINT8ARRAY;
|
||||
|
||||
// arrbuf.slice() ignores buffer.offset until Node v8.0.0
|
||||
if (raw !== false && !buffer.offset && (arrbuf instanceof ARRAYBUFFER)) {
|
||||
return (arrbuf.byteLength === 8) ? arrbuf : arrbuf.slice(offset, offset + 8);
|
||||
}
|
||||
|
||||
var dest = new UINT8ARRAY(8);
|
||||
fromArray(dest, 0, buffer, offset);
|
||||
return dest.buffer;
|
||||
}
|
||||
|
||||
function isValidBuffer(buffer, offset) {
|
||||
var len = buffer && buffer.length;
|
||||
offset |= 0;
|
||||
return len && (offset + 8 <= len) && ("string" !== typeof buffer[offset]);
|
||||
}
|
||||
|
||||
function fromArray(destbuf, destoff, srcbuf, srcoff) {
|
||||
destoff |= 0;
|
||||
srcoff |= 0;
|
||||
for (var i = 0; i < 8; i++) {
|
||||
destbuf[destoff++] = srcbuf[srcoff++] & 255;
|
||||
}
|
||||
}
|
||||
|
||||
function newArray(buffer, offset) {
|
||||
return Array.prototype.slice.call(buffer, offset, offset + 8);
|
||||
}
|
||||
|
||||
function fromPositiveBE(buffer, offset, value) {
|
||||
var pos = offset + 8;
|
||||
while (pos > offset) {
|
||||
buffer[--pos] = value & 255;
|
||||
value /= 256;
|
||||
}
|
||||
}
|
||||
|
||||
function fromNegativeBE(buffer, offset, value) {
|
||||
var pos = offset + 8;
|
||||
value++;
|
||||
while (pos > offset) {
|
||||
buffer[--pos] = ((-value) & 255) ^ 255;
|
||||
value /= 256;
|
||||
}
|
||||
}
|
||||
|
||||
function fromPositiveLE(buffer, offset, value) {
|
||||
var end = offset + 8;
|
||||
while (offset < end) {
|
||||
buffer[offset++] = value & 255;
|
||||
value /= 256;
|
||||
}
|
||||
}
|
||||
|
||||
function fromNegativeLE(buffer, offset, value) {
|
||||
var end = offset + 8;
|
||||
value++;
|
||||
while (offset < end) {
|
||||
buffer[offset++] = ((-value) & 255) ^ 255;
|
||||
value /= 256;
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/retrofox/is-array
|
||||
function _isArray(val) {
|
||||
return !!val && "[object Array]" == Object.prototype.toString.call(val);
|
||||
}
|
||||
|
||||
}( true && typeof exports.nodeName !== 'string' ? exports : (this || {}));
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./node_modules/webm-duration-fix/lib/ebml/EBML.js":
|
||||
@@ -7035,322 +7351,6 @@ function fixWebmDuration(blob) {
|
||||
exports["default"] = fixWebmDuration;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./node_modules/int64-buffer/int64-buffer.js":
|
||||
/*!***************************************************!*\
|
||||
!*** ./node_modules/int64-buffer/int64-buffer.js ***!
|
||||
\***************************************************/
|
||||
/***/ (function(__unused_webpack_module, exports) {
|
||||
|
||||
// int64-buffer.js
|
||||
|
||||
/*jshint -W018 */ // Confusing use of '!'.
|
||||
/*jshint -W030 */ // Expected an assignment or function call and instead saw an expression.
|
||||
/*jshint -W093 */ // Did you mean to return a conditional instead of an assignment?
|
||||
|
||||
var Uint64BE, Int64BE, Uint64LE, Int64LE;
|
||||
|
||||
!function(exports) {
|
||||
// constants
|
||||
|
||||
var UNDEFINED = "undefined";
|
||||
var BUFFER = (UNDEFINED !== typeof Buffer) && Buffer;
|
||||
var UINT8ARRAY = (UNDEFINED !== typeof Uint8Array) && Uint8Array;
|
||||
var ARRAYBUFFER = (UNDEFINED !== typeof ArrayBuffer) && ArrayBuffer;
|
||||
var ZERO = [0, 0, 0, 0, 0, 0, 0, 0];
|
||||
var isArray = Array.isArray || _isArray;
|
||||
var BIT32 = 4294967296;
|
||||
var BIT24 = 16777216;
|
||||
|
||||
// storage class
|
||||
|
||||
var storage; // Array;
|
||||
|
||||
// generate classes
|
||||
|
||||
Uint64BE = factory("Uint64BE", true, true);
|
||||
Int64BE = factory("Int64BE", true, false);
|
||||
Uint64LE = factory("Uint64LE", false, true);
|
||||
Int64LE = factory("Int64LE", false, false);
|
||||
|
||||
// class factory
|
||||
|
||||
function factory(name, bigendian, unsigned) {
|
||||
var posH = bigendian ? 0 : 4;
|
||||
var posL = bigendian ? 4 : 0;
|
||||
var pos0 = bigendian ? 0 : 3;
|
||||
var pos1 = bigendian ? 1 : 2;
|
||||
var pos2 = bigendian ? 2 : 1;
|
||||
var pos3 = bigendian ? 3 : 0;
|
||||
var fromPositive = bigendian ? fromPositiveBE : fromPositiveLE;
|
||||
var fromNegative = bigendian ? fromNegativeBE : fromNegativeLE;
|
||||
var proto = Int64.prototype;
|
||||
var isName = "is" + name;
|
||||
var _isInt64 = "_" + isName;
|
||||
|
||||
// properties
|
||||
proto.buffer = void 0;
|
||||
proto.offset = 0;
|
||||
proto[_isInt64] = true;
|
||||
|
||||
// methods
|
||||
proto.toNumber = toNumber;
|
||||
proto.toString = toString;
|
||||
proto.toJSON = toNumber;
|
||||
proto.toArray = toArray;
|
||||
|
||||
// add .toBuffer() method only when Buffer available
|
||||
if (BUFFER) proto.toBuffer = toBuffer;
|
||||
|
||||
// add .toArrayBuffer() method only when Uint8Array available
|
||||
if (UINT8ARRAY) proto.toArrayBuffer = toArrayBuffer;
|
||||
|
||||
// isUint64BE, isInt64BE
|
||||
Int64[isName] = isInt64;
|
||||
|
||||
// CommonJS
|
||||
exports[name] = Int64;
|
||||
|
||||
return Int64;
|
||||
|
||||
// constructor
|
||||
function Int64(buffer, offset, value, raddix) {
|
||||
if (!(this instanceof Int64)) return new Int64(buffer, offset, value, raddix);
|
||||
return init(this, buffer, offset, value, raddix);
|
||||
}
|
||||
|
||||
// isUint64BE, isInt64BE
|
||||
function isInt64(b) {
|
||||
return !!(b && b[_isInt64]);
|
||||
}
|
||||
|
||||
// initializer
|
||||
function init(that, buffer, offset, value, raddix) {
|
||||
if (UINT8ARRAY && ARRAYBUFFER) {
|
||||
if (buffer instanceof ARRAYBUFFER) buffer = new UINT8ARRAY(buffer);
|
||||
if (value instanceof ARRAYBUFFER) value = new UINT8ARRAY(value);
|
||||
}
|
||||
|
||||
// Int64BE() style
|
||||
if (!buffer && !offset && !value && !storage) {
|
||||
// shortcut to initialize with zero
|
||||
that.buffer = newArray(ZERO, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Int64BE(value, raddix) style
|
||||
if (!isValidBuffer(buffer, offset)) {
|
||||
var _storage = storage || Array;
|
||||
raddix = offset;
|
||||
value = buffer;
|
||||
offset = 0;
|
||||
buffer = (storage === BUFFER) ? BUFFER.alloc(8) : new _storage(8);
|
||||
}
|
||||
|
||||
that.buffer = buffer;
|
||||
that.offset = offset |= 0;
|
||||
|
||||
// Int64BE(buffer, offset) style
|
||||
if (UNDEFINED === typeof value) return;
|
||||
|
||||
// Int64BE(buffer, offset, value, raddix) style
|
||||
if ("string" === typeof value) {
|
||||
fromString(buffer, offset, value, raddix || 10);
|
||||
} else if (isValidBuffer(value, raddix)) {
|
||||
fromArray(buffer, offset, value, raddix);
|
||||
} else if ("number" === typeof raddix) {
|
||||
writeInt32(buffer, offset + posH, value); // high
|
||||
writeInt32(buffer, offset + posL, raddix); // low
|
||||
} else if (value > 0) {
|
||||
fromPositive(buffer, offset, value); // positive
|
||||
} else if (value < 0) {
|
||||
fromNegative(buffer, offset, value); // negative
|
||||
} else {
|
||||
fromArray(buffer, offset, ZERO, 0); // zero, NaN and others
|
||||
}
|
||||
}
|
||||
|
||||
function fromString(buffer, offset, str, raddix) {
|
||||
var pos = 0;
|
||||
var len = str.length;
|
||||
var high = 0;
|
||||
var low = 0;
|
||||
if (str[0] === "-") pos++;
|
||||
var sign = pos;
|
||||
while (pos < len) {
|
||||
var chr = parseInt(str[pos++], raddix);
|
||||
if (!(chr >= 0)) break; // NaN
|
||||
low = low * raddix + chr;
|
||||
high = high * raddix + Math.floor(low / BIT32);
|
||||
low %= BIT32;
|
||||
}
|
||||
if (sign) {
|
||||
high = ~high;
|
||||
if (low) {
|
||||
low = BIT32 - low;
|
||||
} else {
|
||||
high++;
|
||||
}
|
||||
}
|
||||
writeInt32(buffer, offset + posH, high);
|
||||
writeInt32(buffer, offset + posL, low);
|
||||
}
|
||||
|
||||
function toNumber() {
|
||||
var buffer = this.buffer;
|
||||
var offset = this.offset;
|
||||
var high = readInt32(buffer, offset + posH);
|
||||
var low = readInt32(buffer, offset + posL);
|
||||
if (!unsigned) high |= 0; // a trick to get signed
|
||||
return high ? (high * BIT32 + low) : low;
|
||||
}
|
||||
|
||||
function toString(radix) {
|
||||
var buffer = this.buffer;
|
||||
var offset = this.offset;
|
||||
var high = readInt32(buffer, offset + posH);
|
||||
var low = readInt32(buffer, offset + posL);
|
||||
var str = "";
|
||||
var sign = !unsigned && (high & 0x80000000);
|
||||
if (sign) {
|
||||
high = ~high;
|
||||
low = BIT32 - low;
|
||||
}
|
||||
radix = radix || 10;
|
||||
while (1) {
|
||||
var mod = (high % radix) * BIT32 + low;
|
||||
high = Math.floor(high / radix);
|
||||
low = Math.floor(mod / radix);
|
||||
str = (mod % radix).toString(radix) + str;
|
||||
if (!high && !low) break;
|
||||
}
|
||||
if (sign) {
|
||||
str = "-" + str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function writeInt32(buffer, offset, value) {
|
||||
buffer[offset + pos3] = value & 255;
|
||||
value = value >> 8;
|
||||
buffer[offset + pos2] = value & 255;
|
||||
value = value >> 8;
|
||||
buffer[offset + pos1] = value & 255;
|
||||
value = value >> 8;
|
||||
buffer[offset + pos0] = value & 255;
|
||||
}
|
||||
|
||||
function readInt32(buffer, offset) {
|
||||
return (buffer[offset + pos0] * BIT24) +
|
||||
(buffer[offset + pos1] << 16) +
|
||||
(buffer[offset + pos2] << 8) +
|
||||
buffer[offset + pos3];
|
||||
}
|
||||
}
|
||||
|
||||
function toArray(raw) {
|
||||
var buffer = this.buffer;
|
||||
var offset = this.offset;
|
||||
storage = null; // Array
|
||||
|
||||
if (raw !== false && isArray(buffer)) {
|
||||
return (buffer.length === 8) ? buffer : buffer.slice(offset, offset + 8);
|
||||
}
|
||||
|
||||
return newArray(buffer, offset);
|
||||
}
|
||||
|
||||
function toBuffer(raw) {
|
||||
var buffer = this.buffer;
|
||||
var offset = this.offset;
|
||||
storage = BUFFER;
|
||||
|
||||
if (raw !== false && BUFFER.isBuffer(buffer)) {
|
||||
return (buffer.length === 8) ? buffer : buffer.slice(offset, offset + 8);
|
||||
}
|
||||
|
||||
// Buffer.from(arraybuffer) available since Node v4.5.0
|
||||
// https://nodejs.org/en/blog/release/v4.5.0/
|
||||
return BUFFER.from(toArrayBuffer.call(this, raw));
|
||||
}
|
||||
|
||||
function toArrayBuffer(raw) {
|
||||
var buffer = this.buffer;
|
||||
var offset = this.offset;
|
||||
var arrbuf = buffer.buffer;
|
||||
storage = UINT8ARRAY;
|
||||
|
||||
// arrbuf.slice() ignores buffer.offset until Node v8.0.0
|
||||
if (raw !== false && !buffer.offset && (arrbuf instanceof ARRAYBUFFER)) {
|
||||
return (arrbuf.byteLength === 8) ? arrbuf : arrbuf.slice(offset, offset + 8);
|
||||
}
|
||||
|
||||
var dest = new UINT8ARRAY(8);
|
||||
fromArray(dest, 0, buffer, offset);
|
||||
return dest.buffer;
|
||||
}
|
||||
|
||||
function isValidBuffer(buffer, offset) {
|
||||
var len = buffer && buffer.length;
|
||||
offset |= 0;
|
||||
return len && (offset + 8 <= len) && ("string" !== typeof buffer[offset]);
|
||||
}
|
||||
|
||||
function fromArray(destbuf, destoff, srcbuf, srcoff) {
|
||||
destoff |= 0;
|
||||
srcoff |= 0;
|
||||
for (var i = 0; i < 8; i++) {
|
||||
destbuf[destoff++] = srcbuf[srcoff++] & 255;
|
||||
}
|
||||
}
|
||||
|
||||
function newArray(buffer, offset) {
|
||||
return Array.prototype.slice.call(buffer, offset, offset + 8);
|
||||
}
|
||||
|
||||
function fromPositiveBE(buffer, offset, value) {
|
||||
var pos = offset + 8;
|
||||
while (pos > offset) {
|
||||
buffer[--pos] = value & 255;
|
||||
value /= 256;
|
||||
}
|
||||
}
|
||||
|
||||
function fromNegativeBE(buffer, offset, value) {
|
||||
var pos = offset + 8;
|
||||
value++;
|
||||
while (pos > offset) {
|
||||
buffer[--pos] = ((-value) & 255) ^ 255;
|
||||
value /= 256;
|
||||
}
|
||||
}
|
||||
|
||||
function fromPositiveLE(buffer, offset, value) {
|
||||
var end = offset + 8;
|
||||
while (offset < end) {
|
||||
buffer[offset++] = value & 255;
|
||||
value /= 256;
|
||||
}
|
||||
}
|
||||
|
||||
function fromNegativeLE(buffer, offset, value) {
|
||||
var end = offset + 8;
|
||||
value++;
|
||||
while (offset < end) {
|
||||
buffer[offset++] = ((-value) & 255) ^ 255;
|
||||
value /= 256;
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/retrofox/is-array
|
||||
function _isArray(val) {
|
||||
return !!val && "[object Array]" == Object.prototype.toString.call(val);
|
||||
}
|
||||
|
||||
}( true && typeof exports.nodeName !== 'string' ? exports : (this || {}));
|
||||
|
||||
|
||||
/***/ })
|
||||
|
||||
}]);
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user