This commit is contained in:
or-else
2025-03-04 13:05:51 +03:00
parent 3567f323c7
commit 11436a80ee
61 changed files with 9830 additions and 6108 deletions
+83 -9
View File
@@ -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.
*/
+1 -1
View File
File diff suppressed because one or more lines are too long
+3420 -845
View File
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -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
View File
@@ -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;
+1 -1
View File
File diff suppressed because one or more lines are too long
+49
View File
@@ -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
}
}
+49
View File
@@ -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
}
}
+49
View File
@@ -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
}
}
+28
View File
@@ -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]"
+49
View File
@@ -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
}
}
+49
View File
@@ -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
}
}
+49
View File
@@ -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
}
}
+49
View File
@@ -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
}
}
+49
View File
@@ -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
}
}
+49
View File
@@ -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
}
}
+49
View File
@@ -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
}
}
+49
View File
@@ -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
View File
@@ -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;
+4
View File
@@ -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', () => {
+8 -1
View File
@@ -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>&nbsp;
<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>&nbsp;
<tt>@{this.state.alias}</tt>
</div> : null}
<div className="group">
<BadgeList trustedBadges={this.props.trustedBadges} />
</div>
+39 -8
View File
@@ -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'}}>
&nbsp;<a href="#" onClick={this.handleCopyID}>
&nbsp;<a href="#" onClick={e => {this.handleCopyToClipboard(e, this.state.address);}}>
<i className="material-icons">content_copy</i>
</a>&nbsp;
&nbsp;<a href="#" onClick={this.handleShowQRCode}>
@@ -596,6 +611,22 @@ class InfoView extends React.Component {
</a>&nbsp;
</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>&nbsp;
<tt>{alias}</tt>
</div>
<div style={{marginLeft: 'auto'}}>
&nbsp;<a href="#" onClick={e => {this.handleCopyToClipboard(e, alias);}}>
<i className="material-icons">content_copy</i>
</a>&nbsp;
&nbsp;<i className="material-icons" style={{opacity: 0}}>qr_code</i>&nbsp;
</div>
</div>
: null}
</>
: null
}
{this.state.trustedBadges.length > 0 ?
+20 -2
View File
@@ -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}
+7 -2
View File
@@ -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() {
+36 -3
View File
@@ -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);
}
};
+107 -2
View File
@@ -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">
+2 -1
View File
@@ -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
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -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\">&nbsp;{c.name}</span>\n <span className=\"dial-code\">&nbsp;+{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\">&nbsp;{c.name}</span>\n <span className=\"dial-code\">&nbsp;+{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
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+5057 -4823
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
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\">&nbsp;{c.name}</span>\n <span className=\"dial-code\">&nbsp;+{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\">&nbsp;{c.name}</span>\n <span className=\"dial-code\">&nbsp;+{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":""}
+7
View File
@@ -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
View File
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
@@ -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