/******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({ /***/ "./node_modules/@firebase/util/dist/index.esm2017.js": /*!***********************************************************!*\ !*** ./node_modules/@firebase/util/dist/index.esm2017.js ***! \***********************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "CONSTANTS": () => (/* binding */ CONSTANTS), /* harmony export */ "Deferred": () => (/* binding */ Deferred), /* harmony export */ "ErrorFactory": () => (/* binding */ ErrorFactory), /* harmony export */ "FirebaseError": () => (/* binding */ FirebaseError), /* harmony export */ "MAX_VALUE_MILLIS": () => (/* binding */ MAX_VALUE_MILLIS), /* harmony export */ "RANDOM_FACTOR": () => (/* binding */ RANDOM_FACTOR), /* harmony export */ "Sha1": () => (/* binding */ Sha1), /* harmony export */ "areCookiesEnabled": () => (/* binding */ areCookiesEnabled), /* harmony export */ "assert": () => (/* binding */ assert), /* harmony export */ "assertionError": () => (/* binding */ assertionError), /* harmony export */ "async": () => (/* binding */ async), /* harmony export */ "base64": () => (/* binding */ base64), /* harmony export */ "base64Decode": () => (/* binding */ base64Decode), /* harmony export */ "base64Encode": () => (/* binding */ base64Encode), /* harmony export */ "base64urlEncodeWithoutPadding": () => (/* binding */ base64urlEncodeWithoutPadding), /* harmony export */ "calculateBackoffMillis": () => (/* binding */ calculateBackoffMillis), /* harmony export */ "contains": () => (/* binding */ contains), /* harmony export */ "createMockUserToken": () => (/* binding */ createMockUserToken), /* harmony export */ "createSubscribe": () => (/* binding */ createSubscribe), /* harmony export */ "decode": () => (/* binding */ decode), /* harmony export */ "deepCopy": () => (/* binding */ deepCopy), /* harmony export */ "deepEqual": () => (/* binding */ deepEqual), /* harmony export */ "deepExtend": () => (/* binding */ deepExtend), /* harmony export */ "errorPrefix": () => (/* binding */ errorPrefix), /* harmony export */ "extractQuerystring": () => (/* binding */ extractQuerystring), /* harmony export */ "getGlobal": () => (/* binding */ getGlobal), /* harmony export */ "getModularInstance": () => (/* binding */ getModularInstance), /* harmony export */ "getUA": () => (/* binding */ getUA), /* harmony export */ "isAdmin": () => (/* binding */ isAdmin), /* harmony export */ "isBrowser": () => (/* binding */ isBrowser), /* harmony export */ "isBrowserExtension": () => (/* binding */ isBrowserExtension), /* harmony export */ "isElectron": () => (/* binding */ isElectron), /* harmony export */ "isEmpty": () => (/* binding */ isEmpty), /* harmony export */ "isIE": () => (/* binding */ isIE), /* harmony export */ "isIndexedDBAvailable": () => (/* binding */ isIndexedDBAvailable), /* harmony export */ "isMobileCordova": () => (/* binding */ isMobileCordova), /* harmony export */ "isNode": () => (/* binding */ isNode), /* harmony export */ "isNodeSdk": () => (/* binding */ isNodeSdk), /* harmony export */ "isReactNative": () => (/* binding */ isReactNative), /* harmony export */ "isSafari": () => (/* binding */ isSafari), /* harmony export */ "isUWP": () => (/* binding */ isUWP), /* harmony export */ "isValidFormat": () => (/* binding */ isValidFormat), /* harmony export */ "isValidTimestamp": () => (/* binding */ isValidTimestamp), /* harmony export */ "issuedAtTime": () => (/* binding */ issuedAtTime), /* harmony export */ "jsonEval": () => (/* binding */ jsonEval), /* harmony export */ "map": () => (/* binding */ map), /* harmony export */ "ordinal": () => (/* binding */ ordinal), /* harmony export */ "querystring": () => (/* binding */ querystring), /* harmony export */ "querystringDecode": () => (/* binding */ querystringDecode), /* harmony export */ "safeGet": () => (/* binding */ safeGet), /* harmony export */ "stringLength": () => (/* binding */ stringLength), /* harmony export */ "stringToByteArray": () => (/* binding */ stringToByteArray), /* harmony export */ "stringify": () => (/* binding */ stringify), /* harmony export */ "validateArgCount": () => (/* binding */ validateArgCount), /* harmony export */ "validateCallback": () => (/* binding */ validateCallback), /* harmony export */ "validateContextObject": () => (/* binding */ validateContextObject), /* harmony export */ "validateIndexedDBOpenable": () => (/* binding */ validateIndexedDBOpenable), /* harmony export */ "validateNamespace": () => (/* binding */ validateNamespace) /* harmony export */ }); /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Firebase constants. Some of these (@defines) can be overridden at compile-time. */ const CONSTANTS = { /** * @define {boolean} Whether this is the client Node.js SDK. */ NODE_CLIENT: false, /** * @define {boolean} Whether this is the Admin Node.js SDK. */ NODE_ADMIN: false, /** * Firebase SDK Version */ SDK_VERSION: '${JSCORE_VERSION}' }; /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Throws an error if the provided assertion is falsy */ const assert = function (assertion, message) { if (!assertion) { throw assertionError(message); } }; /** * Returns an Error object suitable for throwing. */ const assertionError = function (message) { return new Error('Firebase Database (' + CONSTANTS.SDK_VERSION + ') INTERNAL ASSERT FAILED: ' + message); }; /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const stringToByteArray$1 = function (str) { // TODO(user): Use native implementations if/when available const out = []; let p = 0; for (let i = 0; i < str.length; i++) { let c = str.charCodeAt(i); if (c < 128) { out[p++] = c; } else if (c < 2048) { out[p++] = (c >> 6) | 192; out[p++] = (c & 63) | 128; } else if ((c & 0xfc00) === 0xd800 && i + 1 < str.length && (str.charCodeAt(i + 1) & 0xfc00) === 0xdc00) { // Surrogate Pair c = 0x10000 + ((c & 0x03ff) << 10) + (str.charCodeAt(++i) & 0x03ff); out[p++] = (c >> 18) | 240; out[p++] = ((c >> 12) & 63) | 128; out[p++] = ((c >> 6) & 63) | 128; out[p++] = (c & 63) | 128; } else { out[p++] = (c >> 12) | 224; out[p++] = ((c >> 6) & 63) | 128; out[p++] = (c & 63) | 128; } } return out; }; /** * Turns an array of numbers into the string given by the concatenation of the * characters to which the numbers correspond. * @param bytes Array of numbers representing characters. * @return Stringification of the array. */ const byteArrayToString = function (bytes) { // TODO(user): Use native implementations if/when available const out = []; let pos = 0, c = 0; while (pos < bytes.length) { const c1 = bytes[pos++]; if (c1 < 128) { out[c++] = String.fromCharCode(c1); } else if (c1 > 191 && c1 < 224) { const c2 = bytes[pos++]; out[c++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63)); } else if (c1 > 239 && c1 < 365) { // Surrogate Pair const c2 = bytes[pos++]; const c3 = bytes[pos++]; const c4 = bytes[pos++]; const u = (((c1 & 7) << 18) | ((c2 & 63) << 12) | ((c3 & 63) << 6) | (c4 & 63)) - 0x10000; out[c++] = String.fromCharCode(0xd800 + (u >> 10)); out[c++] = String.fromCharCode(0xdc00 + (u & 1023)); } else { const c2 = bytes[pos++]; const c3 = bytes[pos++]; out[c++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); } } return out.join(''); }; // We define it as an object literal instead of a class because a class compiled down to es5 can't // be treeshaked. https://github.com/rollup/rollup/issues/1691 // Static lookup maps, lazily populated by init_() const base64 = { /** * Maps bytes to characters. */ byteToCharMap_: null, /** * Maps characters to bytes. */ charToByteMap_: null, /** * Maps bytes to websafe characters. * @private */ byteToCharMapWebSafe_: null, /** * Maps websafe characters to bytes. * @private */ charToByteMapWebSafe_: null, /** * Our default alphabet, shared between * ENCODED_VALS and ENCODED_VALS_WEBSAFE */ ENCODED_VALS_BASE: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 'abcdefghijklmnopqrstuvwxyz' + '0123456789', /** * Our default alphabet. Value 64 (=) is special; it means "nothing." */ get ENCODED_VALS() { return this.ENCODED_VALS_BASE + '+/='; }, /** * Our websafe alphabet. */ get ENCODED_VALS_WEBSAFE() { return this.ENCODED_VALS_BASE + '-_.'; }, /** * Whether this browser supports the atob and btoa functions. This extension * started at Mozilla but is now implemented by many browsers. We use the * ASSUME_* variables to avoid pulling in the full useragent detection library * but still allowing the standard per-browser compilations. * */ HAS_NATIVE_SUPPORT: typeof atob === 'function', /** * Base64-encode an array of bytes. * * @param input An array of bytes (numbers with * value in [0, 255]) to encode. * @param webSafe Boolean indicating we should use the * alternative alphabet. * @return The base64 encoded string. */ encodeByteArray(input, webSafe) { if (!Array.isArray(input)) { throw Error('encodeByteArray takes an array as a parameter'); } this.init_(); const byteToCharMap = webSafe ? this.byteToCharMapWebSafe_ : this.byteToCharMap_; const output = []; for (let i = 0; i < input.length; i += 3) { const byte1 = input[i]; const haveByte2 = i + 1 < input.length; const byte2 = haveByte2 ? input[i + 1] : 0; const haveByte3 = i + 2 < input.length; const byte3 = haveByte3 ? input[i + 2] : 0; const outByte1 = byte1 >> 2; const outByte2 = ((byte1 & 0x03) << 4) | (byte2 >> 4); let outByte3 = ((byte2 & 0x0f) << 2) | (byte3 >> 6); let outByte4 = byte3 & 0x3f; if (!haveByte3) { outByte4 = 64; if (!haveByte2) { outByte3 = 64; } } output.push(byteToCharMap[outByte1], byteToCharMap[outByte2], byteToCharMap[outByte3], byteToCharMap[outByte4]); } return output.join(''); }, /** * Base64-encode a string. * * @param input A string to encode. * @param webSafe If true, we should use the * alternative alphabet. * @return The base64 encoded string. */ encodeString(input, webSafe) { // Shortcut for Mozilla browsers that implement // a native base64 encoder in the form of "btoa/atob" if (this.HAS_NATIVE_SUPPORT && !webSafe) { return btoa(input); } return this.encodeByteArray(stringToByteArray$1(input), webSafe); }, /** * Base64-decode a string. * * @param input to decode. * @param webSafe True if we should use the * alternative alphabet. * @return string representing the decoded value. */ decodeString(input, webSafe) { // Shortcut for Mozilla browsers that implement // a native base64 encoder in the form of "btoa/atob" if (this.HAS_NATIVE_SUPPORT && !webSafe) { return atob(input); } return byteArrayToString(this.decodeStringToByteArray(input, webSafe)); }, /** * Base64-decode a string. * * In base-64 decoding, groups of four characters are converted into three * bytes. If the encoder did not apply padding, the input length may not * be a multiple of 4. * * In this case, the last group will have fewer than 4 characters, and * padding will be inferred. If the group has one or two characters, it decodes * to one byte. If the group has three characters, it decodes to two bytes. * * @param input Input to decode. * @param webSafe True if we should use the web-safe alphabet. * @return bytes representing the decoded value. */ decodeStringToByteArray(input, webSafe) { this.init_(); const charToByteMap = webSafe ? this.charToByteMapWebSafe_ : this.charToByteMap_; const output = []; for (let i = 0; i < input.length;) { const byte1 = charToByteMap[input.charAt(i++)]; const haveByte2 = i < input.length; const byte2 = haveByte2 ? charToByteMap[input.charAt(i)] : 0; ++i; const haveByte3 = i < input.length; const byte3 = haveByte3 ? charToByteMap[input.charAt(i)] : 64; ++i; const haveByte4 = i < input.length; const byte4 = haveByte4 ? charToByteMap[input.charAt(i)] : 64; ++i; if (byte1 == null || byte2 == null || byte3 == null || byte4 == null) { throw Error(); } const outByte1 = (byte1 << 2) | (byte2 >> 4); output.push(outByte1); if (byte3 !== 64) { const outByte2 = ((byte2 << 4) & 0xf0) | (byte3 >> 2); output.push(outByte2); if (byte4 !== 64) { const outByte3 = ((byte3 << 6) & 0xc0) | byte4; output.push(outByte3); } } } return output; }, /** * Lazy static initialization function. Called before * accessing any of the static map variables. * @private */ init_() { if (!this.byteToCharMap_) { this.byteToCharMap_ = {}; this.charToByteMap_ = {}; this.byteToCharMapWebSafe_ = {}; this.charToByteMapWebSafe_ = {}; // We want quick mappings back and forth, so we precompute two maps. for (let i = 0; i < this.ENCODED_VALS.length; i++) { this.byteToCharMap_[i] = this.ENCODED_VALS.charAt(i); this.charToByteMap_[this.byteToCharMap_[i]] = i; this.byteToCharMapWebSafe_[i] = this.ENCODED_VALS_WEBSAFE.charAt(i); this.charToByteMapWebSafe_[this.byteToCharMapWebSafe_[i]] = i; // Be forgiving when decoding and correctly decode both encodings. if (i >= this.ENCODED_VALS_BASE.length) { this.charToByteMap_[this.ENCODED_VALS_WEBSAFE.charAt(i)] = i; this.charToByteMapWebSafe_[this.ENCODED_VALS.charAt(i)] = i; } } } } }; /** * URL-safe base64 encoding */ const base64Encode = function (str) { const utf8Bytes = stringToByteArray$1(str); return base64.encodeByteArray(utf8Bytes, true); }; /** * URL-safe base64 encoding (without "." padding in the end). * e.g. Used in JSON Web Token (JWT) parts. */ const base64urlEncodeWithoutPadding = function (str) { // Use base64url encoding and remove padding in the end (dot characters). return base64Encode(str).replace(/\./g, ''); }; /** * URL-safe base64 decoding * * NOTE: DO NOT use the global atob() function - it does NOT support the * base64Url variant encoding. * * @param str To be decoded * @return Decoded result, if possible */ const base64Decode = function (str) { try { return base64.decodeString(str, true); } catch (e) { console.error('base64Decode failed: ', e); } return null; }; /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Do a deep-copy of basic JavaScript Objects or Arrays. */ function deepCopy(value) { return deepExtend(undefined, value); } /** * Copy properties from source to target (recursively allows extension * of Objects and Arrays). Scalar values in the target are over-written. * If target is undefined, an object of the appropriate type will be created * (and returned). * * We recursively copy all child properties of plain Objects in the source- so * that namespace- like dictionaries are merged. * * Note that the target can be a function, in which case the properties in * the source Object are copied onto it as static properties of the Function. * * Note: we don't merge __proto__ to prevent prototype pollution */ function deepExtend(target, source) { if (!(source instanceof Object)) { return source; } switch (source.constructor) { case Date: // Treat Dates like scalars; if the target date object had any child // properties - they will be lost! const dateValue = source; return new Date(dateValue.getTime()); case Object: if (target === undefined) { target = {}; } break; case Array: // Always copy the array source and overwrite the target. target = []; break; default: // Not a plain Object - treat it as a scalar. return source; } for (const prop in source) { // use isValidKey to guard against prototype pollution. See https://snyk.io/vuln/SNYK-JS-LODASH-450202 if (!source.hasOwnProperty(prop) || !isValidKey(prop)) { continue; } target[prop] = deepExtend(target[prop], source[prop]); } return target; } function isValidKey(key) { return key !== '__proto__'; } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class Deferred { constructor() { this.reject = () => { }; this.resolve = () => { }; this.promise = new Promise((resolve, reject) => { this.resolve = resolve; this.reject = reject; }); } /** * Our API internals are not promiseified and cannot because our callback APIs have subtle expectations around * invoking promises inline, which Promises are forbidden to do. This method accepts an optional node-style callback * and returns a node-style callback which will resolve or reject the Deferred's promise. */ wrapCallback(callback) { return (error, value) => { if (error) { this.reject(error); } else { this.resolve(value); } if (typeof callback === 'function') { // Attaching noop handler just in case developer wasn't expecting // promises this.promise.catch(() => { }); // Some of our callbacks don't expect a value and our own tests // assert that the parameter length is 1 if (callback.length === 1) { callback(error); } else { callback(error, value); } } }; } } /** * @license * Copyright 2021 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function createMockUserToken(token, projectId) { if (token.uid) { throw new Error('The "uid" field is no longer supported by mockUserToken. Please use "sub" instead for Firebase Auth User ID.'); } // Unsecured JWTs use "none" as the algorithm. const header = { alg: 'none', type: 'JWT' }; const project = projectId || 'demo-project'; const iat = token.iat || 0; const sub = token.sub || token.user_id; if (!sub) { throw new Error("mockUserToken must contain 'sub' or 'user_id' field!"); } const payload = Object.assign({ // Set all required fields to decent defaults iss: `https://securetoken.google.com/${project}`, aud: project, iat, exp: iat + 3600, auth_time: iat, sub, user_id: sub, firebase: { sign_in_provider: 'custom', identities: {} } }, token); // Unsecured JWTs use the empty string as a signature. const signature = ''; return [ base64urlEncodeWithoutPadding(JSON.stringify(header)), base64urlEncodeWithoutPadding(JSON.stringify(payload)), signature ].join('.'); } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Returns navigator.userAgent string or '' if it's not defined. * @return user agent string */ function getUA() { if (typeof navigator !== 'undefined' && typeof navigator['userAgent'] === 'string') { return navigator['userAgent']; } else { return ''; } } /** * Detect Cordova / PhoneGap / Ionic frameworks on a mobile device. * * Deliberately does not rely on checking `file://` URLs (as this fails PhoneGap * in the Ripple emulator) nor Cordova `onDeviceReady`, which would normally * wait for a callback. */ function isMobileCordova() { return (typeof window !== 'undefined' && // @ts-ignore Setting up an broadly applicable index signature for Window // just to deal with this case would probably be a bad idea. !!(window['cordova'] || window['phonegap'] || window['PhoneGap']) && /ios|iphone|ipod|ipad|android|blackberry|iemobile/i.test(getUA())); } /** * Detect Node.js. * * @return true if Node.js environment is detected. */ // Node detection logic from: https://github.com/iliakan/detect-node/ function isNode() { try { return (Object.prototype.toString.call(__webpack_require__.g.process) === '[object process]'); } catch (e) { return false; } } /** * Detect Browser Environment */ function isBrowser() { return typeof self === 'object' && self.self === self; } function isBrowserExtension() { const runtime = typeof chrome === 'object' ? chrome.runtime : typeof browser === 'object' ? browser.runtime : undefined; return typeof runtime === 'object' && runtime.id !== undefined; } /** * Detect React Native. * * @return true if ReactNative environment is detected. */ function isReactNative() { return (typeof navigator === 'object' && navigator['product'] === 'ReactNative'); } /** Detects Electron apps. */ function isElectron() { return getUA().indexOf('Electron/') >= 0; } /** Detects Internet Explorer. */ function isIE() { const ua = getUA(); return ua.indexOf('MSIE ') >= 0 || ua.indexOf('Trident/') >= 0; } /** Detects Universal Windows Platform apps. */ function isUWP() { return getUA().indexOf('MSAppHost/') >= 0; } /** * Detect whether the current SDK build is the Node version. * * @return true if it's the Node SDK build. */ function isNodeSdk() { return CONSTANTS.NODE_CLIENT === true || CONSTANTS.NODE_ADMIN === true; } /** Returns true if we are running in Safari. */ function isSafari() { return (!isNode() && navigator.userAgent.includes('Safari') && !navigator.userAgent.includes('Chrome')); } /** * This method checks if indexedDB is supported by current browser/service worker context * @return true if indexedDB is supported by current browser/service worker context */ function isIndexedDBAvailable() { return typeof indexedDB === 'object'; } /** * This method validates browser/sw context for indexedDB by opening a dummy indexedDB database and reject * if errors occur during the database open operation. * * @throws exception if current browser/sw context can't run idb.open (ex: Safari iframe, Firefox * private browsing) */ function validateIndexedDBOpenable() { return new Promise((resolve, reject) => { try { let preExist = true; const DB_CHECK_NAME = 'validate-browser-context-for-indexeddb-analytics-module'; const request = self.indexedDB.open(DB_CHECK_NAME); request.onsuccess = () => { request.result.close(); // delete database only when it doesn't pre-exist if (!preExist) { self.indexedDB.deleteDatabase(DB_CHECK_NAME); } resolve(true); }; request.onupgradeneeded = () => { preExist = false; }; request.onerror = () => { var _a; reject(((_a = request.error) === null || _a === void 0 ? void 0 : _a.message) || ''); }; } catch (error) { reject(error); } }); } /** * * This method checks whether cookie is enabled within current browser * @return true if cookie is enabled within current browser */ function areCookiesEnabled() { if (typeof navigator === 'undefined' || !navigator.cookieEnabled) { return false; } return true; } /** * Polyfill for `globalThis` object. * @returns the `globalThis` object for the given environment. */ function getGlobal() { if (typeof self !== 'undefined') { return self; } if (typeof window !== 'undefined') { return window; } if (typeof __webpack_require__.g !== 'undefined') { return __webpack_require__.g; } throw new Error('Unable to locate global object.'); } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Standardized Firebase Error. * * Usage: * * // Typescript string literals for type-safe codes * type Err = * 'unknown' | * 'object-not-found' * ; * * // Closure enum for type-safe error codes * // at-enum {string} * var Err = { * UNKNOWN: 'unknown', * OBJECT_NOT_FOUND: 'object-not-found', * } * * let errors: Map = { * 'generic-error': "Unknown error", * 'file-not-found': "Could not find file: {$file}", * }; * * // Type-safe function - must pass a valid error code as param. * let error = new ErrorFactory('service', 'Service', errors); * * ... * throw error.create(Err.GENERIC); * ... * throw error.create(Err.FILE_NOT_FOUND, {'file': fileName}); * ... * // Service: Could not file file: foo.txt (service/file-not-found). * * catch (e) { * assert(e.message === "Could not find file: foo.txt."); * if (e.code === 'service/file-not-found') { * console.log("Could not read file: " + e['file']); * } * } */ const ERROR_NAME = 'FirebaseError'; // Based on code from: // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Custom_Error_Types class FirebaseError extends Error { constructor( /** The error code for this error. */ code, message, /** Custom data for this error. */ customData) { super(message); this.code = code; this.customData = customData; /** The custom name for all FirebaseErrors. */ this.name = ERROR_NAME; // Fix For ES5 // https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work Object.setPrototypeOf(this, FirebaseError.prototype); // Maintains proper stack trace for where our error was thrown. // Only available on V8. if (Error.captureStackTrace) { Error.captureStackTrace(this, ErrorFactory.prototype.create); } } } class ErrorFactory { constructor(service, serviceName, errors) { this.service = service; this.serviceName = serviceName; this.errors = errors; } create(code, ...data) { const customData = data[0] || {}; const fullCode = `${this.service}/${code}`; const template = this.errors[code]; const message = template ? replaceTemplate(template, customData) : 'Error'; // Service Name: Error message (service/code). const fullMessage = `${this.serviceName}: ${message} (${fullCode}).`; const error = new FirebaseError(fullCode, fullMessage, customData); return error; } } function replaceTemplate(template, data) { return template.replace(PATTERN, (_, key) => { const value = data[key]; return value != null ? String(value) : `<${key}?>`; }); } const PATTERN = /\{\$([^}]+)}/g; /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Evaluates a JSON string into a javascript object. * * @param {string} str A string containing JSON. * @return {*} The javascript object representing the specified JSON. */ function jsonEval(str) { return JSON.parse(str); } /** * Returns JSON representing a javascript object. * @param {*} data Javascript object to be stringified. * @return {string} The JSON contents of the object. */ function stringify(data) { return JSON.stringify(data); } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Decodes a Firebase auth. token into constituent parts. * * Notes: * - May return with invalid / incomplete claims if there's no native base64 decoding support. * - Doesn't check if the token is actually valid. */ const decode = function (token) { let header = {}, claims = {}, data = {}, signature = ''; try { const parts = token.split('.'); header = jsonEval(base64Decode(parts[0]) || ''); claims = jsonEval(base64Decode(parts[1]) || ''); signature = parts[2]; data = claims['d'] || {}; delete claims['d']; } catch (e) { } return { header, claims, data, signature }; }; /** * Decodes a Firebase auth. token and checks the validity of its time-based claims. Will return true if the * token is within the time window authorized by the 'nbf' (not-before) and 'iat' (issued-at) claims. * * Notes: * - May return a false negative if there's no native base64 decoding support. * - Doesn't check if the token is actually valid. */ const isValidTimestamp = function (token) { const claims = decode(token).claims; const now = Math.floor(new Date().getTime() / 1000); let validSince = 0, validUntil = 0; if (typeof claims === 'object') { if (claims.hasOwnProperty('nbf')) { validSince = claims['nbf']; } else if (claims.hasOwnProperty('iat')) { validSince = claims['iat']; } if (claims.hasOwnProperty('exp')) { validUntil = claims['exp']; } else { // token will expire after 24h by default validUntil = validSince + 86400; } } return (!!now && !!validSince && !!validUntil && now >= validSince && now <= validUntil); }; /** * Decodes a Firebase auth. token and returns its issued at time if valid, null otherwise. * * Notes: * - May return null if there's no native base64 decoding support. * - Doesn't check if the token is actually valid. */ const issuedAtTime = function (token) { const claims = decode(token).claims; if (typeof claims === 'object' && claims.hasOwnProperty('iat')) { return claims['iat']; } return null; }; /** * Decodes a Firebase auth. token and checks the validity of its format. Expects a valid issued-at time. * * Notes: * - May return a false negative if there's no native base64 decoding support. * - Doesn't check if the token is actually valid. */ const isValidFormat = function (token) { const decoded = decode(token), claims = decoded.claims; return !!claims && typeof claims === 'object' && claims.hasOwnProperty('iat'); }; /** * Attempts to peer into an auth token and determine if it's an admin auth token by looking at the claims portion. * * Notes: * - May return a false negative if there's no native base64 decoding support. * - Doesn't check if the token is actually valid. */ const isAdmin = function (token) { const claims = decode(token).claims; return typeof claims === 'object' && claims['admin'] === true; }; /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function contains(obj, key) { return Object.prototype.hasOwnProperty.call(obj, key); } function safeGet(obj, key) { if (Object.prototype.hasOwnProperty.call(obj, key)) { return obj[key]; } else { return undefined; } } function isEmpty(obj) { for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { return false; } } return true; } function map(obj, fn, contextObj) { const res = {}; for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { res[key] = fn.call(contextObj, obj[key], key, obj); } } return res; } /** * Deep equal two objects. Support Arrays and Objects. */ function deepEqual(a, b) { if (a === b) { return true; } const aKeys = Object.keys(a); const bKeys = Object.keys(b); for (const k of aKeys) { if (!bKeys.includes(k)) { return false; } const aProp = a[k]; const bProp = b[k]; if (isObject(aProp) && isObject(bProp)) { if (!deepEqual(aProp, bProp)) { return false; } } else if (aProp !== bProp) { return false; } } for (const k of bKeys) { if (!aKeys.includes(k)) { return false; } } return true; } function isObject(thing) { return thing !== null && typeof thing === 'object'; } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Returns a querystring-formatted string (e.g. &arg=val&arg2=val2) from a * params object (e.g. {arg: 'val', arg2: 'val2'}) * Note: You must prepend it with ? when adding it to a URL. */ function querystring(querystringParams) { const params = []; for (const [key, value] of Object.entries(querystringParams)) { if (Array.isArray(value)) { value.forEach(arrayVal => { params.push(encodeURIComponent(key) + '=' + encodeURIComponent(arrayVal)); }); } else { params.push(encodeURIComponent(key) + '=' + encodeURIComponent(value)); } } return params.length ? '&' + params.join('&') : ''; } /** * Decodes a querystring (e.g. ?arg=val&arg2=val2) into a params object * (e.g. {arg: 'val', arg2: 'val2'}) */ function querystringDecode(querystring) { const obj = {}; const tokens = querystring.replace(/^\?/, '').split('&'); tokens.forEach(token => { if (token) { const [key, value] = token.split('='); obj[decodeURIComponent(key)] = decodeURIComponent(value); } }); return obj; } /** * Extract the query string part of a URL, including the leading question mark (if present). */ function extractQuerystring(url) { const queryStart = url.indexOf('?'); if (!queryStart) { return ''; } const fragmentStart = url.indexOf('#', queryStart); return url.substring(queryStart, fragmentStart > 0 ? fragmentStart : undefined); } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview SHA-1 cryptographic hash. * Variable names follow the notation in FIPS PUB 180-3: * http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf. * * Usage: * var sha1 = new sha1(); * sha1.update(bytes); * var hash = sha1.digest(); * * Performance: * Chrome 23: ~400 Mbit/s * Firefox 16: ~250 Mbit/s * */ /** * SHA-1 cryptographic hash constructor. * * The properties declared here are discussed in the above algorithm document. * @constructor * @final * @struct */ class Sha1 { constructor() { /** * Holds the previous values of accumulated variables a-e in the compress_ * function. * @private */ this.chain_ = []; /** * A buffer holding the partially computed hash result. * @private */ this.buf_ = []; /** * An array of 80 bytes, each a part of the message to be hashed. Referred to * as the message schedule in the docs. * @private */ this.W_ = []; /** * Contains data needed to pad messages less than 64 bytes. * @private */ this.pad_ = []; /** * @private {number} */ this.inbuf_ = 0; /** * @private {number} */ this.total_ = 0; this.blockSize = 512 / 8; this.pad_[0] = 128; for (let i = 1; i < this.blockSize; ++i) { this.pad_[i] = 0; } this.reset(); } reset() { this.chain_[0] = 0x67452301; this.chain_[1] = 0xefcdab89; this.chain_[2] = 0x98badcfe; this.chain_[3] = 0x10325476; this.chain_[4] = 0xc3d2e1f0; this.inbuf_ = 0; this.total_ = 0; } /** * Internal compress helper function. * @param buf Block to compress. * @param offset Offset of the block in the buffer. * @private */ compress_(buf, offset) { if (!offset) { offset = 0; } const W = this.W_; // get 16 big endian words if (typeof buf === 'string') { for (let i = 0; i < 16; i++) { // TODO(user): [bug 8140122] Recent versions of Safari for Mac OS and iOS // have a bug that turns the post-increment ++ operator into pre-increment // during JIT compilation. We have code that depends heavily on SHA-1 for // correctness and which is affected by this bug, so I've removed all uses // of post-increment ++ in which the result value is used. We can revert // this change once the Safari bug // (https://bugs.webkit.org/show_bug.cgi?id=109036) has been fixed and // most clients have been updated. W[i] = (buf.charCodeAt(offset) << 24) | (buf.charCodeAt(offset + 1) << 16) | (buf.charCodeAt(offset + 2) << 8) | buf.charCodeAt(offset + 3); offset += 4; } } else { for (let i = 0; i < 16; i++) { W[i] = (buf[offset] << 24) | (buf[offset + 1] << 16) | (buf[offset + 2] << 8) | buf[offset + 3]; offset += 4; } } // expand to 80 words for (let i = 16; i < 80; i++) { const t = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]; W[i] = ((t << 1) | (t >>> 31)) & 0xffffffff; } let a = this.chain_[0]; let b = this.chain_[1]; let c = this.chain_[2]; let d = this.chain_[3]; let e = this.chain_[4]; let f, k; // TODO(user): Try to unroll this loop to speed up the computation. for (let i = 0; i < 80; i++) { if (i < 40) { if (i < 20) { f = d ^ (b & (c ^ d)); k = 0x5a827999; } else { f = b ^ c ^ d; k = 0x6ed9eba1; } } else { if (i < 60) { f = (b & c) | (d & (b | c)); k = 0x8f1bbcdc; } else { f = b ^ c ^ d; k = 0xca62c1d6; } } const t = (((a << 5) | (a >>> 27)) + f + e + k + W[i]) & 0xffffffff; e = d; d = c; c = ((b << 30) | (b >>> 2)) & 0xffffffff; b = a; a = t; } this.chain_[0] = (this.chain_[0] + a) & 0xffffffff; this.chain_[1] = (this.chain_[1] + b) & 0xffffffff; this.chain_[2] = (this.chain_[2] + c) & 0xffffffff; this.chain_[3] = (this.chain_[3] + d) & 0xffffffff; this.chain_[4] = (this.chain_[4] + e) & 0xffffffff; } update(bytes, length) { // TODO(johnlenz): tighten the function signature and remove this check if (bytes == null) { return; } if (length === undefined) { length = bytes.length; } const lengthMinusBlock = length - this.blockSize; let n = 0; // Using local instead of member variables gives ~5% speedup on Firefox 16. const buf = this.buf_; let inbuf = this.inbuf_; // The outer while loop should execute at most twice. while (n < length) { // When we have no data in the block to top up, we can directly process the // input buffer (assuming it contains sufficient data). This gives ~25% // speedup on Chrome 23 and ~15% speedup on Firefox 16, but requires that // the data is provided in large chunks (or in multiples of 64 bytes). if (inbuf === 0) { while (n <= lengthMinusBlock) { this.compress_(bytes, n); n += this.blockSize; } } if (typeof bytes === 'string') { while (n < length) { buf[inbuf] = bytes.charCodeAt(n); ++inbuf; ++n; if (inbuf === this.blockSize) { this.compress_(buf); inbuf = 0; // Jump to the outer loop so we use the full-block optimization. break; } } } else { while (n < length) { buf[inbuf] = bytes[n]; ++inbuf; ++n; if (inbuf === this.blockSize) { this.compress_(buf); inbuf = 0; // Jump to the outer loop so we use the full-block optimization. break; } } } } this.inbuf_ = inbuf; this.total_ += length; } /** @override */ digest() { const digest = []; let totalBits = this.total_ * 8; // Add pad 0x80 0x00*. if (this.inbuf_ < 56) { this.update(this.pad_, 56 - this.inbuf_); } else { this.update(this.pad_, this.blockSize - (this.inbuf_ - 56)); } // Add # bits. for (let i = this.blockSize - 1; i >= 56; i--) { this.buf_[i] = totalBits & 255; totalBits /= 256; // Don't use bit-shifting here! } this.compress_(this.buf_); let n = 0; for (let i = 0; i < 5; i++) { for (let j = 24; j >= 0; j -= 8) { digest[n] = (this.chain_[i] >> j) & 255; ++n; } } return digest; } } /** * Helper to make a Subscribe function (just like Promise helps make a * Thenable). * * @param executor Function which can make calls to a single Observer * as a proxy. * @param onNoObservers Callback when count of Observers goes to zero. */ function createSubscribe(executor, onNoObservers) { const proxy = new ObserverProxy(executor, onNoObservers); return proxy.subscribe.bind(proxy); } /** * Implement fan-out for any number of Observers attached via a subscribe * function. */ class ObserverProxy { /** * @param executor Function which can make calls to a single Observer * as a proxy. * @param onNoObservers Callback when count of Observers goes to zero. */ constructor(executor, onNoObservers) { this.observers = []; this.unsubscribes = []; this.observerCount = 0; // Micro-task scheduling by calling task.then(). this.task = Promise.resolve(); this.finalized = false; this.onNoObservers = onNoObservers; // Call the executor asynchronously so subscribers that are called // synchronously after the creation of the subscribe function // can still receive the very first value generated in the executor. this.task .then(() => { executor(this); }) .catch(e => { this.error(e); }); } next(value) { this.forEachObserver((observer) => { observer.next(value); }); } error(error) { this.forEachObserver((observer) => { observer.error(error); }); this.close(error); } complete() { this.forEachObserver((observer) => { observer.complete(); }); this.close(); } /** * Subscribe function that can be used to add an Observer to the fan-out list. * * - We require that no event is sent to a subscriber sychronously to their * call to subscribe(). */ subscribe(nextOrObserver, error, complete) { let observer; if (nextOrObserver === undefined && error === undefined && complete === undefined) { throw new Error('Missing Observer.'); } // Assemble an Observer object when passed as callback functions. if (implementsAnyMethods(nextOrObserver, [ 'next', 'error', 'complete' ])) { observer = nextOrObserver; } else { observer = { next: nextOrObserver, error, complete }; } if (observer.next === undefined) { observer.next = noop; } if (observer.error === undefined) { observer.error = noop; } if (observer.complete === undefined) { observer.complete = noop; } const unsub = this.unsubscribeOne.bind(this, this.observers.length); // Attempt to subscribe to a terminated Observable - we // just respond to the Observer with the final error or complete // event. if (this.finalized) { // eslint-disable-next-line @typescript-eslint/no-floating-promises this.task.then(() => { try { if (this.finalError) { observer.error(this.finalError); } else { observer.complete(); } } catch (e) { // nothing } return; }); } this.observers.push(observer); return unsub; } // Unsubscribe is synchronous - we guarantee that no events are sent to // any unsubscribed Observer. unsubscribeOne(i) { if (this.observers === undefined || this.observers[i] === undefined) { return; } delete this.observers[i]; this.observerCount -= 1; if (this.observerCount === 0 && this.onNoObservers !== undefined) { this.onNoObservers(this); } } forEachObserver(fn) { if (this.finalized) { // Already closed by previous event....just eat the additional values. return; } // Since sendOne calls asynchronously - there is no chance that // this.observers will become undefined. for (let i = 0; i < this.observers.length; i++) { this.sendOne(i, fn); } } // Call the Observer via one of it's callback function. We are careful to // confirm that the observe has not been unsubscribed since this asynchronous // function had been queued. sendOne(i, fn) { // Execute the callback asynchronously // eslint-disable-next-line @typescript-eslint/no-floating-promises this.task.then(() => { if (this.observers !== undefined && this.observers[i] !== undefined) { try { fn(this.observers[i]); } catch (e) { // Ignore exceptions raised in Observers or missing methods of an // Observer. // Log error to console. b/31404806 if (typeof console !== 'undefined' && console.error) { console.error(e); } } } }); } close(err) { if (this.finalized) { return; } this.finalized = true; if (err !== undefined) { this.finalError = err; } // Proxy is no longer needed - garbage collect references // eslint-disable-next-line @typescript-eslint/no-floating-promises this.task.then(() => { this.observers = undefined; this.onNoObservers = undefined; }); } } /** Turn synchronous function into one called asynchronously. */ // eslint-disable-next-line @typescript-eslint/ban-types function async(fn, onError) { return (...args) => { Promise.resolve(true) .then(() => { fn(...args); }) .catch((error) => { if (onError) { onError(error); } }); }; } /** * Return true if the object passed in implements any of the named methods. */ function implementsAnyMethods(obj, methods) { if (typeof obj !== 'object' || obj === null) { return false; } for (const method of methods) { if (method in obj && typeof obj[method] === 'function') { return true; } } return false; } function noop() { // do nothing } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Check to make sure the appropriate number of arguments are provided for a public function. * Throws an error if it fails. * * @param fnName The function name * @param minCount The minimum number of arguments to allow for the function call * @param maxCount The maximum number of argument to allow for the function call * @param argCount The actual number of arguments provided. */ const validateArgCount = function (fnName, minCount, maxCount, argCount) { let argError; if (argCount < minCount) { argError = 'at least ' + minCount; } else if (argCount > maxCount) { argError = maxCount === 0 ? 'none' : 'no more than ' + maxCount; } if (argError) { const error = fnName + ' failed: Was called with ' + argCount + (argCount === 1 ? ' argument.' : ' arguments.') + ' Expects ' + argError + '.'; throw new Error(error); } }; /** * Generates a string to prefix an error message about failed argument validation * * @param fnName The function name * @param argName The name of the argument * @return The prefix to add to the error thrown for validation. */ function errorPrefix(fnName, argName) { return `${fnName} failed: ${argName} argument `; } /** * @param fnName * @param argumentNumber * @param namespace * @param optional */ function validateNamespace(fnName, namespace, optional) { if (optional && !namespace) { return; } if (typeof namespace !== 'string') { //TODO: I should do more validation here. We only allow certain chars in namespaces. throw new Error(errorPrefix(fnName, 'namespace') + 'must be a valid firebase namespace.'); } } function validateCallback(fnName, argumentName, // eslint-disable-next-line @typescript-eslint/ban-types callback, optional) { if (optional && !callback) { return; } if (typeof callback !== 'function') { throw new Error(errorPrefix(fnName, argumentName) + 'must be a valid function.'); } } function validateContextObject(fnName, argumentName, context, optional) { if (optional && !context) { return; } if (typeof context !== 'object' || context === null) { throw new Error(errorPrefix(fnName, argumentName) + 'must be a valid context object.'); } } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Code originally came from goog.crypt.stringToUtf8ByteArray, but for some reason they // automatically replaced '\r\n' with '\n', and they didn't handle surrogate pairs, // so it's been modified. // Note that not all Unicode characters appear as single characters in JavaScript strings. // fromCharCode returns the UTF-16 encoding of a character - so some Unicode characters // use 2 characters in Javascript. All 4-byte UTF-8 characters begin with a first // character in the range 0xD800 - 0xDBFF (the first character of a so-called surrogate // pair). // See http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.3 /** * @param {string} str * @return {Array} */ const stringToByteArray = function (str) { const out = []; let p = 0; for (let i = 0; i < str.length; i++) { let c = str.charCodeAt(i); // Is this the lead surrogate in a surrogate pair? if (c >= 0xd800 && c <= 0xdbff) { const high = c - 0xd800; // the high 10 bits. i++; assert(i < str.length, 'Surrogate pair missing trail surrogate.'); const low = str.charCodeAt(i) - 0xdc00; // the low 10 bits. c = 0x10000 + (high << 10) + low; } if (c < 128) { out[p++] = c; } else if (c < 2048) { out[p++] = (c >> 6) | 192; out[p++] = (c & 63) | 128; } else if (c < 65536) { out[p++] = (c >> 12) | 224; out[p++] = ((c >> 6) & 63) | 128; out[p++] = (c & 63) | 128; } else { out[p++] = (c >> 18) | 240; out[p++] = ((c >> 12) & 63) | 128; out[p++] = ((c >> 6) & 63) | 128; out[p++] = (c & 63) | 128; } } return out; }; /** * Calculate length without actually converting; useful for doing cheaper validation. * @param {string} str * @return {number} */ const stringLength = function (str) { let p = 0; for (let i = 0; i < str.length; i++) { const c = str.charCodeAt(i); if (c < 128) { p++; } else if (c < 2048) { p += 2; } else if (c >= 0xd800 && c <= 0xdbff) { // Lead surrogate of a surrogate pair. The pair together will take 4 bytes to represent. p += 4; i++; // skip trail surrogate. } else { p += 3; } } return p; }; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * The amount of milliseconds to exponentially increase. */ const DEFAULT_INTERVAL_MILLIS = 1000; /** * The factor to backoff by. * Should be a number greater than 1. */ const DEFAULT_BACKOFF_FACTOR = 2; /** * The maximum milliseconds to increase to. * *

Visible for testing */ const MAX_VALUE_MILLIS = 4 * 60 * 60 * 1000; // Four hours, like iOS and Android. /** * The percentage of backoff time to randomize by. * See * http://go/safe-client-behavior#step-1-determine-the-appropriate-retry-interval-to-handle-spike-traffic * for context. * *

Visible for testing */ const RANDOM_FACTOR = 0.5; /** * Based on the backoff method from * https://github.com/google/closure-library/blob/master/closure/goog/math/exponentialbackoff.js. * Extracted here so we don't need to pass metadata and a stateful ExponentialBackoff object around. */ function calculateBackoffMillis(backoffCount, intervalMillis = DEFAULT_INTERVAL_MILLIS, backoffFactor = DEFAULT_BACKOFF_FACTOR) { // Calculates an exponentially increasing value. // Deviation: calculates value from count and a constant interval, so we only need to save value // and count to restore state. const currBaseValue = intervalMillis * Math.pow(backoffFactor, backoffCount); // A random "fuzz" to avoid waves of retries. // Deviation: randomFactor is required. const randomWait = Math.round( // A fraction of the backoff value to add/subtract. // Deviation: changes multiplication order to improve readability. RANDOM_FACTOR * currBaseValue * // A random float (rounded to int by Math.round above) in the range [-1, 1]. Determines // if we add or subtract. (Math.random() - 0.5) * 2); // Limits backoff to max to avoid effectively permanent backoff. return Math.min(MAX_VALUE_MILLIS, currBaseValue + randomWait); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Provide English ordinal letters after a number */ function ordinal(i) { if (!Number.isFinite(i)) { return `${i}`; } return i + indicator(i); } function indicator(i) { i = Math.abs(i); const cent = i % 100; if (cent >= 10 && cent <= 20) { return 'th'; } const dec = i % 10; if (dec === 1) { return 'st'; } if (dec === 2) { return 'nd'; } if (dec === 3) { return 'rd'; } return 'th'; } /** * @license * Copyright 2021 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function getModularInstance(service) { if (service && service._delegate) { return service._delegate; } else { return service; } } //# sourceMappingURL=index.esm2017.js.map /***/ }), /***/ "./src/config.js": /*!***********************!*\ !*** ./src/config.js ***! \***********************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "API_KEY": () => (/* binding */ API_KEY), /* harmony export */ "APP_NAME": () => (/* binding */ APP_NAME), /* harmony export */ "AVATAR_SIZE": () => (/* binding */ AVATAR_SIZE), /* harmony export */ "BROKEN_IMAGE_SIZE": () => (/* binding */ BROKEN_IMAGE_SIZE), /* harmony export */ "CALL_WEBRTC_CONFIG": () => (/* binding */ CALL_WEBRTC_CONFIG), /* harmony export */ "CHANNEL_ACCESS_MODE": () => (/* binding */ CHANNEL_ACCESS_MODE), /* harmony export */ "DEFAULT_HOST": () => (/* binding */ DEFAULT_HOST), /* harmony export */ "DEFAULT_P2P_ACCESS_MODE": () => (/* binding */ DEFAULT_P2P_ACCESS_MODE), /* harmony export */ "FORWARDED_PREVIEW_LENGTH": () => (/* binding */ FORWARDED_PREVIEW_LENGTH), /* harmony export */ "IMAGE_PREVIEW_DIM": () => (/* binding */ IMAGE_PREVIEW_DIM), /* harmony export */ "IMAGE_THUMBNAIL_DIM": () => (/* binding */ IMAGE_THUMBNAIL_DIM), /* harmony export */ "KEYPRESS_DELAY": () => (/* binding */ KEYPRESS_DELAY), /* harmony export */ "KNOWN_HOSTS": () => (/* binding */ KNOWN_HOSTS), /* harmony export */ "LINK_CONTACT_US": () => (/* binding */ LINK_CONTACT_US), /* harmony export */ "LINK_PRIVACY_POLICY": () => (/* binding */ LINK_PRIVACY_POLICY), /* harmony export */ "LINK_TERMS_OF_SERVICE": () => (/* binding */ LINK_TERMS_OF_SERVICE), /* harmony export */ "LOGGING_ENABLED": () => (/* binding */ LOGGING_ENABLED), /* harmony export */ "MAX_AVATAR_BYTES": () => (/* binding */ MAX_AVATAR_BYTES), /* harmony export */ "MAX_DURATION": () => (/* binding */ MAX_DURATION), /* harmony export */ "MAX_EXTERN_ATTACHMENT_SIZE": () => (/* binding */ MAX_EXTERN_ATTACHMENT_SIZE), /* harmony export */ "MAX_IMAGE_DIM": () => (/* binding */ MAX_IMAGE_DIM), /* harmony export */ "MAX_INBAND_ATTACHMENT_SIZE": () => (/* binding */ MAX_INBAND_ATTACHMENT_SIZE), /* harmony export */ "MAX_ONLINE_IN_TOPIC": () => (/* binding */ MAX_ONLINE_IN_TOPIC), /* harmony export */ "MAX_PEER_TITLE_LENGTH": () => (/* binding */ MAX_PEER_TITLE_LENGTH), /* harmony export */ "MAX_TAG_COUNT": () => (/* binding */ MAX_TAG_COUNT), /* harmony export */ "MAX_TAG_LENGTH": () => (/* binding */ MAX_TAG_LENGTH), /* harmony export */ "MAX_TITLE_LENGTH": () => (/* binding */ MAX_TITLE_LENGTH), /* harmony export */ "MAX_TOPIC_DESCRIPTION_LENGTH": () => (/* binding */ MAX_TOPIC_DESCRIPTION_LENGTH), /* harmony export */ "MEDIA_BREAKPOINT": () => (/* binding */ MEDIA_BREAKPOINT), /* harmony export */ "MESSAGES_PAGE": () => (/* binding */ MESSAGES_PAGE), /* harmony export */ "MESSAGE_PREVIEW_LENGTH": () => (/* binding */ MESSAGE_PREVIEW_LENGTH), /* harmony export */ "MIN_DURATION": () => (/* binding */ MIN_DURATION), /* harmony export */ "MIN_TAG_LENGTH": () => (/* binding */ MIN_TAG_LENGTH), /* harmony export */ "NEW_GRP_ACCESS_MODE": () => (/* binding */ NEW_GRP_ACCESS_MODE), /* harmony export */ "NO_ACCESS_MODE": () => (/* binding */ NO_ACCESS_MODE), /* harmony export */ "QUOTED_REPLY_LENGTH": () => (/* binding */ QUOTED_REPLY_LENGTH), /* harmony export */ "READ_DELAY": () => (/* binding */ READ_DELAY), /* harmony export */ "RECEIVED_DELAY": () => (/* binding */ RECEIVED_DELAY), /* harmony export */ "REM_SIZE": () => (/* binding */ REM_SIZE) /* harmony export */ }); /* harmony import */ var _version_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./version.js */ "./src/version.js"); const APP_NAME = 'TinodeWeb/' + (_version_js__WEBPACK_IMPORTED_MODULE_0__.PACKAGE_VERSION || '0.17'); const API_KEY = 'AQEAAAABAAD_rAp4DJh05a1HAwFT3A6K'; const KNOWN_HOSTS = { hosted: 'web.tinode.co', local: 'localhost:6060' }; const DEFAULT_HOST = KNOWN_HOSTS.hosted; const LOGGING_ENABLED = true; const KEYPRESS_DELAY = 3000; const RECEIVED_DELAY = 500; const READ_DELAY = 1000; const MIN_TAG_LENGTH = 2; const MAX_TAG_LENGTH = 96; const MAX_TAG_COUNT = 16; const DEFAULT_P2P_ACCESS_MODE = 'JRWPS'; const NEW_GRP_ACCESS_MODE = 'JRWPSAO'; const CHANNEL_ACCESS_MODE = 'JR'; const NO_ACCESS_MODE = 'N'; const MEDIA_BREAKPOINT = 640; const REM_SIZE = 13; const AVATAR_SIZE = 384; const MAX_AVATAR_BYTES = 4096; const BROKEN_IMAGE_SIZE = 32; const MESSAGES_PAGE = 24; const MAX_INBAND_ATTACHMENT_SIZE = 262144; const MAX_EXTERN_ATTACHMENT_SIZE = 1 << 23; const MAX_IMAGE_DIM = 1024; const IMAGE_PREVIEW_DIM = 64; const IMAGE_THUMBNAIL_DIM = 36; const MAX_ONLINE_IN_TOPIC = 4; const MAX_TITLE_LENGTH = 60; const MAX_TOPIC_DESCRIPTION_LENGTH = 360; const MAX_PEER_TITLE_LENGTH = 20; const MESSAGE_PREVIEW_LENGTH = 80; const QUOTED_REPLY_LENGTH = 30; const FORWARDED_PREVIEW_LENGTH = 84; const MIN_DURATION = 2000; const MAX_DURATION = 600000; const LINK_CONTACT_US = 'mailto:support@tinode.co'; const LINK_PRIVACY_POLICY = 'https://tinode.co/privacy.html'; const LINK_TERMS_OF_SERVICE = 'https://tinode.co/terms.html'; const CALL_WEBRTC_CONFIG = { iceServers: [{ urls: ["stun:bn-turn1.xirsys.com"] }, { username: "0kYXFmQL9xojOrUy4VFemlTnNPVFZpp7jfPjpB3AjxahuRe4QWrCs6Ll1vDc7TTjAAAAAGAG2whXZWJUdXRzUGx1cw==", credential: "285ff060-5a58-11eb-b269-0242ac140004", urls: ["turn:bn-turn1.xirsys.com:80?transport=udp", "turn:bn-turn1.xirsys.com:3478?transport=udp", "turn:bn-turn1.xirsys.com:80?transport=tcp", "turn:bn-turn1.xirsys.com:3478?transport=tcp", "turns:bn-turn1.xirsys.com:443?transport=tcp", "turns:bn-turn1.xirsys.com:5349?transport=tcp"] }] }; /***/ }), /***/ "./src/constants.js": /*!**************************!*\ !*** ./src/constants.js ***! \**************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "CALL_MESSAGE_MIME_TYPE": () => (/* binding */ CALL_MESSAGE_MIME_TYPE), /* harmony export */ "CALL_STATE_INCOMING_RECEIVED": () => (/* binding */ CALL_STATE_INCOMING_RECEIVED), /* harmony export */ "CALL_STATE_IN_PROGRESS": () => (/* binding */ CALL_STATE_IN_PROGRESS), /* harmony export */ "CALL_STATE_NONE": () => (/* binding */ CALL_STATE_NONE), /* harmony export */ "CALL_STATE_OUTGOING_INITATED": () => (/* binding */ CALL_STATE_OUTGOING_INITATED) /* harmony export */ }); const CALL_STATE_NONE = 0; const CALL_STATE_OUTGOING_INITATED = 1; const CALL_STATE_INCOMING_RECEIVED = 2; const CALL_STATE_IN_PROGRESS = 3; const CALL_MESSAGE_MIME_TYPE = 'application/x-tinode-webrtc'; /***/ }), /***/ "./src/lib/blob-helpers.js": /*!*********************************!*\ !*** ./src/lib/blob-helpers.js ***! \*********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "MIME_EXTENSIONS": () => (/* binding */ MIME_EXTENSIONS), /* harmony export */ "SUPPORTED_IMAGE_FORMATS": () => (/* binding */ SUPPORTED_IMAGE_FORMATS), /* harmony export */ "base64DecodedLen": () => (/* binding */ base64DecodedLen), /* harmony export */ "base64EncodedLen": () => (/* binding */ base64EncodedLen), /* harmony export */ "base64ReEncode": () => (/* binding */ base64ReEncode), /* harmony export */ "base64ToBlob": () => (/* binding */ base64ToBlob), /* harmony export */ "base64ToIntArray": () => (/* binding */ base64ToIntArray), /* harmony export */ "blobToBase64": () => (/* binding */ blobToBase64), /* harmony export */ "fileNameForMime": () => (/* binding */ fileNameForMime), /* harmony export */ "filePasted": () => (/* binding */ filePasted), /* harmony export */ "fileToBase64": () => (/* binding */ fileToBase64), /* harmony export */ "fitImageSize": () => (/* binding */ fitImageSize), /* harmony export */ "getMimeType": () => (/* binding */ getMimeType), /* harmony export */ "imageCrop": () => (/* binding */ imageCrop), /* harmony export */ "imageScaled": () => (/* binding */ imageScaled), /* harmony export */ "intArrayToBase64": () => (/* binding */ intArrayToBase64), /* harmony export */ "makeImageUrl": () => (/* binding */ makeImageUrl) /* harmony export */ }); const SUPPORTED_IMAGE_FORMATS = ['image/jpeg', 'image/gif', 'image/png', 'image/svg', 'image/svg+xml']; const MIME_EXTENSIONS = ['jpg', 'gif', 'png', 'svg', 'svg']; function makeImageUrl(photo) { if (photo && typeof photo == 'object') { if (photo.ref) { return photo.ref; } if (photo.data && photo.type) { const mime = photo.type.startsWith('image/') ? photo.type : 'image/' + photo.type; return 'data:' + mime + ';base64,' + photo.data; } } return null; } function fitImageSize(width, height, maxWidth, maxHeight, forceSquare) { width = width | 0; height = height | 0; maxWidth = maxWidth | 0; maxHeight = maxHeight | 0; if (width <= 0 || height <= 0 || maxWidth <= 0 || maxHeight <= 0) { return null; } if (forceSquare) { maxWidth = maxHeight = Math.min(maxWidth, maxHeight); } const scale = Math.min(Math.min(width, maxWidth) / width, Math.min(height, maxHeight) / height); const size = { dstWidth: width * scale | 0, dstHeight: height * scale | 0 }; if (forceSquare) { size.dstWidth = size.dstHeight = Math.min(size.dstWidth, size.dstHeight); size.srcWidth = size.srcHeight = Math.min(width, height); size.xoffset = (width - size.srcWidth) / 2 | 0; size.yoffset = (height - size.srcWidth) / 2 | 0; } else { size.xoffset = size.yoffset = 0; size.srcWidth = width; size.srcHeight = height; } return size; } function fileNameForMime(fname, mime) { const idx = SUPPORTED_IMAGE_FORMATS.indexOf(mime); if (idx < 0 || !fname) { return fname; } const ext = MIME_EXTENSIONS[idx]; const at = fname.lastIndexOf('.'); if (at >= 0) { fname = fname.substring(0, at); } return fname + '.' + ext; } function imageScaled(fileOrBlob, maxWidth, maxHeight, maxSize, forceSquare) { return new Promise((resolve, reject) => { const img = new Image(); img.crossOrigin = 'Anonymous'; img.onerror = function (err) { reject(new Error("Image format unrecognized")); }; img.onload = async function () { URL.revokeObjectURL(img.src); const dim = fitImageSize(img.width, img.height, maxWidth, maxHeight, forceSquare); if (!dim) { reject(new Error("Invalid image")); return; } let canvas = document.createElement('canvas'); canvas.width = dim.dstWidth; canvas.height = dim.dstHeight; let ctx = canvas.getContext('2d'); ctx.imageSmoothingEnabled = true; ctx.drawImage(img, dim.xoffset, dim.yoffset, dim.srcWidth, dim.srcHeight, 0, 0, dim.dstWidth, dim.dstHeight); const mime = SUPPORTED_IMAGE_FORMATS.includes(fileOrBlob.type) ? fileOrBlob.type : 'image/jpeg'; let blob = await new Promise(resolve => canvas.toBlob(resolve, mime)); if (!blob) { reject(new Error("Unsupported image format")); return; } while (maxSize > 0 && blob.length > maxSize) { dim.dstWidth = dim.dstWidth * 0.70710678118 | 0; dim.dstHeight = dim.dstHeight * 0.70710678118 | 0; canvas.width = dim.dstWidth; canvas.height = dim.dstHeight; ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(img, dim.xoffset, dim.yoffset, dim.srcWidth, dim.srcHeight, 0, 0, dim.dstWidth, dim.dstHeight); blob = await new Promise(resolve => canvas.toBlob(resolve, mime)); } canvas = null; resolve({ mime: mime, blob: blob, width: dim.dstWidth, height: dim.dstHeight, name: fileNameForMime(fileOrBlob.name, mime) }); }; img.src = URL.createObjectURL(fileOrBlob); }); } function imageCrop(mime, objURL, left, top, width, height, scale) { return new Promise((resolve, reject) => { const img = new Image(); img.crossOrigin = 'Anonymous'; img.onerror = err => { reject(new Error("Image format unrecognized")); }; img.onload = () => { URL.revokeObjectURL(img.src); let canvas = document.createElement('canvas'); canvas.width = width * scale; canvas.height = height * scale; let ctx = canvas.getContext('2d'); ctx.imageSmoothingEnabled = true; ctx.drawImage(img, left, top, width, height, 0, 0, canvas.width, canvas.height); mime = SUPPORTED_IMAGE_FORMATS.includes(mime) ? mime : 'image/jpeg'; canvas.toBlob(blob => { canvas = null; if (blob) { resolve({ mime: mime, blob: blob, width: width, height: height }); } else { reject(new Error("Unsupported image format")); } }, mime); }; img.src = objURL; }); } function fileToBase64(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onerror = evt => { reject(reader.error); }; reader.onload = () => { resolve({ mime: file.type, bits: reader.result.split(',')[1], name: file.name }); }; reader.readAsDataURL(file); }); } function blobToBase64(blob) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onerror = _ => { reject(reader.error); }; reader.onload = () => { resolve({ mime: blob.type, bits: reader.result.split(',')[1] }); }; reader.readAsDataURL(blob); }); } function filePasted(event, onImageSuccess, onAttachmentSuccess, onError) { const items = (event.clipboardData || event.originalEvent.clipboardData || {}).items; if (!items || !items.length) { return false; } for (let i in items) { const item = items[i]; if (item.kind === 'file') { const file = item.getAsFile(); if (!file) { console.error("Failed to get file object from pasted file item", item.kind, item.type); onError("Failed to get file object from pasted file item"); continue; } if (file.type && file.type.split('/')[0] == 'image') { onImageSuccess(file); } else { onAttachmentSuccess(file); } return true; } } return false; } function getMimeType(header) { var mime = /^data:(image\/[-+a-z0-9.]+);base64/.exec(header); return mime && mime.length > 1 ? mime[1] : null; } function base64EncodedLen(n) { return Math.floor((n + 2) / 3) * 4; } function base64DecodedLen(n) { return Math.floor(n / 4) * 3; } function base64ReEncode(str) { if (str) { str = str.replace(/-/g, '+').replace(/_/g, '/'); try { str = btoa(atob(str)); } catch (err) { console.error("Failed to base64 re-encode string.", err); str = null; } } return str; } function base64ToBlob(str, mime) { if (!str) { return null; } try { const bin = atob(str); const length = bin.length; const buf = new ArrayBuffer(length); const arr = new Uint8Array(buf); for (let i = 0; i < length; i++) { arr[i] = bin.charCodeAt(i); } return new Blob([buf], { type: mime }); } catch (err) { console.error("Failed to convert base64 to blob: ", err); } return null; } function intArrayToBase64(arr) { if (!Array.isArray(arr)) { return null; } try { let bin = ''; new Uint8Array(arr).forEach(b => bin += String.fromCharCode(b)); return window.btoa(bin); } catch (err) {} return null; } function base64ToIntArray(b64) { const arr = []; try { const bin = window.atob(b64); [...bin].forEach(c => { arr.push(c.charCodeAt(0)); }); return arr; } catch (err) {} return null; } /***/ }), /***/ "./src/lib/formatters.js": /*!*******************************!*\ !*** ./src/lib/formatters.js ***! \*******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "fullFormatter": () => (/* binding */ fullFormatter), /* harmony export */ "previewFormatter": () => (/* binding */ previewFormatter), /* harmony export */ "replyFormatter": () => (/* binding */ replyFormatter) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _widgets_audio_player_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/audio-player.jsx */ "./src/widgets/audio-player.jsx"); /* harmony import */ var _widgets_lazy_image_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../widgets/lazy-image.jsx */ "./src/widgets/lazy-image.jsx"); /* harmony import */ var _widgets_uploading_image_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../widgets/uploading-image.jsx */ "./src/widgets/uploading-image.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _blob_helpers_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _strformat_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./utils.js */ "./src/lib/utils.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ drafty_form: { id: "drafty_form", defaultMessage: [{ "type": 0, "value": "Form:" }] }, drafty_attachment: { id: "drafty_attachment", defaultMessage: [{ "type": 0, "value": "Attachment" }] }, drafty_image: { id: "drafty_image", defaultMessage: [{ "type": 0, "value": "Picture" }] }, drafty_unknown: { id: "drafty_unknown", defaultMessage: [{ "type": 0, "value": "Unsupported" }] } }); function handleImageData(el, data, attr) { if (!data) { attr.src = 'img/broken_image.png'; attr.style = { width: _config_js__WEBPACK_IMPORTED_MODULE_6__.IMAGE_THUMBNAIL_DIM + 'px', height: _config_js__WEBPACK_IMPORTED_MODULE_6__.IMAGE_THUMBNAIL_DIM + 'px' }; return el; } attr.className = 'inline-image'; const dim = (0,_blob_helpers_js__WEBPACK_IMPORTED_MODULE_7__.fitImageSize)(data.width, data.height, this.viewportWidth > 0 ? Math.min(this.viewportWidth - _config_js__WEBPACK_IMPORTED_MODULE_6__.REM_SIZE * 6.5, _config_js__WEBPACK_IMPORTED_MODULE_6__.REM_SIZE * 34.5) : _config_js__WEBPACK_IMPORTED_MODULE_6__.REM_SIZE * 34.5, _config_js__WEBPACK_IMPORTED_MODULE_6__.REM_SIZE * 24, false) || { dstWidth: _config_js__WEBPACK_IMPORTED_MODULE_6__.BROKEN_IMAGE_SIZE, dstHeight: _config_js__WEBPACK_IMPORTED_MODULE_6__.BROKEN_IMAGE_SIZE }; attr.style = { width: dim.dstWidth + 'px', height: dim.dstHeight + 'px', minWidth: dim.dstWidth + 'px', minHeight: dim.dstHeight + 'px' }; if (!tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isProcessing(data)) { attr.src = this.authorizeURL((0,_utils_js__WEBPACK_IMPORTED_MODULE_9__.sanitizeUrlForMime)(attr.src, 'image')); attr.alt = data.name; if (attr.src) { if (Math.max(data.width || 0, data.height || 0) > _config_js__WEBPACK_IMPORTED_MODULE_6__.IMAGE_THUMBNAIL_DIM) { attr.onClick = this.onImagePreview; attr.className += ' image-clickable'; } attr.loading = 'lazy'; } else { attr.src = 'img/broken_image.png'; } } else { el = _widgets_uploading_image_jsx__WEBPACK_IMPORTED_MODULE_5__["default"]; } return el; } function fullFormatter(style, data, values, key, stack) { if (stack.includes('QQ')) { return quoteFormatter.call(this, style, data, values, key); } if (!style) { return values; } let el = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.tagName(style); let attr = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attrValue(style, data) || {}; attr.key = key; switch (style) { case 'AU': if (attr.src) { attr.src = this.authorizeURL((0,_utils_js__WEBPACK_IMPORTED_MODULE_9__.sanitizeUrlForMime)(attr.src, 'audio')); attr.duration = data.duration > 0 ? data.duration | 0 : undefined; attr.preview = data.preview; attr.loading = 'lazy'; } el = _widgets_audio_player_jsx__WEBPACK_IMPORTED_MODULE_3__["default"]; values = null; break; case 'BR': values = null; break; case 'EX': break; case 'HL': attr.className = 'highlight'; break; case 'HD': el = null; values = null; break; case 'IM': el = handleImageData.call(this, el, data, attr); values = null; break; case 'BN': attr.onClick = this.onFormButtonClick; let inner = react__WEBPACK_IMPORTED_MODULE_0___default().Children.map(values, child => { return typeof child == 'string' ? child : undefined; }); if (!inner || inner.length == 0) { inner = [attr.name]; } attr['data-title'] = inner.join(''); break; case 'MN': attr.className = 'mention'; if (data) { attr.className += ' ' + (0,_strformat_js__WEBPACK_IMPORTED_MODULE_8__.idToColorClass)(data.val, false, true); } break; case 'FM': attr.className = 'bot-form'; break; case 'RW': break; case 'QQ': attr.className = 'reply-quote'; attr.onClick = this.onQuoteClick; break; default: if (!el) { el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); attr = { key: key }; let body = values; if (!Array.isArray(values) || !values.join('').trim()) { body = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { key: "x1", className: "gray" }, this.formatMessage(messages.drafty_unknown))]; } values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { key: "x0", className: "material-icons gray" }, "extension"), ' '].concat(body); } break; } if (!el) { return values; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(el, attr, values); } function previewFormatter(style, data, values, key) { if (!style) { return values; } let el = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.tagName(style); const attr = { key: key }; switch (style) { case 'AU': el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { key: "au", className: "material-icons" }, "mic"), ' ', (0,_strformat_js__WEBPACK_IMPORTED_MODULE_8__.secondsToTime)(data.duration / 1000)]; break; case 'BR': el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [' ']; break; case 'HL': attr.className = 'highlight preview'; break; case 'LN': case 'MN': el = 'span'; break; case 'IM': el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { key: "im", className: "material-icons" }, "photo"), ' ', this.formatMessage(messages.drafty_image)]; break; case 'BN': el = 'span'; attr.className = 'flat-button faux'; break; case 'FM': el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { key: "fm", className: "material-icons" }, "dashboard"), this.formatMessage(messages.drafty_form)].concat(' ', values || []); break; case 'RW': el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); break; case 'EX': if (data) { if (data.mime == 'application/json') { return null; } delete data.val; delete data.ref; } el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { key: "ex", className: "material-icons" }, "attachment"), ' ', this.formatMessage(messages.drafty_attachment)]; break; case 'QQ': case 'HD': el = null; values = null; break; default: if (!el) { el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { key: "x0", className: "material-icons gray" }, "extension"), ' ', this.formatMessage(messages.drafty_unknown)]; } break; } if (!el) { return values; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(el, attr, values); } ; function inlineImageAttr(attr, data) { attr.style = { width: _config_js__WEBPACK_IMPORTED_MODULE_6__.IMAGE_THUMBNAIL_DIM + 'px', height: _config_js__WEBPACK_IMPORTED_MODULE_6__.IMAGE_THUMBNAIL_DIM + 'px', maxWidth: _config_js__WEBPACK_IMPORTED_MODULE_6__.IMAGE_THUMBNAIL_DIM + 'px', maxHeight: _config_js__WEBPACK_IMPORTED_MODULE_6__.IMAGE_THUMBNAIL_DIM + 'px' }; attr.className = 'inline-image'; attr.alt = this.formatMessage(messages.drafty_image); if (!data) { attr.src = 'img/broken_image.png'; } attr.title = attr.alt; return attr; } function quoteFormatter(style, data, values, key) { if (['BR', 'EX', 'IM', 'MN'].includes(style)) { let el = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.tagName(style); let attr = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attrValue(style, data) || {}; attr.key = key; switch (style) { case 'BR': values = null; break; case 'IM': attr = inlineImageAttr.call(this, attr, data); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement('img', attr, null), ' ', attr.alt]; el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); attr = { key: key }; break; case 'MN': el = 'span'; attr.className = 'mention'; if (data) { attr.className += ' ' + (0,_strformat_js__WEBPACK_IMPORTED_MODULE_8__.idToColorClass)(data.val, false, true); } break; case 'EX': let fname; if (data) { if (data.mime == 'application/json') { return null; } fname = data.name; delete data.val; delete data.ref; } el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { key: "ex", className: "material-icons" }, "attachment"), (0,_strformat_js__WEBPACK_IMPORTED_MODULE_8__.shortenFileName)(fname, 16) || this.formatMessage(messages.drafty_attachment)]; break; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(el, attr, values); } return previewFormatter.call(this, style, data, values, key); } function quoteImage(data) { let promise; if (data.val) { const blob = (0,_blob_helpers_js__WEBPACK_IMPORTED_MODULE_7__.base64ToBlob)(data.val, data.mime); if (!blob) { throw new Error("Invalid image"); } promise = Promise.resolve(blob); } else if (data.ref) { promise = fetch(this.authorizeURL((0,_utils_js__WEBPACK_IMPORTED_MODULE_9__.sanitizeUrlForMime)(data.ref, 'image'))).then(evt => { if (evt.ok) { return evt.blob(); } else { throw new Error("Image fetch unsuccessful: ".concat(evt.status, " ").concat(evt.statusText)); } }); } else { throw new Error("Missing image data"); } return promise.then(blob => { return (0,_blob_helpers_js__WEBPACK_IMPORTED_MODULE_7__.imageScaled)(blob, _config_js__WEBPACK_IMPORTED_MODULE_6__.IMAGE_THUMBNAIL_DIM, _config_js__WEBPACK_IMPORTED_MODULE_6__.IMAGE_THUMBNAIL_DIM, -1, true); }).then(scaled => { data.mime = scaled.mime; data.size = scaled.blob.size; data.width = scaled.width; data.height = scaled.height; delete data.ref; data.src = URL.createObjectURL(scaled.blob); return (0,_blob_helpers_js__WEBPACK_IMPORTED_MODULE_7__.blobToBase64)(scaled.blob); }).then(b64 => { data.val = b64.bits; return data; }).catch(err => { delete data.val; delete data.src; data.width = _config_js__WEBPACK_IMPORTED_MODULE_6__.IMAGE_THUMBNAIL_DIM; data.height = _config_js__WEBPACK_IMPORTED_MODULE_6__.IMAGE_THUMBNAIL_DIM; throw err; }); } function replyFormatter(style, data, values, key, stack) { if (style == 'IM') { const attr = inlineImageAttr.call(this, { key: key }, data); let loadedPromise; try { loadedPromise = (0,_utils_js__WEBPACK_IMPORTED_MODULE_9__.cancelablePromise)(quoteImage.call(this, data)); } catch (error) { loadedPromise = (0,_utils_js__WEBPACK_IMPORTED_MODULE_9__.cancelablePromise)(error); } attr.whenDone = loadedPromise; values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_lazy_image_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], attr, null), ' ', attr.alt]; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), { key: key }, values); } else if (style == 'QQ') { if (stack.includes('QQ')) { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement('span', { key: key }, [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { key: "qq", className: "material-icons" }, "format_quote"), ' ']); } const attr = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attrValue('QQ', data) || {}; attr.key = key; attr.className = 'reply-quote'; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.tagName('QQ'), attr, values); } return quoteFormatter.call(this, style, data, values, key); } /***/ }), /***/ "./src/lib/host-name.js": /*!******************************!*\ !*** ./src/lib/host-name.js ***! \******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "detectServerAddress": () => (/* binding */ detectServerAddress), /* harmony export */ "isLocalHost": () => (/* binding */ isLocalHost), /* harmony export */ "isSecureConnection": () => (/* binding */ isSecureConnection) /* harmony export */ }); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); function detectServerAddress() { let host = _config_js__WEBPACK_IMPORTED_MODULE_0__.DEFAULT_HOST; if (typeof window.location == 'object') { if (window.location.protocol == 'file:' || window.location.hostname == 'localhost') { host = _config_js__WEBPACK_IMPORTED_MODULE_0__.KNOWN_HOSTS.local; } else if (window.location.hostname) { host = window.location.hostname + (window.location.port ? ':' + window.location.port : ''); } } return host; } function isSecureConnection() { if (typeof window.location == 'object') { return window.location.protocol == 'https:'; } return false; } function isLocalHost() { if (typeof window.location == 'object') { return window.location.hostname == 'localhost'; } return false; } /***/ }), /***/ "./src/lib/local-storage.js": /*!**********************************!*\ !*** ./src/lib/local-storage.js ***! \**********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ LocalStorageUtil) /* harmony export */ }); class LocalStorageUtil { static setObject(key, value) { localStorage.setItem(key, JSON.stringify(value)); } static getObject(key) { const value = localStorage.getItem(key); return value && JSON.parse(value); } static updateObject(key, value) { const oldVal = this.getObject(key); this.setObject(key, Object.assign(oldVal || {}, value)); } static removeItem(key) { localStorage.removeItem(key); } } /***/ }), /***/ "./src/lib/navigation.js": /*!*******************************!*\ !*** ./src/lib/navigation.js ***! \*******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ HashNavigation) /* harmony export */ }); class HashNavigation { static parseUrlHash(hash) { const parts = hash.split('?', 2); const params = {}; let path = []; if (parts[0]) { path = parts[0].replace('#', '').split('/'); } if (parts[1]) { parts[1].split('&').forEach(function (part) { const item = part.split('='); if (item[0]) { params[decodeURIComponent(item[0])] = decodeURIComponent(item[1]); } }); } return { path: path, params: params }; } static navigateTo(url) { window.location.hash = url; } static composeUrlHash(path, params) { let url = path.join('/'); const args = []; for (const key in params) { if (params.hasOwnProperty(key)) { args.push(key + '=' + params[key]); } } if (args.length > 0) { url += '?' + args.join('&'); } return url; } static addUrlParam(hash, key, value) { const parsed = this.parseUrlHash(hash); parsed.params[key] = value; return this.composeUrlHash(parsed.path, parsed.params); } static removeUrlParam(hash, key) { const parsed = this.parseUrlHash(hash); delete parsed.params[key]; return this.composeUrlHash(parsed.path, parsed.params); } static setUrlSidePanel(hash, sidepanel) { const parsed = this.parseUrlHash(hash); parsed.path[0] = sidepanel; return this.composeUrlHash(parsed.path, parsed.params); } static setUrlInfoPanel(hash, infopanel) { const parsed = this.parseUrlHash(hash); if (infopanel) { parsed.params.info = infopanel; } else { delete parsed.params.info; } return this.composeUrlHash(parsed.path, parsed.params); } static setUrlTopic(hash, topic) { const parsed = this.parseUrlHash(hash); parsed.path[1] = topic; delete parsed.params.info; return this.composeUrlHash(parsed.path, parsed.params); } } /***/ }), /***/ "./src/lib/strformat.js": /*!******************************!*\ !*** ./src/lib/strformat.js ***! \******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "bytesToHumanSize": () => (/* binding */ bytesToHumanSize), /* harmony export */ "idToColorClass": () => (/* binding */ idToColorClass), /* harmony export */ "letterTileColorId": () => (/* binding */ letterTileColorId), /* harmony export */ "secondsToTime": () => (/* binding */ secondsToTime), /* harmony export */ "shortDateFormat": () => (/* binding */ shortDateFormat), /* harmony export */ "shortenFileName": () => (/* binding */ shortenFileName) /* harmony export */ }); function shortDateFormat(then, locale) { locale = locale || window.navigator.userLanguage || window.navigator.language; const now = new Date(); if (then.getFullYear() == now.getFullYear()) { if (then.getMonth() == now.getMonth() && then.getDate() == now.getDate()) { return then.toLocaleTimeString(locale, { hour12: false, hour: '2-digit', minute: '2-digit' }); } return then.toLocaleDateString(locale, { hour12: false, month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }); } return then.toLocaleDateString(locale, { year: 'numeric', month: 'short', day: 'numeric' }); } function secondsToTime(seconds, fixedMin) { let min = Math.floor(seconds / 60) | 0; let hours = Math.floor(min / 60) | 0; if (fixedMin || hours > 0) { min = min < 10 ? "0".concat(min) : min; } let sec = seconds % 60 | 0; sec = sec < 10 ? "0".concat(sec) : sec; if (hours == 0) { return "".concat(min, ":").concat(sec); } return "".concat(hours, ":").concat(min, ":").concat(sec); } function bytesToHumanSize(bytes) { if (!bytes || bytes == 0) { return '0 Bytes'; } const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB']; const bucket = Math.min(Math.floor(Math.log2(bytes) / 10) | 0, sizes.length - 1); const count = bytes / Math.pow(1024, bucket); const round = bucket > 0 ? count < 3 ? 2 : count < 30 ? 1 : 0 : 0; return count.toFixed(round) + ' ' + sizes[bucket]; } function shortenFileName(filename, maxLength) { if (typeof filename != 'string') { return filename; } return filename.length > maxLength ? filename.slice(0, maxLength / 2 - 1) + '…' + filename.slice(1 - maxLength / 2) : filename; } function stringToColorHash(value) { let hash = 0; value = '' + value; for (let i = 0; i < value.length; i++) { hash = (hash << 5) - hash + value.charCodeAt(i); hash = hash & hash; } return hash; } function letterTileColorId(userId) { return Math.abs(stringToColorHash(userId)) % 16; } function idToColorClass(id, light, fg) { return (light ? 'lt-' : 'dk-') + (fg ? 'fg-' : 'bg-') + letterTileColorId(id); } /***/ }), /***/ "./src/lib/utils.js": /*!**************************!*\ !*** ./src/lib/utils.js ***! \**************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "arrayEqual": () => (/* binding */ arrayEqual), /* harmony export */ "asEmail": () => (/* binding */ asEmail), /* harmony export */ "asPhone": () => (/* binding */ asPhone), /* harmony export */ "cancelablePromise": () => (/* binding */ cancelablePromise), /* harmony export */ "clipStr": () => (/* binding */ clipStr), /* harmony export */ "deliveryMarker": () => (/* binding */ deliveryMarker), /* harmony export */ "isUrlRelative": () => (/* binding */ isUrlRelative), /* harmony export */ "isVideoCall": () => (/* binding */ isVideoCall), /* harmony export */ "sanitizeUrl": () => (/* binding */ sanitizeUrl), /* harmony export */ "sanitizeUrlForMime": () => (/* binding */ sanitizeUrlForMime), /* harmony export */ "theCard": () => (/* binding */ theCard), /* harmony export */ "updateFavicon": () => (/* binding */ updateFavicon) /* harmony export */ }); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../constants.js */ "./src/constants.js"); function updateFavicon(count) { const oldIcon = document.getElementById('shortcut-icon'); const head = document.head || document.getElementsByTagName('head')[0]; const newIcon = document.createElement('link'); newIcon.type = 'image/png'; newIcon.id = 'shortcut-icon'; newIcon.rel = 'shortcut icon'; newIcon.href = 'img/logo32x32' + (count > 0 ? 'a' : '') + '.png'; if (oldIcon) { head.removeChild(oldIcon); } head.appendChild(newIcon); document.title = (count > 0 ? '(' + count + ') ' : '') + 'Tinode'; } function theCard(fn, imageUrl, imageMimeType, note) { let card = null; fn = fn && fn.trim(); note = note && note.trim(); if (fn) { card = { fn: fn }; } if (typeof note == 'string') { card = card || {}; card.note = note ? note : tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.DEL_CHAR; } if (imageUrl) { card = card || {}; let mimeType = imageMimeType; const matches = /^data:(image\/[-a-z0-9+.]+)?(;base64)?,/i.exec(imageUrl); if (matches) { mimeType = matches[1]; card.photo = { data: imageUrl.substring(imageUrl.indexOf(',') + 1), ref: tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.DEL_CHAR }; } else { card.photo = { data: tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.DEL_CHAR, ref: imageUrl }; } card.photo.type = (mimeType || 'image/jpeg').substring('image/'.length); } return card; } function arrayEqual(a, b) { if (a === b) { return true; } if (!Array.isArray(a) || !Array.isArray(b)) { return false; } if (a.length != b.length) { return false; } a.sort(); b.sort(); for (let i = 0, l = a.length; i < l; i++) { if (a[i] !== b[i]) { return false; } } return true; } function asPhone(val) { val = val.trim(); if (/^(?:\+?(\d{1,3}))?[- (.]*(\d{3})[- ).]*(\d{3})[- .]*(\d{2})[- .]*(\d{2})?$/.test(val)) { return val.replace(/[- ().]*/, ''); } return null; } function asEmail(val) { val = val.trim(); if (/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/.test(val)) { return val; } return null; } function isUrlRelative(url) { return url && !/^\s*([a-z][a-z0-9+.-]*:|\/\/)/im.test(url); } function sanitizeUrl(url, allowedSchemes) { if (typeof url != 'string') { return url; } url = url.replace(/[^\x20-\x7E]/gmi, '').trim(); if (!/^([a-z][a-z0-9+.-]*:|\/\/)/i.test(url)) { return url; } if (/^blob:http/.test(url)) { return url; } const schemes = Array.isArray(allowedSchemes) ? allowedSchemes.join('|') : 'http|https'; const re = new RegExp('^((' + schemes + '):|//)', 'i'); if (!re.test(url)) { return null; } return url; } function sanitizeUrlForMime(url, mimeMajor) { if (!url) { return null; } const sanitizedUrl = sanitizeUrl(url); if (sanitizedUrl) { return sanitizedUrl; } const re = new RegExp("data:".concat(mimeMajor, "/[a-z0-9.-]+;base64,"), 'i'); if (re.test(url.trim())) { return url; } return null; } function deliveryMarker(received) { switch (received) { case tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.MESSAGE_STATUS_SENDING: return { name: 'access_time' }; case tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.MESSAGE_STATUS_FAILED: return { name: 'warning', color: 'danger-color' }; case tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.MESSAGE_STATUS_SENT: return { name: 'done' }; case tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.MESSAGE_STATUS_RECEIVED: return { name: 'done_all' }; case tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.MESSAGE_STATUS_READ: return { name: 'done_all', color: 'blue' }; } return null; } function cancelablePromise(promise) { let hasCanceled = false; const wrappedPromise = promise instanceof Error ? Promise.reject(promise) : new Promise((resolve, reject) => { promise.then(result => hasCanceled ? reject({ isCanceled: true }) : resolve(result), error => hasCanceled ? reject({ isCanceled: true }) : reject(error)); }); return { promise: wrappedPromise, cancel() { hasCanceled = true; } }; } ; function isVideoCall(mime) { return mime == _constants_js__WEBPACK_IMPORTED_MODULE_1__.CALL_MESSAGE_MIME_TYPE; } function clipStr(str, length) { return str && str.substring(0, length); } /***/ }), /***/ "./src/version.js": /*!************************!*\ !*** ./src/version.js ***! \************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "PACKAGE_VERSION": () => (/* binding */ PACKAGE_VERSION) /* harmony export */ }); const PACKAGE_VERSION = "0.20.0-alpha1"; /***/ }), /***/ "./src/views/acc-notifications-view.jsx": /*!**********************************************!*\ !*** ./src/views/acc-notifications-view.jsx ***! \**********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ EditAccountView) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/checkbox.jsx */ "./src/widgets/checkbox.jsx"); class EditAccountView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleCheckboxClick = this.handleCheckboxClick.bind(this); } handleCheckboxClick(what, checked) { if (what == 'sound') { this.props.onToggleMessageSounds(checked); } else if (what == 'alert') { this.props.onTogglePushNotifications(checked); } else if (what == 'incognito') { this.props.onToggleIncognitoMode(checked); } } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "scrollable-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { htmlFor: "message-sound" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_message_sound", defaultMessage: [{ "type": 0, "value": "Message sound:" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { name: "sound", id: "message-sound", checked: this.props.messageSounds, onChange: this.handleCheckboxClick })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { htmlFor: "desktop-alerts" }, this.props.desktopAlertsEnabled ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_push_notifications", defaultMessage: [{ "type": 0, "value": "Notification alerts:" }] }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_push_notifications_disabled", defaultMessage: [{ "type": 0, "value": "Notification alerts (requires HTTPS):" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { name: "alert", id: "desktop-alerts", checked: this.props.desktopAlerts, onChange: this.props.desktopAlertsEnabled ? this.handleCheckboxClick : null })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { htmlFor: "incognito-mode" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_incognito_mode", defaultMessage: [{ "type": 0, "value": "Incognito mode:" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { name: "incognito", id: "incognito-mode", checked: this.props.incognitoMode, onChange: this.handleCheckboxClick }))); } } ; /***/ }), /***/ "./src/views/acc-security-view.jsx": /*!*****************************************!*\ !*** ./src/views/acc-security-view.jsx ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/in-place-edit.jsx */ "./src/widgets/in-place-edit.jsx"); /* harmony import */ var _widgets_permissions_editor_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/permissions-editor.jsx */ "./src/widgets/permissions-editor.jsx"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ delete_account: { id: "delete_account", defaultMessage: [{ "type": 0, "value": "Delete account" }] }, delete_account_warning: { id: "delete_account_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to delete your account? It cannot be undone." }] } }); class AccSecurityView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); const me = this.props.tinode.getMeTopic(); let blockedCount = 0; me.contacts(c => { if (c.acs && !c.acs.isJoiner()) { blockedCount++; } }); const defacs = me.getDefaultAccess(); this.state = { auth: defacs ? defacs.auth : null, anon: defacs ? defacs.anon : null, showPermissionEditorFor: undefined, blockedCount: blockedCount }; this.handlePasswordUpdate = this.handlePasswordUpdate.bind(this); this.handleLaunchPermissionsEditor = this.handleLaunchPermissionsEditor.bind(this); this.handleHidePermissionsEditor = this.handleHidePermissionsEditor.bind(this); this.handlePermissionsChanged = this.handlePermissionsChanged.bind(this); this.handleDeleteAccount = this.handleDeleteAccount.bind(this); } handlePasswordUpdate(pwd) { this.setState({ password: pwd }); this.props.onUpdatePassword(pwd); } handleLaunchPermissionsEditor(which) { this.setState({ showPermissionEditorFor: which, editedPermissions: this.state[which] }); } handleHidePermissionsEditor() { this.setState({ showPermissionEditorFor: undefined }); } handlePermissionsChanged(perm) { let defacs = {}; defacs[this.state.showPermissionEditorFor] = perm; this.props.onUpdateAccountDesc('me', undefined, undefined, defacs); let newState = { showPermissionEditorFor: undefined }; newState[this.state.showPermissionEditorFor] = perm; this.setState(newState); } handleDeleteAccount(e) { e.preventDefault(); const { formatMessage } = this.props.intl; this.props.onShowAlert(formatMessage(messages.delete_account), formatMessage(messages.delete_account_warning), () => { this.props.onDeleteAccount(); }, null, true, null); } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, this.state.showPermissionEditorFor ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_permissions_editor_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { mode: this.state.editedPermissions, skip: "O", onSubmit: this.handlePermissionsChanged, onCancel: this.handleHidePermissionsEditor }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "scrollable-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_password", defaultMessage: [{ "type": 0, "value": "Password" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "password_unchanged_prompt", defaultMessage: [{ "type": 0, "value": "Unchanged" }] }, password_unchanged => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { placeholder: password_unchanged, type: "password", onFinished: this.handlePasswordUpdate })))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "danger flat-button", onClick: e => { e.preventDefault(); this.props.onLogout(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "exit_to_app"), " \xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_logout", defaultMessage: [{ "type": 0, "value": "Logout" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "danger flat-button", onClick: e => { this.handleDeleteAccount(e); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "delete"), " \xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_delete_account", defaultMessage: [{ "type": 0, "value": "Delete account" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_default_access_mode", defaultMessage: [{ "type": 0, "value": "Default access mode:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "quoted" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, "Auth: ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", { className: "clickable", onClick: this.handleLaunchPermissionsEditor.bind(this, 'auth') }, this.state.auth)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, "Anon: ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", { className: "clickable", onClick: this.handleLaunchPermissionsEditor.bind(this, 'anon') }, this.state.anon)))), this.state.blockedCount > 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "block"), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "gray", onClick: e => { e.preventDefault(); this.props.onShowBlocked(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "blocked_contacts_link", defaultMessage: [{ "type": 0, "value": "Blocked contacts (" }, { "type": 1, "value": "count" }, { "type": 0, "value": ")" }], values: { count: this.state.blockedCount } })))) : null)); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(AccSecurityView)); /***/ }), /***/ "./src/views/acc-support-view.jsx": /*!****************************************!*\ !*** ./src/views/acc-support-view.jsx ***! \****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ AccSupportView) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); class AccSupportView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "scrollable-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: _config_js__WEBPACK_IMPORTED_MODULE_3__.LINK_CONTACT_US, className: "flat-button", target: "_blank" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "email"), " \xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "link_contact_us", defaultMessage: [{ "type": 0, "value": "Contact Us" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: _config_js__WEBPACK_IMPORTED_MODULE_3__.LINK_TERMS_OF_SERVICE, className: "flat-button", target: "_blank" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "description"), " \xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "link_terms_of_service", defaultMessage: [{ "type": 0, "value": "Terms of Service" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: _config_js__WEBPACK_IMPORTED_MODULE_3__.LINK_PRIVACY_POLICY, className: "flat-button", target: "_blank" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "policy"), " \xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "link_privacy_policy", defaultMessage: [{ "type": 0, "value": "Privacy Policy" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_client", defaultMessage: [{ "type": 0, "value": "Client:" }] })), _config_js__WEBPACK_IMPORTED_MODULE_3__.APP_NAME), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_sdk", defaultMessage: [{ "type": 0, "value": "SDK:" }] })), tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.getLibrary()), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_server", defaultMessage: [{ "type": 0, "value": "Server:" }] })), this.props.serverVersion), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_server_address", defaultMessage: [{ "type": 0, "value": "Server address:" }] })), this.props.serverAddress))); } } ; /***/ }), /***/ "./src/views/account-settings-view.jsx": /*!*********************************************!*\ !*** ./src/views/account-settings-view.jsx ***! \*********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ AccountSettingsView) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/avatar-upload.jsx */ "./src/widgets/avatar-upload.jsx"); /* harmony import */ var _widgets_badge_list_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/badge-list.jsx */ "./src/widgets/badge-list.jsx"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); function _clip(str, length) { return str && str.substring(0, length); } class AccountSettingsView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); const me = this.props.tinode.getMeTopic(); this.state = { fullName: _clip(me.public ? me.public.fn : undefined, _config_js__WEBPACK_IMPORTED_MODULE_5__.MAX_TITLE_LENGTH), description: _clip(me.public ? me.public.note : undefined, _config_js__WEBPACK_IMPORTED_MODULE_5__.MAX_TOPIC_DESCRIPTION_LENGTH), avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__.makeImageUrl)(me.public ? me.public.photo : null) }; } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "scrollable-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "flat-button float-right", onClick: e => { e.preventDefault(); this.props.onNavigate('general'); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "edit"), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_edit", defaultMessage: [{ "type": 0, "value": "Edit" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("center", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { tinode: this.props.tinode, avatar: this.state.avatar, readOnly: true, uid: this.props.myUserId, title: this.state.fullName })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_your_name", defaultMessage: [{ "type": 0, "value": "Your name" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "large ellipsized" }, this.state.fullName)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_user_id", defaultMessage: [{ "type": 0, "value": "ID:" }] })), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", null, this.props.myUserId)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_badge_list_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { trustedBadges: this.props.trustedBadges })), this.state.description ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_description", defaultMessage: [{ "type": 0, "value": "Description" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, this.state.description)) : null), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "flat-button", onClick: e => { e.preventDefault(); this.props.onNavigate('notif'); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "notifications"), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "sidepanel_title_acc_notifications", defaultMessage: [{ "type": 0, "value": "Notifications" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "flat-button", onClick: e => { e.preventDefault(); this.props.onNavigate('security'); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "security"), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_security", defaultMessage: [{ "type": 0, "value": "Security" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "flat-button", onClick: e => { e.preventDefault(); this.props.onNavigate('support'); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "contact_support"), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "sidepanel_title_acc_support", defaultMessage: [{ "type": 0, "value": "Support" }] })))); } } ; /***/ }), /***/ "./src/views/contacts-view.jsx": /*!*************************************!*\ !*** ./src/views/contacts-view.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ContactsView) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_contact_list_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/contact-list.jsx */ "./src/widgets/contact-list.jsx"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ archived_contacts_title: { id: "archived_contacts", defaultMessage: [{ "type": 0, "value": "Archived contacts (" }, { "type": 1, "value": "count" }, { "type": 0, "value": ")" }] } }); class ContactsView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.handleAction = this.handleAction.bind(this); this.state = ContactsView.deriveStateFromProps(props); } static deriveStateFromProps(props) { const contacts = []; let unreadThreads = 0; let archivedCount = 0; props.chatList.map(c => { const blocked = c.acs && !c.acs.isJoiner(); if (blocked && props.blocked) { contacts.push(c); } if (blocked || props.blocked) { return; } if (c.private && c.private.arch) { if (props.archive) { contacts.push(c); } else { archivedCount++; } } else if (!props.archive) { contacts.push(c); unreadThreads += c.unread > 0 ? 1 : 0; } }); contacts.sort((a, b) => { return (b.touched || 0) - (a.touched || 0); }); if (archivedCount > 0) { contacts.push({ action: 'archive', title: messages.archived_contacts_title, values: { count: archivedCount } }); } return { contactList: contacts, unreadThreads: unreadThreads }; } componentDidUpdate(prevProps, prevState) { if (prevProps.chatList != this.props.chatList || prevProps.archive != this.props.archive || prevProps.blocked != this.props.blocked) { const newState = ContactsView.deriveStateFromProps(this.props); this.setState(newState); if (newState.unreadThreads != prevState.unreadThreads) { (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_3__.updateFavicon)(newState.unreadThreads); } } } handleAction(action_ignored) { this.props.onShowArchive(); } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "contacts_not_found", defaultMessage: [{ "type": 0, "value": "You have no chats" }, { "type": 0, "value": "
" }, { "type": 0, "value": "¯∖_(ツ)_/¯" }] }, no_contacts => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_contact_list_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { tinode: this.props.tinode, connected: this.props.connected, contacts: this.state.contactList, emptyListMessage: no_contacts, topicSelected: this.props.topicSelected, myUserId: this.props.myUserId, showOnline: true, showUnread: true, onTopicSelected: this.props.onTopicSelected, showContextMenu: this.props.showContextMenu, onAction: this.handleAction })); } } ; /***/ }), /***/ "./src/views/create-account-view.jsx": /*!*******************************************!*\ !*** ./src/views/create-account-view.jsx ***! \*******************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ CreateAccountView) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/avatar-upload.jsx */ "./src/widgets/avatar-upload.jsx"); /* harmony import */ var _widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/checkbox.jsx */ "./src/widgets/checkbox.jsx"); /* harmony import */ var _widgets_visible_password_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../widgets/visible-password.jsx */ "./src/widgets/visible-password.jsx"); /* harmony import */ var _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/local-storage.js */ "./src/lib/local-storage.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); class CreateAccountView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { login: '', password: '', email: '', fn: '', imageDataUrl: null, errorCleared: false, saveToken: _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_5__["default"].getObject('keep-logged-in') }; this.handleLoginChange = this.handleLoginChange.bind(this); this.handlePasswordChange = this.handlePasswordChange.bind(this); this.handleEmailChange = this.handleEmailChange.bind(this); this.handleFnChange = this.handleFnChange.bind(this); this.handleImageChanged = this.handleImageChanged.bind(this); this.handleToggleSaveToken = this.handleToggleSaveToken.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleLoginChange(e) { this.setState({ login: e.target.value }); } handlePasswordChange(password) { this.setState({ password: password }); } handleEmailChange(e) { this.setState({ email: e.target.value }); } handleFnChange(e) { this.setState({ fn: e.target.value }); } handleImageChanged(img) { this.setState({ imageDataUrl: img }); } handleToggleSaveToken() { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_5__["default"].setObject('keep-logged-in', !this.state.saveToken); this.setState({ saveToken: !this.state.saveToken }); } handleSubmit(e) { e.preventDefault(); this.setState({ errorCleared: false }); this.props.onCreateAccount(this.state.login.trim(), this.state.password.trim(), (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_6__.theCard)(this.state.fn.trim().substring(0, _config_js__WEBPACK_IMPORTED_MODULE_7__.MAX_TITLE_LENGTH), this.state.imageDataUrl), { 'meth': 'email', 'val': this.state.email }); } render() { let submitClasses = 'primary'; if (this.props.disabled) { submitClasses += ' disabled'; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("form", { className: "panel-form-column", onSubmit: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "login_prompt", defaultMessage: [{ "type": 0, "value": "Login" }] }, login_prompt => react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", placeholder: login_prompt, autoComplete: "user-name", value: this.state.login, onChange: this.handleLoginChange, required: true, autoFocus: true })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "password_prompt", defaultMessage: [{ "type": 0, "value": "Password" }] }, password_prompt => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_visible_password_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { placeholder: password_prompt, autoComplete: "new-password", value: this.state.password, onFinished: this.handlePasswordChange, required: true }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { tinode: this.props.tinode, onImageChanged: this.handleImageChanged, onError: this.props.onError })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "full_name_prompt", defaultMessage: [{ "type": 0, "value": "Full name, e.g. John Doe" }] }, full_name_prompt => react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", placeholder: full_name_prompt, autoComplete: "name", value: this.state.fn, onChange: this.handleFnChange, required: true }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "email_prompt", defaultMessage: [{ "type": 0, "value": "Email, e.g. jdoe@example.com" }] }, email_prompt => react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "email", placeholder: email_prompt, autoComplete: "email", value: this.state.email, onChange: this.handleEmailChange, required: true }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { id: "save-token", name: "save-token", checked: this.state.saveToken, onChange: this.handleToggleSaveToken }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "stay_logged_in", defaultMessage: [{ "type": 0, "value": "Stay logged in" }] }, stay_logged_in => react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { htmlFor: "save-token" }, "\xA0", stay_logged_in))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "dialog-buttons" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: submitClasses, type: "submit" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_sign_up", defaultMessage: [{ "type": 0, "value": "Sign up" }] })))); } } ; /***/ }), /***/ "./src/views/incoming-call-view.jsx": /*!******************************************!*\ !*** ./src/views/incoming-call-view.jsx ***! \******************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ IncomingCallView) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/avatar-upload.jsx */ "./src/widgets/avatar-upload.jsx"); /* harmony import */ var _widgets_badge_list_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/badge-list.jsx */ "./src/widgets/badge-list.jsx"); /* harmony import */ var _widgets_menu_cancel_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../widgets/menu-cancel.jsx */ "./src/widgets/menu-cancel.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../constants.js */ "./src/constants.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); const RING_SOUND = new Audio('audio/call-in.mp3'); class IncomingCallView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { topic: null, fullName: undefined, avatar: null, trustedBadges: [], previousMetaDesc: undefined }; this.resetDesc = this.resetDesc.bind(this); this.onMetaDesc = this.onMetaDesc.bind(this); this.handleRejectCall = this.handleRejectCall.bind(this); this.handleAcceptCall = this.handleAcceptCall.bind(this); this.ringTimer = null; } componentDidMount() { const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } this.resetDesc(topic, this.props); if (this.props.callState == _constants_js__WEBPACK_IMPORTED_MODULE_6__.CALL_STATE_INCOMING_RECEIVED) { RING_SOUND.play(); this.ringTimer = setInterval(() => RING_SOUND.play(), 2000); this.props.onRinging(this.props.topic, this.props.seq); } } componentDidUpdate(props) { const topic = this.props.tinode.getTopic(props.topic); if (!topic) { return; } if (this.onMetaDesc != topic.onMetaDesc) { this.previousMetaDesc = topic.onMetaDesc; topic.onMetaDesc = this.onMetaDesc; } if (this.state.topic != props.topic) { this.setState({ topic: props.topic }); this.resetDesc(topic, props); } } componentWillUnmount() { if (this.ringTimer != null) { clearInterval(this.ringTimer); RING_SOUND.pause(); } const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } this.setState({ topic: null }); topic.onMetaDesc = this.previousMetaDesc; } resetDesc(topic, props) { const defacs = topic.getDefaultAccess() || {}; const acs = topic.getAccessMode(); const badges = []; if (topic.trusted) { for (const [key, val] of Object.entries(topic.trusted)) { if (val) { badges.push(key); } } } this.setState({ fullName: (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_8__.clipStr)(topic.public ? topic.public.fn : undefined, _config_js__WEBPACK_IMPORTED_MODULE_5__.MAX_TITLE_LENGTH), avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_7__.makeImageUrl)(topic.public ? topic.public.photo : null), trustedBadges: badges }); } onMetaDesc(desc) { const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } this.resetDesc(topic, this.props); if (this.previousMetaDesc && this.previousMetaDesc != this.onMetaDesc) { this.previousMetaDesc(desc); } } handleAcceptCall() { this.props.onAcceptCall(this.props.topic); } handleRejectCall() { this.props.onReject(this.props.topic, this.props.seq); this.props.onClose(); } render() { let panelTitle = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "calls_incoming_title", defaultMessage: [{ "type": 0, "value": "Incoming Call" }] }); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "info-view" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "caption-panel", id: "info-caption-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-title", id: "info-title" }, panelTitle), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_menu_cancel_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { onCancel: this.handleRejectCall }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "info-view-content", className: "scrollable-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("center", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { tinode: this.props.tinode, avatar: this.state.avatar, readOnly: true, uid: this.props.topic, title: this.state.fullName })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group incoming-call-title" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "large ellipsized" }, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_8__.clipStr)(this.state.fullName))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group incoming-call-badges" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_badge_list_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { trustedBadges: this.state.trustedBadges })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "actions", className: "group incoming-call-actions" }, this.props.callState == _constants_js__WEBPACK_IMPORTED_MODULE_6__.CALL_STATE_INCOMING_RECEIVED ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "danger", onClick: this.handleRejectCall }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "call_end")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "positive", onClick: this.handleAcceptCall }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "call"))) : null)))); } } ; /***/ }), /***/ "./src/views/info-view.jsx": /*!*********************************!*\ !*** ./src/views/info-view.jsx ***! \*********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _widgets_avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/avatar-upload.jsx */ "./src/widgets/avatar-upload.jsx"); /* harmony import */ var _widgets_badge_list_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../widgets/badge-list.jsx */ "./src/widgets/badge-list.jsx"); /* harmony import */ var _widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../widgets/checkbox.jsx */ "./src/widgets/checkbox.jsx"); /* harmony import */ var _widgets_contact_list_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../widgets/contact-list.jsx */ "./src/widgets/contact-list.jsx"); /* harmony import */ var _widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../widgets/error-panel.jsx */ "./src/widgets/error-panel.jsx"); /* harmony import */ var _widgets_group_manager_jsx__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../widgets/group-manager.jsx */ "./src/widgets/group-manager.jsx"); /* harmony import */ var _widgets_menu_cancel_jsx__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../widgets/menu-cancel.jsx */ "./src/widgets/menu-cancel.jsx"); /* harmony import */ var _widgets_permissions_editor_jsx__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../widgets/permissions-editor.jsx */ "./src/widgets/permissions-editor.jsx"); /* harmony import */ var _widgets_topic_common_jsx__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../widgets/topic-common.jsx */ "./src/widgets/topic-common.jsx"); /* harmony import */ var _widgets_topic_security_jsx__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../widgets/topic-security.jsx */ "./src/widgets/topic-security.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ info: { id: "panel_title_info", defaultMessage: [{ "type": 0, "value": "Info" }] }, general: { id: "panel_title_general", defaultMessage: [{ "type": 0, "value": "General" }] }, security: { id: "panel_title_security", defaultMessage: [{ "type": 0, "value": "Security" }] }, members: { id: "panel_title_members", defaultMessage: [{ "type": 0, "value": "Members" }] }, crop: { id: "panel_title_crop", defaultMessage: [{ "type": 0, "value": "Drag to Adjust" }] }, perm_want: { id: "requested_permissions", defaultMessage: [{ "type": 0, "value": "Requested" }] }, perm_given: { id: "granted_permissions", defaultMessage: [{ "type": 0, "value": "Granted" }] }, perm_auth: { id: "permissions_authenticated", defaultMessage: [{ "type": 0, "value": "Authenticated" }] }, perm_anon: { id: "permissions_anonymous", defaultMessage: [{ "type": 0, "value": "Anonymous" }] }, perm_user: { id: "permissions_user", defaultMessage: [{ "type": 0, "value": "User's Permissions" }] }, edit_permissions: { id: "menu_item_edit_permissions", defaultMessage: [{ "type": 0, "value": "Edit permissions" }] } }); class InfoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { topic: null, owner: false, admin: false, sharer: false, deleter: false, muted: false, address: null, groupTopic: undefined, channel: undefined, fullName: undefined, description: undefined, avatar: null, private: null, selectedContact: null, access: null, modeGiven: null, modeWant: null, modeGiven2: null, modeWant2: null, auth: null, anon: null, contactList: [], trustedBadges: [], previousMetaDesc: undefined, previousSubsUpdated: undefined }; this.resetSubs = this.resetSubs.bind(this); this.resetDesc = this.resetDesc.bind(this); this.resetTags = this.resetTags.bind(this); this.onMetaDesc = this.onMetaDesc.bind(this); this.onSubsUpdated = this.onSubsUpdated.bind(this); this.handleImageChanged = this.handleImageChanged.bind(this); this.handleMuted = this.handleMuted.bind(this); this.handleUnarchive = this.handleUnarchive.bind(this); this.handlePermissionsChanged = this.handlePermissionsChanged.bind(this); this.handleLaunchPermissionsEditor = this.handleLaunchPermissionsEditor.bind(this); this.handleShowAddMembers = this.handleShowAddMembers.bind(this); this.handleMemberUpdateRequest = this.handleMemberUpdateRequest.bind(this); this.handleMemberSelected = this.handleMemberSelected.bind(this); this.handleContextMenu = this.handleContextMenu.bind(this); this.handleBackNavigate = this.handleBackNavigate.bind(this); } componentDidUpdate(props) { const topic = this.props.tinode.getTopic(props.topic); if (!topic) { return; } if (this.onMetaDesc != topic.onMetaDesc) { this.previousMetaDesc = topic.onMetaDesc; topic.onMetaDesc = this.onMetaDesc; this.previousSubsUpdated = topic.onSubsUpdated; topic.onSubsUpdated = this.onSubsUpdated; } if (this.state.topic != props.topic) { this.setState({ topic: props.topic }); this.resetDesc(topic, props); this.resetSubs(topic, props); this.resetTags(topic); } } componentWillUnmount() { const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } this.setState({ topic: null }); topic.onMetaDesc = this.previousMetaDesc; topic.onSubsUpdated = this.previousSubsUpdated; } resetSubs(topic, props) { const newState = { contactList: [] }; if (topic.getType() == 'p2p') { const user2 = topic.subscriber(props.topic); if (user2) { newState.modeGiven2 = user2.acs.getGiven(); newState.modeWant2 = user2.acs.getWant(); } else { newState.modeGiven2 = _config_js__WEBPACK_IMPORTED_MODULE_13__.NO_ACCESS_MODE; newState.modeWant2 = _config_js__WEBPACK_IMPORTED_MODULE_13__.NO_ACCESS_MODE; } } else { topic.subscribers(sub => { newState.contactList.push(sub); }, this); } this.setState(newState); } resetDesc(topic, props) { const defacs = topic.getDefaultAccess() || {}; const acs = topic.getAccessMode(); const badges = []; if (topic.trusted) { for (const [key, val] of Object.entries(topic.trusted)) { if (val) { badges.push(key); } } } this.setState({ owner: acs && acs.isOwner(), admin: acs && acs.isAdmin(), sharer: acs && acs.isSharer(), deleter: acs && acs.isDeleter(), muted: acs && acs.isMuted(), fullName: (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_15__.clipStr)(topic.public && topic.public.fn, _config_js__WEBPACK_IMPORTED_MODULE_13__.MAX_TITLE_LENGTH), description: (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_15__.clipStr)(topic.public && topic.public.note, _config_js__WEBPACK_IMPORTED_MODULE_13__.MAX_TOPIC_DESCRIPTION_LENGTH), avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_14__.makeImageUrl)(topic.public ? topic.public.photo : null), trustedBadges: badges, private: (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_15__.clipStr)(topic.private && topic.private.comment, _config_js__WEBPACK_IMPORTED_MODULE_13__.MAX_TITLE_LENGTH), archived: topic.isArchived(), address: topic.name, groupTopic: topic.isGroupType(), channel: topic.isChannelType() || topic.chan, access: acs ? acs.getMode() : undefined, modeGiven: acs ? acs.getGiven() : undefined, modeWant: acs ? acs.getWant() : undefined, auth: defacs.auth, anon: defacs.anon }); } resetTags(topic) { if (topic.getType() != 'grp') { return; } const acs = topic.getAccessMode(); if (acs && acs.isOwner()) { topic.getMeta(topic.startMetaQuery().withTags().build()); } } onMetaDesc(desc) { const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } this.resetDesc(topic, this.props); if (this.previousMetaDesc && this.previousMetaDesc != this.onMetaDesc) { this.previousMetaDesc(desc); } } onSubsUpdated(subs) { const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } this.resetSubs(topic, this.props); if (this.previousSubsUpdated && this.previousSubsUpdated != this.onSubsUpdated) { this.previousSubsUpdated(subs); } } handleImageChanged(img) { this.setState({ avatar: img }); this.props.onTopicDescUpdate(this.props.topic, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_15__.theCard)(null, img || tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.DEL_CHAR), null); } handleMuted(ignored, checked) { this.setState({ muted: checked }); this.props.onChangePermissions(this.props.topic, checked ? '-P' : '+P'); } handleUnarchive(ignored, ignored2) { this.props.onTopicUnArchive(this.props.topic); } handlePermissionsChanged(which, perm) { switch (which) { case 'auth': this.props.onTopicDescUpdateRequest(this.props.topic, null, null, { auth: perm }); break; case 'anon': this.props.onTopicDescUpdateRequest(this.props.topic, null, null, { anon: perm }); break; case 'mode': case 'want': this.props.onChangePermissions(this.props.topic, perm); break; case 'given': this.props.onChangePermissions(this.props.topic, perm, this.props.topic); break; case 'user': this.props.onChangePermissions(this.props.topic, perm, this.state.userPermissionsEdited); break; } this.handleBackNavigate(); } handleLaunchPermissionsEditor(which, uid) { const { formatMessage } = this.props.intl; let toEdit, toCompare, toSkip, titleEdit, titleCompare, userTitle, userAvatar; switch (which) { case 'mode': toEdit = this.state.access; break; case 'want': toEdit = this.state.modeWant; toCompare = this.state.modeGiven; if (this.state.owner) { toSkip = 'O'; } else { toSkip = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.AccessMode.encode(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.AccessMode.diff('ASDO', this.state.modeGiven)); if (this.state.channel) { toSkip += 'W'; } } titleEdit = formatMessage(messages.perm_want); titleCompare = formatMessage(messages.perm_given); break; case 'given': toEdit = this.state.modeGiven2; toCompare = this.state.modeWant2; toSkip = this.state.groupTopic ? this.state.owner ? '' : 'O' : 'ASDO'; titleEdit = formatMessage(messages.perm_given); titleCompare = formatMessage(messages.perm_want); break; case 'auth': toEdit = this.state.auth; toSkip = 'O'; break; case 'anon': toEdit = this.state.anon; toSkip = 'O'; break; case 'user': { const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } const user = topic.subscriber(uid); if (!user || !user.acs) { return; } toEdit = user.acs.getGiven(); toCompare = user.acs.getWant(); toSkip = this.state.owner ? '' : 'O'; titleEdit = formatMessage(messages.perm_given); titleCompare = formatMessage(messages.perm_want); if (user.public) { userTitle = user.public.fn; userAvatar = user.public.photo; } break; } default: console.error("Unknown permission editing mode '" + which + "'"); return; } this.setState({ userPermissionsEdited: uid, userPermissionsTitle: userTitle, userPermissionsAvatar: userAvatar, editedPermissions: toEdit, immutablePermissions: toCompare, editedPermissionsTitle: titleEdit, immutablePermissionsTitle: titleCompare, editedPermissionsSkipped: toSkip }); this.props.onNavigate("perm/".concat(which)); } handleShowAddMembers(e) { e.preventDefault(); this.props.onInitFind(); this.props.onNavigate('members'); } handleMemberUpdateRequest(members, added, removed) { this.props.onMemberUpdateRequest(this.props.topic, added, removed); this.props.onNavigate('info'); } handleMemberSelected(uid) { this.setState({ selectedContact: uid }); } handleBackNavigate() { const args = (this.props.panel || 'info').split('/'); if (args[0] == 'info') { this.props.onNavigate(null); } else if (args[0] == 'perm') { if (args[1] == 'user') { this.props.onNavigate('info'); } else { this.props.onNavigate('security'); } } else { this.props.onNavigate('info'); } } handleContextMenu(params) { const { formatMessage } = this.props.intl; const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } const user = topic.subscriber(params.topicName); if (!user || !user.acs) { return; } const isMe = this.props.tinode.isMe(params.topicName); const menuItems = [{ title: formatMessage(messages.edit_permissions), handler: () => { this.handleLaunchPermissionsEditor(isMe ? 'want' : 'user', params.topicName); } }]; if (!isMe) { menuItems.push('member_delete'); } menuItems.push(user.acs.isMuted() ? 'member_unmute' : 'member_mute'); if (!isMe) { menuItems.push(user.acs.isJoiner() ? 'member_block' : 'member_unblock'); } this.props.showContextMenu({ topicName: this.props.topic, x: params.x, y: params.y, user: params.topicName }, menuItems); } render() { const args = (this.props.panel || 'info').split('/'); const view = args[0]; args.shift(); const { formatMessage } = this.props.intl; const panelTitle = formatMessage((view == 'perm' ? messages['perm_' + args[0]] : messages[view]) || messages['info']); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "info-view" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "caption-panel", id: "info-caption-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-title", id: "info-title" }, panelTitle), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_menu_cancel_jsx__WEBPACK_IMPORTED_MODULE_9__["default"], { onCancel: this.handleBackNavigate }))), this.props.displayMobile ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_7__["default"], { level: this.props.errorLevel, text: this.props.errorText, onClearError: this.props.onError }) : null, view == 'members' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_group_manager_jsx__WEBPACK_IMPORTED_MODULE_8__["default"], { tinode: this.props.tinode, members: this.state.contactList, requiredMember: this.props.myUserId, keepInitialMembers: !this.state.admin && !this.state.owner, myUserId: this.props.myUserId, contacts: this.props.searchableContacts, onCancel: this.handleBackNavigate, onSubmit: this.handleMemberUpdateRequest }) : view == 'perm' && args.length > 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_permissions_editor_jsx__WEBPACK_IMPORTED_MODULE_10__["default"], { tinode: this.props.tinode, mode: this.state.editedPermissions, compare: this.state.immutablePermissions, skip: this.state.editedPermissionsSkipped, modeTitle: this.state.editedPermissionsTitle, compareTitle: this.state.immutablePermissionsTitle, userTitle: this.state.userPermissionsTitle, item: this.state.userPermissionsEdited, userAvatar: this.state.userPermissionsAvatar, onSubmit: mode => this.handlePermissionsChanged(args[0], mode), onCancel: this.handleBackNavigate }) : view == 'general' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_topic_common_jsx__WEBPACK_IMPORTED_MODULE_11__["default"], { tinode: this.props.tinode, topic: this.props.topic, onCredAdd: this.props.onCredAdd, onTopicTagsUpdateRequest: this.props.onTopicTagsUpdateRequest, onCredConfirm: this.props.onCredConfirm, onCredDelete: this.props.onCredDelete, onUpdateTopicDesc: this.props.onTopicDescUpdateRequest, onError: this.props.onError }) : view == 'security' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_topic_security_jsx__WEBPACK_IMPORTED_MODULE_12__["default"], { topic: this.props.topic, owner: this.state.owner, admin: this.state.admin, sharer: this.state.sharer, deleter: this.state.deleter, muted: this.state.muted, groupTopic: this.state.groupTopic, channel: this.state.channel, access: this.state.access, modeGiven: this.state.modeGiven, modeWant: this.state.modeWant, modeGiven2: this.state.modeGiven2, modeWant2: this.state.modeWant2, auth: this.state.auth, anon: this.state.anon, onShowAlert: this.props.onShowAlert, onDeleteMessages: this.props.onDeleteMessages, onLeaveTopic: this.props.onLeaveTopic, onBlockTopic: this.props.onBlockTopic, onReportTopic: this.props.onReportTopic, onLaunchPermissionsEditor: this.handleLaunchPermissionsEditor, onNavigate: this.props.onNavigate }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "info-view-content", className: "scrollable-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "flat-button float-right", onClick: e => { e.preventDefault(); this.props.onNavigate('general'); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "edit"), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_edit", defaultMessage: [{ "type": 0, "value": "Edit" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("center", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, avatar: this.state.avatar, readOnly: true, uid: this.props.topic, title: this.state.fullName })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_topic_name", defaultMessage: [{ "type": 0, "value": "Name" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "large ellipsized" }, this.state.fullName, this.state.channel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { src: "/img/channel.png", className: "channel", alt: "channel" }) : null)), this.state.private ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_private", defaultMessage: [{ "type": 0, "value": "Private comment" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "large ellipsized" }, this.state.private)) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_user_id", defaultMessage: [{ "type": 0, "value": "ID:" }] })), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", null, this.state.address)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_badge_list_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { trustedBadges: this.state.trustedBadges })), this.state.description ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_description", defaultMessage: [{ "type": 0, "value": "Description" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, this.state.description)) : null), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_muting_topic", defaultMessage: [{ "type": 0, "value": "Muted:" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { name: "P", checked: this.state.muted, onChange: this.handleMuted })), this.state.archived ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_unarchive_topic", defaultMessage: [{ "type": 0, "value": "Archived:" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { name: "archived", checked: true, onChange: this.handleUnarchive })) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "flat-button", onClick: e => { e.preventDefault(); this.props.onNavigate('security'); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "security"), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_security", defaultMessage: [{ "type": 0, "value": "Security" }] }))), this.state.groupTopic && this.state.sharer ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_group_members", defaultMessage: [{ "type": 0, "value": "Group members:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "flat-button", onClick: this.handleShowAddMembers }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "person_add"), " \xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_add_members", defaultMessage: [{ "type": 0, "value": "Add members" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "group_has_no_members", defaultMessage: [{ "type": 0, "value": "No members" }] }, no_members => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_contact_list_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], { tinode: this.props.tinode, contacts: this.state.contactList, myUserId: this.props.myUserId, emptyListMessage: no_members, topicSelected: this.state.selectedContact, showOnline: false, showUnread: false, showMode: true, noScroll: true, onTopicSelected: this.handleMemberSelected, showContextMenu: this.state.admin ? this.handleContextMenu : false }))) : null)); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(InfoView)); /***/ }), /***/ "./src/views/login-view.jsx": /*!**********************************!*\ !*** ./src/views/login-view.jsx ***! \**********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ LoginView) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/checkbox.jsx */ "./src/widgets/checkbox.jsx"); /* harmony import */ var _widgets_visible_password_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/visible-password.jsx */ "./src/widgets/visible-password.jsx"); /* harmony import */ var _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/local-storage.js */ "./src/lib/local-storage.js"); class LoginView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { login: props.login, password: '', hostName: props.serverAddress, saveToken: props.persist }; this.handleLoginChange = this.handleLoginChange.bind(this); this.handlePasswordChange = this.handlePasswordChange.bind(this); this.handleToggleSaveToken = this.handleToggleSaveToken.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleLoginChange(e) { this.setState({ login: e.target.value }); } handlePasswordChange(e) { this.setState({ password: e.target.value }); } handleToggleSaveToken() { this.props.onPersistenceChange(!this.state.saveToken); this.setState({ saveToken: !this.state.saveToken }); } handleSubmit(e) { e.preventDefault(); this.props.onLogin(this.state.login.trim(), this.state.password.trim()); } render() { let submitClasses = 'primary'; if (this.props.disabled) { submitClasses += ' disabled'; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("form", { id: "login-form", onSubmit: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "login_prompt", defaultMessage: [{ "type": 0, "value": "Login" }] }, login_prompt => react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", id: "inputLogin", placeholder: login_prompt, autoComplete: "username", autoCorrect: "off", autoCapitalize: "none", value: this.state.login, onChange: this.handleLoginChange, required: true, autoFocus: true })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "password_prompt", defaultMessage: [{ "type": 0, "value": "Password" }] }, password_prompt => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_visible_password_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { type: "password", id: "inputPassword", placeholder: password_prompt, autoComplete: "current-password", value: this.state.password, onChange: this.handlePasswordChange, required: true })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { id: "save-token", name: "save-token", checked: this.state.saveToken, onChange: this.handleToggleSaveToken }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { htmlFor: "save-token" }, "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "stay_logged_in", defaultMessage: [{ "type": 0, "value": "Stay logged in" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#reset" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "forgot_password_link", defaultMessage: [{ "type": 0, "value": "Forgot password?" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "dialog-buttons" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: submitClasses, type: "submit" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_sign_in", defaultMessage: [{ "type": 0, "value": "Sign in" }] })))); } } ; /***/ }), /***/ "./src/views/logo-view.jsx": /*!*********************************!*\ !*** ./src/views/logo-view.jsx ***! \*********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ LogoView) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); class LogoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { const version = _config_js__WEBPACK_IMPORTED_MODULE_3__.APP_NAME + ' (' + tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.getLibrary() + ')'; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "dummy-view" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "https://github.com/tinode/chat/" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { id: "logo", alt: "logo", src: "img/logo.svg" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("h2", null, "Tinode Web")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("p", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_client", defaultMessage: [{ "type": 0, "value": "Client:" }] }), " ", version), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("p", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_server", defaultMessage: [{ "type": 0, "value": "Server:" }] }), " ", this.props.serverVersion, " (", this.props.serverAddress, ")"))); } } ; /***/ }), /***/ "./src/views/messages-view.jsx": /*!*************************************!*\ !*** ./src/views/messages-view.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _widgets_call_panel_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/call-panel.jsx */ "./src/widgets/call-panel.jsx"); /* harmony import */ var _widgets_chat_message_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../widgets/chat-message.jsx */ "./src/widgets/chat-message.jsx"); /* harmony import */ var _widgets_contact_badges_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../widgets/contact-badges.jsx */ "./src/widgets/contact-badges.jsx"); /* harmony import */ var _widgets_doc_preview_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../widgets/doc-preview.jsx */ "./src/widgets/doc-preview.jsx"); /* harmony import */ var _widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../widgets/error-panel.jsx */ "./src/widgets/error-panel.jsx"); /* harmony import */ var _widgets_group_subs_jsx__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../widgets/group-subs.jsx */ "./src/widgets/group-subs.jsx"); /* harmony import */ var _widgets_image_preview_jsx__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../widgets/image-preview.jsx */ "./src/widgets/image-preview.jsx"); /* harmony import */ var _widgets_invitation_jsx__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../widgets/invitation.jsx */ "./src/widgets/invitation.jsx"); /* harmony import */ var _widgets_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../widgets/letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _widgets_load_spinner_jsx__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../widgets/load-spinner.jsx */ "./src/widgets/load-spinner.jsx"); /* harmony import */ var _logo_view_jsx__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./logo-view.jsx */ "./src/views/logo-view.jsx"); /* harmony import */ var _widgets_meta_message_jsx__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../widgets/meta-message.jsx */ "./src/widgets/meta-message.jsx"); /* harmony import */ var _widgets_send_message_jsx__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../widgets/send-message.jsx */ "./src/widgets/send-message.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../constants.js */ "./src/constants.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); const NOTIFICATION_EXEC_INTERVAL = 300; const SHOW_GO_TO_LAST_DIST = 100; const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ online_now: { id: "online_now", defaultMessage: [{ "type": 0, "value": "online now" }] }, last_seen: { id: "last_seen_timestamp", defaultMessage: [{ "type": 0, "value": "Last seen" }] }, not_found: { id: "title_not_found", defaultMessage: [{ "type": 0, "value": "Not found" }] }, channel: { id: "channel", defaultMessage: [{ "type": 0, "value": "channel" }] }, file_attachment_too_large: { id: "file_attachment_too_large", defaultMessage: [{ "type": 0, "value": "The file size " }, { "type": 1, "value": "size" }, { "type": 0, "value": " exceeds the " }, { "type": 1, "value": "limit" }, { "type": 0, "value": " limit." }] }, invalid_content: { id: "invalid_content", defaultMessage: [{ "type": 0, "value": "invalid content" }] } }); function isUnconfirmed(acs) { if (acs) { const ex = acs.getExcessive() || ''; return acs.isJoiner('given') && (ex.includes('R') || ex.includes('W')); } return false; } function isPeerRestricted(acs) { if (acs) { const ms = acs.getMissing() || ''; return acs.isJoiner('want') && (ms.includes('R') || ms.includes('W')); } return false; } function shouldPresentCallPanel(callState) { return callState == _constants_js__WEBPACK_IMPORTED_MODULE_17__.CALL_STATE_OUTGOING_INITATED || callState == _constants_js__WEBPACK_IMPORTED_MODULE_17__.CALL_STATE_IN_PROGRESS; } class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = MessagesView.getDerivedStateFromProps(props, {}); this.leave = this.leave.bind(this); this.sendMessage = this.sendMessage.bind(this); this.retrySend = this.retrySend.bind(this); this.sendImageAttachment = this.sendImageAttachment.bind(this); this.sendFileAttachment = this.sendFileAttachment.bind(this); this.sendAudioAttachment = this.sendAudioAttachment.bind(this); this.sendKeyPress = this.sendKeyPress.bind(this); this.subscribe = this.subscribe.bind(this); this.handleScrollReference = this.handleScrollReference.bind(this); this.handleScrollEvent = this.handleScrollEvent.bind(this); this.handleDescChange = this.handleDescChange.bind(this); this.handleSubsUpdated = this.handleSubsUpdated.bind(this); this.handleMessageUpdate = this.handleMessageUpdate.bind(this); this.handleAllMessagesReceived = this.handleAllMessagesReceived.bind(this); this.handleInfoReceipt = this.handleInfoReceipt.bind(this); this.handleImagePostview = this.handleImagePostview.bind(this); this.handleClosePreview = this.handleClosePreview.bind(this); this.handleFormResponse = this.handleFormResponse.bind(this); this.handleContextClick = this.handleContextClick.bind(this); this.handleShowMessageContextMenu = this.handleShowMessageContextMenu.bind(this); this.handleNewChatAcceptance = this.handleNewChatAcceptance.bind(this); this.handleEnablePeer = this.handleEnablePeer.bind(this); this.handleAttachFile = this.handleAttachFile.bind(this); this.handleAttachImage = this.handleAttachImage.bind(this); this.handleCancelUpload = this.handleCancelUpload.bind(this); this.postReadNotification = this.postReadNotification.bind(this); this.clearNotificationQueue = this.clearNotificationQueue.bind(this); this.goToLatestMessage = this.goToLatestMessage.bind(this); this.handlePickReply = this.handlePickReply.bind(this); this.handleCancelReply = this.handleCancelReply.bind(this); this.handleQuoteClick = this.handleQuoteClick.bind(this); this.handleCallHangup = this.handleCallHangup.bind(this); this.chatMessageRefs = {}; this.getOrCreateMessageRef = this.getOrCreateMessageRef.bind(this); this.readNotificationQueue = []; this.readNotificationTimer = null; } getOrCreateMessageRef(seqId) { if (this.chatMessageRefs.hasOwnProperty(seqId)) { return this.chatMessageRefs[seqId]; } const ref = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.chatMessageRefs[seqId] = ref; return ref; } componentDidMount() { if (this.messagesScroller) { this.messagesScroller.addEventListener('scroll', this.handleScrollEvent); } } componentWillUnmount() { if (this.messagesScroller) { this.messagesScroller.removeEventListener('scroll', this.handleScrollEvent); } this.clearNotificationQueue(); } componentDidUpdate(prevProps, prevState) { if (this.messagesScroller && (prevState.topic != this.state.topic || prevState.messageCount != this.state.messageCount)) { if (this.state.scrollPosition < SHOW_GO_TO_LAST_DIST) { this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.state.scrollPosition - this.messagesScroller.offsetHeight; } } const topic = this.props.tinode ? this.props.tinode.getTopic(this.state.topic) : undefined; if (this.state.topic != prevState.topic) { if (prevState.topic && !tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isNewGroupTopicName(prevState.topic)) { this.leave(prevState.topic); if (prevState.rtcPanel) { this.handleCallHangup(prevState.topic, prevProps.callSeq); } } if (topic) { topic.onData = this.handleMessageUpdate; topic.onAllMessagesReceived = this.handleAllMessagesReceived; topic.onInfo = this.handleInfoReceipt; topic.onMetaDesc = this.handleDescChange; topic.onSubsUpdated = this.handleSubsUpdated; topic.onPres = this.handleSubsUpdated; } } if (!this.props.applicationVisible) { this.clearNotificationQueue(); } else { this.postReadNotification(0); } if (topic && (this.state.topic != prevState.topic || !prevProps.ready)) { if (topic._new && topic.isP2PType()) { topic.getMeta(topic.startMetaQuery().withDesc().build()); } else { this.subscribe(topic); } } } static getDerivedStateFromProps(nextProps, prevState) { let nextState = {}; if (!nextProps.topic) { nextState = { messageCount: 0, latestClearId: -1, onlineSubs: [], topic: null, title: '', avatar: null, isVerified: false, isStaff: false, isDangerous: false, deleted: false, docPreview: null, imagePreview: null, imagePostview: null, rtcPanel: null, typingIndicator: false, scrollPosition: 0, fetchingMessages: false, peerMessagingDisabled: false, channel: false, reply: null, showGoToLastButton: false }; } else if (nextProps.topic != prevState.topic) { const topic = nextProps.tinode.getTopic(nextProps.topic); nextState = { topic: nextProps.topic, docPreview: null, imagePreview: null, imagePostview: null, rtcPanel: null, typingIndicator: false, scrollPosition: 0, fetchingMessages: false, showGoToLastButton: false, deleted: topic._deleted }; if (nextProps.forwardMessage) { nextState.reply = { content: nextProps.forwardMessage.preview, seq: null }; } if (topic) { const subs = []; if (nextProps.connected) { topic.subscribers(sub => { if (sub.online && sub.user != nextProps.myUserId) { subs.push(sub); } }); } Object.assign(nextState, { onlineSubs: subs }); if (topic.public) { Object.assign(nextState, { title: topic.public.fn, avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_18__.makeImageUrl)(topic.public.photo) }); } else { Object.assign(nextState, { title: '', avatar: null }); } const peer = topic.p2pPeerDesc(); if (peer) { Object.assign(nextState, { peerMessagingDisabled: isPeerRestricted(peer.acs) }); } else if (prevState.peerMessagingDisabled) { Object.assign(nextState, { peerMessagingDisabled: false }); } Object.assign(nextState, { messageCount: topic.messageCount(), latestClearId: topic.maxClearId(), channel: topic.isChannelType() }); if (nextProps.callTopic == topic.name && shouldPresentCallPanel(nextProps.callState)) { nextState.rtcPanel = nextProps.callTopic; } } else { Object.assign(nextState, { messageCount: 0, latestClearId: -1, onlineSubs: [], title: '', avatar: null, peerMessagingDisabled: false, channel: false }); } } else { if (nextProps.callTopic == prevState.topic && !prevState.rtcPanel && shouldPresentCallPanel(nextProps.callState)) { nextState.rtcPanel = nextProps.callTopic; } } if (nextProps.acs) { if (nextProps.acs.isWriter() != prevState.isWriter) { nextState.isWriter = !prevState.isWriter; } if (nextProps.acs.isReader() != prevState.isReader) { nextState.isReader = !prevState.isReader; } if (!nextProps.acs.isReader('given') != prevState.readingBlocked) { nextState.readingBlocked = !prevState.readingBlocked; } if (nextProps.acs.isSharer() != prevState.isSharer) { nextState.isSharer = !prevState.isSharer; } } else { if (prevState.isWriter) { nextState.isWriter = false; } if (prevState.isReader) { nextState.isReader = false; } if (!prevState.readingBlocked) { prevState.readingBlocked = true; } if (prevState.isSharer) { nextState.isSharer = false; } } if (isUnconfirmed(nextProps.acs) == !prevState.unconformed) { nextState.unconfirmed = !prevState.unconformed; } if (!nextProps.connected && prevState.onlineSubs && prevState.onlineSubs.length > 0) { nextState.onlineSubs = []; } return nextState; } subscribe(topic) { if (topic.isSubscribed() || !this.props.ready) { return; } const newTopic = this.props.newTopicParams && this.props.newTopicParams._topicName == this.props.topic; let getQuery = topic.startMetaQuery().withLaterDesc().withLaterSub(); if (this.state.isReader || newTopic) { getQuery = getQuery.withLaterData(_config_js__WEBPACK_IMPORTED_MODULE_16__.MESSAGES_PAGE); if (this.state.isReader) { getQuery = getQuery.withLaterDel(); } this.setState({ fetchingMessages: true }); } const setQuery = newTopic ? this.props.newTopicParams : undefined; topic.subscribe(getQuery.build(), setQuery).then(ctrl => { if (ctrl.code == 303) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_19__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_19__["default"].setUrlTopic('', ctrl.params.topic)); return; } if (this.state.topic != ctrl.topic) { this.setState({ topic: ctrl.topic }); } this.props.onNewTopicCreated(this.props.topic, ctrl.topic); topic.queuedMessages(pub => { if (pub._sending) { return; } if (topic.isSubscribed()) { this.retrySend(pub); } }); }).catch(err => { console.error("Failed subscription to", this.state.topic, err); this.props.onError(err.message, 'err'); const blankState = MessagesView.getDerivedStateFromProps({}, {}); blankState.title = this.props.intl.formatMessage(messages.not_found); this.setState(blankState); }); } leave(oldTopicName) { if (!oldTopicName || !this.props.tinode.isTopicCached(oldTopicName)) { return; } const oldTopic = this.props.tinode.getTopic(oldTopicName); if (oldTopic && oldTopic.isSubscribed()) { oldTopic.leave(false).catch(() => {}).finally(() => { this.setState({ fetchingMessages: false }); oldTopic.onData = undefined; oldTopic.onAllMessagesReceived = undefined; oldTopic.onInfo = undefined; oldTopic.onMetaDesc = undefined; oldTopic.onSubsUpdated = undefined; oldTopic.onPres = undefined; }); } } handleScrollReference(node) { if (node) { node.addEventListener('scroll', this.handleScrollEvent); this.messagesScroller = node; this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.state.scrollPosition; } } handleScrollEvent(event) { const pos = event.target.scrollHeight - event.target.scrollTop - event.target.offsetHeight; this.setState({ scrollPosition: pos, showGoToLastButton: pos > SHOW_GO_TO_LAST_DIST && pos < this.state.scrollPosition }); if (this.state.fetchingMessages) { return; } if (event.target.scrollTop <= 0) { const topic = this.props.tinode.getTopic(this.state.topic); if (topic && topic.isSubscribed() && topic.msgHasMoreMessages()) { this.setState({ fetchingMessages: true }, () => { topic.getMessagesPage(_config_js__WEBPACK_IMPORTED_MODULE_16__.MESSAGES_PAGE).catch(err => this.props.onError(err.message, 'err')).finally(() => this.setState({ fetchingMessages: false })); }); } } } goToLatestMessage() { this.setState({ scrollPosition: 0 }); if (this.messagesScroller) { this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight; } } handleDescChange(desc) { if (desc.public) { this.setState({ title: desc.public.fn, avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_18__.makeImageUrl)(desc.public.photo) }); } else { this.setState({ title: '', avatar: null }); } if (desc.acs) { this.setState({ isWriter: desc.acs.isWriter(), isReader: desc.acs.isReader(), readingBlocked: !desc.acs.isReader('given'), unconfirmed: isUnconfirmed(desc.acs) }); } } postReadNotification(seq) { if (!this.props.applicationVisible) { return; } if (!this.readNotificationTimer) { this.readNotificationTimer = setInterval(() => { if (this.readNotificationQueue.length == 0) { clearInterval(this.readNotificationTimer); this.readNotificationTimer = null; return; } let seq = -1; while (this.readNotificationQueue.length > 0) { const n = this.readNotificationQueue[0]; if (n.topicName != this.state.topic) { this.readNotificationQueue.shift(); continue; } const now = new Date(); if (n.sendAt <= now) { this.readNotificationQueue.shift(); seq = Math.max(seq, n.seq); } else { break; } } if (seq >= 0) { const topic = this.props.tinode.getTopic(this.state.topic); if (topic) { topic.noteRead(seq); } } }, NOTIFICATION_EXEC_INTERVAL); } const now = new Date(); this.readNotificationQueue.push({ topicName: this.state.topic, seq: seq, sendAt: now.setMilliseconds(now.getMilliseconds() + _config_js__WEBPACK_IMPORTED_MODULE_16__.READ_DELAY) }); } clearNotificationQueue() { this.readNotificationQueue = []; if (this.readNotificationTimer) { clearInterval(this.readNotificationTimer); this.readNotificationTimer = null; } } handleSubsUpdated() { if (this.state.topic) { const subs = []; const topic = this.props.tinode.getTopic(this.state.topic); topic.subscribers(sub => { if (sub.online && sub.user != this.props.myUserId) { subs.push(sub); } }); const newState = { onlineSubs: subs }; const peer = topic.p2pPeerDesc(); if (peer) { Object.assign(newState, { peerMessagingDisabled: isPeerRestricted(peer.acs) }); } else if (this.state.peerMessagingDisabled) { Object.assign(newState, { peerMessagingDisabled: false }); } this.setState(newState); } } handleMessageUpdate(msg) { const topic = this.props.tinode.getTopic(this.state.topic); if (!msg) { this.setState({ latestClearId: topic.maxClearId() }); return; } clearTimeout(this.keyPressTimer); this.setState({ messageCount: topic.messageCount(), typingIndicator: false }); if (topic.isNewMessage(msg.seq)) { if (this.state.scrollPosition > SHOW_GO_TO_LAST_DIST) { this.setState({ showGoToLastButton: true }); } else { this.setState({ scrollPosition: 0 }); } } const status = topic.msgStatus(msg, true); if (status >= tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_SENT && msg.from != this.props.myUserId) { this.postReadNotification(msg.seq); } this.props.onData(msg); } handleAllMessagesReceived(count) { this.setState({ fetchingMessages: false }); if (count > 0) { this.postReadNotification(0); } } handleInfoReceipt(info) { switch (info.what) { case 'kp': { clearTimeout(this.keyPressTimer); this.keyPressTimer = setTimeout(() => { this.setState({ typingIndicator: false }); }, _config_js__WEBPACK_IMPORTED_MODULE_16__.KEYPRESS_DELAY + 1000); if (!this.state.typingIndicator) { this.setState({ typingIndicator: true }); } break; } case 'read': case 'recv': this.forceUpdate(); break; default: console.info("Other change in topic: ", info.what); } } handleImagePostview(content) { this.setState({ imagePostview: content }); } handleClosePreview() { if (this.state.imagePreview && this.state.imagePreview.url) { URL.revokeObjectURL(this.state.imagePreview.url); } this.setState({ imagePostview: null, imagePreview: null, docPreview: null }); } handleFormResponse(action, text, data) { if (action == 'pub') { this.sendMessage(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attachJSON(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.parse(text), data)); } else if (action == 'url') { const url = new URL(data.ref); const params = url.searchParams; for (let key in data.resp) { if (data.resp.hasOwnProperty(key)) { params.set(key, data.resp[key]); } } ['name', 'seq'].map(key => { if (data[key]) { params.set(key, data[key]); } }); params.set('uid', this.props.myUserId); params.set('topic', this.state.topic); url.search = params; window.open(url, '_blank'); } else { console.info("Unknown action in form", action); } } handleContextClick(e) { e.preventDefault(); e.stopPropagation(); this.props.showContextMenu({ topicName: this.state.topic, y: e.pageY, x: e.pageX }); } handleShowMessageContextMenu(params, messageSpecificMenuItems) { if (params.userFrom == 'chan') { params.userFrom = this.state.topic; params.userName = this.state.title; } params.topicName = this.state.topic; const menuItems = messageSpecificMenuItems || []; const topic = this.props.tinode.getTopic(params.topicName); if (topic) { if (!topic.isChannelType()) { menuItems.push('message_delete'); } const acs = topic.getAccessMode(); if (acs && acs.isDeleter()) { menuItems.push('message_delete_hard'); } } this.props.showContextMenu(params, menuItems); } handleNewChatAcceptance(action) { this.props.onNewChat(this.state.topic, action); } handleEnablePeer(e) { e.preventDefault(); this.props.onChangePermissions(this.state.topic, _config_js__WEBPACK_IMPORTED_MODULE_16__.DEFAULT_P2P_ACCESS_MODE, this.state.topic); } sendKeyPress() { const topic = this.props.tinode.getTopic(this.state.topic); if (topic.isSubscribed()) { topic.noteKeyPress(); } } sendMessage(msg, uploadCompletionPromise, uploader) { let head; if (this.props.forwardMessage) { msg = this.props.forwardMessage.msg; head = this.props.forwardMessage.head; this.handleCancelReply(); } else if (this.state.reply && this.state.reply.content) { head = { reply: '' + this.state.reply.seq }; if (typeof msg == 'string') { msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.parse(msg); } msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.append(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.sanitizeEntities(this.state.reply.content), msg); this.handleCancelReply(); } this.props.sendMessage(msg, uploadCompletionPromise, uploader, head); } retrySend(pub) { this.props.sendMessage(pub.content, undefined, undefined, pub.head); } sendFileAttachment(file) { const maxInbandAttachmentSize = this.props.tinode.getServerLimit('maxMessageSize', _config_js__WEBPACK_IMPORTED_MODULE_16__.MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024 | 0; if (file.size > maxInbandAttachmentSize) { const uploader = this.props.tinode.getLargeFileHelper(); if (!uploader) { this.props.onError(this.props.intl.formatMessage(messages.cannot_initiate_upload)); return; } const uploadCompletionPromise = uploader.upload(file); const msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attachFile(null, { mime: file.type, filename: file.name, size: file.size, urlPromise: uploadCompletionPromise }); this.sendMessage(msg, uploadCompletionPromise, uploader); } else { (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_18__.fileToBase64)(file).then(b64 => this.sendMessage(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attachFile(null, { mime: b64.mime, data: b64.bits, filename: b64.name }))).catch(err => this.props.onError(err)); } } handleAttachFile(file) { const maxExternAttachmentSize = this.props.tinode.getServerLimit('maxFileUploadSize', _config_js__WEBPACK_IMPORTED_MODULE_16__.MAX_EXTERN_ATTACHMENT_SIZE); if (file.size > maxExternAttachmentSize) { this.props.onError(this.props.intl.formatMessage(messages.file_attachment_too_large, { size: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_20__.bytesToHumanSize)(file.size), limit: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_20__.bytesToHumanSize)(maxExternAttachmentSize) }), 'err'); } else { this.setState({ docPreview: { file: file, name: file.name, size: file.size, type: file.type } }); } } handleCallHangup(topic, seq) { this.props.onVideoCallClosed(); this.setState({ rtcPanel: null }); this.props.onCallHangup(topic, seq); } sendImageAttachment(caption, blob) { const mime = this.state.imagePreview.mime; const width = this.state.imagePreview.width; const height = this.state.imagePreview.height; const fname = this.state.imagePreview.name; const maxInbandAttachmentSize = this.props.tinode.getServerLimit('maxMessageSize', _config_js__WEBPACK_IMPORTED_MODULE_16__.MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024 | 0; if (blob.size > maxInbandAttachmentSize) { const uploader = this.props.tinode.getLargeFileHelper(); if (!uploader) { this.props.onError(this.props.intl.formatMessage(messages.cannot_initiate_upload)); return; } const uploadCompletionPromise = uploader.upload(blob); (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_18__.imageScaled)(blob, _config_js__WEBPACK_IMPORTED_MODULE_16__.IMAGE_PREVIEW_DIM, _config_js__WEBPACK_IMPORTED_MODULE_16__.IMAGE_PREVIEW_DIM, -1, false).then(scaled => (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_18__.blobToBase64)(scaled.blob)).then(b64 => { let msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.insertImage(null, 0, { mime: mime, _tempPreview: b64.bits, width: width, height: height, filename: fname, size: blob.size, urlPromise: uploadCompletionPromise }); if (caption) { msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendLineBreak(msg); msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.append(msg, tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.parse(caption)); } this.sendMessage(msg, uploadCompletionPromise, uploader); }).catch(err => { this.props.onError(err, 'err'); }); return; } (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_18__.blobToBase64)(blob).then(b64 => { let msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.insertImage(null, 0, { mime: b64.mime, preview: b64.bits, width: width, height: height, filename: fname, size: blob.size }); if (caption) { msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendLineBreak(msg); msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.append(msg, tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.parse(caption)); } this.sendMessage(msg); }); } handleAttachImage(file) { const maxExternAttachmentSize = this.props.tinode.getServerLimit('maxFileUploadSize', _config_js__WEBPACK_IMPORTED_MODULE_16__.MAX_EXTERN_ATTACHMENT_SIZE); (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_18__.imageScaled)(file, _config_js__WEBPACK_IMPORTED_MODULE_16__.MAX_IMAGE_DIM, _config_js__WEBPACK_IMPORTED_MODULE_16__.MAX_IMAGE_DIM, maxExternAttachmentSize, false).then(scaled => { this.setState({ imagePreview: { url: URL.createObjectURL(scaled.blob), blob: scaled.blob, name: scaled.name, width: scaled.width, height: scaled.height, size: scaled.blob.size, mime: scaled.mime } }); }).catch(err => { this.props.onError(err, 'err'); }); } sendAudioAttachment(url, preview, duration) { fetch(url).then(result => result.blob()).then(blob => { const maxInbandAttachmentSize = this.props.tinode.getServerLimit('maxMessageSize', _config_js__WEBPACK_IMPORTED_MODULE_16__.MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024; if (blob.size > maxInbandAttachmentSize) { const uploader = this.props.tinode.getLargeFileHelper(); if (!uploader) { this.props.onError(this.props.intl.formatMessage(messages.cannot_initiate_upload)); return; } const uploadCompletionPromise = uploader.upload(blob); const msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendAudio(null, { mime: blob.type, size: blob.size, duration: duration, preview: preview, urlPromise: uploadCompletionPromise }); this.sendMessage(msg, uploadCompletionPromise, uploader); } else { (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_18__.blobToBase64)(blob).then(b64 => { this.sendMessage(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendAudio(null, { mime: b64.mime, size: blob.size, data: b64.bits, duration: duration, preview: preview })); }); } }).catch(err => { this.props.onError(err); }); ; } handleCancelUpload(seq, uploader) { const topic = this.props.tinode.getTopic(this.state.topic); const found = topic.findMessage(seq); if (found) { found._cancelled = true; } uploader.cancel(); } handlePickReply(seq, content, senderId, senderName) { this.setState({ reply: null }); if (!seq || !content) { return; } content = typeof content == 'string' ? tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.init(content) : content; if (tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isValid(content)) { content = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.replyContent(content, _config_js__WEBPACK_IMPORTED_MODULE_16__.QUOTED_REPLY_LENGTH); } else { content = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.append(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.init('\u26A0 '), tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.wrapInto(this.props.intl.formatMessage(messages.invalid_content), 'EM')); } this.setState({ reply: { content: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.quote(senderName, senderId, content), seq: seq } }); this.props.onCancelForwardMessage(); } handleCancelReply() { this.setState({ reply: null }); this.props.onCancelForwardMessage(); } handleQuoteClick(replyToSeq) { const ref = this.getOrCreateMessageRef(replyToSeq); if (ref && ref.current) { ref.current.scrollIntoView({ block: "center", behavior: "smooth" }); ref.current.classList.add('flash'); setTimeout(() => { ref.current.classList.remove('flash'); }, 1000); } else { console.error("Unresolved message ref", replyToSeq); } } render() { const { formatMessage } = this.props.intl; let component; if (this.props.hideSelf) { component = null; } else if (!this.state.topic) { component = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_logo_view_jsx__WEBPACK_IMPORTED_MODULE_13__["default"], { serverVersion: this.props.serverVersion, serverAddress: this.props.serverAddress }); } else { let component2; if (this.state.imagePreview) { component2 = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_image_preview_jsx__WEBPACK_IMPORTED_MODULE_9__["default"], { content: this.state.imagePreview, tinode: this.props.tinode, reply: this.state.reply, onCancelReply: this.handleCancelReply, onClose: this.handleClosePreview, onSendMessage: this.sendImageAttachment }); } else if (this.state.imagePostview) { component2 = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_image_preview_jsx__WEBPACK_IMPORTED_MODULE_9__["default"], { content: this.state.imagePostview, onClose: this.handleClosePreview }); } else if (this.state.docPreview) { component2 = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_doc_preview_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], { content: this.state.docPreview, tinode: this.props.tinode, reply: this.state.reply, onCancelReply: this.handleCancelReply, onClose: this.handleClosePreview, onSendMessage: this.sendFileAttachment }); } else if (this.state.rtcPanel) { component2 = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_call_panel_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { topic: this.state.topic, seq: this.props.callSeq, callState: this.props.callState, tinode: this.props.tinode, title: this.state.title, avatar: this.state.avatar || true, onError: this.props.onError, onHangup: this.handleCallHangup, onInvite: this.props.onCallInvite, onSendOffer: this.props.onCallSendOffer, onIceCandidate: this.props.onCallIceCandidate, onSendAnswer: this.props.onCallSendAnswer }); } else { const topic = this.props.tinode.getTopic(this.state.topic); const isChannel = topic.isChannelType(); const groupTopic = topic.isGroupType() && !isChannel; const icon_badges = []; if (topic.trusted) { if (topic.trusted.verified) { icon_badges.push({ icon: 'verified', color: 'badge-inv' }); } if (topic.trusted.staff) { icon_badges.push({ icon: 'staff', color: 'badge-inv' }); } if (topic.trusted.danger) { icon_badges.push({ icon: 'dangerous', color: 'badge-inv' }); } } const messageNodes = []; let previousFrom = null; let prevDate = null; let chatBoxClass = null; const dateFmt = new Intl.DateTimeFormat(this.props.intl.locale); topic.messages((msg, prev, next, i) => { let nextFrom = next ? next.from || 'chan' : null; let sequence = 'single'; let thisFrom = msg.from || 'chan'; if (thisFrom == previousFrom) { if (thisFrom == nextFrom) { sequence = 'middle'; } else { sequence = 'last'; } } else if (thisFrom == nextFrom) { sequence = 'first'; } previousFrom = thisFrom; const isReply = !(thisFrom == this.props.myUserId); const deliveryStatus = topic.msgStatus(msg, true); let userFrom = thisFrom, userName, userAvatar; const user = topic.userDesc(thisFrom); if (user && user.public) { userName = user.public.fn; userAvatar = (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_18__.makeImageUrl)(user.public.photo); } chatBoxClass = groupTopic ? 'chat-box group' : 'chat-box'; const ref = this.getOrCreateMessageRef(msg.seq); let replyToSeq = msg.head ? parseInt(msg.head.reply) : null; if (!replyToSeq || isNaN(replyToSeq)) { replyToSeq = null; } if (msg.hi) { messageNodes.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_meta_message_jsx__WEBPACK_IMPORTED_MODULE_14__["default"], { deleted: true, key: msg.seq })); } else { const thisDate = new Date(msg.ts); if (!prevDate || prevDate.toDateString() != thisDate.toDateString()) { messageNodes.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_meta_message_jsx__WEBPACK_IMPORTED_MODULE_14__["default"], { date: dateFmt.format(msg.ts), locale: this.props.intl.locale, key: 'date-' + msg.seq })); prevDate = thisDate; } let duration; if (msg.head && (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_21__.isVideoCall)(msg.head.mime)) { topic.messageVersions(msg, (cur, before) => { if (cur.content == 'finished' && before.content == 'accepted') { duration = msg.ts - before.ts; } }); } messageNodes.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_chat_message_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { tinode: this.props.tinode, content: msg.content, mimeType: msg.head ? msg.head.mime : null, timestamp: msg.ts, duration: duration, response: isReply, seq: msg.seq, isGroup: groupTopic, isChan: this.state.channel, userFrom: userFrom, userName: userName, userAvatar: userAvatar, sequence: sequence, received: deliveryStatus, uploader: msg._uploader, viewportWidth: this.props.viewportWidth, showContextMenu: this.handleShowMessageContextMenu, onImagePreview: this.handleImagePostview, onFormResponse: this.handleFormResponse, onError: this.props.onError, onCancelUpload: this.handleCancelUpload, pickReply: this.handlePickReply, replyToSeq: replyToSeq, onQuoteClick: this.handleQuoteClick, ref: ref, userIsWriter: this.state.isWriter, key: msg.seq })); } }); let lastSeen = null; if (isChannel) { lastSeen = formatMessage(messages.channel); } else { const cont = this.props.tinode.getMeTopic().getContact(this.state.topic); if (cont && tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isP2PTopicName(cont.topic)) { if (cont.online) { lastSeen = formatMessage(messages.online_now); } else if (cont.seen) { lastSeen = formatMessage(messages.last_seen) + ": " + (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_20__.shortDateFormat)(cont.seen.when, this.props.intl.locale); } } } const avatar = this.state.avatar || true; const online = this.state.deleted ? null : this.props.online ? 'online' + (this.state.typingIndicator ? ' typing' : '') : 'offline'; const titleClass = 'panel-title' + (this.state.deleted ? ' deleted' : ''); component2 = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "topic-caption-panel", className: "caption-panel" }, this.props.displayMobile ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", id: "hide-message-view", onClick: e => { e.preventDefault(); this.props.onHideMessagesView(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "arrow_back")) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "avatar-box" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_11__["default"], { tinode: this.props.tinode, avatar: avatar, topic: this.state.topic, title: this.state.title, deleted: this.state.deleted }), !isChannel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: online }) : null), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "topic-title-group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "topic-title", className: titleClass }, this.state.title || react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "unnamed_topic", defaultMessage: [{ "type": 0, "value": "Unnamed" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_contact_badges_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { badges: icon_badges })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "topic-last-seen" }, lastSeen)), groupTopic ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_group_subs_jsx__WEBPACK_IMPORTED_MODULE_8__["default"], { tinode: this.props.tinode, subscribers: this.state.onlineSubs }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "topic-users" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleContextClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "more_vert")))), this.props.displayMobile ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_7__["default"], { level: this.props.errorLevel, text: this.props.errorText, onClearError: this.props.onError }) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_load_spinner_jsx__WEBPACK_IMPORTED_MODULE_12__["default"], { show: this.state.fetchingMessages }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "messages-container" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: 'action-button' + (this.state.showGoToLastButton ? '' : ' hidden'), onClick: this.goToLatestMessage }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "arrow_downward")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "messages-panel", ref: this.handleScrollReference }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("ul", { id: "scroller", className: chatBoxClass }, messageNodes)), !this.state.isReader ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "write-only-background" }, this.state.readingBlocked ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "write-only-note" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "messages_not_readable", defaultMessage: [{ "type": 0, "value": "no access to messages" }] })) : null) : null), this.state.peerMessagingDisabled && !this.state.unconfirmed ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "peer-messaging-disabled-note" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons secondary" }, "block"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "peers_messaging_disabled", defaultMessage: [{ "type": 0, "value": "Peer's messaging is disabled." }] }), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleEnablePeer }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "enable_peers_messaging", defaultMessage: [{ "type": 0, "value": "Enable" }] })), ".") : null, this.state.unconfirmed ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_invitation_jsx__WEBPACK_IMPORTED_MODULE_10__["default"], { onAction: this.handleNewChatAcceptance }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_send_message_jsx__WEBPACK_IMPORTED_MODULE_15__["default"], { tinode: this.props.tinode, topicName: this.state.topic, noInput: !!this.props.forwardMessage, disabled: !this.state.isWriter || this.state.deleted, onKeyPress: this.sendKeyPress, onSendMessage: this.sendMessage, onAttachFile: this.props.forwardMessage ? null : this.handleAttachFile, onAttachImage: this.props.forwardMessage ? null : this.handleAttachImage, onAttachAudio: this.props.forwardMessage ? null : this.sendAudioAttachment, onError: this.props.onError, reply: this.state.reply, onQuoteClick: this.handleQuoteClick, onCancelReply: this.handleCancelReply })); } component = react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "topic-view" }, component2); } return component; } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(MessagesView)); /***/ }), /***/ "./src/views/new-topic-view.jsx": /*!**************************************!*\ !*** ./src/views/new-topic-view.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _widgets_contact_list_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/contact-list.jsx */ "./src/widgets/contact-list.jsx"); /* harmony import */ var _widgets_new_topic_by_id_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../widgets/new-topic-by-id.jsx */ "./src/widgets/new-topic-by-id.jsx"); /* harmony import */ var _widgets_new_topic_group_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../widgets/new-topic-group.jsx */ "./src/widgets/new-topic-group.jsx"); /* harmony import */ var _widgets_search_contacts_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../widgets/search-contacts.jsx */ "./src/widgets/search-contacts.jsx"); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ search_for_contacts: { id: "search_for_contacts", defaultMessage: [{ "type": 0, "value": "Use search to find contacts" }] }, search_no_results: { id: "search_no_results", defaultMessage: [{ "type": 0, "value": "Search returned no results" }] }, search_placeholder: { id: "search_placeholder", defaultMessage: [{ "type": 0, "value": "List like email:alice@example.com, tel:17025550003..." }] } }); class NewTopicView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { tabSelected: 'find', searchQuery: null }; this.handleTabClick = this.handleTabClick.bind(this); this.handleSearchContacts = this.handleSearchContacts.bind(this); this.handleSearchResultSelected = this.handleSearchResultSelected.bind(this); this.handleNewGroupSubmit = this.handleNewGroupSubmit.bind(this); this.handleGroupByID = this.handleGroupByID.bind(this); } componentDidMount() { this.props.onInitFind(); } handleTabClick(e) { e.preventDefault(); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].addUrlParam(window.location.hash, 'tab', e.currentTarget.dataset.id)); this.setState({ tabSelected: e.currentTarget.dataset.id }); } handleSearchContacts(query) { this.props.onSearchContacts(query); this.setState({ searchQuery: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isNullValue(query) ? null : query }); } handleSearchResultSelected(name) { if (this.state.tabSelected == 'find') { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].removeUrlParam(window.location.hash, 'tab')); this.props.onCreateTopic(name); } } handleNewGroupSubmit(name, description, dataUrl, priv, tags, isChannel) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].removeUrlParam(window.location.hash, 'tab')); this.props.onCreateTopic(undefined, { public: (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_8__.theCard)(name, dataUrl, null, description), private: priv, tags: tags }, isChannel); } handleGroupByID(topicName) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].removeUrlParam(window.location.hash, 'tab')); this.props.onCreateTopic(topicName); } render() { const { formatMessage } = this.props.intl; const no_contacts_placeholder = formatMessage(this.state.searchQuery ? messages.search_no_results : messages.search_for_contacts); const search_placeholder = formatMessage(messages.search_placeholder); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "flex-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("ul", { className: "tabbar" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { className: this.state.tabSelected === "find" ? "active" : null }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", "data-id": "find", onClick: this.handleTabClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "tabtitle_find_user", defaultMessage: [{ "type": 0, "value": "find" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { className: this.state.tabSelected === "grp" ? "active" : null }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", "data-id": "grp", onClick: this.handleTabClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "tabtitle_new_group", defaultMessage: [{ "type": 0, "value": "new group" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { className: this.state.tabSelected === "byid" ? "active" : null }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", "data-id": "byid", onClick: this.handleTabClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "tabtitle_group_by_id", defaultMessage: [{ "type": 0, "value": "by id" }] })))), this.state.tabSelected === 'grp' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_new_topic_group_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { tinode: this.props.tinode, onSubmit: this.handleNewGroupSubmit }) : this.state.tabSelected === 'byid' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_new_topic_by_id_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { onSubmit: this.handleGroupByID, onError: this.props.onError }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "flex-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_search_contacts_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], { placeholder: search_placeholder, onSearchContacts: this.handleSearchContacts }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_contact_list_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, contacts: this.props.searchResults, myUserId: this.props.myUserId, emptyListMessage: no_contacts_placeholder, showOnline: false, showUnread: false, showContextMenu: false, onTopicSelected: this.handleSearchResultSelected }))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(NewTopicView)); /***/ }), /***/ "./src/views/password-reset-view.jsx": /*!*******************************************!*\ !*** ./src/views/password-reset-view.jsx ***! \*******************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ PasswordResetView) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_visible_password_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/visible-password.jsx */ "./src/widgets/visible-password.jsx"); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); class PasswordResetView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { email: '', password: '', sent: false }; this.handleSubmit = this.handleSubmit.bind(this); this.handleEmailChange = this.handleEmailChange.bind(this); this.handlePasswordChange = this.handlePasswordChange.bind(this); } componentDidMount() { const parsed = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].parseUrlHash(window.location.hash); this.setState({ token: parsed.params.token, scheme: parsed.params.scheme }); } handleSubmit(e) { e.preventDefault(); if (this.state.token) { this.props.onReset(this.state.scheme, this.state.password.trim(), this.state.token); } else if (this.state.sent) { this.props.onCancel(); } else { const email = this.state.email.trim(); this.setState({ email: email }); this.props.onRequest('email', email).then(() => { this.setState({ sent: true }); }); } } handleEmailChange(e) { this.setState({ email: e.target.value }); } handlePasswordChange(e) { this.setState({ password: e.target.value }); } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("form", { id: "password-reset-form", onSubmit: this.handleSubmit }, this.state.token && this.state.scheme ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { htmlFor: "new-password" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_new_password", defaultMessage: [{ "type": 0, "value": "New password" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "new_password_placeholder", defaultMessage: [{ "type": 0, "value": "Enter new password" }] }, placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_visible_password_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { id: "new-password", placeholder: placeholder, autoComplete: "new-password", value: this.state.password, required: true, autoFocus: true, onChange: this.handlePasswordChange }))) : this.state.sent ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("br", null), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("center", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons huge green" }, "task_alt")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("br", null), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("center", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "password_reset_email_sent", defaultMessage: [{ "type": 0, "value": "An email has been sent to " }, { "type": 1, "value": "email" }, { "type": 0, "value": ". Follow the directions in the email to reset your password." }], values: { email: react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", null, this.state.email) } }))) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { htmlFor: "inputEmail" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_reset_password", defaultMessage: [{ "type": 0, "value": "Send a password reset email:" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "credential_email_prompt", defaultMessage: [{ "type": 0, "value": "Your registration email" }] }, placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "email", id: "inputEmail", placeholder: placeholder, autoComplete: "email", value: this.state.email, onChange: this.handleEmailChange, required: true, autoFocus: true }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "dialog-buttons" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "primary", type: "submit" }, this.state.token && this.state.scheme ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_reset", defaultMessage: [{ "type": 0, "value": "Reset" }] }) : this.state.sent ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_ok", defaultMessage: [{ "type": 0, "value": "OK" }] }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_send_request", defaultMessage: [{ "type": 0, "value": "Send request" }] })))); } } /***/ }), /***/ "./src/views/settings-view.jsx": /*!*************************************!*\ !*** ./src/views/settings-view.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ SettingsView) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_host_selector_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/host-selector.jsx */ "./src/widgets/host-selector.jsx"); class SettingsView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { transport: props.transport || 'def', serverAddress: props.serverAddress }; this.handleSubmit = this.handleSubmit.bind(this); this.handleTransportSelected = this.handleTransportSelected.bind(this); this.handleServerAddressChange = this.handleServerAddressChange.bind(this); } handleSubmit(e) { e.preventDefault(); this.props.onUpdate({ transport: this.state.transport, serverAddress: this.state.serverAddress }); } handleTransportSelected(e) { this.setState({ transport: e.currentTarget.value }); } handleServerAddressChange(name) { this.setState({ serverAddress: name }); } render() { const names = { def: "default", ws: "websocket", lp: "long polling" }; const transportOptions = []; ['def', 'ws', 'lp'].map(item => { const id = 'transport-' + item; const name = names[item]; transportOptions.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { key: item }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "radio", id: id, name: "transport-select", value: item, checked: this.state.transport === item, onChange: this.handleTransportSelected }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { htmlFor: id }, name))); }); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("form", { id: "settings-form", className: "panel-form", onSubmit: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_server_to_use", defaultMessage: [{ "type": 0, "value": "Server to use:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_host_selector_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { serverAddress: this.state.serverAddress, onServerAddressChange: this.handleServerAddressChange }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_wire_transport", defaultMessage: [{ "type": 0, "value": "Wire transport:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("ul", { className: "quoted" }, transportOptions)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "dialog-buttons" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { type: "submit", className: "primary" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_update", defaultMessage: [{ "type": 0, "value": "Update" }] })))); } } ; /***/ }), /***/ "./src/views/sidepanel-view.jsx": /*!**************************************!*\ !*** ./src/views/sidepanel-view.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/error-panel.jsx */ "./src/widgets/error-panel.jsx"); /* harmony import */ var _widgets_load_spinner_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/load-spinner.jsx */ "./src/widgets/load-spinner.jsx"); /* harmony import */ var _widgets_side_navbar_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../widgets/side-navbar.jsx */ "./src/widgets/side-navbar.jsx"); /* harmony import */ var _widgets_topic_common_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../widgets/topic-common.jsx */ "./src/widgets/topic-common.jsx"); /* harmony import */ var _account_settings_view_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./account-settings-view.jsx */ "./src/views/account-settings-view.jsx"); /* harmony import */ var _contacts_view_jsx__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./contacts-view.jsx */ "./src/views/contacts-view.jsx"); /* harmony import */ var _create_account_view_jsx__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./create-account-view.jsx */ "./src/views/create-account-view.jsx"); /* harmony import */ var _acc_notifications_view_jsx__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./acc-notifications-view.jsx */ "./src/views/acc-notifications-view.jsx"); /* harmony import */ var _acc_security_view_jsx__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./acc-security-view.jsx */ "./src/views/acc-security-view.jsx"); /* harmony import */ var _acc_support_view_jsx__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./acc-support-view.jsx */ "./src/views/acc-support-view.jsx"); /* harmony import */ var _login_view_jsx__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./login-view.jsx */ "./src/views/login-view.jsx"); /* harmony import */ var _new_topic_view_jsx__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./new-topic-view.jsx */ "./src/views/new-topic-view.jsx"); /* harmony import */ var _password_reset_view_jsx__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./password-reset-view.jsx */ "./src/views/password-reset-view.jsx"); /* harmony import */ var _settings_view_jsx__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./settings-view.jsx */ "./src/views/settings-view.jsx"); /* harmony import */ var _validation_view_jsx__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./validation-view.jsx */ "./src/views/validation-view.jsx"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ login: { id: "sidepanel_title_login", defaultMessage: [{ "type": 0, "value": "Sign In" }] }, register: { id: "sidepanel_title_register", defaultMessage: [{ "type": 0, "value": "Create Account" }] }, settings: { id: "sidepanel_title_settings", defaultMessage: [{ "type": 0, "value": "Settings" }] }, edit: { id: "sidepanel_title_account_settings", defaultMessage: [{ "type": 0, "value": "Account Settings" }] }, general: { id: "panel_title_general", defaultMessage: [{ "type": 0, "value": "General" }] }, security: { id: "panel_title_security", defaultMessage: [{ "type": 0, "value": "Security" }] }, crop: { id: "panel_title_crop", defaultMessage: [{ "type": 0, "value": "Drag to Adjust" }] }, notif: { id: "sidepanel_title_acc_notifications", defaultMessage: [{ "type": 0, "value": "Notifications" }] }, support: { id: "sidepanel_title_acc_support", defaultMessage: [{ "type": 0, "value": "Support" }] }, newtpk: { id: "sidepanel_title_newtpk", defaultMessage: [{ "type": 0, "value": "Start New Chat" }] }, cred: { id: "sidepanel_title_cred", defaultMessage: [{ "type": 0, "value": "Confirm Credentials" }] }, reset: { id: "sidepanel_title_reset", defaultMessage: [{ "type": 0, "value": "Reset Password" }] }, archive: { id: "sidepanel_title_archive", defaultMessage: [{ "type": 0, "value": "Archived Chats" }] }, blocked: { id: "sidepanel_title_blocked", defaultMessage: [{ "type": 0, "value": "Blocked Chats" }] } }); class SidepanelView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.handleNewTopic = this.handleNewTopic.bind(this); } handleNewTopic() { this.props.onNavigate('newtpk'); } render() { const { formatMessage } = this.props.intl; const view = this.props.state || (this.props.myUserId ? 'contacts' : 'login'); let title, avatar, badges; if (view == 'contacts') { title = this.props.title; avatar = this.props.avatar ? this.props.avatar : true; badges = this.props.trustedBadges; } else { title = formatMessage(messages[view]); avatar = false; badges = null; } let onCancel; if (['login', 'contacts'].indexOf(view) == -1) { onCancel = this.props.onCancel; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "sidepanel", className: this.props.hideSelf ? 'nodisplay' : null }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_side_navbar_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { state: view, title: title, avatar: avatar, tinode: this.props.tinode, trustedBadges: badges, myUserId: this.props.myUserId, onSignUp: this.props.onSignUp, onSettings: this.props.onSettings, onNewTopic: this.handleNewTopic, onCancel: onCancel }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { level: this.props.errorLevel, text: this.props.errorText, action: this.props.errorAction, actionText: this.props.errorActionText, onClearError: this.props.onError }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_load_spinner_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { show: this.props.loadSpinnerVisible }), view === 'login' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_login_view_jsx__WEBPACK_IMPORTED_MODULE_12__["default"], { login: this.props.login, disabled: this.props.loginDisabled, persist: this.props.persist, onLogin: this.props.onLoginRequest, onPersistenceChange: this.props.onPersistenceChange }) : view === 'register' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_create_account_view_jsx__WEBPACK_IMPORTED_MODULE_8__["default"], { tinode: this.props.tinode, onCreateAccount: this.props.onCreateAccount, onCancel: this.props.onCancel, onError: this.props.onError }) : view === 'settings' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_settings_view_jsx__WEBPACK_IMPORTED_MODULE_15__["default"], { transport: this.props.transport, serverAddress: this.props.serverAddress, onCancel: this.props.onCancel, onUpdate: this.props.onGlobalSettings }) : view === 'edit' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_account_settings_view_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], { tinode: this.props.tinode, myUserId: this.props.myUserId, trustedBadges: this.props.trustedBadges, onNavigate: this.props.onNavigate }) : view === 'general' || view === 'crop' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_topic_common_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { topic: "me", tinode: this.props.tinode, myUserId: this.props.myUserId, onUpdateTopicDesc: this.props.onUpdateAccountDesc, onUpdateTags: this.props.onUpdateAccountTags, onCredAdd: this.props.onCredAdd, onCredDelete: this.props.onCredDelete, onCredConfirm: this.props.onCredConfirm, onError: this.props.onError }) : view === 'notif' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_acc_notifications_view_jsx__WEBPACK_IMPORTED_MODULE_9__["default"], { messageSounds: this.props.messageSounds, desktopAlerts: this.props.desktopAlerts, desktopAlertsEnabled: this.props.desktopAlertsEnabled, incognitoMode: this.props.incognitoMode, onTogglePushNotifications: this.props.onTogglePushNotifications, onToggleMessageSounds: this.props.onToggleMessageSounds, onToggleIncognitoMode: this.props.onToggleIncognitoMode }) : view === 'security' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_acc_security_view_jsx__WEBPACK_IMPORTED_MODULE_10__["default"], { tinode: this.props.tinode, onUpdateAccountDesc: this.props.onUpdateAccountDesc, onUpdatePassword: this.props.onUpdatePassword, onLogout: this.props.onLogout, onDeleteAccount: this.props.onDeleteAccount, onShowAlert: this.props.onShowAlert, onShowBlocked: this.props.onShowBlocked }) : view === 'support' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_acc_support_view_jsx__WEBPACK_IMPORTED_MODULE_11__["default"], { serverAddress: this.props.serverAddress, serverVersion: this.props.serverVersion }) : view === 'contacts' || view == 'archive' || view == 'blocked' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_contacts_view_jsx__WEBPACK_IMPORTED_MODULE_7__["default"], { tinode: this.props.tinode, myUserId: this.props.myUserId, connected: this.props.connected, topicSelected: this.props.topicSelected, archive: view == 'archive', blocked: view == 'blocked', chatList: this.props.chatList, showContextMenu: this.props.showContextMenu, onTopicSelected: this.props.onTopicSelected, onShowArchive: this.props.onShowArchive }) : view === 'newtpk' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_new_topic_view_jsx__WEBPACK_IMPORTED_MODULE_13__["default"], { tinode: this.props.tinode, searchResults: this.props.searchResults, onInitFind: this.props.onInitFind, onSearchContacts: this.props.onSearchContacts, onCreateTopic: this.props.onCreateTopic, onError: this.props.onError }) : view === 'cred' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_validation_view_jsx__WEBPACK_IMPORTED_MODULE_16__["default"], { credCode: this.props.credCode, credMethod: this.props.credMethod, onSubmit: this.props.onValidateCredentials, onCancel: this.props.onCancel, onError: this.props.onError }) : view === 'reset' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_password_reset_view_jsx__WEBPACK_IMPORTED_MODULE_14__["default"], { onRequest: this.props.onPasswordResetRequest, onReset: this.props.onResetPassword, onCancel: this.props.onCancel }) : null); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(SidepanelView)); /***/ }), /***/ "./src/views/tinode-web.jsx": /*!**********************************!*\ !*** ./src/views/tinode-web.jsx ***! \**********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var firebase_app__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! firebase/app */ "./node_modules/firebase/app/dist/index.esm.js"); /* harmony import */ var firebase_messaging__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! firebase/messaging */ "./node_modules/firebase/messaging/dist/index.esm.js"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_4__); /* harmony import */ var _widgets_alert_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../widgets/alert.jsx */ "./src/widgets/alert.jsx"); /* harmony import */ var _widgets_context_menu_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../widgets/context-menu.jsx */ "./src/widgets/context-menu.jsx"); /* harmony import */ var _widgets_forward_dialog_jsx__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../widgets/forward-dialog.jsx */ "./src/widgets/forward-dialog.jsx"); /* harmony import */ var _info_view_jsx__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./info-view.jsx */ "./src/views/info-view.jsx"); /* harmony import */ var _incoming_call_view_jsx__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./incoming-call-view.jsx */ "./src/views/incoming-call-view.jsx"); /* harmony import */ var _messages_view_jsx__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./messages-view.jsx */ "./src/views/messages-view.jsx"); /* harmony import */ var _sidepanel_view_jsx__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./sidepanel-view.jsx */ "./src/views/sidepanel-view.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../constants.js */ "./src/constants.js"); /* harmony import */ var _version_js__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../version.js */ "./src/version.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_host_name_js__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../lib/host-name.js */ "./src/lib/host-name.js"); /* harmony import */ var _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../lib/local-storage.js */ "./src/lib/local-storage.js"); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); const POP_SOUND = new Audio('audio/msg.mp3'); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ reconnect_countdown: { id: "reconnect_countdown", defaultMessage: [{ "type": 0, "value": "Disconnected. Reconnecting in " }, { "type": 1, "value": "seconds" }, { "type": 0, "value": "…" }] }, reconnect_now: { id: "reconnect_now", defaultMessage: [{ "type": 0, "value": "Try now" }] }, push_init_failed: { id: "push_init_failed", defaultMessage: [{ "type": 0, "value": "Failed to initialize push notifications" }] }, invalid_security_token: { id: "invalid_security_token", defaultMessage: [{ "type": 0, "value": "Invalid security token" }] }, no_connection: { id: "no_connection", defaultMessage: [{ "type": 0, "value": "No connection" }] }, code_doesnot_match: { id: "code_doesnot_match", defaultMessage: [{ "type": 0, "value": "Code does not match" }] }, menu_item_info: { id: "menu_item_info", defaultMessage: [{ "type": 0, "value": "Info" }] }, menu_item_video_call: { id: "menu_item_video_call", defaultMessage: [{ "type": 0, "value": "Video Call" }] } }); class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.selfRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.state = this.getBlankState(); this.handleResize = this.handleResize.bind(this); this.handleHashRoute = this.handleHashRoute.bind(this); this.handleOnline = this.handleOnline.bind(this); this.checkForAppUpdate = this.checkForAppUpdate.bind(this); this.handleVisibilityEvent = this.handleVisibilityEvent.bind(this); this.handleError = this.handleError.bind(this); this.handleLoginRequest = this.handleLoginRequest.bind(this); this.handlePersistenceChange = this.handlePersistenceChange.bind(this); this.handleConnected = this.handleConnected.bind(this); this.handleAutoreconnectIteration = this.handleAutoreconnectIteration.bind(this); this.doLogin = this.doLogin.bind(this); this.handleCredentialsRequest = this.handleCredentialsRequest.bind(this); this.handleLoginSuccessful = this.handleLoginSuccessful.bind(this); this.handleDisconnect = this.handleDisconnect.bind(this); this.tnMeMetaDesc = this.tnMeMetaDesc.bind(this); this.tnMeContactUpdate = this.tnMeContactUpdate.bind(this); this.tnMeSubsUpdated = this.tnMeSubsUpdated.bind(this); this.resetContactList = this.resetContactList.bind(this); this.tnData = this.tnData.bind(this); this.tnInitFind = this.tnInitFind.bind(this); this.tnFndSubsUpdated = this.tnFndSubsUpdated.bind(this); this.handleSearchContacts = this.handleSearchContacts.bind(this); this.handleTopicSelected = this.handleTopicSelected.bind(this); this.handleHideMessagesView = this.handleHideMessagesView.bind(this); this.handleSendMessage = this.handleSendMessage.bind(this); this.handleNewChatInvitation = this.handleNewChatInvitation.bind(this); this.handleNewAccount = this.handleNewAccount.bind(this); this.handleNewAccountRequest = this.handleNewAccountRequest.bind(this); this.handleUpdatePasswordRequest = this.handleUpdatePasswordRequest.bind(this); this.handleUpdateAccountTagsRequest = this.handleUpdateAccountTagsRequest.bind(this); this.handleToggleIncognitoMode = this.handleToggleIncognitoMode.bind(this); this.handleSettings = this.handleSettings.bind(this); this.handleGlobalSettings = this.handleGlobalSettings.bind(this); this.handleShowArchive = this.handleShowArchive.bind(this); this.handleShowBlocked = this.handleShowBlocked.bind(this); this.handleToggleMessageSounds = this.handleToggleMessageSounds.bind(this); this.handleCredAdd = this.handleCredAdd.bind(this); this.handleCredDelete = this.handleCredDelete.bind(this); this.handleCredConfirm = this.handleCredConfirm.bind(this); this.initFCMessaging = this.initFCMessaging.bind(this); this.toggleFCMToken = this.toggleFCMToken.bind(this); this.handlePushMessage = this.handlePushMessage.bind(this); this.handleSidepanelCancel = this.handleSidepanelCancel.bind(this); this.handleStartTopicRequest = this.handleStartTopicRequest.bind(this); this.handleNewTopicCreated = this.handleNewTopicCreated.bind(this); this.handleTopicUpdateRequest = this.handleTopicUpdateRequest.bind(this); this.handleUnarchive = this.handleUnarchive.bind(this); this.handleChangePermissions = this.handleChangePermissions.bind(this); this.handleTagsUpdateRequest = this.handleTagsUpdateRequest.bind(this); this.handleLogout = this.handleLogout.bind(this); this.handleDeleteAccount = this.handleDeleteAccount.bind(this); this.handleDeleteTopicRequest = this.handleDeleteTopicRequest.bind(this); this.handleDeleteMessagesRequest = this.handleDeleteMessagesRequest.bind(this); this.handleLeaveUnsubRequest = this.handleLeaveUnsubRequest.bind(this); this.handleBlockTopicRequest = this.handleBlockTopicRequest.bind(this); this.handleReportTopic = this.handleReportTopic.bind(this); this.handleShowContextMenu = this.handleShowContextMenu.bind(this); this.defaultTopicContextMenu = this.defaultTopicContextMenu.bind(this); this.handleHideContextMenu = this.handleHideContextMenu.bind(this); this.handleShowAlert = this.handleShowAlert.bind(this); this.handleShowInfoView = this.handleShowInfoView.bind(this); this.handleMemberUpdateRequest = this.handleMemberUpdateRequest.bind(this); this.handleValidateCredentialsRequest = this.handleValidateCredentialsRequest.bind(this); this.handlePasswordResetRequest = this.handlePasswordResetRequest.bind(this); this.handleResetPassword = this.handleResetPassword.bind(this); this.handleContextMenuAction = this.handleContextMenuAction.bind(this); this.handleShowForwardDialog = this.handleShowForwardDialog.bind(this); this.handleHideForwardDialog = this.handleHideForwardDialog.bind(this); this.handleStartVideoCall = this.handleStartVideoCall.bind(this); this.handleInfoMessage = this.handleInfoMessage.bind(this); this.handleCallClose = this.handleCallClose.bind(this); this.handleCallInvite = this.handleCallInvite.bind(this); this.handleCallRinging = this.handleCallRinging.bind(this); this.handleCallHangup = this.handleCallHangup.bind(this); this.handleCallSendOffer = this.handleCallSendOffer.bind(this); this.handleCallIceCandidate = this.handleCallIceCandidate.bind(this); this.handleCallSendAnswer = this.handleCallSendAnswer.bind(this); this.handleCallAcceptCall = this.handleCallAcceptCall.bind(this); this.sendMessageToTopic = this.sendMessageToTopic.bind(this); } getBlankState() { const settings = _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('settings') || {}; const persist = !!_lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('keep-logged-in'); return { connected: false, ready: false, autoLogin: false, transport: settings.transport || null, serverAddress: settings.serverAddress || (0,_lib_host_name_js__WEBPACK_IMPORTED_MODULE_16__.detectServerAddress)(), serverVersion: "no connection", messageSounds: !settings.messageSoundsOff, incognitoMode: false, desktopAlerts: persist && !!settings.desktopAlerts, desktopAlertsEnabled: ((0,_lib_host_name_js__WEBPACK_IMPORTED_MODULE_16__.isSecureConnection)() || (0,_lib_host_name_js__WEBPACK_IMPORTED_MODULE_16__.isLocalHost)()) && typeof firebase_app__WEBPACK_IMPORTED_MODULE_2__.initializeApp != 'undefined' && typeof navigator != 'undefined' && typeof FIREBASE_INIT != 'undefined', firebaseToken: persist ? _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('firebase-token') : null, applicationVisible: !document.hidden, errorText: '', errorLevel: null, errorAction: undefined, errorActionText: null, sidePanelSelected: 'login', sidePanelTitle: null, sidePanelAvatar: null, myTrustedBadges: [], loadSpinnerVisible: false, login: '', password: '', persist: persist, myUserId: null, liveConnection: navigator.onLine, topicSelected: '', topicSelectedOnline: false, topicSelectedAcs: null, newTopicParams: null, loginDisabled: false, displayMobile: window.innerWidth <= _config_js__WEBPACK_IMPORTED_MODULE_12__.MEDIA_BREAKPOINT, infoPanel: undefined, mobilePanel: 'sidepanel', callTopic: undefined, callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_NONE, callShouldStart: false, contextMenuVisible: false, contextMenuBounds: null, contextMenuClickAt: null, contextMenuParams: null, contextMenuItems: [], forwardDialogVisible: false, forwardMessage: null, alertVisible: false, alertParams: {}, chatList: [], searchResults: [], searchableContacts: [], credMethod: undefined, credCode: undefined, requestedTopic: undefined }; } componentDidMount() { window.addEventListener('resize', this.handleResize); window.addEventListener('online', e => { this.handleOnline(true); }); window.addEventListener('offline', e => { this.handleOnline(false); }); window.addEventListener('hashchange', this.handleHashRoute); if (typeof BroadcastChannel == 'function') { const serviceWorkerChannel = new BroadcastChannel('tinode-sw'); serviceWorkerChannel.addEventListener('message', this.handlePushMessage); } else { console.warn("Your browser does not support BroadcastChannel. Some features will not be available"); } document.addEventListener('visibilitychange', this.handleVisibilityEvent); this.setState({ viewportWidth: document.documentElement.clientWidth, viewportHeight: document.documentElement.clientHeight }); new Promise((resolve, reject) => { this.tinode = TinodeWeb.tnSetup(this.state.serverAddress, this.state.transport, this.props.intl.locale, this.state.persist, resolve); this.tinode.onConnect = this.handleConnected; this.tinode.onDisconnect = this.handleDisconnect; this.tinode.onAutoreconnectIteration = this.handleAutoreconnectIteration; this.tinode.onInfoMessage = this.handleInfoMessage; }).then(() => { if (this.state.desktopAlertsEnabled) { this.initFCMessaging().then(() => { if (this.state.desktopAlerts) { this.tinode.setDeviceToken(this.state.firebaseToken); } }).catch(() => {}); } const parsedNav = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].parseUrlHash(window.location.hash); this.resetContactList(); const token = this.state.persist ? _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('auth-token') : undefined; if (token) { this.setState({ autoLogin: true }); token.expires = new Date(token.expires); this.tinode.setAuthToken(token); this.tinode.connect().catch(err => { this.handleError(err.message, 'err'); }); } if (!['cred', 'reset', 'register'].includes(parsedNav.path[0])) { this.setState({ requestedTopic: parsedNav.path[1] }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(''); } this.readTimer = null; this.readTimerCallback = null; this.handleHashRoute(); }); } componentWillUnmount() { window.removeEventListener('resize', this.handleResize); window.removeEventListener('hashchange', this.handleHashRoute); document.removeEventListener('visibilitychange', this.handleVisibilityEvent); } static tnSetup(serverAddress, transport, locale, persistentCache, onSetupCompleted) { const tinode = new tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode({ appName: _config_js__WEBPACK_IMPORTED_MODULE_12__.APP_NAME, host: serverAddress, apiKey: _config_js__WEBPACK_IMPORTED_MODULE_12__.API_KEY, transport: transport, secure: (0,_lib_host_name_js__WEBPACK_IMPORTED_MODULE_16__.isSecureConnection)(), persist: persistentCache }, onSetupCompleted); tinode.setHumanLanguage(locale); tinode.enableLogging(_config_js__WEBPACK_IMPORTED_MODULE_12__.LOGGING_ENABLED, true); return tinode; } handlePushMessage(payload) { this.tinode.oobNotification(payload.data || {}); } initFCMessaging() { const { formatMessage, locale } = this.props.intl; const onError = (msg, err) => { console.error(msg, err); this.handleError(formatMessage(messages.push_init_failed), 'err'); this.setState({ desktopAlertsEnabled: false, firebaseToken: null }); _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { desktopAlerts: false }); }; try { this.fcm = (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.getMessaging)((0,firebase_app__WEBPACK_IMPORTED_MODULE_2__.initializeApp)(FIREBASE_INIT, _config_js__WEBPACK_IMPORTED_MODULE_12__.APP_NAME)); return navigator.serviceWorker.register('/service-worker.js').then(reg => { this.checkForAppUpdate(reg); reg.active.postMessage(JSON.stringify({ locale: locale, version: _version_js__WEBPACK_IMPORTED_MODULE_14__.PACKAGE_VERSION })); return reg; }).then(reg => { return TinodeWeb.requestFCMToken(this.fcm, reg); }).then(token => { const persist = _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('keep-logged-in'); if (token != this.state.firebaseToken) { this.tinode.setDeviceToken(token); if (persist) { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].setObject('firebase-token', token); } } this.setState({ firebaseToken: token, desktopAlerts: true }); if (persist) { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { desktopAlerts: true }); } (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.onMessage)(this.fcm, payload => { this.handlePushMessage(payload); }); }).catch(err => { onError(err); throw err; }); } catch (err) { onError(err); return Promise.reject(err); } } static requestFCMToken(fcm, sw) { return (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.getToken)(fcm, { serviceWorkerRegistration: sw, vapidKey: FIREBASE_INIT.messagingVapidKey }).then(token => { if (token) { return token; } else { return Notification.requestPermission().then(permission => { if (permission === 'granted') { return (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.getToken)(fcm, { serviceWorkerRegistration: reg, vapidKey: FIREBASE_INIT.messagingVapidKey }).then(token => { if (token) { return token; } else { throw new Error("Failed to initialize notifications"); } }); } else { throw new Error("No permission to send notifications: " + permission); } }); } }); } handleResize() { const mobile = document.documentElement.clientWidth <= _config_js__WEBPACK_IMPORTED_MODULE_12__.MEDIA_BREAKPOINT; this.setState({ viewportWidth: document.documentElement.clientWidth, viewportHeight: document.documentElement.clientHeight }); if (this.state.displayMobile != mobile) { this.setState({ displayMobile: mobile }); } } checkForAppUpdate(reg) { reg.onupdatefound = () => { const installingWorker = reg.installing; installingWorker.onstatechange = () => { if (installingWorker.state == 'installed' && navigator.serviceWorker.controller) { const msg = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "update_available", defaultMessage: [{ "type": 0, "value": "Update available." }] }), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "reload_update", defaultMessage: [{ "type": 0, "value": "Reload" }] })), "."); this.handleError(msg, 'info'); } }; }; } handleHashRoute() { const hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].parseUrlHash(window.location.hash); if (hash.path && hash.path.length > 0) { if (['register', 'settings', 'edit', 'notif', 'security', 'support', 'general', 'crop', 'cred', 'reset', 'newtpk', 'archive', 'blocked', 'contacts', ''].includes(hash.path[0])) { this.setState({ sidePanelSelected: hash.path[0] }); } else { console.warn("Unknown sidepanel view", hash.path[0]); } let topicName = hash.path[1] || null; if (topicName != this.state.topicSelected) { if (!tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.topicType(topicName)) { topicName = null; } this.setState({ topicSelected: topicName, topicSelectedAcs: this.tinode.getTopicAccessMode(topicName) }); } } else { this.setState({ sidePanelSelected: '', topicSelected: null }); } if (hash.params.method) { this.setState({ credMethod: hash.params.method }); } if (hash.params.code) { this.setState({ credCode: hash.params.code }); } this.setState({ infoPanel: hash.params.info, newTopicTabSelected: hash.params.tab }); } handleOnline(online) { if (online) { this.handleError(); clearInterval(this.reconnectCountdown); this.tinode.reconnect(); } else { this.handleError(this.props.intl.formatMessage(messages.no_connection), 'warn'); } this.setState({ liveConnection: online }); } handleVisibilityEvent() { this.setState({ applicationVisible: !document.hidden }); } handleError(err, level, action, actionText) { this.setState({ errorText: err, errorLevel: level, errorAction: action, errorActionText: actionText, callShouldStart: false }); } handleLoginRequest(login, password) { this.setState({ loginDisabled: true, login: login, password: password, loadSpinnerVisible: true, autoLogin: true }); this.handleError('', null); if (this.tinode.isConnected()) { this.doLogin(login, password, { meth: this.state.credMethod, resp: this.state.credCode }); } else { this.tinode.connect().catch(err => { this.setState({ loginDisabled: false, autoLogin: false, loadSpinnerVisible: false }); this.handleError(err.message, 'err'); }); } } handlePersistenceChange(persist) { if (persist) { this.tinode.initStorage().then(() => { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].setObject('keep-logged-in', true); this.setState({ persist: true }); }); } else { this.tinode.clearStorage().then(() => { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].setObject('keep-logged-in', false); this.setState({ persist: false }); }); } } handleConnected() { clearInterval(this.reconnectCountdown); this.handleError(); const params = this.tinode.getServerInfo(); this.setState({ serverVersion: params.ver + ' ' + (params.build ? params.build : 'none') }); if (this.state.autoLogin) { this.doLogin(this.state.login, this.state.password, { meth: this.state.credMethod, resp: this.state.credCode }); } } handleAutoreconnectIteration(sec, prom) { clearInterval(this.reconnectCountdown); if (sec < 0) { this.handleError(); return; } if (prom) { prom.then(() => { this.handleError(); }).catch(err => { this.handleError(err.message, 'err'); }); return; } const { formatMessage } = this.props.intl; let count = sec / 1000; count = count | count; this.reconnectCountdown = setInterval(() => { const timeLeft = count > 99 ? (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_19__.secondsToTime)(count) : count; this.handleError(formatMessage(messages.reconnect_countdown, { seconds: timeLeft }), 'warn', _ => { clearInterval(this.reconnectCountdown); this.tinode.reconnect(); }, formatMessage(messages.reconnect_now)); count -= 1; }, 1000); } handleDisconnect(err) { this.setState({ connected: false, ready: false, topicSelectedOnline: false, errorText: err && err.message ? err.message : "Disconnected", errorLevel: err && err.message ? 'err' : 'warn', loginDisabled: false, contextMenuVisible: false, forwardDialogVisible: false, serverVersion: "no connection" }); } doLogin(login, password, cred) { if (this.tinode.isAuthenticated()) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(''); return; } cred = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.credential(cred); let promise = null; let token = this.tinode.getAuthToken(); if (login && password) { token = null; this.setState({ password: null }); promise = this.tinode.loginBasic(login, password, cred); } else if (token) { promise = this.tinode.loginToken(token.token, cred); } if (promise) { promise.then(ctrl => { if (ctrl.code >= 300 && ctrl.text === 'validate credentials') { this.setState({ loadSpinnerVisible: false }); if (cred) { this.handleError(this.props.intl.formatMessage(messages.code_doesnot_match), 'warn'); } this.handleCredentialsRequest(ctrl.params); } else { this.handleLoginSuccessful(); } }).catch(err => { this.setState({ loginDisabled: false, credMethod: undefined, credCode: undefined, loadSpinnerVisible: false, autoLogin: false }); this.handleError(err.message, 'err'); if (token) { this.handleLogout(); } _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(''); }); } else { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(''); this.setState({ loginDisabled: false }); } } handleCredentialsRequest(params) { const parsed = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].parseUrlHash(window.location.hash); parsed.path[0] = 'cred'; parsed.params['method'] = params.cred[0]; _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].composeUrlHash(parsed.path, parsed.params)); } handleLoginSuccessful() { this.handleError(); if (_lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('keep-logged-in')) { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].setObject('auth-token', this.tinode.getAuthToken()); } const goToTopic = this.state.requestedTopic; const me = this.tinode.getMeTopic(); me.onMetaDesc = this.tnMeMetaDesc; me.onContactUpdate = this.tnMeContactUpdate; me.onSubsUpdated = this.tnMeSubsUpdated; this.setState({ connected: true, credMethod: undefined, credCode: undefined, myUserId: this.tinode.getCurrentUserID(), autoLogin: true, requestedTopic: undefined }); me.subscribe(me.startMetaQuery().withLaterSub().withDesc().withTags().withCred().build()).catch(err => { this.tinode.disconnect(); localStorage.removeItem('auth-token'); this.handleError(err.message, 'err'); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(''); }).finally(() => { this.setState({ loadSpinnerVisible: false }); }); let urlHash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlSidePanel(window.location.hash, 'contacts'); if (goToTopic) { urlHash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlTopic(urlHash, goToTopic); } _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(urlHash); } tnMeMetaDesc(desc) { if (desc) { if (desc.public) { this.setState({ sidePanelTitle: desc.public.fn, sidePanelAvatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__.makeImageUrl)(desc.public.photo) }); } if (desc.trusted) { const badges = []; for (const [key, val] of Object.entries(desc.trusted)) { if (val) { badges.push(key); } } this.setState({ myTrustedBadges: badges }); } if (desc.acs) { this.setState({ incognitoMode: !desc.acs.isPresencer() }); } } } tnMeContactUpdate(what, cont) { if (what == 'on' || what == 'off') { this.resetContactList(); if (this.state.topicSelected == cont.topic) { this.setState({ topicSelectedOnline: what == 'on' }); } } else if (what == 'read') { this.resetContactList(); } else if (what == 'msg') { const topic = this.tinode.getTopic(cont.topic); const archived = topic && topic.isArchived(); if (cont.unread > 0 && this.state.messageSounds && !archived) { if (document.hidden || this.state.topicSelected != cont.topic) { POP_SOUND.play(); } } this.resetContactList(); } else if (what == 'recv') {} else if (what == 'gone' || what == 'unsub') { if (this.state.topicSelected == cont.topic) { this.handleTopicSelected(null); } this.resetContactList(); } else if (what == 'acs') { if (this.state.topicSelected == cont.topic) { this.setState({ topicSelectedAcs: cont.acs }); } } else if (what == 'del') {} else if (what == 'upd') {} else { console.info("Unsupported (yet) presence update:" + what + " in: " + cont.topic); } } tnMeSubsUpdated(unused) { this.resetContactList(); } static prepareSearchableContacts(chatList, foundContacts) { const merged = {}; for (const c of chatList) { if (tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isP2PTopicName(c.topic)) { merged[c.topic] = { user: c.topic, updated: c.updated, public: c.public, private: c.private, acs: c.acs }; } } for (const c of foundContacts) { if (!merged[c.user]) { merged[c.user] = c; } } return Object.values(merged); } resetContactList() { const newState = { chatList: [] }; if (!this.state.ready) { newState.ready = true; } this.tinode.getMeTopic().contacts(c => { if (!c.topic && !c.user) { c.topic = c.name; } newState.chatList.push(c); if (this.state.topicSelected == c.topic) { newState.topicSelectedOnline = c.online; newState.topicSelectedAcs = c.acs; } }); const past = new Date(0); newState.chatList.sort((a, b) => { return (a.touched || past).getTime() - (b.touched || past).getTime(); }); newState.searchableContacts = TinodeWeb.prepareSearchableContacts(newState.chatList, this.state.searchResults); this.setState(newState); } tnData(data) { const topic = this.tinode.getTopic(data.topic); if (topic.msgStatus(data, true) >= tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.MESSAGE_STATUS_SENT && data.from != this.state.myUserId) { clearTimeout(this.receivedTimer); this.receivedTimer = setTimeout(() => { this.receivedTimer = undefined; topic.noteRecv(data.seq); }, _config_js__WEBPACK_IMPORTED_MODULE_12__.RECEIVED_DELAY); } } tnInitFind() { const fnd = this.tinode.getFndTopic(); fnd.onSubsUpdated = this.tnFndSubsUpdated; if (fnd.isSubscribed()) { this.tnFndSubsUpdated(); } else { fnd.subscribe(fnd.startMetaQuery().withSub().build()).catch(err => { this.handleError(err.message, 'err'); }); } } tnFndSubsUpdated() { const foundContacts = []; this.tinode.getFndTopic().contacts(s => { foundContacts.push(s); }); this.setState({ searchResults: foundContacts, searchableContacts: TinodeWeb.prepareSearchableContacts(this.state.chatList, foundContacts) }); } handleSearchContacts(query) { const fnd = this.tinode.getFndTopic(); fnd.setMeta({ desc: { public: query } }).then(ctrl => { return fnd.getMeta(fnd.startMetaQuery().withSub().build()); }).catch(err => { this.handleError(err.message, 'err'); }); } handleTopicSelected(topicName) { if (this.state.newTopicParams && this.state.newTopicParams._topicName != topicName) { this.setState({ newTopicParams: null }); } if (topicName) { this.setState({ errorText: '', errorLevel: null, mobilePanel: 'topic-view', infoPanel: undefined }); if (this.state.topicSelected != topicName) { this.setState({ topicSelectedOnline: this.tinode.isTopicOnline(topicName), topicSelectedAcs: this.tinode.getTopicAccessMode(topicName), forwardMessage: null }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlTopic('', topicName)); } } else { this.setState({ errorText: '', errorLevel: null, mobilePanel: 'sidepanel', topicSelectedOnline: false, topicSelectedAcs: null, infoPanel: undefined, forwardMessage: null }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlTopic('', null)); } } handleHideMessagesView() { this.setState({ mobilePanel: 'sidepanel' }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlTopic(window.location.hash, null)); } handleSendMessage(msg, uploadCompletionPromise, uploader, head) { const topic = this.tinode.getTopic(this.state.topicSelected); return this.sendMessageToTopic(topic, msg, uploadCompletionPromise, uploader, head); } sendMessageToTopic(topic, msg, uploadCompletionPromise, uploader, head) { msg = topic.createMessage(msg, false); msg._uploader = uploader; if (head) { msg.head = Object.assign(msg.head || {}, head); } const completion = []; if (uploadCompletionPromise) { completion.push(uploadCompletionPromise); } if (!topic.isSubscribed()) { const subscribePromise = topic.subscribe().then(() => { topic.queuedMessages(pub => { if (pub._sending || pub.seq == msg.seq) { return; } if (topic.isSubscribed()) { topic.publishMessage(pub); } }); }); completion.push(subscribePromise); } return topic.publishDraft(msg, Promise.all(completion)).then(ctrl => { if (topic.isArchived()) { topic.archive(false); } return ctrl; }).catch(err => { this.handleError(err.message, 'err'); }); } handleNewChatInvitation(topicName, action) { const topic = this.tinode.getTopic(topicName); let response = null; switch (action) { case 'accept': const mode = topic.getAccessMode().getGiven(); response = topic.setMeta({ sub: { mode: mode } }); if (topic.isP2PType()) { response = response.then(ctrl => { topic.setMeta({ sub: { user: topicName, mode: mode } }); }); } break; case 'delete': response = topic.delTopic(true); break; case 'block': const am = topic.getAccessMode().updateWant('-JP').getWant(); response = topic.setMeta({ sub: { mode: am } }).then(ctrl => { return this.handleTopicSelected(null); }); break; default: console.warn("Unknown invitation action", '"' + action + '""'); } if (response != null) { response.catch(err => { this.handleError(err.message, 'err'); }); } } handleNewAccount() { this.handleError(); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlSidePanel(window.location.hash, 'register')); } handleNewAccountRequest(login_, password_, public_, cred_, tags_) { this.handleError(); this.tinode.connect(this.state.serverAddress).then(() => { return this.tinode.createAccountBasic(login_, password_, { public: public_, tags: tags_, cred: tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.credential(cred_) }); }).then(ctrl => { if (ctrl.code >= 300 && ctrl.text == 'validate credentials') { this.handleCredentialsRequest(ctrl.params); } else { this.handleLoginSuccessful(this); } }).catch(err => { this.handleError(err.message, 'err'); }); } handleToggleIncognitoMode(on) { this.setState({ incognitoMode: null }); const me = this.tinode.getMeTopic(); const am = me.getAccessMode().updateWant(on ? '-P' : '+P').getWant(); me.setMeta({ sub: { mode: am } }).catch(err => { this.setState({ incognitoMode: !on }); this.handleError(err.message, 'err'); }); } handleUpdateAccountTagsRequest(tags) { this.tinode.getMeTopic().setMeta({ tags: tags }).catch(err => { this.handleError(err.message, 'err'); }); } handleSettings() { this.handleError(); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlSidePanel(window.location.hash, this.state.myUserId ? 'edit' : 'settings')); } handleGlobalSettings(settings) { const serverAddress = settings.serverAddress || this.state.serverAddress; const transport = settings.transport || this.state.transport; if (this.tinode) { this.tinode.clearStorage(); this.tinode.onDisconnect = undefined; this.tinode.disconnect(); } this.tinode = TinodeWeb.tnSetup(serverAddress, transport, this.props.intl.locale, _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('keep-logged-in')); this.tinode.onConnect = this.handleConnected; this.tinode.onDisconnect = this.handleDisconnect; this.tinode.onAutoreconnectIteration = this.handleAutoreconnectIteration; this.setState({ serverAddress: serverAddress, transport: transport }); _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].setObject('settings', { serverAddress: serverAddress, transport: transport }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlSidePanel(window.location.hash, '')); } handleShowArchive() { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlSidePanel(window.location.hash, this.state.myUserId ? 'archive' : '')); } handleShowBlocked() { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlSidePanel(window.location.hash, this.state.myUserId ? 'blocked' : '')); } toggleFCMToken(enabled) { if (enabled) { this.setState({ desktopAlerts: null }); if (!this.state.firebaseToken) { this.initFCMessaging(); } else { this.setState({ desktopAlerts: true }); if (_lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('keep-logged-in')) { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { desktopAlerts: true }); } } } else if (this.state.firebaseToken && this.fcm) { (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.deleteToken)(this.fcm).catch(err => { console.error("Unable to delete token.", err); }).finally(() => { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { desktopAlerts: false }); localStorage.removeItem('firebase-token'); this.setState({ desktopAlerts: false, firebaseToken: null }); this.tinode.setDeviceToken(null); }); } else { this.setState({ desktopAlerts: false, firebaseToken: null }); _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { desktopAlerts: false }); } } handleToggleMessageSounds(enabled) { this.setState({ messageSounds: enabled }); _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { messageSoundsOff: !enabled }); } handleCredAdd(method, value) { const me = this.tinode.getMeTopic(); me.setMeta({ cred: { meth: method, val: value } }).catch(err => { this.handleError(err.message, 'err'); }); } handleCredDelete(method, value) { const me = this.tinode.getMeTopic(); me.delCredential(method, value).catch(err => { this.handleError(err.message, 'err'); }); } handleCredConfirm(method, response) { this.handleCredentialsRequest({ cred: [method] }); } handleSidepanelCancel() { const parsed = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].parseUrlHash(window.location.hash); let path = ''; if (['security', 'support', 'general', 'notif'].includes(parsed.path[0])) { path = 'edit'; } else if ('crop' == parsed.path[0]) { path = 'general'; } else if ('blocked' == parsed.path[0]) { path = 'security'; } else if (this.state.myUserId) { path = 'contacts'; } parsed.path[0] = path; if (parsed.params) { delete parsed.params.code; delete parsed.params.method; delete parsed.params.tab; delete parsed.params.scheme; delete parsed.params.token; } _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].composeUrlHash(parsed.path, parsed.params)); this.setState({ errorText: '', errorLevel: null }); } basicNavigator(hash) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlSidePanel(window.location.hash, hash)); } infoNavigator(hash) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlInfoPanel(window.location.hash, hash)); } handleStartTopicRequest(topicName, newTopicParams, isChannel) { if (topicName && this.tinode.isTopicCached(topicName)) { this.handleTopicSelected(topicName); return; } const params = {}; if (tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isP2PTopicName(topicName)) { params.sub = { mode: _config_js__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_P2P_ACCESS_MODE }; params.desc = { defacs: { auth: _config_js__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_P2P_ACCESS_MODE } }; } else { topicName = topicName || this.tinode.newGroupTopicName(isChannel); if (newTopicParams) { params.desc = { public: newTopicParams.public, private: { comment: newTopicParams.private } }; params.tags = newTopicParams.tags; } } params._topicName = topicName; this.setState({ newTopicParams: params }, () => { this.handleTopicSelected(topicName); }); } handleNewTopicCreated(oldName, newName) { let nextState = {}; if (this.state.callShouldStart) { nextState = { callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_IN_PROGRESS, callShouldStart: false }; } if (this.state.topicSelected == oldName && oldName != newName) { nextState.topicSelected = newName; } this.setState(nextState, _ => { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlTopic('', newName)); }); } handleTopicUpdateRequest(topicName, pub, priv, defacs) { this.handleError(); const topic = this.tinode.getTopic(topicName); if (topic) { const params = {}; let attachments; if (pub) { if (pub.photo) { if (pub.photo.ref && pub.photo.ref != tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.DEL_CHAR) { attachments = [pub.photo.ref]; } else if (!pub.photo.data || pub.photo.data == tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.DEL_CHAR) { pub.photo = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.DEL_CHAR; } } params.public = pub; } if (typeof priv == 'string') { params.private = priv === tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.DEL_CHAR ? tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.DEL_CHAR : { comment: priv }; } if (defacs) { params.defacs = defacs; } topic.setMeta({ desc: params, attachments: attachments }).catch(err => { this.handleError(err.message, 'err'); }); } } handleUnarchive(topicName) { const topic = this.tinode.getTopic(topicName); if (topic) { topic.archive(false); } } handleUpdatePasswordRequest(password) { this.handleError(); if (password) { this.tinode.updateAccountBasic(null, this.tinode.getCurrentLogin(), password).catch(err => { this.handleError(err.message, 'err'); }); } } handleChangePermissions(topicName, mode, uid) { const topic = this.tinode.getTopic(topicName); if (topic) { const am = topic.getAccessMode(); if (uid) { am.updateGiven(mode); mode = am.getGiven(); } else { am.updateWant(mode); mode = am.getWant(); } topic.setMeta({ sub: { user: uid, mode: mode } }).catch(err => { this.handleError(err.message, 'err'); }); } } handleTagsUpdateRequest(topicName, tags) { const topic = this.tinode.getTopic(topicName); if (topic) { topic.setMeta({ tags: tags }).catch(err => { this.handleError(err.message, 'err'); }); } } handleLogout() { (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_20__.updateFavicon)(0); localStorage.removeItem('auth-token'); localStorage.removeItem('firebase-token'); localStorage.removeItem('settings'); if (this.state.firebaseToken) { (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.deleteToken)(this.fcm); } clearInterval(this.reconnectCountdown); let cleared; if (this.tinode) { cleared = this.tinode.clearStorage(); this.tinode.onDisconnect = undefined; this.tinode.disconnect(); } else { cleared = Promose.resolve(); } this.setState(this.getBlankState()); cleared.then(() => { this.tinode = TinodeWeb.tnSetup(this.state.serverAddress, this.state.transport, this.props.intl.locale, _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('keep-logged-in'), () => { this.tinode.onConnect = this.handleConnected; this.tinode.onDisconnect = this.handleDisconnect; this.tinode.onAutoreconnectIteration = this.handleAutoreconnectIteration; _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(''); }); }); } handleDeleteAccount() { this.tinode.delCurrentUser(true).then(_ => { this.handleLogout(); }); } handleDeleteTopicRequest(topicName) { const topic = this.tinode.getTopic(topicName); if (!topic) { return; } topic.delTopic(true).then(ctrl => { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlTopic(window.location.hash, '')); }).catch(err => { this.handleError(err.message, 'err'); }); } handleDeleteMessagesRequest(topicName) { const topic = this.tinode.getTopic(topicName); if (!topic) { return; } topic.delMessagesAll(true).catch(err => { this.handleError(err.message, 'err'); }); } handleLeaveUnsubRequest(topicName) { const topic = this.tinode.getTopic(topicName); if (!topic) { return; } topic.leave(true).then(ctrl => { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlTopic(window.location.hash, '')); }).catch(err => { this.handleError(err.message, 'err'); }); } handleBlockTopicRequest(topicName) { const topic = this.tinode.getTopic(topicName); if (!topic) { return; } topic.updateMode(null, '-JP').then(_ => { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlTopic(window.location.hash, '')); }).catch(err => { this.handleError(err.message, 'err'); }); } handleReportTopic(topicName) { const topic = this.tinode.getTopic(topicName); if (!topic) { return; } this.tinode.report('report', topicName); topic.updateMode(null, '-JP').then(ctrl => { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlTopic(window.location.hash, '')); }).catch(err => { this.handleError(err.message, 'err'); }); } handleShowContextMenu(params, menuItems) { this.setState({ contextMenuVisible: true, contextMenuClickAt: { x: params.x, y: params.y }, contextMenuParams: params, contextMenuItems: menuItems || this.defaultTopicContextMenu(params.topicName), contextMenuBounds: this.selfRef.current.getBoundingClientRect() }); } handleShowForwardDialog(params) { if (this.state.sidePanelSelected == 'newtpk') { this.handleSidepanelCancel(); } const header = '➦ ' + params.userName; const content = typeof params.content == 'string' ? tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.init(params.content) : tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.forwardedContent(params.content); const preview = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.preview(content, _config_js__WEBPACK_IMPORTED_MODULE_12__.FORWARDED_PREVIEW_LENGTH, true); const msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.append(tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.appendLineBreak(tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.mention(header, params.userFrom)), content); const msgPreview = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.quote(header, params.userFrom, preview); const head = { forwarded: params.topicName + ':' + params.seq }; this.setState({ forwardDialogVisible: true, forwardMessage: { head: head, msg: msg, preview: msgPreview } }); } defaultTopicContextMenu(topicName) { const topic = this.tinode.getTopic(topicName); if (topic._deleted) { return ['topic_delete']; } let muted = false, blocked = false, self_blocked = false, subscribed = false, deleter = false, archived = false; if (topic) { subscribed = topic.isSubscribed(); archived = topic.isArchived(); const acs = topic.getAccessMode(); if (acs) { muted = acs.isMuted(); blocked = !acs.isJoiner(); self_blocked = !acs.isJoiner('want'); deleter = acs.isDeleter(); } } return [subscribed ? { title: this.props.intl.formatMessage(messages.menu_item_info), handler: this.handleShowInfoView } : null, subscribed && tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isP2PTopicName(topicName) ? { title: this.props.intl.formatMessage(messages.menu_item_video_call), handler: this.handleStartVideoCall } : null, subscribed ? 'messages_clear' : null, subscribed && deleter ? 'messages_clear_hard' : null, muted ? blocked ? null : 'topic_unmute' : 'topic_mute', self_blocked ? 'topic_unblock' : 'topic_block', archived ? 'topic_restore' : 'topic_archive', 'topic_delete']; } handleHideContextMenu() { this.setState({ contextMenuVisible: false, contextMenuClickAt: null, contextMenuParams: null, contextMenuBounds: null }); } handleHideForwardDialog(keepForwardedMessage) { this.setState({ forwardDialogVisible: false, forwardMessage: keepForwardedMessage ? this.state.forwardMessage : null }); } handleContextMenuAction(action, promise, params) { if (action == 'topic_archive') { if (promise && params.topicName && params.topicName == this.state.topicSelected) { promise.then(() => { this.handleTopicSelected(null); }); } } else if (action == 'menu_item_forward') { this.handleShowForwardDialog(params); } } handleShowAlert(title, content, onConfirm, confirmText, onReject, rejectText) { this.setState({ alertVisible: true, alertParams: { title: title, content: content, onConfirm: onConfirm, confirm: confirmText, onReject: onReject, reject: rejectText } }); } handleShowInfoView() { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].addUrlParam(window.location.hash, 'info', 'info')); this.setState({ infoPanel: 'info' }); } handleMemberUpdateRequest(topicName, added, removed) { if (!topicName) { return; } const topic = this.tinode.getTopic(topicName); if (!topic) { return; } if (added && added.length > 0) { added.map(uid => { topic.invite(uid, null).catch(err => { this.handleError(err.message, 'err'); }); }); } if (removed && removed.length > 0) { removed.map(uid => { topic.delSubscription(uid).catch(err => { this.handleError(err.message, 'err'); }); }); } } handleValidateCredentialsRequest(cred, code) { if (this.tinode.isAuthenticated()) { const me = this.tinode.getMeTopic(); me.setMeta({ cred: { meth: cred, resp: code } }).then(() => { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(''); }).catch(err => { this.handleError(err.message, 'err'); }); } else { this.setState({ credMethod: cred, credCode: code }); this.doLogin(null, null, { meth: cred, resp: code }); } } handlePasswordResetRequest(method, value) { return this.tinode.connect().then(() => { return this.tinode.requestResetAuthSecret('basic', method, value); }).catch(err => { this.handleError(err.message, 'err'); }); } handleResetPassword(scheme, newPassword, token) { token = (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__.base64ReEncode)(token); if (!token) { this.handleError(this.props.intl.formatMessage(messages.invalid_security_token), 'err'); } else { this.tinode.connect().then(() => { return this.tinode.updateAccountBasic(null, null, newPassword, { token: token }); }).then(() => { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(''); }).catch(err => { this.handleError(err.message, 'err'); }); } } handleStartVideoCall() { this.setState({ callTopic: this.state.topicSelected, callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_OUTGOING_INITATED }); } handleCallInvite(callTopic, callSeq, callState) { switch (callState) { case _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_OUTGOING_INITATED: let head = { mime: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_MESSAGE_MIME_TYPE }; this.handleSendMessage('started', undefined, undefined, head).then(ctrl => { if (ctrl.code < 200 || ctrl.code >= 300 || !ctrl.params || !ctrl.params.seq) { this.handleCallClose(); return; } this.setState({ callSeq: ctrl.params['seq'] }); }); break; case _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_IN_PROGRESS: const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('accept', callSeq); break; } } handleCallRinging(callTopic, callSeq) { const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('ringing', callSeq); } handleCallHangup(callTopic, callSeq) { const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('hang-up', callSeq); } handleCallSendOffer(callTopic, callSeq, sdp) { const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('offer', callSeq, sdp); } handleCallIceCandidate(callTopic, callSeq, candidate) { const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('ice-candidate', callSeq, candidate); } handleCallSendAnswer(callTopic, callSeq, sdp) { const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('answer', callSeq, sdp); } handleCallClose() { if (this.state.callTimeout) { console.log('closing call timeout ', this.state.callTimeout); clearTimeout(this.state.callTimeout); } this.setState({ callTopic: undefined, callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_NONE }); } handleCallAcceptCall(topicName) { const topic = this.tinode.getTopic(topicName); if (!topic) { return; } if (topic.isSubscribed()) { this.handleTopicSelected(this.state.callTopic); this.setState({ callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_IN_PROGRESS }); } else { this.setState({ callShouldStart: true }, () => this.handleTopicSelected(this.state.callTopic)); } } handleInfoMessage(info) { if (info.what != 'call') { return; } switch (info.event) { case 'invite': if (info.from != this.state.myUserId) { this.setState({ callTopic: info.src, callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_INCOMING_RECEIVED, callSeq: info.seq }); } break; case 'accept': console.log('TinodeWeb: received accept msg ', info); if (tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isMeTopicName(info.topic) && this.tinode.isMe(info.from)) { this.setState({ callTopic: null, callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_NONE, callSeq: null }); return; } if (info.topic == this.state.callTopic) { this.setState({ callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_IN_PROGRESS }); } break; case 'hang-up': this.handleCallClose(); break; } } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "app-container", ref: this.selfRef }, this.state.contextMenuVisible ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_context_menu_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], { tinode: this.tinode, bounds: this.state.contextMenuBounds, clickAt: this.state.contextMenuClickAt, params: this.state.contextMenuParams, items: this.state.contextMenuItems, hide: this.handleHideContextMenu, onShowAlert: this.handleShowAlert, onAction: this.handleContextMenuAction, onTopicRemoved: topicName => { if (topicName == this.state.topicSelected) { this.handleTopicSelected(null); } }, onError: this.handleError }) : null, this.state.forwardDialogVisible ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_forward_dialog_jsx__WEBPACK_IMPORTED_MODULE_7__["default"], { tinode: this.tinode, contacts: this.state.chatList, topicSelected: this.state.topicSelected, myUserId: this.state.myUserId, hide: this.handleHideForwardDialog, onInitFind: this.tnInitFind, searchResults: this.state.searchResults, onSearchContacts: this.handleSearchContacts, onTopicSelected: this.handleStartTopicRequest }) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_alert_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { visible: this.state.alertVisible, title: this.state.alertParams.title, content: this.state.alertParams.content, onReject: this.state.alertParams.onReject ? () => { this.setState({ alertVisible: false }); } : null, reject: this.state.alertParams.reject, onConfirm: () => { this.setState({ alertVisible: false }); this.state.alertParams.onConfirm(); }, confirm: this.state.alertParams.confirm }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_sidepanel_view_jsx__WEBPACK_IMPORTED_MODULE_11__["default"], { tinode: this.tinode, connected: this.state.connected, displayMobile: this.state.displayMobile, hideSelf: this.state.displayMobile && this.state.mobilePanel !== 'sidepanel', state: this.state.sidePanelSelected, title: this.state.sidePanelTitle, avatar: this.state.sidePanelAvatar, trustedBadges: this.state.myTrustedBadges, login: this.state.login, persist: this.state.persist, myUserId: this.state.myUserId, loginDisabled: this.state.loginDisabled, loadSpinnerVisible: this.state.loadSpinnerVisible, errorText: this.state.errorText, errorLevel: this.state.errorLevel, errorAction: this.state.errorAction, errorActionText: this.state.errorActionText, topicSelected: this.state.topicSelected, chatList: this.state.chatList, credMethod: this.state.credMethod, credCode: this.state.credCode, transport: this.state.transport, messageSounds: this.state.messageSounds, desktopAlerts: this.state.desktopAlerts, desktopAlertsEnabled: this.state.desktopAlertsEnabled, incognitoMode: this.state.incognitoMode, serverAddress: this.state.serverAddress, serverVersion: this.state.serverVersion, onGlobalSettings: this.handleGlobalSettings, onSignUp: this.handleNewAccount, onSettings: this.handleSettings, onNavigate: this.basicNavigator, onLoginRequest: this.handleLoginRequest, onPersistenceChange: this.handlePersistenceChange, onCreateAccount: this.handleNewAccountRequest, onUpdateAccountDesc: this.handleTopicUpdateRequest, onUpdatePassword: this.handleUpdatePasswordRequest, onUpdateAccountTags: this.handleUpdateAccountTagsRequest, onTogglePushNotifications: this.toggleFCMToken, onToggleMessageSounds: this.handleToggleMessageSounds, onToggleIncognitoMode: this.handleToggleIncognitoMode, onCredAdd: this.handleCredAdd, onCredDelete: this.handleCredDelete, onCredConfirm: this.handleCredConfirm, onTopicSelected: this.handleTopicSelected, onCreateTopic: this.handleStartTopicRequest, onLogout: this.handleLogout, onDeleteAccount: this.handleDeleteAccount, onShowAlert: this.handleShowAlert, onCancel: this.handleSidepanelCancel, onError: this.handleError, onValidateCredentials: this.handleValidateCredentialsRequest, onPasswordResetRequest: this.handlePasswordResetRequest, onResetPassword: this.handleResetPassword, onShowArchive: this.handleShowArchive, onShowBlocked: this.handleShowBlocked, onInitFind: this.tnInitFind, searchResults: this.state.searchResults, onSearchContacts: this.handleSearchContacts, showContextMenu: this.handleShowContextMenu }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_messages_view_jsx__WEBPACK_IMPORTED_MODULE_10__["default"], { tinode: this.tinode, connected: this.state.connected, ready: this.state.ready, online: this.state.topicSelectedOnline, acs: this.state.topicSelectedAcs, displayMobile: this.state.displayMobile, viewportWidth: this.state.viewportWidth, viewportHeight: this.state.viewportHeight, hideSelf: this.state.displayMobile && (this.state.mobilePanel !== 'topic-view' || this.state.infoPanel), topic: this.state.topicSelected, myUserId: this.state.myUserId, myUserName: this.state.sidePanelTitle, serverVersion: this.state.serverVersion, serverAddress: this.state.serverAddress, applicationVisible: this.state.applicationVisible, forwardMessage: this.state.forwardMessage, onCancelForwardMessage: this.handleHideForwardDialog, callTopic: this.state.callTopic, callSeq: this.state.callSeq, callState: this.state.callState, onCallHangup: this.handleCallHangup, onCallInvite: this.handleCallInvite, onCallSendOffer: this.handleCallSendOffer, onCallIceCandidate: this.handleCallIceCandidate, onCallSendAnswer: this.handleCallSendAnswer, errorText: this.state.errorText, errorLevel: this.state.errorLevel, errorAction: this.state.errorAction, errorActionText: this.state.errorActionText, newTopicParams: this.state.newTopicParams, onHideMessagesView: this.handleHideMessagesView, onData: this.tnData, onError: this.handleError, onNewTopicCreated: this.handleNewTopicCreated, showContextMenu: this.handleShowContextMenu, onChangePermissions: this.handleChangePermissions, onNewChat: this.handleNewChatInvitation, sendMessage: this.handleSendMessage, onVideoCallClosed: this.handleCallClose }), this.state.infoPanel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_info_view_jsx__WEBPACK_IMPORTED_MODULE_8__["default"], { tinode: this.tinode, connected: this.state.connected, displayMobile: this.state.displayMobile, topic: this.state.topicSelected, searchableContacts: this.state.searchableContacts, myUserId: this.state.myUserId, panel: this.state.infoPanel, errorText: this.state.errorText, errorLevel: this.state.errorLevel, errorAction: this.state.errorAction, errorActionText: this.state.errorActionText, onNavigate: this.infoNavigator, onTopicDescUpdateRequest: this.handleTopicUpdateRequest, onShowAlert: this.handleShowAlert, onChangePermissions: this.handleChangePermissions, onMemberUpdateRequest: this.handleMemberUpdateRequest, onDeleteTopic: this.handleDeleteTopicRequest, onDeleteMessages: this.handleDeleteMessagesRequest, onLeaveTopic: this.handleLeaveUnsubRequest, onBlockTopic: this.handleBlockTopicRequest, onReportTopic: this.handleReportTopic, onAddMember: this.handleManageGroupMembers, onTopicTagsUpdateRequest: this.handleTagsUpdateRequest, onTopicUnArchive: this.handleUnarchive, onInitFind: this.tnInitFind, onError: this.handleError, showContextMenu: this.handleShowContextMenu }) : null, this.state.callTopic && this.state.callState == _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_INCOMING_RECEIVED ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_incoming_call_view_jsx__WEBPACK_IMPORTED_MODULE_9__["default"], { tinode: this.tinode, onClose: this.handleCallClose, topic: this.state.callTopic, seq: this.state.callSeq, callState: this.state.callState, onRinging: this.handleCallRinging, onAcceptCall: this.handleCallAcceptCall, onReject: this.handleCallHangup }) : null); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(TinodeWeb)); /***/ }), /***/ "./src/views/validation-view.jsx": /*!***************************************!*\ !*** ./src/views/validation-view.jsx ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ phone: { id: "phone_dative", defaultMessage: [{ "type": 0, "value": "phone" }] }, email: { id: "email_dative", defaultMessage: [{ "type": 0, "value": "email" }] } }); class ValidationView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { code: props.credCode || '' }; this.handleChange = this.handleChange.bind(this); this.handleKeyPress = this.handleKeyPress.bind(this); this.handleSubmit = this.handleSubmit.bind(this); this.handleCancel = this.handleCancel.bind(this); } handleChange(e) { this.setState({ code: e.target.value }); } handleKeyPress(e) { if (e.key === 'Enter') { this.handleSubmit(e); } else if (e.key == 'Escape') { this.handleCancel(e); } } handleSubmit(e) { e.preventDefault(); if (this.state.code && this.state.code.trim()) { this.props.onSubmit(this.props.credMethod, this.state.code.trim()); } } handleCancel(e) { e.preventDefault(); this.props.onCancel(); } render() { const { formatMessage } = this.props.intl; const methods = { 'email': formatMessage(messages.email), 'tel': formatMessage(messages.phone) }; let method = methods[this.props.credMethod] || this.props.credMethod; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small", htmlFor: "enter-confirmation-code" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "enter_confirmation_code_prompt", defaultMessage: [{ "type": 0, "value": "Enter confirmation code sent to you by " }, { "type": 1, "value": "method" }, { "type": 0, "value": ":" }], values: { method: method } }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "numeric_confirmation_code_prompt", defaultMessage: [{ "type": 0, "value": "Numbers only" }] }, numbers_only => react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", id: "enter-confirmation-code", placeholder: numbers_only, value: this.state.code, onChange: this.handleChange, onKeyPress: this.handleKeyPress, required: true }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "dialog-buttons" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "secondary", onClick: this.handleCancel }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_cancel", defaultMessage: [{ "type": 0, "value": "Cancel" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "primary", onClick: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_confirm", defaultMessage: [{ "type": 0, "value": "Confirm" }] })))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(ValidationView)); /***/ }), /***/ "./src/widgets/alert.jsx": /*!*******************************!*\ !*** ./src/widgets/alert.jsx ***! \*******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ Alert) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); class Alert extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return this.props.visible ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "alert-container" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "alert" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "title" }, this.props.title), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "content" }, this.props.content), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "dialog-buttons" }, this.props.onReject ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "outline", onClick: this.props.onReject }, this.props.reject || react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_cancel", defaultMessage: [{ "type": 0, "value": "Cancel" }] })) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "primary", onClick: this.props.onConfirm }, this.props.confirm || react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_ok", defaultMessage: [{ "type": 0, "value": "OK" }] }))))) : null; } } ; /***/ }), /***/ "./src/widgets/attachment.jsx": /*!************************************!*\ !*** ./src/widgets/attachment.jsx ***! \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ Attachment) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _file_progress_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./file-progress.jsx */ "./src/widgets/file-progress.jsx"); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); class Attachment extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { downloader: null, progress: 0 }; this.downloadFile = this.downloadFile.bind(this); this.handleCancel = this.handleCancel.bind(this); } downloadFile(url, filename, mimetype) { if (!url) { this.props.onError("Invalid download URL '" + url + "'"); return; } const downloader = this.props.tinode.getLargeFileHelper(); this.setState({ downloader: downloader }); downloader.download(url, filename, mimetype, loaded => { this.setState({ progress: loaded / this.props.size }); }, err => { this.props.onError(err, 'err'); }).then(() => { this.setState({ downloader: null, progress: 0 }); }).catch(err => { if (err) { this.props.onError("Error downloading file: " + err.message, 'err'); } this.setState({ downloader: null, progress: 0 }); }); } handleCancel() { if (this.props.uploading) { this.props.onCancelUpload(); } else if (this.state.downloader) { this.state.downloader.cancel(); } } render() { let filename = this.props.filename || 'file_attachment'; if (filename.length > 36) { filename = filename.substr(0, 16) + '...' + filename.substr(-16); } let size = this.props.size > 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "small gray" }, "(", (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_3__.bytesToHumanSize)(this.props.size), ")") : null; let url, helperFunc; if (!this.props.uploading && !this.state.downloader && (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_4__.isUrlRelative)(this.props.downloadUrl)) { url = '#'; helperFunc = e => { e.preventDefault(); this.downloadFile(this.props.downloadUrl, this.props.filename, this.props.mimetype); }; } else { url = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_4__.sanitizeUrl)(this.props.downloadUrl); helperFunc = null; } const downloadWidget = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "file_download"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "save_attachment", defaultMessage: [{ "type": 0, "value": "save" }] })); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "attachment" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons big gray" }, "insert_drive_file")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "flex-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, filename, " ", size), this.props.uploading || this.state.downloader ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_file_progress_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { progress: this.props.uploading ? this.props.progress : this.state.progress, onCancel: this.handleCancel }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, url ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: url, download: this.props.filename, onClick: helperFunc }, downloadWidget) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "light-gray" }, downloadWidget)))); } } ; /***/ }), /***/ "./src/widgets/audio-player.jsx": /*!**************************************!*\ !*** ./src/widgets/audio-player.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ AudioPlayer) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _lib_strformat__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../lib/strformat */ "./src/lib/strformat.js"); /* harmony import */ var _lib_blob_helpers__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/blob-helpers */ "./src/lib/blob-helpers.js"); const CANVAS_UPSCALING = 2.0; const LINE_WIDTH = 3 * CANVAS_UPSCALING; const SPACING = 2 * CANVAS_UPSCALING; const BAR_COLOR = '#888A'; const BAR_COLOR_DARK = '#666C'; const THUMB_COLOR = '#444E'; const MIN_PREVIEW_LENGTH = 16; class AudioPlayer extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); let preview = (0,_lib_blob_helpers__WEBPACK_IMPORTED_MODULE_2__.base64ToIntArray)(this.props.preview); if (!Array.isArray(preview) || preview.length < MIN_PREVIEW_LENGTH) { preview = null; } this.state = { canPlay: false, playing: false, currentTime: '0:00', duration: this.props.duration > 0 ? (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_1__.secondsToTime)(this.props.duration / 1000) : '-:--', longMin: this.props.duration >= 600000, preview: preview }; this.initAudio = this.initAudio.bind(this); this.initCanvas = this.initCanvas.bind(this); this.resampleBars = this.resampleBars.bind(this); this.visualize = this.visualize.bind(this); this.handlePlay = this.handlePlay.bind(this); this.handleSeek = this.handleSeek.bind(this); this.handleError = this.handleError.bind(this); this.audioPlayer = null; this.viewBuffer = []; this.canvasRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); } componentDidMount() { if (this.props.src) { this.initAudio(); } this.initCanvas(); } componentWillUnmount() { if (this.audioPlayer) { this.audioPlayer.oncanplay = null; this.audioPlayer.ontimeupdate = null; this.audioPlayer.onended = null; this.audioPlayer.pause(); this.audioPlayer = null; } } componentDidUpdate(prevProps) { if (this.props.src != prevProps.src) { this.initAudio(); } if (this.props.preview != prevProps.preview) { let preview = (0,_lib_blob_helpers__WEBPACK_IMPORTED_MODULE_2__.base64ToIntArray)(this.props.preview); if (!Array.isArray(preview) || preview.length < MIN_PREVIEW_LENGTH) { preview = null; } this.setState({ preview: preview }, this.initCanvas); } } initAudio() { this.audioPlayer = new Audio(this.props.src); this.audioPlayer.oncanplay = _ => this.setState({ canPlay: true }); this.audioPlayer.ontimeupdate = _ => this.setState({ currentTime: (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_1__.secondsToTime)(this.audioPlayer.currentTime, this.state.longMin) }); this.audioPlayer.onended = _ => { this.audioPlayer.currentTime = 0; this.setState({ playing: false, currentTime: (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_1__.secondsToTime)(0, this.state.longMin) }); }; } initCanvas() { this.canvasRef.current.width = this.canvasRef.current.offsetWidth * CANVAS_UPSCALING; this.canvasRef.current.height = this.canvasRef.current.offsetHeight * CANVAS_UPSCALING; this.canvasContext = this.canvasRef.current.getContext('2d'); this.canvasContext.lineCap = 'round'; this.viewBuffer = this.resampleBars(this.state.preview); this.visualize(); } visualize() { if (!this.canvasRef.current) { return; } const width = this.effectiveWidth; const height = this.canvasRef.current.height; this.canvasContext.lineWidth = LINE_WIDTH; const drawFrame = () => { if (!this.canvasRef.current || !this.audioPlayer) { return; } this.canvasContext.clearRect(0, 0, this.canvasRef.current.width, height); if (this.viewBuffer) { if (this.state.playing) { window.requestAnimationFrame(drawFrame); } const thumbAt = this.props.duration ? Math.max(0, Math.min(this.audioPlayer.currentTime * 1000 / this.props.duration, 1)) * (width - LINE_WIDTH * 2) : -1; this.canvasContext.beginPath(); this.canvasContext.strokeStyle = BAR_COLOR_DARK; for (let i = 0; i < this.viewBuffer.length; i++) { let x = 1 + i * (LINE_WIDTH + SPACING) + LINE_WIDTH * 0.5; let y = this.viewBuffer[i] * height * 0.9; const color = x < thumbAt ? BAR_COLOR_DARK : BAR_COLOR; if (this.canvasContext.strokeStyle != color) { this.canvasContext.stroke(); this.canvasContext.beginPath(); this.canvasContext.strokeStyle = color; } this.canvasContext.moveTo(x, (height - y) * 0.5); this.canvasContext.lineTo(x, height * 0.5 + y * 0.5); } this.canvasContext.stroke(); if (this.props.duration) { this.canvasContext.beginPath(); this.canvasContext.arc(thumbAt + LINE_WIDTH * 2, height * 0.5, LINE_WIDTH * 2, 0, 2 * Math.PI); this.canvasContext.fillStyle = THUMB_COLOR; this.canvasContext.fill(); } } }; drawFrame(); } resampleBars(original) { const dstCount = (this.canvasRef.current.width - SPACING) / (LINE_WIDTH + SPACING) | 0; this.effectiveWidth = dstCount * (LINE_WIDTH + SPACING) + SPACING; if (!Array.isArray(original) || original.length == 0) { return Array.apply(null, Array(dstCount)).map(_ => 0.01); } const factor = original.length / dstCount; let amps = []; let maxAmp = -1; for (let i = 0; i < dstCount; i++) { let lo = i * factor | 0; let hi = (i + 1) * factor | 0; if (hi == lo) { amps[i] = original[lo]; } else { let amp = 0.0; for (let j = lo; j < hi; j++) { amp += original[j]; } amps[i] = Math.max(0, amp / (hi - lo)); } maxAmp = Math.max(amps[i], maxAmp); } if (maxAmp > 0) { return amps.map(a => a / maxAmp); } return Array.apply(null, Array(dstCount)).map(_ => 0.01); } handlePlay(e) { e.preventDefault(); if (!this.state.canPlay) { return; } if (this.state.playing) { this.audioPlayer.pause(); this.setState({ playing: false }); } else { this.audioPlayer.play(); this.setState({ playing: true }, this.visualize); } } handleError(err) { console.error(err); } handleSeek(e) { e.preventDefault(); if (e.target && this.props.duration) { const rect = e.target.getBoundingClientRect(); const offset = (e.clientX - rect.left) / this.effectiveWidth * CANVAS_UPSCALING; this.audioPlayer.currentTime = this.props.duration * offset / 1000; this.setState({ currentTime: (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_1__.secondsToTime)(this.audioPlayer.currentTime, this.state.longMin) }); if (!this.state.playing) { this.visualize(); } } } render() { const playClass = 'material-icons' + (this.props.short ? '' : ' large') + (this.state.canPlay ? '' : ' disabled'); const play = react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handlePlay, title: "Play" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: playClass }, this.state.playing ? 'pause_circle' : this.state.canPlay ? 'play_circle' : 'not_interested')); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "audio-player" }, this.props.short ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("canvas", { className: "playback", ref: this.canvasRef, onClick: this.handleSeek }), play) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, play, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("canvas", { className: "playback", ref: this.canvasRef, onClick: this.handleSeek }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "timer" }, this.state.currentTime, "/", this.state.duration)))); } } /***/ }), /***/ "./src/widgets/audio-recorder.jsx": /*!****************************************!*\ !*** ./src/widgets/audio-recorder.jsx ***! \****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ AudioRecorder) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _audio_player_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./audio-player.jsx */ "./src/widgets/audio-player.jsx"); /* harmony import */ var fix_webm_duration__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! fix-webm-duration */ "./node_modules/fix-webm-duration/fix-webm-duration.js"); /* harmony import */ var fix_webm_duration__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(fix_webm_duration__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_strformat__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/strformat */ "./src/lib/strformat.js"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); const BUFFER_SIZE = 256; const CANVAS_UPSCALING = 2.0; const LINE_WIDTH = 3 * CANVAS_UPSCALING; const SPACING = 2 * CANVAS_UPSCALING; const MILLIS_PER_BAR = 100; const BAR_COLOR = '#BBBD'; const BAR_SCALE = 64.0; const VISUALIZATION_BARS = 96; const MAX_SAMPLES_PER_BAR = 10; const AUDIO_MIME_TYPE = 'audio/webm'; class AudioRecorder extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { enabled: true, audioRecord: null, recording: true, paused: false, duration: '0:00', blobUrl: null, preview: null }; this.visualize = this.visualize.bind(this); this.initMediaRecording = this.initMediaRecording.bind(this); this.initCanvas = this.initCanvas.bind(this); this.getRecording = this.getRecording.bind(this); this.cleanUp = this.cleanUp.bind(this); this.handleResume = this.handleResume.bind(this); this.handlePause = this.handlePause.bind(this); this.handleDelete = this.handleDelete.bind(this); this.handleDone = this.handleDone.bind(this); this.durationMillis = 0; this.startedOn = null; this.viewBuffer = []; this.canvasRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); } componentDidMount() { this.stream = null; this.mediaRecorder = null; this.audioContext = null; this.audioInput = null; this.analyser = null; this.audioChunks = []; try { navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(this.initMediaRecording, this.props.onError); } catch (err) { this.props.onError(err); } } componentWillUnmount() { this.startedOn = null; if (this.stream) { this.cleanUp(); } } visualize() { this.initCanvas(); const pcmData = new Uint8Array(this.analyser.frequencyBinCount); const width = this.canvasWidth; const height = this.canvasHeight; const viewLength = width / (LINE_WIDTH + SPACING) | 0; const viewDuration = MILLIS_PER_BAR * viewLength; this.canvasContext.lineWidth = LINE_WIDTH; this.canvasContext.strokeStyle = BAR_COLOR; let prevBarCount = 0; let volume = 0.0; let countPerBar = 0; const drawFrame = () => { if (!this.startedOn) { return; } window.requestAnimationFrame(drawFrame); const duration = this.durationMillis + (Date.now() - this.startedOn); this.setState({ duration: (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_4__.secondsToTime)(duration / 1000) }); if (duration > _config_js__WEBPACK_IMPORTED_MODULE_5__.MAX_DURATION) { this.startedOn = null; this.mediaRecorder.pause(); this.durationMillis += Date.now() - this.startedOn; this.setState({ enabled: false, recording: false, duration: (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_4__.secondsToTime)(this.durationMillis / 1000) }); } this.analyser.getByteTimeDomainData(pcmData); let amp = 0.0; for (const amplitude of pcmData) { amp += (amplitude - 127) ** 2; } volume += Math.sqrt(amp / pcmData.length); countPerBar++; let barCount = duration / MILLIS_PER_BAR | 0; const dx = viewDuration > duration ? 0 : (duration - MILLIS_PER_BAR * barCount) / MILLIS_PER_BAR * (LINE_WIDTH + SPACING); if (prevBarCount != barCount) { prevBarCount = barCount; this.viewBuffer.push(volume / countPerBar); volume = 0.0; countPerBar = 0; if (this.viewBuffer.length > viewLength) { this.viewBuffer.shift(); } } this.canvasContext.clearRect(0, 0, width, height); this.canvasContext.beginPath(); for (let i = 0; i < this.viewBuffer.length; i++) { let x = i * (LINE_WIDTH + SPACING) - dx; let y = Math.min(this.viewBuffer[i] / BAR_SCALE, 0.9) * height; this.canvasContext.moveTo(x, (height - y) * 0.5); this.canvasContext.lineTo(x, height * 0.5 + y * 0.5); } this.canvasContext.stroke(); }; drawFrame(); } handlePause(e) { e.preventDefault(); this.mediaRecorder.pause(); this.mediaRecorder.requestData(); this.durationMillis += Date.now() - this.startedOn; this.startedOn = null; this.setState({ recording: false }); } handleResume(e) { e.preventDefault(); if (this.state.enabled) { this.startedOn = Date.now(); this.mediaRecorder.resume(); this.setState({ recording: true }, this.visualize); } } handleDelete(e) { e.preventDefault(); this.durationMillis = 0; this.startedOn = null; this.mediaRecorder.stop(); this.cleanUp(); this.setState({ recording: false }); } handleDone(e) { e.preventDefault(); this.setState({ recording: false }); if (this.startedOn) { this.durationMillis += Date.now() - this.startedOn; this.startedOn = null; } if (this.mediaRecorder) { this.mediaRecorder.stop(); } } initCanvas() { this.canvasRef.current.width = this.canvasRef.current.offsetWidth * CANVAS_UPSCALING; this.canvasRef.current.height = this.canvasRef.current.offsetHeight * CANVAS_UPSCALING; this.canvasContext = this.canvasRef.current.getContext('2d'); this.canvasContext.lineCap = 'round'; this.canvasContext.translate(0.5, 0.5); this.canvasWidth = this.canvasRef.current.width; this.canvasHeight = this.canvasRef.current.height; } initMediaRecording(stream) { this.stream = stream; this.mediaRecorder = new MediaRecorder(stream, { mimeType: AUDIO_MIME_TYPE }); this.audioContext = new AudioContext(); this.audioInput = this.audioContext.createMediaStreamSource(stream); this.analyser = this.audioContext.createAnalyser(); this.analyser.fftSize = BUFFER_SIZE; this.audioInput.connect(this.analyser); this.mediaRecorder.onstop = _ => { if (this.durationMillis > _config_js__WEBPACK_IMPORTED_MODULE_5__.MIN_DURATION) { this.getRecording(this.mediaRecorder.mimeType, this.durationMillis).then(result => this.props.onFinished(result.url, result.preview, this.durationMillis)); } else { this.props.onDeleted(); } this.cleanUp(); }; this.mediaRecorder.ondataavailable = e => { if (e.data.size > 0) { this.audioChunks.push(e.data); } if (this.mediaRecorder.state != 'inactive') { this.getRecording(this.mediaRecorder.mimeType).then(result => { this.setState({ blobUrl: result.url, preview: result.preview }); }); } }; this.durationMillis = 0; this.startedOn = Date.now(); this.mediaRecorder.start(); this.visualize(); } getRecording(mimeType, duration) { let blob = new Blob(this.audioChunks, { type: mimeType || AUDIO_MIME_TYPE }); return (duration > 0 ? fix_webm_duration__WEBPACK_IMPORTED_MODULE_2___default()(blob, duration, { logger: false }) : Promise.resolve(blob)).then(fixedBlob => { blob = fixedBlob; return fixedBlob.arrayBuffer(); }).then(arrayBuff => this.audioContext.decodeAudioData(arrayBuff)).then(decoded => this.createPreview(decoded)).then(preview => ({ url: window.URL.createObjectURL(blob), preview: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_3__.intArrayToBase64)(preview) })); } createPreview(audio) { const data = audio.getChannelData(0); const viewLength = Math.min(data.length, VISUALIZATION_BARS); const totalSPB = data.length / viewLength | 0; const samplingRate = Math.max(1, totalSPB / MAX_SAMPLES_PER_BAR | 0); let buffer = []; let max = -1; for (let i = 0; i < viewLength; i++) { let amplitude = 0; let count = 0; for (let j = 0; j < totalSPB; j += samplingRate) { amplitude += data[totalSPB * i + j] ** 2; count++; } const val = Math.sqrt(amplitude / count); buffer.push(val); max = Math.max(max, val); } if (max > 0) { buffer = buffer.map(a => 100 * a / max | 0); } return buffer; } cleanUp() { this.audioInput.disconnect(); this.stream.getTracks().forEach(track => track.stop()); } render() { const resumeClass = 'material-icons ' + (this.state.enabled ? 'red' : 'gray'); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "audio" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleDelete, title: "Delete" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, "delete_outline")), this.state.recording ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("canvas", { ref: this.canvasRef }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_audio_player_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { src: this.state.blobUrl, preview: this.state.preview, duration: this.durationMillis, short: true }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "duration" }, this.state.duration), this.state.recording ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handlePause, title: "Pause" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "pause_circle_outline")) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleResume, title: "Resume" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: resumeClass }, "radio_button_checked")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleDone, title: "Send" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "send"))); } } /***/ }), /***/ "./src/widgets/avatar-crop.jsx": /*!*************************************!*\ !*** ./src/widgets/avatar-crop.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ AvatarCrop) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _cropper_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./cropper.jsx */ "./src/widgets/cropper.jsx"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); class AvatarCrop extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { top: 0, left: 0, width: 0, height: 0, scale: 1 }; this.handleSubmit = this.handleSubmit.bind(this); this.handleChange = this.handleChange.bind(this); } handleChange(left, top, width, height, scale) { this.setState({ left: left, top: top, width: width, height: height, scale: scale }); } handleSubmit() { (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_3__.imageCrop)(this.props.mime, this.props.avatar, this.state.left, this.state.top, this.state.width, this.state.height, this.state.scale).then(img => { this.props.onSubmit(img.mime, img.blob, img.width, img.height); }).catch(err => { this.props.onError(err); }); } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_cropper_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { source: this.props.avatar, onChange: this.handleChange })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "dialog-buttons" }, this.props.onCancel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "secondary", onClick: this.props.onCancel }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_cancel", defaultMessage: [{ "type": 0, "value": "Cancel" }] })) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "primary", onClick: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_ok", defaultMessage: [{ "type": 0, "value": "OK" }] })))); } } ; /***/ }), /***/ "./src/widgets/avatar-upload.jsx": /*!***************************************!*\ !*** ./src/widgets/avatar-upload.jsx ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ AvatarUpload) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _load_spinner_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./load-spinner.jsx */ "./src/widgets/load-spinner.jsx"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); class AvatarUpload extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { source: props.avatar }; this.handleFileReceived = this.handleFileReceived.bind(this); } componentDidUpdate(prevProps) { if (this.props.avatar != prevProps.avatar) { this.setState({ source: this.props.avatar }); } } handleFileReceived(e) { const image = e.target.files[0]; this.props.onImageUpdated(image.type, URL.createObjectURL(image), image.name); e.target.value = ''; } render() { const randId = 'file-input-avatar-' + ('' + Math.random()).substring(0, 4); const className = 'avatar-upload' + (this.props.readOnly ? ' read-only' : ''); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: className }, this.props.readOnly || !this.state.source ? null : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "clear-avatar", onClick: e => { e.preventDefault(); this.props.onImageUpdated(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "clear")), this.state.source ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { src: this.props.tinode.authorizeURL((0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_3__.sanitizeUrlForMime)(this.state.source, 'image')), className: "preview" }) : this.props.readOnly && this.props.uid ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "avatar-box" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { tinode: this.props.tinode, avatar: true, topic: this.props.uid, title: this.props.title })) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "blank" }, _config_js__WEBPACK_IMPORTED_MODULE_4__.AVATAR_SIZE, "\xD7", _config_js__WEBPACK_IMPORTED_MODULE_4__.AVATAR_SIZE), this.props.readOnly ? null : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "file", id: randId, className: "inputfile hidden", accept: "image/*", onChange: this.handleFileReceived }), this.props.readOnly ? null : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { htmlFor: randId, className: "round" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "file_upload")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_load_spinner_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { show: this.props.uploading, large: true, clear: true, centered: true })); } } ; /***/ }), /***/ "./src/widgets/badge-list.jsx": /*!************************************!*\ !*** ./src/widgets/badge-list.jsx ***! \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); const icon_mapping = { 'staff': 'verified_user' }; const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ badge_verified: { id: "badge_verified", defaultMessage: [{ "type": 0, "value": "Verified/official" }] }, badge_staff: { id: "badge_staff", defaultMessage: [{ "type": 0, "value": "Staff-managed" }] }, badge_danger: { id: "badge_danger", defaultMessage: [{ "type": 0, "value": "Untrustworthy" }] } }); class BadgeList extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { const { formatMessage } = this.props.intl; let badges = null; if (this.props.trustedBadges && this.props.trustedBadges.length > 0) { badges = []; this.props.trustedBadges.map(b => { const comment = formatMessage(messages['badge_' + b]); const style = 'material-icons ' + b + '-color'; badges.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "trusted-badge", key: b }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: style }, icon_mapping[b] || b), " ", comment)); }); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, badges); } return null; } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(BadgeList)); /***/ }), /***/ "./src/widgets/button-back.jsx": /*!*************************************!*\ !*** ./src/widgets/button-back.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ButtonBack) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class ButtonBack extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onBack(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "arrow_back")); } } /***/ }), /***/ "./src/widgets/call-panel.jsx": /*!************************************!*\ !*** ./src/widgets/call-panel.jsx ***! \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../constants.js */ "./src/constants.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ already_in_call: { id: "already_in_call", defaultMessage: [{ "type": 0, "value": "You already in an ongoing call!" }] } }); class CallPanel extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { localStream: undefined, pc: undefined, previousOnInfo: undefined }; this.localStreamConstraints = { audio: true, video: true }; this.localRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.remoteRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.onInfo = this.onInfo.bind(this); this.start = this.start.bind(this); this.stop = this.stop.bind(this); this.createPeerConnection = this.createPeerConnection.bind(this); this.handleNegotiationNeededEvent = this.handleNegotiationNeededEvent.bind(this); this.handleICECandidateEvent = this.handleICECandidateEvent.bind(this); this.handleNewICECandidateMsg = this.handleNewICECandidateMsg.bind(this); this.handleICEConnectionStateChangeEvent = this.handleICEConnectionStateChangeEvent.bind(this); this.handleSignalingStateChangeEvent = this.handleSignalingStateChangeEvent.bind(this); this.handleICEGatheringStateChangeEvent = this.handleICEGatheringStateChangeEvent.bind(this); this.handleTrackEvent = this.handleTrackEvent.bind(this); this.handleVideoOfferMsg = this.handleVideoOfferMsg.bind(this); this.handleVideoAnswerMsg = this.handleVideoAnswerMsg.bind(this); this.handleNewICECandidateMsg = this.handleNewICECandidateMsg.bind(this); this.reportError = this.reportError.bind(this); this.handleGetUserMediaError = this.handleGetUserMediaError.bind(this); this.stopTracks = this.stopTracks.bind(this); this.handleCloseClick = this.handleCloseClick.bind(this); this.handleToggleCameraClick = this.handleToggleCameraClick.bind(this); this.handleToggleMicClick = this.handleToggleMicClick.bind(this); this.toggleMedia = this.toggleMedia.bind(this); this.handleRemoteHangup = this.handleRemoteHangup.bind(this); this.handleVideoCallAccepted = this.handleVideoCallAccepted.bind(this); } componentDidMount() { const topic = this.props.tinode.getTopic(this.props.topic); this.previousOnInfo = topic.onInfo; topic.onInfo = this.onInfo; if ((this.props.callState == _constants_js__WEBPACK_IMPORTED_MODULE_4__.CALL_STATE_OUTGOING_INITATED || this.props.callState == _constants_js__WEBPACK_IMPORTED_MODULE_4__.CALL_STATE_IN_PROGRESS) && this.localRef.current) { this.start(); } } componentWillUnmount() { const topic = this.props.tinode.getTopic(this.props.topic); topic.onInfo = this.previousOnInfo; this.stop(); } handleVideoCallAccepted(info) { const pc = this.createPeerConnection(); const stream = this.state.localStream; stream.getTracks().forEach(track => { pc.addTrack(track, stream); }); } onInfo(info) { if (info.what != 'call') { return; } switch (info.event) { case 'accept': this.handleVideoCallAccepted(info); break; case 'offer': this.handleVideoOfferMsg(info); break; case 'answer': this.handleVideoAnswerMsg(info); break; case 'ice-candidate': this.handleNewICECandidateMsg(info); break; case 'hang-up': this.handleRemoteHangup(info); break; } } start() { if (this.state.localStream) { this.props.onError(this.props.intl.formatMessage(messages.already_in_call)); return; } if (this.props.callState == _constants_js__WEBPACK_IMPORTED_MODULE_4__.CALL_STATE_IN_PROGRESS) { this.props.onInvite(this.props.topic, this.props.seq, this.props.callState); return; } navigator.mediaDevices.getUserMedia(this.localStreamConstraints).then(stream => { this.setState({ localStream: stream }); this.localRef.current.srcObject = stream; this.props.onInvite(this.props.topic, this.props.seq, this.props.callState); }).catch(this.handleGetUserMediaError); } stop() { this.stopTracks(this.localRef.current); this.stopTracks(this.remoteRef.current); if (this.state.pc) { this.state.pc.ontrack = null; this.state.pc.onremovetrack = null; this.state.pc.onremovestream = null; this.state.pc.onicecandidate = null; this.state.pc.oniceconnectionstatechange = null; this.state.pc.onsignalingstatechange = null; this.state.pc.onicegatheringstatechange = null; this.state.pc.onnegotiationneeded = null; this.state.pc.close(); } this.setState({ pc: null }); } stopTracks(el) { if (!el) { return; } let stream = el.srcObject; if (!stream) { return; } let tracks = stream.getTracks(); if (tracks) { tracks.forEach(track => { track.stop(); track.enabled = false; }); } el.srcObject = null; el.src = ''; } createPeerConnection() { var pc = new RTCPeerConnection(_config_js__WEBPACK_IMPORTED_MODULE_3__.CALL_WEBRTC_CONFIG); pc.onicecandidate = this.handleICECandidateEvent; pc.oniceconnectionstatechange = this.handleICEConnectionStateChangeEvent; pc.onicegatheringstatechange = this.handleICEGatheringStateChangeEvent; pc.onsignalingstatechange = this.handleSignalingStateChangeEvent; pc.onnegotiationneeded = this.handleNegotiationNeededEvent; pc.ontrack = this.handleTrackEvent; this.setState({ pc: pc }); return pc; } handleVideoAnswerMsg(info) { var desc = new RTCSessionDescription(info.payload); this.state.pc.setRemoteDescription(desc).catch(this.reportError); } reportError(err) { this.props.onError(err.message, 'err'); } handleNegotiationNeededEvent() { this.state.pc.createOffer().then(offer => { return this.state.pc.setLocalDescription(offer); }).then(_ => { this.props.onSendOffer(this.props.topic, this.props.seq, this.state.pc.localDescription.toJSON()); }).catch(this.reportError); } handleICECandidateEvent(event) { if (event.candidate) { this.props.onIceCandidate(this.props.topic, this.props.seq, event.candidate.toJSON()); } } handleNewICECandidateMsg(info) { var candidate = new RTCIceCandidate(info.payload); this.state.pc.addIceCandidate(candidate).catch(this.reportError); } handleICEConnectionStateChangeEvent(event) { switch (this.state.pc.iceConnectionState) { case 'closed': case 'failed': this.handleCloseClick(); break; } } handleSignalingStateChangeEvent(event) { if (this.state.pc.signalingState == 'closed') { this.handleCloseClick(); } } handleICEGatheringStateChangeEvent(event) { console.log('ICE gathering change state: ', event); } handleTrackEvent(event) { this.remoteRef.current.srcObject = event.streams[0]; this.forceUpdate(); } handleGetUserMediaError(e) { switch (e.name) { case 'NotFoundError': this.reportError(e); break; case 'SecurityError': case 'PermissionDeniedError': break; default: console.log('Error opening your camera and/or microphone: ' + e.message); break; } this.handleCloseClick(); } handleVideoOfferMsg(info) { var localStream = null; const pc = this.createPeerConnection(); var desc = new RTCSessionDescription(info.payload); pc.setRemoteDescription(desc).then(() => { return navigator.mediaDevices.getUserMedia(this.localStreamConstraints); }).then(stream => { localStream = stream; this.localRef.current.srcObject = stream; this.setState({ localStream: stream }); localStream.getTracks().forEach(track => { pc.addTrack(track, localStream); }); }).then(() => { return pc.createAnswer(); }).then(answer => { return pc.setLocalDescription(answer); }).then(() => { this.props.onSendAnswer(this.props.topic, this.props.seq, pc.localDescription.toJSON()); }).catch(this.handleGetUserMediaError); } handleRemoteHangup() { this.handleCloseClick(); } handleCloseClick() { this.stop(); this.props.onHangup(this.props.topic, this.props.seq); } toggleMedia(kind) { const stream = this.state.localStream; stream.getTracks().forEach(track => { if (track.kind != kind) { return; } track.enabled = !track.enabled; }); this.forceUpdate(); } handleToggleCameraClick() { this.toggleMedia('video'); } handleToggleMicClick() { this.toggleMedia('audio'); } render() { const remoteActive = this.remoteRef.current && this.remoteRef.current.srcObject; const audioIcon = this.state.localStream && this.state.localStream.getAudioTracks()[0].enabled ? 'mic' : 'mic_off'; const videoIcon = this.state.localStream && this.state.localStream.getVideoTracks()[0].enabled ? 'videocam' : 'videocam_off'; const peerTitle = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_5__.clipStr)(this.props.title, _config_js__WEBPACK_IMPORTED_MODULE_3__.MAX_PEER_TITLE_LENGTH); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "video-container" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "video-container-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "call-party self" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("video", { ref: this.localRef, autoPlay: true, muted: true, playsInline: true }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "title inactive" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "calls_you_label", defaultMessage: [{ "type": 0, "value": "You" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "call-party peer" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("video", { ref: this.remoteRef, autoPlay: true, playsInline: true }), remoteActive ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "title inactive" }, peerTitle) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "peer-card" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "avatar-box" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { tinode: this.props.tinode, avatar: this.props.avatar, topic: this.props.topic, title: this.props.title })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "title" }, peerTitle)))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "video-container-controls" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "danger", onClick: this.handleCloseClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "call_end")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "secondary", onClick: this.handleToggleCameraClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, videoIcon)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "secondary", onClick: this.handleToggleMicClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, audioIcon))))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(CallPanel)); /***/ }), /***/ "./src/widgets/chat-message.jsx": /*!**************************************!*\ !*** ./src/widgets/chat-message.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _attachment_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./attachment.jsx */ "./src/widgets/attachment.jsx"); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _received_marker_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./received-marker.jsx */ "./src/widgets/received-marker.jsx"); /* harmony import */ var _lib_formatters_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/formatters.js */ "./src/lib/formatters.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { progress: 0 }; if (props.uploader) { props.uploader.onProgress = this.handleProgress.bind(this); } this.handleImagePreview = this.handleImagePreview.bind(this); this.handleFormButtonClick = this.handleFormButtonClick.bind(this); this.handleContextClick = this.handleContextClick.bind(this); this.handleCancelUpload = this.handleCancelUpload.bind(this); this.handleQuoteClick = this.handleQuoteClick.bind(this); this.formatterContext = { formatMessage: props.intl.formatMessage.bind(props.intl), viewportWidth: props.viewportWidth, authorizeURL: props.tinode.authorizeURL.bind(props.tinode), onImagePreview: this.handleImagePreview, onFormButtonClick: this.handleFormButtonClick, onQuoteClick: this.handleQuoteClick }; } handleImagePreview(e) { e.preventDefault(); this.props.onImagePreview({ url: e.target.src, filename: e.target.title, width: e.target.dataset.width, height: e.target.dataset.height, size: e.target.dataset.size, type: e.target.dataset.mime }); } handleFormButtonClick(e) { e.preventDefault(); const data = { seq: this.props.seq }; data.resp = {}; if (e.target.dataset.name) { data.resp[e.target.dataset.name] = e.target.dataset.val ? e.target.dataset.val : e.target.dataset.val === undefined ? 1 : '' + e.target.dataset.val; } if (e.target.dataset.act == 'url') { data.ref = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_7__.sanitizeUrl)(e.target.dataset.ref) || 'about:blank'; } const text = e.target.dataset.title || 'unknown'; this.props.onFormResponse(e.target.dataset.act, text, data); } handleContextClick(e) { e.preventDefault(); e.stopPropagation(); const menuItems = []; if (this.props.received == tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_FAILED) { menuItems.push('menu_item_send_retry'); } if (this.props.userIsWriter && this.props.received > tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_FAILED && this.props.received < tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_DEL_RANGE) { menuItems.push('menu_item_reply'); } menuItems.push('menu_item_forward'); this.props.showContextMenu({ seq: this.props.seq, content: this.props.content, userFrom: this.props.userFrom, userName: this.props.userName, y: e.pageY, x: e.pageX, pickReply: this.props.pickReply }, menuItems); } handleProgress(ratio) { this.setState({ progress: ratio }); } handleCancelUpload() { this.props.onCancelUpload(this.props.seq, this.props.uploader); } handleQuoteClick(e) { e.preventDefault(); e.stopPropagation(); const replyToSeq = this.props.replyToSeq; if (replyToSeq) { this.props.onQuoteClick(replyToSeq); } } render() { const sideClass = this.props.sequence + ' ' + (this.props.response ? 'left' : 'right'); const bubbleClass = this.props.sequence == 'single' || this.props.sequence == 'last' ? 'bubble tip' : 'bubble'; const avatar = this.props.userAvatar || true; const fullDisplay = this.props.isGroup && this.props.response && (this.props.sequence == 'single' || this.props.sequence == 'last'); let content = this.props.content; const attachments = []; if (this.props.mimeType == tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.getContentType() && tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isValid(content)) { tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attachments(content, (att, i) => { if (att.mime == 'application/json') { return; } attachments.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_attachment_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, downloadUrl: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.getDownloadUrl(att), filename: att.name, uploading: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isProcessing(att), mimetype: att.mime, size: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.getEntitySize(att), progress: this.state.progress, onCancelUpload: this.handleCancelUpload, onError: this.props.onError, key: i })); }, this); const tree = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.format(content, _lib_formatters_js__WEBPACK_IMPORTED_MODULE_6__.fullFormatter, this.formatterContext); content = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, tree); } else if (this.props.deleted) { content = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, "block"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "gray" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "deleted_content", defaultMessage: [{ "type": 0, "value": "content deleted" }] }))); } else if ((0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_7__.isVideoCall)(this.props.mimeType)) { const direction = this.props.response ? 'call_received' : 'call_made'; const text = this.props.response ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "calls_incoming", defaultMessage: [{ "type": 0, "value": "Incoming Call" }] }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "calls_outgoing", defaultMessage: [{ "type": 0, "value": "Outgoing Call" }] }); const isCallDropped = this.props.content == 'disconnected'; content = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons", style: { color: isCallDropped ? 'red' : 'green' } }, direction), text, !isCallDropped && this.props.duration ? [' (', (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_8__.secondsToTime)(this.props.duration / 1000), ')'] : null); } else if (typeof content != 'string') { content = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, "warning_amber"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "gray" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "invalid_content", defaultMessage: [{ "type": 0, "value": "invalid content" }] }))); } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { ref: this.props.innerRef, className: sideClass }, this.props.isGroup && this.props.response ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "avatar-box" }, fullDisplay ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { tinode: this.props.tinode, topic: this.props.userFrom, title: this.props.userName, avatar: avatar }) : null) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: bubbleClass }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "content-meta" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "message-content" }, content, attachments), this.props.timestamp ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_received_marker_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { timestamp: this.props.timestamp, received: this.props.received }) : null), this.props.showContextMenu ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "menuTrigger" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleContextClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "expand_more"))) : null), fullDisplay ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "author" }, this.props.userName || react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "user_not_found", defaultMessage: [{ "type": 0, "value": "Not found" }] }))) : null)); } } ; const IntlChatMessage = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(BaseChatMessage); const ChatMessage = react__WEBPACK_IMPORTED_MODULE_0___default().forwardRef((props, ref) => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(IntlChatMessage, _extends({ innerRef: ref }, props))); /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ChatMessage); /***/ }), /***/ "./src/widgets/checkbox.jsx": /*!**********************************!*\ !*** ./src/widgets/checkbox.jsx ***! \**********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ CheckBox) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class CheckBox extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); } handleChange() { this.props.onChange(this.props.name, !this.props.checked); } render() { return this.props.onChange ? this.props.checked === true ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons blue clickable", onClick: this.handleChange }, "check_box") : this.props.checked === false ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons blue clickable", onClick: this.handleChange }, "check_box_outline_blank") : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons lt-blue" }, "indeterminate_check_box") : this.props.checked ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "check_box") : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "check_box_outline_blank"); } } /***/ }), /***/ "./src/widgets/chip-input.jsx": /*!************************************!*\ !*** ./src/widgets/chip-input.jsx ***! \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ChipInput) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _chip_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./chip.jsx */ "./src/widgets/chip.jsx"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); class ChipInput extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = ChipInput.deriveStateFromProps(props); this.state.input = ''; this.state.focused = false; this.handleTextInput = this.handleTextInput.bind(this); this.removeChipAt = this.removeChipAt.bind(this); this.handleChipCancel = this.handleChipCancel.bind(this); this.handleFocusGained = this.handleFocusGained.bind(this); this.handleFocusLost = this.handleFocusLost.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); } static deriveStateFromProps(props) { return { placeholder: props.chips ? '' : props.prompt, sortedChips: ChipInput.sortChips(props.chips, props.staticMembers), chipIndex: ChipInput.indexChips(props.chips) }; } componentDidUpdate(prevProps, prevState) { if (prevProps.chips != this.props.chips || prevProps.staticMembers != this.props.staticMembers || prevProps.prompt != this.props.prompt) { this.setState(ChipInput.deriveStateFromProps(this.props)); } if (!prevState || this.props.chips.length > prevState.sortedChips.length) { this.setState({ input: '' }); } } static indexChips(chips) { const index = {}; let count = 0; chips.map(item => { index[item.user] = count; count++; }); return index; } static sortChips(chips, keep) { const required = []; const normal = []; chips.map(item => { if (keep && keep.includes(item.user)) { required.push(item); } else { normal.push(item); } }); return required.concat(normal); } handleTextInput(e) { this.setState({ input: e.target.value }); if (this.props.filterFunc) { this.props.filterFunc(e.target.value); } } removeChipAt(idx) { const removed = this.state.sortedChips[idx]; this.props.onChipRemoved(removed.user, this.state.chipIndex[removed.user]); } handleChipCancel(item, idx) { this.removeChipAt(idx); } handleFocusGained() { this.setState({ focused: true }); } handleFocusLost() { this.setState({ focused: false }); if (this.props.onFocusLost) { this.props.onFocusLost(this.state.input); } } handleKeyDown(e) { if (e.key === 'Backspace') { if (this.state.input.length == 0 && this.state.sortedChips.length > 0) { const at = this.state.sortedChips.length - 1; if (this.state.sortedChips[at].user !== this.props.staticMembers) { this.removeChipAt(at); } } } else if (e.key === 'Enter') { if (this.props.onEnter) { this.props.onEnter(this.state.input); } } else if (e.key === 'Escape') { if (this.props.onCancel) { this.props.onCancel(); } } } render() { const chips = []; let count = 0; const staticMembers = this.props.staticMembers || []; this.state.sortedChips.map(item => { chips.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_chip_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { tinode: this.props.tinode, onCancel: this.handleChipCancel, avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_2__.makeImageUrl)(item.public ? item.public.photo : null), title: item.public ? item.public.fn : undefined, noAvatar: this.props.avatarDisabled, topic: item.user, required: staticMembers.includes(item.user), invalid: item.invalid, index: count, key: item.user })); count++; }); const className = "chip-input" + (this.state.focused ? ' focused' : ''); const autoFocus = !(this.props.tabIndex > 0); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: className }, chips, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", placeholder: this.state.placeholder, onChange: this.handleTextInput, onFocus: this.handleFocusGained, onBlur: this.handleFocusLost, onKeyDown: this.handleKeyDown, value: this.state.input, tabIndex: this.props.tabIndex, autoFocus: autoFocus })); } } ; /***/ }), /***/ "./src/widgets/chip.jsx": /*!******************************!*\ !*** ./src/widgets/chip.jsx ***! \******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ Chip) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); class Chip extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleCancel = this.handleCancel.bind(this); } handleCancel(e) { e.preventDefault(); this.props.onCancel(this.props.topic, this.props.index); } render() { const title = this.props.title || this.props.topic; const className = this.props.invalid ? 'chip invalid' : 'chip'; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: className }, this.props.noAvatar ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "spacer" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "avatar-box" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { tinode: this.props.tinode, avatar: this.props.avatar || true, topic: this.props.topic, title: this.props.title })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, title), this.props.onCancel && !this.props.required ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleCancel }, "\xD7") : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "spacer" })); } } ; /***/ }), /***/ "./src/widgets/contact-action.jsx": /*!****************************************!*\ !*** ./src/widgets/contact-action.jsx ***! \****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); class ContactAction extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } handleClick(e) { e.preventDefault(); e.stopPropagation(); this.props.onAction(this.props.action); } render() { const { formatMessage } = this.props.intl; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { onClick: this.handleClick, className: "action" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "action-text" }, formatMessage(this.props.title, this.props.values))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(ContactAction)); /***/ }), /***/ "./src/widgets/contact-badges.jsx": /*!****************************************!*\ !*** ./src/widgets/contact-badges.jsx ***! \****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ContactBadges) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); const icon_mapping = { 'muted': 'notifications_off', 'banned': 'block', 'staff': 'verified_user' }; class ContactBadges extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { let badges = null; if (this.props.badges && this.props.badges.length > 0) { badges = []; this.props.badges.map(b => { const color = b.color ? ' ' + b.color : ''; if (b.icon) { badges.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: 'material-icons as-badge' + color, key: b.key || b.icon }, icon_mapping[b.icon] || b.icon)); } else { badges.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: 'badge' + color, key: b.key || b.name }, b.name)); } }); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, badges); } return null; } } ; /***/ }), /***/ "./src/widgets/contact-list.jsx": /*!**************************************!*\ !*** ./src/widgets/contact-list.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _contact_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./contact.jsx */ "./src/widgets/contact.jsx"); /* harmony import */ var _contact_action_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./contact-action.jsx */ "./src/widgets/contact-action.jsx"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ badge_you: { id: "badge_you", defaultMessage: [{ "type": 0, "value": "you" }] }, badge_owner: { id: "badge_owner", defaultMessage: [{ "type": 0, "value": "owner" }] } }); class ContactList extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { render() { const { formatMessage } = this.props.intl; const showCheckmark = Array.isArray(this.props.topicSelected); const contactNodes = []; let contactsCount = 0; if (this.props.contacts && this.props.contacts.length > 0) { this.props.contacts.map(c => { if (c.action) { contactNodes.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_contact_action_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { title: c.title, action: c.action, values: c.values, key: c.action, onAction: this.props.onAction })); } else { const key = this.props.showMode ? c.user : c.topic || c.user; if (this.props.filterFunc && this.props.filter) { const filterOn = [key]; if (c.private && c.private.comment) { filterOn.push(('' + c.private.comment).toLowerCase()); } if (c.public && c.public.fn) { filterOn.push(('' + c.public.fn).toLowerCase()); } if (!this.props.filterFunc(this.props.filter, filterOn)) { return; } } const isChannel = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isChannelTopicName(key); const selected = showCheckmark ? this.props.topicSelected.indexOf(key) > -1 : this.props.topicSelected === key; const badges = []; if (this.props.showMode) { if (key == this.props.myUserId) { badges.push({ name: formatMessage(messages.badge_you), color: 'green' }); } if (c.acs && c.acs.isOwner()) { badges.push({ name: formatMessage(messages.badge_owner), color: 'blue' }); } } const comment = Array.isArray(c.private) ? c.private.join(',') : c.private ? c.private.comment : null; let preview; let forwarded; let previewIsVideoCall; let previewIsResponse; let deliveryStatus; if (!this.props.showMode && c.latestMessage) { const msg = c.latestMessage(true); if (msg) { forwarded = msg.head ? msg.head.forwarded : null; deliveryStatus = msg._status || c.msgStatus(msg, true); previewIsVideoCall = msg.head ? (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_6__.isVideoCall)(msg.head.mime) : null; previewIsResponse = msg.from != this.props.myUserId; if (msg.content) { preview = typeof msg.content == 'string' ? msg.content.substr(0, _config_js__WEBPACK_IMPORTED_MODULE_7__.MESSAGE_PREVIEW_LENGTH) : tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.preview(msg.content, _config_js__WEBPACK_IMPORTED_MODULE_7__.MESSAGE_PREVIEW_LENGTH); } } } contactNodes.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_contact_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, title: c.public ? c.public.fn : null, avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_5__.makeImageUrl)(c.public ? c.public.photo : null), comment: comment, preview: preview, previewIsVideoCall: previewIsVideoCall, previewIsResponse: previewIsResponse, forwarded: forwarded, received: deliveryStatus, unread: this.props.showUnread ? c.unread : 0, now: c.online && this.props.connected, acs: c.acs, showMode: this.props.showMode, badges: badges, showCheckmark: showCheckmark, selected: selected, showOnline: this.props.showOnline && !isChannel, isChannel: isChannel, showContextMenu: this.props.showContextMenu, isVerified: c.trusted && c.trusted.verified, isStaff: c.trusted && c.trusted.staff, isDangerous: c.trusted && c.trusted.danger, deleted: c._deleted, onSelected: this.props.onTopicSelected, item: key, index: contactNodes.length, key: key })); contactsCount++; } }, this); } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: this.props.noScroll ? null : "scrollable-panel" }, contactsCount == 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "center-medium-text", dangerouslySetInnerHTML: { __html: this.props.emptyListMessage } }) : null, contactNodes.length > 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("ul", { className: "contact-box" }, contactNodes) : null); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(ContactList)); /***/ }), /***/ "./src/widgets/contact.jsx": /*!*********************************!*\ !*** ./src/widgets/contact.jsx ***! \*********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _contact_badges_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./contact-badges.jsx */ "./src/widgets/contact-badges.jsx"); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _unread_badge_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./unread-badge.jsx */ "./src/widgets/unread-badge.jsx"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_5__); /* harmony import */ var _lib_formatters_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/formatters.js */ "./src/lib/formatters.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); class Contact extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); this.handleContextClick = this.handleContextClick.bind(this); } handleClick(e) { e.preventDefault(); e.stopPropagation(); if (this.props.onSelected) { this.props.onSelected(this.props.item, this.props.index); } } handleContextClick(e) { e.preventDefault(); e.stopPropagation(); this.props.showContextMenu({ topicName: this.props.item, y: e.pageY, x: e.pageX }); } render() { let title = this.props.title; if (!title) { title = react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "unnamed_topic", defaultMessage: [{ "type": 0, "value": "Unnamed" }] })); } else if (title.length > 30) { title = title.substring(0, 28) + '…'; } const online = this.props.now ? 'online' : 'offline'; const avatar = this.props.avatar ? this.props.avatar : true; const badges = this.props.badges ? this.props.badges.slice() : []; const icon_badges = []; if (this.props.isVerified) { icon_badges.push({ icon: 'verified', color: 'verified-color' }); } if (this.props.isStaff) { icon_badges.push({ icon: 'staff', color: 'staff-color' }); } if (this.props.isDangerous) { icon_badges.push({ icon: 'dangerous', color: 'danger-color' }); } if (this.props.acs) { if (this.props.showMode) { badges.push({ name: this.props.acs.getMode(), key: 'mode' }); } if (this.props.acs.isMuted()) { icon_badges.push({ icon: 'muted' }); } if (!this.props.acs.isJoiner()) { icon_badges.push({ icon: 'banned' }); } } let preview; if (this.props.previewIsVideoCall) { preview = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, this.props.previewIsResponse ? 'call_received' : 'call_made'), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "video_call")); } else if (typeof this.props.preview == 'string') { preview = this.props.preview; } else if (tinode_sdk__WEBPACK_IMPORTED_MODULE_5__.Drafty.isValid(this.props.preview)) { preview = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, tinode_sdk__WEBPACK_IMPORTED_MODULE_5__.Drafty.format(this.props.preview, _lib_formatters_js__WEBPACK_IMPORTED_MODULE_6__.previewFormatter, { formatMessage: this.props.intl.formatMessage })); } else if (this.props.preview) { preview = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, "warning_amber"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "gray" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "invalid_content", defaultMessage: [{ "type": 0, "value": "invalid content" }] }))); } const icon = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_7__.deliveryMarker)(this.props.received); const marker = icon ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: 'material-icons small space-right' + (icon.color ? ' ' + icon.color : '') }, icon.name) : null; const titleClass = 'contact-title' + (this.props.deleted ? ' deleted' : ''); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { className: !this.props.showCheckmark && this.props.selected ? 'selected' : null, onClick: this.handleClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "avatar-box" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, avatar: avatar, title: this.props.title, topic: this.props.item, deleted: this.props.deleted }), this.props.deleted ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "deleted material-icons" }, "cancel") : this.props.showOnline ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: online }) : this.props.showCheckmark && this.props.selected ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "checkmark material-icons" }, "check_circle") : null), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "text-box" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: titleClass }, title), this.props.isChannel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { src: "/img/channel.png", className: "channel", alt: "channel" }) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_contact_badges_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { badges: icon_badges }), !this.props.deleted ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_unread_badge_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { count: this.props.unread }) : null), this.props.showMode ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_contact_badges_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { badges: badges })) : this.props.small ? null : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "contact-comment" }, marker, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, preview || this.props.comment || '\u00A0'))), this.props.showContextMenu ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "menuTrigger" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleContextClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "expand_more"))) : null); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(Contact)); /***/ }), /***/ "./src/widgets/context-menu.jsx": /*!**************************************!*\ !*** ./src/widgets/context-menu.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ info: { id: "menu_item_info", defaultMessage: [{ "type": 0, "value": "Info" }] }, clear_messages: { id: "menu_item_clear_messages", defaultMessage: [{ "type": 0, "value": "Clear messages" }] }, clear_for_all: { id: "menu_item_clear_messages_for_all", defaultMessage: [{ "type": 0, "value": "Clear for All" }] }, delete: { id: "menu_item_delete", defaultMessage: [{ "type": 0, "value": "Delete" }] }, delete_for_all: { id: "menu_item_delete_for_all", defaultMessage: [{ "type": 0, "value": "Delete for All" }] }, send_retry: { id: "menu_item_send_retry", defaultMessage: [{ "type": 0, "value": "Retry" }] }, mute: { id: "menu_item_mute", defaultMessage: [{ "type": 0, "value": "Mute" }] }, unmute: { id: "menu_item_unmute", defaultMessage: [{ "type": 0, "value": "Unmute" }] }, reply: { id: "menu_item_reply", defaultMessage: [{ "type": 0, "value": "Reply" }] }, forward: { id: "menu_item_forward", defaultMessage: [{ "type": 0, "value": "Forward" }] }, topic_delete: { id: "menu_item_delete_topic", defaultMessage: [{ "type": 0, "value": "Delete" }] }, topic_delete_warning: { id: "topic_delete_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to delete this conversation? It cannot be undone." }] }, delete_messages_warning: { id: "delete_messages_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to delete all messages for everyone? It cannot be undone." }] }, unblock: { id: "menu_item_unblock", defaultMessage: [{ "type": 0, "value": "Unblock" }] }, block: { id: "menu_item_block", defaultMessage: [{ "type": 0, "value": "Block" }] }, topic_block_warning: { id: "topic_block_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to block this conversation?" }] }, member_delete: { id: "menu_item_member_delete", defaultMessage: [{ "type": 0, "value": "Remove" }] }, archive: { id: "menu_item_archive_topic", defaultMessage: [{ "type": 0, "value": "Archive" }] }, unarchive: { id: "menu_item_restore_topic", defaultMessage: [{ "type": 0, "value": "Restore" }] }, edit_permissions: { id: "menu_item_edit_permissions", defaultMessage: [{ "type": 0, "value": "Edit permissions" }] }, clear_messages_warning: { id: "clear_messages_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to clear all messages? It cannot be undone." }] } }); class ContextMenu extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.selfRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); const { formatMessage } = props.intl; this.handlePageClick = this.handlePageClick.bind(this); this.handleEscapeKey = this.handleEscapeKey.bind(this); this.handleClick = this.handleClick.bind(this); this.MenuItems = { 'topic_info': { id: 'topic_info', title: formatMessage(messages.info), handler: null }, 'messages_clear': { id: 'messages_clear', title: formatMessage(messages.clear_messages), handler: (params, errorHandler) => { return props.onShowAlert(formatMessage(messages.clear_messages), formatMessage(messages.clear_messages_warning), () => { this.deleteMessages(true, false, params, errorHandler); }, null, true, null); } }, 'messages_clear_hard': { id: 'messages_clear_hard', title: formatMessage(messages.clear_for_all), handler: (params, errorHandler) => { return props.onShowAlert(formatMessage(messages.clear_for_all), formatMessage(message.delete_messages_warning), () => { return this.deleteMessages(true, true, params, errorHandler); }, null, true, null); } }, 'message_delete': { id: 'message_delete', title: formatMessage(messages.delete), handler: (params, errorHandler) => { return this.deleteMessages(false, false, params, errorHandler); } }, 'message_delete_hard': { id: 'message_delete_hard', title: formatMessage(messages.delete_for_all), handler: (params, errorHandler) => { return this.deleteMessages(false, true, params, errorHandler); } }, 'menu_item_send_retry': { id: 'menu_item_send_retry', title: formatMessage(messages.send_retry), handler: (params, errorHandler) => { return this.retryMessage(params, errorHandler); } }, 'menu_item_reply': { id: 'menu_item_reply', title: formatMessage(messages.reply), handler: (params, errorHandler) => { return this.replyToMessage(params, errorHandler); } }, 'menu_item_forward': { id: 'menu_item_forward', title: formatMessage(messages.forward), handler: () => {} }, 'topic_unmute': { id: 'topic_unmute', title: formatMessage(messages.unmute), handler: this.topicPermissionSetter.bind(this, '+P') }, 'topic_mute': { id: 'topic_mute', title: formatMessage(messages.mute), handler: this.topicPermissionSetter.bind(this, '-P') }, 'topic_unblock': { id: 'topic_unblock', title: formatMessage(messages.unblock), handler: this.topicPermissionSetter.bind(this, '+JP') }, 'topic_block': { id: 'topic_block', title: formatMessage(messages.block), handler: (params, errorHandler) => { return props.onShowAlert(formatMessage(messages.block), formatMessage(messages.topic_block_warning), () => { return this.topicPermissionSetter('-JP', params, errorHandler).then(ctrl => { this.props.onTopicRemoved(params.topicName); return ctrl; }); }, null, true, null); } }, 'topic_delete': { id: 'topic_delete', title: formatMessage(messages.topic_delete), handler: (params, errorHandler) => { return props.onShowAlert(formatMessage(messages.topic_delete), formatMessage(messages.topic_delete_warning), () => { const topic = this.props.tinode.getTopic(params.topicName); if (!topic) { console.warn("Topic not found: ", params.topicName); return; } return topic.delTopic(true).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); }, null, true, null); } }, 'topic_archive': { id: 'topic_archive', title: formatMessage(messages.archive), handler: (params, errorHandler) => { const topic = this.props.tinode.getTopic(params.topicName); if (!topic) { console.warn("Topic not found: ", params.topicName); return; } return topic.archive(true).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } }, 'topic_restore': { id: 'topic_restore', title: formatMessage(messages.unarchive), handler: (params, errorHandler) => { const topic = this.props.tinode.getTopic(params.topicName); if (!topic) { console.warn("Topic not found: ", params.topicName); return; } return topic.archive(false).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } }, 'permissions': { id: 'permissions', title: formatMessage(messages.edit_permissions), handler: null }, 'member_delete': { id: 'member_delete', title: formatMessage(messages.member_delete), handler: (params, errorHandler) => { const topic = this.props.tinode.getTopic(params.topicName); if (!topic || !params.user) { console.warn("Topic or user not found: '" + params.topicName + "', '" + params.user + "'"); return; } return topic.delSubscription(params.user).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } }, 'member_mute': { id: 'member_mute', title: formatMessage(messages.mute), handler: this.topicPermissionSetter.bind(this, '-P') }, 'member_unmute': { id: 'member_unmute', title: formatMessage(messages.unmute), handler: this.topicPermissionSetter.bind(this, '+P') }, 'member_block': { id: 'member_block', title: formatMessage(messages.block), handler: this.topicPermissionSetter.bind(this, '-JP') }, 'member_unblock': { id: 'member_unblock', title: formatMessage(messages.unblock), handler: this.topicPermissionSetter.bind(this, '+JP') } }; } componentDidMount() { document.addEventListener('mousedown', this.handlePageClick, false); document.addEventListener('keyup', this.handleEscapeKey, false); } componentWillUnmount() { document.removeEventListener('mousedown', this.handlePageClick, false); document.removeEventListener('keyup', this.handleEscapeKey, false); } handlePageClick(e) { if (this.selfRef.current.contains(e.target)) { return; } e.preventDefault(); e.stopPropagation(); this.props.hide(); } handleEscapeKey(e) { if (e.keyCode === 27) { this.props.hide(); } } handleClick(e) { e.preventDefault(); e.stopPropagation(); this.props.hide(); let item = this.props.items[e.currentTarget.dataset.id]; if (typeof item == 'string') { item = this.MenuItems[item]; } if (!item) { console.error("Invalid menu item ID", e.currentTarget.dataset.id); } else { this.props.onAction(item.id, item.handler(this.props.params, this.props.onError), this.props.params); } } deleteMessages(all, hard, params, errorHandler) { const topic = this.props.tinode.getTopic(params.topicName); if (!topic) { console.warn("Topic not found: ", params.topicName); return; } if (!all && topic.cancelSend(params.seq)) { return; } const promise = all ? topic.delMessagesAll(hard) : topic.delMessagesList([params.seq], hard); return promise.catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } retryMessage(params, errorHandler) { const topic = this.props.tinode.getTopic(params.topicName); if (!topic || !topic.flushMessage(params.seq)) { return; } const msg = topic.createMessage(params.content, false); return topic.publishDraft(msg).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } topicPermissionSetter(mode, params, errorHandler) { const topic = this.props.tinode.getTopic(params.topicName); if (!topic) { console.warn("Topic not found", params.topicName); return; } let result = topic.updateMode(params.user, mode); if (errorHandler) { result = result.catch(err => { errorHandler(err.message, 'err'); }); } return result; } replyToMessage(params, errorHandler) { params.pickReply(params.seq, params.content, params.userFrom, params.userName, errorHandler); } render() { const menu = []; let count = 0; this.props.items.map(item => { if (typeof item == 'string') { item = this.MenuItems[item]; } if (item && item.title) { menu.push(item.title == '-' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { className: "separator", key: count }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { onClick: this.handleClick, "data-id": count, key: count }, item.title)); } count++; }); const hSize = 12 * _config_js__WEBPACK_IMPORTED_MODULE_2__.REM_SIZE; const vSize = _config_js__WEBPACK_IMPORTED_MODULE_2__.REM_SIZE * (0.7 + menu.length * 2.5); const left = this.props.bounds.right - this.props.clickAt.x < hSize ? this.props.clickAt.x - this.props.bounds.left - hSize : this.props.clickAt.x - this.props.bounds.left; const top = this.props.bounds.bottom - this.props.clickAt.y < vSize ? this.props.clickAt.y - this.props.bounds.top - vSize : this.props.clickAt.y - this.props.bounds.top; const position = { left: left + 'px', top: top + 'px' }; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("ul", { className: "menu", style: position, ref: this.selfRef }, menu); } } /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(ContextMenu)); /***/ }), /***/ "./src/widgets/cropper.jsx": /*!*********************************!*\ !*** ./src/widgets/cropper.jsx ***! \*********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ Cropper) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); const DEFAULT_MAX_ZOOM = 2.5; class Cropper extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { panX: 0, panY: 0, originX: 0, originY: 0, zoom: 1, minZoom: 0, maxZoom: DEFAULT_MAX_ZOOM }; this.overlay = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.cutout = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.preview = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.boundingBox = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.imageWidth = 0; this.imageHeight = 0; this.mouseX = 0; this.mouseY = 0; this.prevDistance = 0; this.cutoutRect = {}; this.bBoxRect = {}; this.originX = 0; this.originY = 0; this.initScaling = this.initScaling.bind(this); this.onZoom = this.onZoom.bind(this); this.handleZoom = this.handleZoom.bind(this); this.mouseDown = this.mouseDown.bind(this); this.mouseUp = this.mouseUp.bind(this); this.mouseMove = this.mouseMove.bind(this); this.mouseTouch = this.mouseTouch.bind(this); this.positionAll = this.positionAll.bind(this); this.translate = this.translate.bind(this); } componentDidMount() { this.overlay.current.addEventListener('mousedown', this.mouseDown, { passive: true }); this.overlay.current.addEventListener('touchstart', this.mouseDown, { passive: true }); this.bBoxRect = this.boundingBox.current.getBoundingClientRect(); this.originX = this.bBoxRect.width / 2; this.originY = this.bBoxRect.height / 2; this.cutoutRect = this.cutout.current.getBoundingClientRect(); } componentWillUnmount() { this.overlay.current.removeEventListener('mousedown', this.mouseDown); this.overlay.current.removeEventListener('touchstart', this.mouseDown); } positionAll(panX, panY, zoom) { this.setState({ panX: panX, panY: panY, zoom: zoom, originX: this.originX - panX, originY: this.originY - panY }); const left = (this.originX - panX) * zoom - this.originX; const top = (this.originY - panY) * zoom - this.originY; this.props.onChange((left + this.cutoutRect.left - this.bBoxRect.left) / zoom, (top + this.cutoutRect.top - this.bBoxRect.top) / zoom, this.cutoutRect.width / zoom, this.cutoutRect.height / zoom, zoom); } static checkBound(currPan, img, cutout, delta) { let nextDiff = Math.min(0, cutout[0] - img[0] - delta, img[1] - cutout[1] + delta); if (nextDiff == 0) { currPan += delta; } else if (Math.min(0, cutout[0] - img[0], img[1] - cutout[1]) < nextDiff) { currPan += delta; } return currPan; } initScaling() { const imgRect = this.preview.current.getBoundingClientRect(); this.imageWidth = imgRect.width; this.imageHeight = imgRect.height; const minZoom = Math.max(this.cutoutRect.width / imgRect.width, this.cutoutRect.height / imgRect.height); this.setState({ minZoom: minZoom, maxZoom: Math.max(DEFAULT_MAX_ZOOM, minZoom + 1) }); const zoom = Math.max(this.bBoxRect.width / imgRect.width, this.bBoxRect.height / imgRect.height); const panX = this.cutoutRect.left - this.bBoxRect.left - (imgRect.width - this.cutoutRect.width) / 2; const panY = this.cutoutRect.top - this.bBoxRect.top - (imgRect.height - this.cutoutRect.height) / 2; this.positionAll(panX, panY, zoom); } onZoom(e) { this.handleZoom(e.target.value); } handleZoom(zoom) { let panX = this.state.panX; let panY = this.state.panY; const imgLeft = this.originX - (this.originX - panX) * zoom; const imgRight = imgLeft + this.imageWidth * zoom; const coLeft = this.cutoutRect.left - this.bBoxRect.left; const coRight = coLeft + this.cutoutRect.width; if (coLeft < imgLeft) { panX -= imgLeft - coLeft; } else if (coRight > imgRight) { panX += coRight - imgRight; } const imgTop = this.originY - (this.originY - panY) * zoom; const imgBottom = imgTop + this.imageHeight * zoom; const coTop = this.cutoutRect.top - this.bBoxRect.top; const coBottom = coTop + this.cutoutRect.height; if (coTop < imgTop) { panY -= imgTop - coTop; } else if (coBottom > imgBottom) { panY += coBottom - imgBottom; } this.positionAll(panX, panY, zoom); } mouseDown(e) { if (e.touches) { this.mouseX = e.touches[0].pageX; this.mouseY = e.touches[0].pageY; } else { this.mouseX = e.pageX; this.mouseY = e.pageY; } window.addEventListener('mousemove', this.mouseMove, { passive: false }); window.addEventListener('touchmove', this.mouseTouch, { passive: false }); window.addEventListener('mouseup', this.mouseUp, { passive: true }); window.addEventListener('touchend', this.mouseUp, { passive: true }); document.body.style['userSelect'] = 'none'; } translate(pageX, pageY) { const dX = pageX - this.mouseX; const dY = pageY - this.mouseY; this.mouseX = pageX; this.mouseY = pageY; const imgRect = this.preview.current.getBoundingClientRect(); let panX = Cropper.checkBound(this.state.panX, [imgRect.left, imgRect.right], [this.cutoutRect.left, this.cutoutRect.right], dX); let panY = Cropper.checkBound(this.state.panY, [imgRect.top, imgRect.bottom], [this.cutoutRect.top, this.cutoutRect.bottom], dY); this.positionAll(panX, panY, this.state.zoom); } mouseMove(e) { e.preventDefault(); this.translate(e.pageX, e.pageY); } mouseTouch(e) { e.preventDefault(); if (e.touches.length == 1) { this.translate(e.touches[0].pageX, e.touches[0].pageY); return; } const [touch0, touch1] = e.touches; const distance = Math.sqrt((touch0.pageX - touch1.pageX) * (touch0.pageX - touch1.pageX) + (touch0.pageY - touch1.pageY) * (touch0.pageY - touch1.pageY)); if (!this.prevDistance) { this.prevDistance = distance / this.state.zoom; } let scale = distance / this.prevDistance; this.handleZoom(Math.max(this.minZoom, Math.min(this.maxZoom, scale))); } mouseUp(e) { window.removeEventListener('mousemove', this.mouseMove); window.removeEventListener('touchmove', this.mouseTouch); window.removeEventListener('mouseup', this.mouseUp); window.removeEventListener('touchend', this.mouseUp); document.body.style['userSelect'] = ''; this.positionAll(this.state.panX, this.state.panY, this.state.zoom); } render() { const t3d = "translate3d(".concat(this.state.panX, "px, ").concat(this.state.panY, "px, 0) scale(").concat(this.state.zoom, ")"); const orig = "".concat(this.state.originX, "px ").concat(this.state.originY, "px"); const overlay = { top: "".concat(this.originY - this.state.originY * this.state.zoom, "px"), left: "".concat(this.originX - this.state.originX * this.state.zoom, "px"), width: "".concat(this.imageWidth * this.state.zoom, "px"), height: "".concat(this.imageHeight * this.state.zoom, "px") }; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "cropper" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "bounding-box", ref: this.boundingBox }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { src: this.props.source, className: "preview", alt: "", style: { transform: t3d, transformOrigin: orig }, ref: this.preview, onLoad: this.initScaling }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "cutout circle", ref: this.cutout }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "overlay", style: overlay, ref: this.overlay })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "zoom-wrapper" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "range", className: "zoomer", step: "0.001", min: this.state.minZoom, max: this.state.maxZoom, value: this.state.zoom, onChange: this.onZoom }))); } } /***/ }), /***/ "./src/widgets/doc-preview.jsx": /*!*************************************!*\ !*** ./src/widgets/doc-preview.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ DocPreview) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_send_message_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/send-message.jsx */ "./src/widgets/send-message.jsx"); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); function iconFromMime(mime) { const mimeToIcon = { default: 'insert_drive_file', image: 'image', text: 'description', video: 'theaters' }; return mimeToIcon[mime] || mimeToIcon[(mime || '').split('/')[0]] || mimeToIcon['default']; } class DocPreview extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleSendDoc = this.handleSendDoc.bind(this); } handleSendDoc(caption) { this.props.onClose(); this.props.onSendMessage(this.props.content.file); } render() { if (!this.props.content) { return null; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "image-preview" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "image-preview-caption-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, this.props.content.name), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onClose(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, "close"))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "image-preview-container" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "flex-column narrow" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, iconFromMime(this.props.content.type)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_file_name", defaultMessage: [{ "type": 0, "value": "File name:" }] })), " ", (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_3__.shortenFileName)(this.props.content.name, 24) || '-'), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_content_type", defaultMessage: [{ "type": 0, "value": "Content type:" }] })), " ", this.props.content.type || 'application/octet-stream'), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_size", defaultMessage: [{ "type": 0, "value": "Size:" }] })), " ", (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_3__.bytesToHumanSize)(this.props.content.size)))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_send_message_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { noInput: true, tinode: this.props.tinode, reply: this.props.reply, onCancelReply: this.props.onCancelReply, onSendMessage: this.handleSendDoc, onError: this.props.onError })); } } ; /***/ }), /***/ "./src/widgets/error-panel.jsx": /*!*************************************!*\ !*** ./src/widgets/error-panel.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ErrorPanel) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _menu_cancel_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./menu-cancel.jsx */ "./src/widgets/menu-cancel.jsx"); class ErrorPanel extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { show: false }; this.hide = this.hide.bind(this); } componentDidUpdate(prevProps) { if (prevProps.level !== this.props.level) { this.setState({ show: !!this.props.level }); } } hide() { this.setState({ show: false }); if (this.props.onClearError) { this.props.onClearError(); } } render() { const icons = { err: 'error', warn: 'warning', info: 'info' }; const level = icons[this.props.level] || ''; const className = 'info-box ' + level; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: className }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "icon" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, level)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, this.props.text, this.props.action ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", style: { whiteSpace: 'nowrap' }, onClick: e => { e.preventDefault(); this.props.action(); } }, this.props.actionText)) : null), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "cancel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_menu_cancel_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { onCancel: this.hide }))); } } ; /***/ }), /***/ "./src/widgets/file-progress.jsx": /*!***************************************!*\ !*** ./src/widgets/file-progress.jsx ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ FileProgress) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); class FileProgress extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "uploader" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { style: { width: this.props.progress * 100 + "%" } })), this.props.progress < 0.999 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onCancel(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "close"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "action_cancel", defaultMessage: [{ "type": 0, "value": "cancel" }] })) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "upload_finishing", defaultMessage: [{ "type": 0, "value": "finishing..." }] })); } } /***/ }), /***/ "./src/widgets/forward-dialog.jsx": /*!****************************************!*\ !*** ./src/widgets/forward-dialog.jsx ***! \****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ForwardDialog) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _contact_list_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./contact-list.jsx */ "./src/widgets/contact-list.jsx"); /* harmony import */ var _search_contacts_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./search-contacts.jsx */ "./src/widgets/search-contacts.jsx"); class ForwardDialog extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { query: null }; this.handleEscapeKey = this.handleEscapeKey.bind(this); this.handleClose = this.handleClose.bind(this); this.handleSearchContacts = this.handleSearchContacts.bind(this); this.handleContactSelected = this.handleContactSelected.bind(this); } componentDidMount() { this.props.onInitFind(); } handleEscapeKey(e) { if (e.keyCode === 27) { this.props.hide(false); } } handleClose(e) { e.preventDefault(); this.props.hide(false); } handleSearchContacts(query) { this.setState({ query: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isNullValue(query) ? null : query }); this.props.onSearchContacts(query); } handleContactSelected(uid) { this.props.onTopicSelected(uid); this.props.hide(true); } render() { let contacts = this.state.query != null ? this.props.searchResults : this.props.contacts; contacts = contacts.filter(c => { return c.name != this.props.topicSelected && c.acs.isJoiner() && c.acs.isWriter(); }); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "alert-container" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "forward-dialog" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "title with-control" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "forward_to", defaultMessage: [{ "type": 0, "value": "Forward to" }], desription: "Title of the contact selector dialog when forwarding a message" })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleClose }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "close")))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "forward_to_search_placeholder", defaultMessage: [{ "type": 0, "value": "Search contacts" }] }, search_placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_search_contacts_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { placeholder: search_placeholder, onSearchContacts: this.handleSearchContacts })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "search_no_results", defaultMessage: [{ "type": 0, "value": "Search returned no results" }] }, not_found_placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_contact_list_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, contacts: contacts, myUserId: this.props.myUserId, emptyListMessage: not_found_placeholder, showOnline: false, showUnread: false, showContextMenu: false, onTopicSelected: this.handleContactSelected })))); } } /***/ }), /***/ "./src/widgets/group-manager.jsx": /*!***************************************!*\ !*** ./src/widgets/group-manager.jsx ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _chip_input_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./chip-input.jsx */ "./src/widgets/chip-input.jsx"); /* harmony import */ var _contact_list_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./contact-list.jsx */ "./src/widgets/contact-list.jsx"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ no_contacts: { id: "no_contacts", defaultMessage: [{ "type": 0, "value": "You have no contacts :-(" }] }, contacts_not_found_short: { id: "contacts_not_found_short", defaultMessage: [{ "type": 0, "value": "No contacts match '" }, { "type": 1, "value": "query" }, { "type": 0, "value": "'" }] } }); class GroupManager extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { members: props.members, index: GroupManager.indexMembers(props.members), staticMembers: GroupManager.staticMembers(props.members, props.keepInitialMembers, props.requiredMember), contactFilter: '', noContactsMessage: props.intl.formatMessage(messages.no_contacts), selectedContacts: GroupManager.selectedContacts(props.members) }; this.handleContactSelected = this.handleContactSelected.bind(this); this.handleMemberRemoved = this.handleMemberRemoved.bind(this); this.handleContactFilter = this.handleContactFilter.bind(this); this.handleSubmit = this.handleSubmit.bind(this); this.handleCancel = this.handleCancel.bind(this); } static indexMembers(members) { let index = {}; members.map(m => { index[m.user] = { delta: 0, present: true }; }); return index; } static staticMembers(members, keepInitial, requiredMember) { let stat = []; members.map(m => { if (keepInitial || m.user == requiredMember) { stat.push(m.user); } }); return stat; } static selectedContacts(members) { let sel = []; members.map(m => { sel.push(m.user); }); return sel; } handleContactSelected(userId, index) { let status = this.state.index[userId]; if (status) { if (status.present) { return; } status.delta += 1; status.present = true; } else { status = { delta: 1, present: true }; } let m = this.state.members.slice(); m.push(this.props.contacts[index]); const sel = GroupManager.selectedContacts(m); const i = this.state.index; i[userId] = status; this.setState({ members: m, index: i, selectedContacts: sel }); } handleMemberRemoved(userId, index) { const status = this.state.index[userId]; if (!status || !status.present) { return; } status.present = false; status.delta -= 1; let m = this.state.members.slice(); m.splice(index, 1); const sel = GroupManager.selectedContacts(m); const i = this.state.index; i[userId] = status; this.setState({ members: m, index: i, selectedContacts: sel }); } handleContactFilter(val) { const { formatMessage } = this.props.intl; const msg = !val ? formatMessage(messages.no_contacts) : formatMessage(messages.contacts_not_found_short, { query: val }); this.setState({ contactFilter: val, noContactsMessage: msg }); } static doContactFiltering(filter, values) { if (filter) { for (let i = 0; i < values.length; i++) { if (values[i].indexOf(filter) >= 0) { return true; } } return false; } return true; } handleSubmit() { var instance = this; var members = []; var added = []; var removed = []; var keys = Object.keys(this.state.index); keys.map(function (k) { if (instance.state.index[k].present) { members.push(k); } if (instance.state.index[k].delta > 0) { added.push(k); } else if (instance.state.index[k].delta < 0) { removed.push(k); } }); this.props.onSubmit(members, added, removed); } handleCancel() { this.props.onCancel(); } render() { const { formatMessage } = this.props.intl; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "group-manager" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "title_group_members", defaultMessage: [{ "type": 0, "value": "Group Members" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_chip_input_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { tinode: this.props.tinode, chips: this.state.members, staticMembers: this.state.staticMembers, prompt: "add members", filterFunc: this.handleContactFilter, onChipRemoved: this.handleMemberRemoved })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "title_all_contacts", defaultMessage: [{ "type": 0, "value": "All Contacts" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_contact_list_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, contacts: this.props.contacts, myUserId: this.props.myUserId, topicSelected: this.state.selectedContacts, filter: this.state.contactFilter, filterFunc: GroupManager.doContactFiltering, emptyListMessage: this.state.noContactsMessage, showOnline: false, showUnread: false, onTopicSelected: this.handleContactSelected }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "group-manager-buttons", className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "secondary", onClick: this.handleCancel }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_cancel", defaultMessage: [{ "type": 0, "value": "Cancel" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "primary", onClick: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_ok", defaultMessage: [{ "type": 0, "value": "OK" }] })))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(GroupManager)); /***/ }), /***/ "./src/widgets/group-subs.jsx": /*!************************************!*\ !*** ./src/widgets/group-subs.jsx ***! \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ GroupSubs) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); class GroupSubs extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); } render() { const usersOnline = []; const totalCount = (this.props.subscribers || []).length; const countToShow = Math.min(_config_js__WEBPACK_IMPORTED_MODULE_2__.MAX_ONLINE_IN_TOPIC, totalCount); (this.props.subscribers || []).some(sub => { usersOnline.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "avatar-box", key: sub.user }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, topic: sub.user, avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__.makeImageUrl)(sub.public ? sub.public.photo : null) || true, title: sub.public ? sub.public.fn : null }))); return usersOnline.length == countToShow; }); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "topic-users" }, usersOnline, " ", totalCount > countToShow ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "more_online_members", defaultMessage: [{ "type": 0, "value": "+" }, { "type": 1, "value": "overflow" }, { "type": 0, "value": " more" }], values: { overflow: totalCount - countToShow } })) : null); } } ; /***/ }), /***/ "./src/widgets/host-selector.jsx": /*!***************************************!*\ !*** ./src/widgets/host-selector.jsx ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ HostSelector) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); class HostSelector extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { hostName: props.serverAddress, changed: false }; this.handleHostNameChange = this.handleHostNameChange.bind(this); this.handleEditingFinished = this.handleEditingFinished.bind(this); } handleHostNameChange(e) { this.setState({ hostName: e.target.value, changed: true }); } handleEditingFinished() { if (this.state.changed) { this.setState({ changed: false }); this.props.onServerAddressChange(this.state.hostName.trim()); } } render() { var hostOptions = []; for (let key in _config_js__WEBPACK_IMPORTED_MODULE_1__.KNOWN_HOSTS) { let item = _config_js__WEBPACK_IMPORTED_MODULE_1__.KNOWN_HOSTS[key]; hostOptions.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("option", { key: item, value: item })); } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "search", id: "host-name", placeholder: this.props.hostName, list: "known-hosts", className: "quoted", value: this.state.hostName, onChange: this.handleHostNameChange, onBlur: this.handleEditingFinished, required: true }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("datalist", { id: "known-hosts" }, hostOptions)); } } /***/ }), /***/ "./src/widgets/image-preview.jsx": /*!***************************************!*\ !*** ./src/widgets/image-preview.jsx ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ImagePreview) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_send_message_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/send-message.jsx */ "./src/widgets/send-message.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); class ImagePreview extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { width: 0, height: 0 }; this.handleSendImage = this.handleSendImage.bind(this); } assignWidth(node) { if (node && !this.state.width) { const bounds = node.getBoundingClientRect(); this.setState({ width: bounds.width | 0, height: bounds.height | 0 }); } } handleSendImage(caption) { this.props.onClose(); this.props.onSendMessage(caption, this.props.content.blob); } render() { if (!this.props.content) { return null; } const dim = (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__.fitImageSize)(this.props.content.width, this.props.content.height, this.state.width, this.state.height, false); const size = dim ? { width: dim.dstWidth + 'px', height: dim.dstHeight + 'px' } : this.props.content.width > this.props.content.height ? { width: '100%' } : { height: '100%' }; size.maxWidth = '100%'; size.maxHeight = '100%'; const maxlength = Math.max((this.state.width / _config_js__WEBPACK_IMPORTED_MODULE_3__.REM_SIZE / 1.5 | 0) - 2, 12); const fname = (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_5__.shortenFileName)(this.props.content.name, maxlength) || '-'; const width = this.props.content.width || '-'; const height = this.props.content.height || '-'; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "image-preview" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "image-preview-caption-panel" }, !this.props.onSendMessage ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: this.props.content.url, download: true }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "file_download"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "download_action", defaultMessage: [{ "type": 0, "value": "download" }] })) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, fname), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onClose(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, "close"))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "image-preview-container", ref: node => this.assignWidth(node) }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { src: this.props.content.url, style: size, className: "image-preview", alt: this.props.content.name })), this.props.onSendMessage ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_send_message_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { messagePrompt: "add_image_caption", acceptBlank: true, tinode: this.props.tinode, reply: this.props.reply, onCancelReply: this.props.onCancelReply, onSendMessage: this.handleSendImage, onError: this.props.onError }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "image-preview-footer" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_file_name", defaultMessage: [{ "type": 0, "value": "File name:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { title: this.props.content.name }, fname))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_content_type", defaultMessage: [{ "type": 0, "value": "Content type:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, this.props.content.type)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_size", defaultMessage: [{ "type": 0, "value": "Size:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, width, " \xD7 ", height, " px; ", (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_5__.bytesToHumanSize)(this.props.content.size))))); } } ; /***/ }), /***/ "./src/widgets/in-place-edit.jsx": /*!***************************************!*\ !*** ./src/widgets/in-place-edit.jsx ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ InPlaceEdit) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _visible_password_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./visible-password.jsx */ "./src/widgets/visible-password.jsx"); class InPlaceEdit extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.selfRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.state = { active: props.active, initialValue: props.value || '', value: props.value || '' }; this.handeTextChange = this.handeTextChange.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); this.handleStartEditing = this.handleStartEditing.bind(this); this.handleEditingFinished = this.handleEditingFinished.bind(this); this.handlePasswordFinished = this.handlePasswordFinished.bind(this); } componentDidUpdate(prevProps, prevState) { const newValue = this.props.value || ''; if (prevState.initialValue != newValue && !prevState.active) { this.setState({ initialValue: newValue, value: newValue }); } } handeTextChange(e) { this.setState({ value: e.target.value || '' }); } handleKeyDown(e) { if (e.keyCode === 27) { this.setState({ value: this.props.value, active: false }); } else if (e.keyCode === 13) { this.handleEditingFinished(e); } } handleStartEditing() { if (!this.props.readOnly) { this.setState({ active: true }, () => { if (this.selfRef.current) { this.selfRef.current.focus(); } }); } } handleEditingFinished(event) { const value = this.state.value.trim(); if (this.props.required && (!event.target.checkValidity() || !value)) { this.setState({ value: this.props.value, active: false }); return; } this.setState({ active: false }); if ((value || this.props.value) && value !== this.props.value) { this.props.onFinished(value); } } handlePasswordFinished(value) { this.setState({ active: false }); if (value && value !== this.props.value) { this.props.onFinished(value); } } render() { if (!this.state.active) { let spanText = this.props.type == 'password' ? '••••••••' : this.state.value; let spanClass = 'in-place-edit' + (this.props.readOnly ? ' disabled' : ''); if (!spanText) { spanText = this.props.placeholder; spanClass += ' placeholder'; } if (!this.props.multiline || this.props.multiline == 1) { spanClass += ' short'; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: spanClass, onClick: this.handleStartEditing }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, spanText)); } let element; const attr = {}; if (this.props.type == 'password') { element = _visible_password_jsx__WEBPACK_IMPORTED_MODULE_1__["default"]; attr.onFinished = this.handlePasswordFinished; } else { if (this.props.multiline > 1) { element = 'textarea'; attr.rows = this.props.multiline; attr.className = 'inplace-edit'; } else { element = 'input'; attr.type = this.props.type || 'text'; } attr.value = this.state.value; attr.onChange = this.handeTextChange; attr.onKeyDown = this.handleKeyDown; attr.onBlur = this.handleEditingFinished; } attr.placeholder = this.props.placeholder; attr.required = this.props.required ? 'required' : ''; attr.autoComplete = this.props.autoComplete; attr.autoFocus = true; attr.ref = this.selfRef; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(element, attr, null); } } ; /***/ }), /***/ "./src/widgets/invitation.jsx": /*!************************************!*\ !*** ./src/widgets/invitation.jsx ***! \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ Invitation) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); class Invitation extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleButtonAction = this.handleButtonAction.bind(this); } handleButtonAction(evt, data) { evt.preventDefault(); this.props.onAction(data); } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "accept-invite-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "title" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "chat_invitation", defaultMessage: [{ "type": 0, "value": "You are invited to start a new chat. What would you like to do?" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "footer" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "primary", onClick: event => { this.handleButtonAction(event, "accept"); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "chat_invitation_accept", defaultMessage: [{ "type": 0, "value": "Accept" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "secondary", onClick: event => { this.handleButtonAction(event, "delete"); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "chat_invitation_ignore", defaultMessage: [{ "type": 0, "value": "Ignore" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "secondary", onClick: event => { this.handleButtonAction(event, "block"); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "chat_invitation_block", defaultMessage: [{ "type": 0, "value": "Block" }] })))); } } ; /***/ }), /***/ "./src/widgets/lazy-image.jsx": /*!************************************!*\ !*** ./src/widgets/lazy-image.jsx ***! \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ LazyImage) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); class LazyImage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { src: 'img/placeholder.png', style: Object.assign({ padding: '4px' }, this.props.style), className: this.props.className, alt: this.props.alt, onClick: this.props.onClick }; } componentDidMount() { this.props.whenDone.promise.then(data => this.setState({ src: data.src, style: { ...this.state.style, padding: 0 } })).catch(() => this.setState({ src: 'img/broken_image.png' })); } componentWillUnmount() { this.props.whenDone.cancel(); } componentDidUpdate(prevProps) { if (prevProps.whenDone != this.props.whenDone) { this.setState({ src: 'img/placeholder.png', style: { ...this.state.style, padding: '4px' } }); this.props.whenDone.promise.then(data => this.setState({ src: data.src, style: { ...this.state.style, padding: 0 } })).catch(() => this.setState({ src: 'img/broken_image.png' })); } } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement('img', this.state); } } ; /***/ }), /***/ "./src/widgets/letter-tile.jsx": /*!*************************************!*\ !*** ./src/widgets/letter-tile.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ LetterTile) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); class LetterTile extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { let avatar; if (this.props.avatar === true) { const isGroup = tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Tinode.isGroupTopicName(this.props.topic); const iconColor = (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_2__.idToColorClass)(this.props.topic, isGroup); if (this.props.topic && this.props.title && this.props.title.trim()) { const letter = this.props.title.trim().charAt(0); const className = 'lettertile ' + iconColor + (this.props.deleted ? ' disabled' : ''); avatar = react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: className }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, letter)); } else { const className = 'material-icons ' + iconColor + (this.props.deleted ? ' disabled' : ''); avatar = isGroup ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: className }, "group") : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: className }, "person"); } } else if (this.props.avatar) { const url = this.props.tinode.authorizeURL((0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_3__.sanitizeUrlForMime)(this.props.avatar, 'image')); const className = 'avatar' + (this.props.deleted ? ' deleted' : ''); avatar = react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { className: className, alt: "avatar", src: url, onError: e => { e.target.onerror = null; e.target.src = "../img/broken_image.png"; } }); } else { avatar = null; } return avatar; } } /***/ }), /***/ "./src/widgets/load-spinner.jsx": /*!**************************************!*\ !*** ./src/widgets/load-spinner.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ LoadSpinner) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class LoadSpinner extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { const className = 'load-spinner-box' + (this.props.large ? ' large' : '') + (this.props.clear ? ' clear' : '') + (this.props.centered ? ' centered' : ''); return this.props.show ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: className }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "loader-spinner" })) : null; } } /***/ }), /***/ "./src/widgets/menu-cancel.jsx": /*!*************************************!*\ !*** ./src/widgets/menu-cancel.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ MenuCancel) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class MenuCancel extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onCancel(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "close")); } } /***/ }), /***/ "./src/widgets/menu-contacts.jsx": /*!***************************************!*\ !*** ./src/widgets/menu-contacts.jsx ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ MenuContacts) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class MenuContacts extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onNewTopic(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "chat")), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onSettings(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "settings"))); } } ; /***/ }), /***/ "./src/widgets/menu-start.jsx": /*!************************************!*\ !*** ./src/widgets/menu-start.jsx ***! \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ MenuStart) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class MenuStart extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onSignUp(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "person_add")), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onSettings(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "settings"))); } } ; /***/ }), /***/ "./src/widgets/meta-message.jsx": /*!**************************************!*\ !*** ./src/widgets/meta-message.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ MetaMessage) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); class MetaMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); } render() { let content = null; let bubbleClass = 'bubble'; if (this.props.deleted) { content = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, "block"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "gray" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "deleted_content", defaultMessage: [{ "type": 0, "value": "content deleted" }] }))); bubbleClass += ' deleted'; } else if (this.props.date) { content = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, this.props.date); bubbleClass += ' date'; } if (!content) { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, null); } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { className: "meta" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: bubbleClass }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "message-content" }, content))); } } ; /***/ }), /***/ "./src/widgets/new-topic-by-id.jsx": /*!*****************************************!*\ !*** ./src/widgets/new-topic-by-id.jsx ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ invalid_id: { id: "error_invalid_id", defaultMessage: [{ "type": 0, "value": "Invalid ID" }] } }); class NewTopicById extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { groupId: '' }; this.handleChange = this.handleChange.bind(this); this.handleKeyPress = this.handleKeyPress.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(e) { this.setState({ groupId: e.target.value }); } handleKeyPress(e) { if (e.key === 'Enter') { this.handleSubmit(e); } } handleSubmit(e) { e.preventDefault(); if (this.state.groupId) { const name = this.state.groupId.trim(); const prefix = name.substr(0, 3); if (name.length > 3 && ['usr', 'grp', 'chn'].includes(prefix)) { this.props.onSubmit(name); } else { this.props.onError(this.props.intl.formatMessage(messages.invalid_id), 'err'); } } } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "group_user_id_prompt", defaultMessage: [{ "type": 0, "value": "Group or User ID" }] }, prompt => react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", placeholder: prompt, value: this.state.groupId, onChange: this.handleChange, onKeyPress: this.handleKeyPress, required: true, autoFocus: true }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "dialog-buttons" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "primary", onClick: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_subscribe", defaultMessage: [{ "type": 0, "value": "Subscribe" }] })))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(NewTopicById)); /***/ }), /***/ "./src/widgets/new-topic-group.jsx": /*!*****************************************!*\ !*** ./src/widgets/new-topic-group.jsx ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ NewTopicGroup) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./avatar-upload.jsx */ "./src/widgets/avatar-upload.jsx"); /* harmony import */ var _checkbox_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./checkbox.jsx */ "./src/widgets/checkbox.jsx"); /* harmony import */ var _tag_manager_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./tag-manager.jsx */ "./src/widgets/tag-manager.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); class NewTopicGroup extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.fullName = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.state = { fullName: '', private: '', description: '', imageDataUrl: null, tags: [], isChannel: false }; this.handleFieldEdit = this.handleFieldEdit.bind(this); this.handleImageChanged = this.handleImageChanged.bind(this); this.handleTagsChanged = this.handleTagsChanged.bind(this); this.handleChannelToggle = this.handleChannelToggle.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } componentDidMount() {} handleFieldEdit(name, e) { this.setState({ [name]: e.target.value || '' }); } handleImageChanged(img) { this.setState({ imageDataUrl: img }); } handleTagsChanged(tags) { this.setState({ tags: tags }); } handleChannelToggle() { this.setState({ isChannel: !this.state.isChannel }); } handleSubmit(e) { e.preventDefault(); const fn = this.state.fullName.trim().substring(0, _config_js__WEBPACK_IMPORTED_MODULE_5__.MAX_TITLE_LENGTH); const comment = this.state.private.trim().substring(0, _config_js__WEBPACK_IMPORTED_MODULE_5__.MAX_TITLE_LENGTH); const description = this.state.description.trim().substring(0, _config_js__WEBPACK_IMPORTED_MODULE_5__.MAX_TOPIC_DESCRIPTION_LENGTH); if (fn) { this.props.onSubmit(fn, description, this.state.imageDataUrl, comment, this.state.tags, this.state.isChannel); } } render() { let submitClasses = 'primary'; if (this.props.disabled) { submitClasses += ' disabled'; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("form", { className: "panel-form", onSubmit: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("center", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { tinode: this.props.tinode, onError: this.props.onError, onImageChanged: this.handleImageChanged })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small", htmlFor: "new-topic-fn" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_topic_name", defaultMessage: [{ "type": 0, "value": "Name" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "topic_name_editing_placeholder", defaultMessage: [{ "type": 0, "value": "Freeform name of the group" }] }, placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", id: "new-topic-fn", placeholder: placeholder, ref: this.fullName, value: this.state.fullName, onChange: this.handleFieldEdit.bind(this, 'fullName'), autoFocus: true, required: true, tabIndex: 0 }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small", htmlFor: "new-topic-priv" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_private", defaultMessage: [{ "type": 0, "value": "Private comment" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "private_editing_placeholder", defaultMessage: [{ "type": 0, "value": "Visible to you only" }] }, placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", id: "new-topic-priv", placeholder: placeholder, value: this.state.private, onChange: this.handleFieldEdit.bind(this, 'private'), tabIndex: 1 }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small", htmlFor: "new-topic-desc" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_description", defaultMessage: [{ "type": 0, "value": "Description" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "description_editing_placeholder", defaultMessage: [{ "type": 0, "value": "Description (optional)" }] }, placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", id: "new-topic-desc", placeholder: placeholder, value: this.state.description, onChange: this.handleFieldEdit.bind(this, 'description'), tabIndex: 2 })))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_checkbox_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { checked: this.state.isChannel, tabIndex: 3, onChange: this.handleChannelToggle }), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { onClick: this.handleChannelToggle }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "channel_prompt", defaultMessage: [{ "type": 0, "value": "This is a channel" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "title_tag_manager", defaultMessage: [{ "type": 0, "value": "Tags (search & discovery)" }] }, title => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_tag_manager_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { tinode: this.props.tinode, tags: this.state.tags, activated: true, onTagsChanged: this.handleTagsChanged, tabIndex: 4, title: title })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "dialog-buttons" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: submitClasses }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_create", defaultMessage: [{ "type": 0, "value": "Create" }] })))); } } ; /***/ }), /***/ "./src/widgets/permissions-editor.jsx": /*!********************************************!*\ !*** ./src/widgets/permissions-editor.jsx ***! \********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./checkbox.jsx */ "./src/widgets/checkbox.jsx"); /* harmony import */ var _contact_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./contact.jsx */ "./src/widgets/contact.jsx"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ joiner: { id: "permission_join", defaultMessage: [{ "type": 0, "value": "Join (" }, { "type": 1, "value": "val" }, { "type": 0, "value": ")" }] }, reader: { id: "permission_read", defaultMessage: [{ "type": 0, "value": "Read (" }, { "type": 1, "value": "val" }, { "type": 0, "value": ")" }] }, writer: { id: "permission_write", defaultMessage: [{ "type": 0, "value": "Write (" }, { "type": 1, "value": "val" }, { "type": 0, "value": ")" }] }, preser: { id: "permission_pres", defaultMessage: [{ "type": 0, "value": "Get notified (" }, { "type": 1, "value": "val" }, { "type": 0, "value": ")" }] }, approver: { id: "permission_admin", defaultMessage: [{ "type": 0, "value": "Approve (" }, { "type": 1, "value": "val" }, { "type": 0, "value": ")" }] }, sharer: { id: "permission_share", defaultMessage: [{ "type": 0, "value": "Share (" }, { "type": 1, "value": "val" }, { "type": 0, "value": ")" }] }, deleter: { id: "permission_delete", defaultMessage: [{ "type": 0, "value": "Delete (" }, { "type": 1, "value": "val" }, { "type": 0, "value": ")" }] }, owner: { id: "permission_owner", defaultMessage: [{ "type": 0, "value": "Owner (" }, { "type": 1, "value": "val" }, { "type": 0, "value": ")" }] } }); class PermissionsEditor extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { mode: (props.mode || '').replace('N', '') }; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); this.handleCancel = this.handleCancel.bind(this); } handleChange(val) { let mode = this.state.mode; const idx = mode.indexOf(val); if (idx == -1) { mode += val; } else { mode = mode.replace(val, ''); } this.setState({ mode: mode }); } handleSubmit() { const mode = (this.state.mode || 'N').split('').sort().join(''); const before = (this.props.mode || 'N').split('').sort().join(''); if (mode !== before) { this.props.onSubmit(mode); } else { this.props.onCancel(); } } handleCancel() { this.props.onCancel(); } render() { const { formatMessage } = this.props.intl; const all = 'JRWPASDO'; const names = { 'J': formatMessage(messages.joiner, { val: 'J' }), 'R': formatMessage(messages.reader, { val: 'R' }), 'W': formatMessage(messages.writer, { val: 'W' }), 'P': formatMessage(messages.preser, { val: 'P' }), 'A': formatMessage(messages.approver, { val: 'A' }), 'S': formatMessage(messages.sharer, { val: 'S' }), 'D': formatMessage(messages.deleter, { val: 'D' }), 'O': formatMessage(messages.owner, { val: 'O' }) }; let skip = this.props.skip || ''; let mode = this.state.mode; let compare = (this.props.compare || '').replace('N', ''); let items = []; for (let i = 0; i < all.length; i++) { let c = all.charAt(i); if (skip.indexOf(c) >= 0 && mode.indexOf(c) < 0) { continue; } items.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tr", { key: c }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", null, names[c]), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { className: "checkbox" }, skip.indexOf(c) < 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { name: c, checked: mode.indexOf(c) >= 0, onChange: this.handleChange }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { name: c, checked: mode.indexOf(c) >= 0 })), this.props.compare ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { className: "checkbox" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { name: c, checked: compare.indexOf(c) >= 0 })) : null)); } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, this.props.userTitle ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("ul", { className: "contact-box small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_contact_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, item: this.props.item, title: this.props.userTitle, small: true, avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__.makeImageUrl)(this.props.userAvatar ? this.props.userAvatar : null) })) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "title_permissions", defaultMessage: [{ "type": 0, "value": "Permissions" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("table", { className: "permission-editor" }, this.props.compare ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("thead", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tr", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("th", null), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("th", null, this.props.modeTitle), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("th", null, this.props.compareTitle))) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tbody", null, items)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("br", null), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "dialog-buttons" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "outline", onClick: this.handleCancel }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_cancel", defaultMessage: [{ "type": 0, "value": "Cancel" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "primary", onClick: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_ok", defaultMessage: [{ "type": 0, "value": "OK" }] })))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(PermissionsEditor)); /***/ }), /***/ "./src/widgets/received-marker.jsx": /*!*****************************************!*\ !*** ./src/widgets/received-marker.jsx ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ message_sending: { id: "message_sending", defaultMessage: [{ "type": 0, "value": "sending..." }] }, message_sending_failed: { id: "message_sending_failed", defaultMessage: [{ "type": 0, "value": "failed" }] } }); class ReceivedMarker extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { const { formatMessage } = this.props.intl; let timestamp; if (this.props.received <= tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_SENDING) { timestamp = formatMessage(messages.message_sending); } else if (this.props.received == tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_FAILED) { timestamp = formatMessage(messages.message_sending_failed); } else { timestamp = this.props.timestamp.toLocaleTimeString(this.props.intl.locale, { timeStyle: 'short' }); } const icon = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_3__.deliveryMarker)(this.props.received); const marker = icon ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: 'material-icons small ' + icon.color }, icon.name) : null; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "timestamp" }, timestamp, '\u00a0', marker); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(ReceivedMarker)); /***/ }), /***/ "./src/widgets/search-contacts.jsx": /*!*****************************************!*\ !*** ./src/widgets/search-contacts.jsx ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ SearchContacts) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_1__); class SearchContacts extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { edited: false, search: '' }; this.handleSearchChange = this.handleSearchChange.bind(this); this.handleSearch = this.handleSearch.bind(this); this.handleClear = this.handleClear.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); } componentWillUnmount() { if (this.state.edited) { this.setState({ search: '', edited: false }); this.props.onSearchContacts(tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Tinode.DEL_CHAR); } } handleSearchChange(e) { this.setState({ search: e.target.value }); } handleSearch(e) { e.preventDefault(); var query = this.state.search.trim(); this.setState({ edited: query.length > 0 }); this.props.onSearchContacts(query.length > 0 ? query : tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Tinode.DEL_CHAR); } handleClear(e) { e.preventDefault(); if (this.state.edited) { this.props.onSearchContacts(tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Tinode.DEL_CHAR); } this.setState({ search: '', edited: false }); } handleKeyDown(e) { if (e.key === 'Enter') { this.handleSearch(e); } else if (e.key === 'Escape') { this.handleClear(); } } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons search" }, "search"), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { className: "search", type: "text", placeholder: this.props.placeholder, value: this.state.search, onChange: this.handleSearchChange, onKeyDown: this.handleKeyDown, required: true, autoFocus: true }), this.state.search ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleClear }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "highlight_off")) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "\xA0")))); } } ; /***/ }), /***/ "./src/widgets/send-message.jsx": /*!**************************************!*\ !*** ./src/widgets/send-message.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _audio_recorder_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./audio-recorder.jsx */ "./src/widgets/audio-recorder.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_formatters_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/formatters.js */ "./src/lib/formatters.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ messaging_disabled: { id: "messaging_disabled_prompt", defaultMessage: [{ "type": 0, "value": "Messaging disabled" }] }, type_new_message: { id: "new_message_prompt", defaultMessage: [{ "type": 0, "value": "New message" }] }, add_image_caption: { id: "image_caption_prompt", defaultMessage: [{ "type": 0, "value": "Image caption" }] }, file_attachment_too_large: { id: "file_attachment_too_large", defaultMessage: [{ "type": 0, "value": "The file size " }, { "type": 1, "value": "size" }, { "type": 0, "value": " exceeds the " }, { "type": 1, "value": "limit" }, { "type": 0, "value": " limit." }] }, cannot_initiate_upload: { id: "cannot_initiate_file_upload", defaultMessage: [{ "type": 0, "value": "Cannot initiate file upload." }] } }); class SendMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { quote: null, message: '', audioRec: false, audioAvailable: !!navigator.mediaDevices.getUserMedia, keypressTimestamp: new Date().getTime() - _config_js__WEBPACK_IMPORTED_MODULE_4__.KEYPRESS_DELAY - 1 }; this.handlePasteEvent = this.handlePasteEvent.bind(this); this.handleAttachImage = this.handleAttachImage.bind(this); this.handleAttachFile = this.handleAttachFile.bind(this); this.handleAttachAudio = this.handleAttachAudio.bind(this); this.handleSend = this.handleSend.bind(this); this.handleKeyPress = this.handleKeyPress.bind(this); this.handleMessageTyping = this.handleMessageTyping.bind(this); this.handleQuoteClick = this.handleQuoteClick.bind(this); this.formatReply = this.formatReply.bind(this); } componentDidMount() { if (this.messageEditArea) { this.messageEditArea.addEventListener('paste', this.handlePasteEvent, false); } this.setState({ quote: this.formatReply() }); } componentWillUnmount() { if (this.messageEditArea) { this.messageEditArea.removeEventListener('paste', this.handlePasteEvent, false); } } componentDidUpdate(prevProps) { if (this.messageEditArea) { this.messageEditArea.focus(); } if (prevProps.topicName != this.props.topicName) { this.setState({ message: '', audioRec: false, quote: null }); } if (prevProps.reply != this.props.reply) { this.setState({ quote: this.formatReply() }); } } formatReply() { return this.props.reply ? tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.format(this.props.reply.content, _lib_formatters_js__WEBPACK_IMPORTED_MODULE_6__.replyFormatter, { formatMessage: this.props.intl.formatMessage.bind(this.props.intl), authorizeURL: this.props.tinode.authorizeURL.bind(this.props.tinode) }) : null; } handlePasteEvent(e) { if (this.props.disabled) { return; } if ((0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_5__.filePasted)(e, file => { this.props.onAttachImage(file); }, file => { this.props.onAttachFile(file); }, this.props.onError)) { e.preventDefault(); } } handleAttachImage(e) { if (e.target.files && e.target.files.length > 0) { this.props.onAttachImage(e.target.files[0]); } e.target.value = ''; } handleAttachFile(e) { if (e.target.files && e.target.files.length > 0) { this.props.onAttachFile(e.target.files[0]); } e.target.value = ''; } handleAttachAudio(url, preview, duration) { this.setState({ audioRec: false }); this.props.onAttachAudio(url, preview, duration); } handleSend(e) { e.preventDefault(); const message = this.state.message.trim(); if (message || this.props.acceptBlank || this.props.noInput) { this.props.onSendMessage(message); this.setState({ message: '' }); } } handleKeyPress(e) { if (this.state.audioRec) { e.preventDefault(); e.stopPropagation(); return; } if (e.key === 'Enter') { if (!e.shiftKey) { e.preventDefault(); e.stopPropagation(); this.handleSend(e); } } } handleMessageTyping(e) { const newState = { message: e.target.value }; if (this.props.onKeyPress) { const now = new Date().getTime(); if (now - this.state.keypressTimestamp > _config_js__WEBPACK_IMPORTED_MODULE_4__.KEYPRESS_DELAY) { this.props.onKeyPress(); newState.keypressTimestamp = now; } } this.setState(newState); } handleQuoteClick(e) { e.preventDefault(); e.stopPropagation(); if (this.props.reply && this.props.onQuoteClick) { const replyToSeq = this.props.reply.seq; this.props.onQuoteClick(replyToSeq); } } render() { const { formatMessage } = this.props.intl; const prompt = this.props.disabled ? formatMessage(messages.messaging_disabled) : this.props.messagePrompt ? formatMessage(messages[this.props.messagePrompt]) : formatMessage(messages.type_new_message); const quote = this.state.quote ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "reply-quote-preview" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "cancel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onCancelReply(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, "close"))), this.state.quote) : null; const audioEnabled = this.state.audioAvailable && this.props.onAttachAudio; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "send-message-wrapper" }, !this.props.noInput ? quote : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "send-message-panel" }, !this.props.disabled ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, this.props.onAttachFile && !this.state.audioRec ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.attachImage.click(); }, title: "Add image" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons secondary" }, "photo")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.attachFile.click(); }, title: "Attach file" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons secondary" }, "attach_file"))) : null, this.props.noInput ? quote || react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr thin" }) : this.state.audioRec ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_audio_recorder_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { onDeleted: _ => this.setState({ audioRec: false }), onFinished: this.handleAttachAudio }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("textarea", { id: "sendMessage", placeholder: prompt, value: this.state.message, onChange: this.handleMessageTyping, onKeyPress: this.handleKeyPress, ref: ref => { this.messageEditArea = ref; }, autoFocus: true }), this.state.message || !audioEnabled ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleSend, title: "Send" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "send")) : !this.state.audioRec ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.setState({ audioRec: true }); }, title: "Voice" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "mic")) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "file", ref: ref => { this.attachFile = ref; }, onChange: this.handleAttachFile, style: { display: 'none' } }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "file", ref: ref => { this.attachImage = ref; }, accept: "image/*", onChange: this.handleAttachImage, style: { display: 'none' } })) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "writing-disabled" }, prompt))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(SendMessage)); /***/ }), /***/ "./src/widgets/side-navbar.jsx": /*!*************************************!*\ !*** ./src/widgets/side-navbar.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ SideNavbar) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _button_back_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./button-back.jsx */ "./src/widgets/button-back.jsx"); /* harmony import */ var _contact_badges_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./contact-badges.jsx */ "./src/widgets/contact-badges.jsx"); /* harmony import */ var _menu_contacts_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./menu-contacts.jsx */ "./src/widgets/menu-contacts.jsx"); /* harmony import */ var _menu_start_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./menu-start.jsx */ "./src/widgets/menu-start.jsx"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); class SideNavbar extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { const icon_badges = []; if (this.props.trustedBadges) { this.props.trustedBadges.map(b => { icon_badges.push({ icon: b, color: 'badge-inv' }); }); } let avatar = null; if (this.props.tinode) { avatar = this.props.tinode.authorizeURL((0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_6__.sanitizeUrlForMime)(this.props.avatar, 'image')); } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "side-caption-panel", className: "caption-panel" }, this.props.onCancel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_button_back_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { onBack: this.props.onCancel }) : null, avatar ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "self-avatar", className: "avatar-box" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { tinode: this.props.tinode, avatar: avatar, topic: this.props.myUserId, title: this.props.title })) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "sidepanel-title", className: "panel-title" }, this.props.title, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_contact_badges_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { badges: icon_badges })), this.props.state === 'login' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_menu_start_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { onSignUp: this.props.onSignUp, onSettings: this.props.onSettings }) : this.props.state === 'contacts' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_menu_contacts_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { onNewTopic: this.props.onNewTopic, onSettings: this.props.onSettings }) : null); } } ; /***/ }), /***/ "./src/widgets/tag-manager.jsx": /*!*************************************!*\ !*** ./src/widgets/tag-manager.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ TagManager) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _chip_input_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./chip-input.jsx */ "./src/widgets/chip-input.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); class TagManager extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { tags: this.props.tags || [], tagInput: '', activated: this.props.activated }; this.handleTagInput = this.handleTagInput.bind(this); this.handleAddTag = this.handleAddTag.bind(this); this.handleRemoveTag = this.handleRemoveTag.bind(this); this.handleSubmit = this.handleSubmit.bind(this); this.handleCancel = this.handleCancel.bind(this); } static getDerivedStateFromProps(nextProps, prevState) { const tags = nextProps.tags || []; if (!(0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_4__.arrayEqual)(tags, prevState.tags) && !prevState.activated) { return { tags: tags }; } return null; } handleTagInput(text) { this.setState({ tagInput: text }); if (text.length > 0) { const last = text[text.length - 1]; if (text[0] == '"') { if (text.length > 1 && last == '"') { this.handleAddTag(text.substring(1, text.length - 1)); } } else if (last == ',' || last == ' ' || last == ';' || last == '"') { this.handleAddTag(text.substring(0, text.length - 1).trim()); } } } handleAddTag(tag) { const maxTagCount = this.props.tinode.getServerLimit('maxTagCount', _config_js__WEBPACK_IMPORTED_MODULE_3__.MAX_TAG_COUNT); if (tag.length > 0 && this.state.tags.length < maxTagCount) { const tags = this.state.tags.slice(0); tags.push(tag); this.setState({ tags: tags, tagInput: '' }); if (this.props.onTagsChanged) { this.props.onTagsChanged(tags); } return tags; } return this.state.tags; } handleRemoveTag(tag, index) { const tags = this.state.tags.slice(0); tags.splice(index, 1); this.setState({ tags: tags }); if (this.props.onTagsChanged) { this.props.onTagsChanged(tags); } } handleSubmit() { this.props.onSubmit(this.handleAddTag(this.state.tagInput.trim())); this.setState({ activated: false, tags: this.props.tags || [] }); } handleCancel() { this.setState({ activated: false, tagInput: '', tags: this.props.tags || [] }); if (this.props.onCancel) { this.props.onCancel(); } } render() { const minTagLength = this.props.tinode.getServerLimit('minTagLength', _config_js__WEBPACK_IMPORTED_MODULE_3__.MIN_TAG_LENGTH); const maxTagLength = this.props.tinode.getServerLimit('maxTagLength', _config_js__WEBPACK_IMPORTED_MODULE_3__.MAX_TAG_LENGTH); let tags = []; if (this.state.activated) { this.state.tags.map(tag => { tags.push({ user: tag, invalid: tag.length < minTagLength || tag.length > maxTagLength }); }); } else { this.state.tags.map(tag => { tags.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "badge", key: tags.length }, tag)); }); if (tags.length == 0) { tags = react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "tags_not_found", defaultMessage: [{ "type": 0, "value": "No tags defined. Add some." }] })); } } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, this.props.title)), this.state.activated ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "tags_editor_no_tags", defaultMessage: [{ "type": 0, "value": "Add some tags" }] }, add_tags_prompt => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_chip_input_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { tinode: this.props.tinode, chips: tags, avatarDisabled: true, prompt: add_tags_prompt, tabIndex: this.props.tabIndex, onEnter: this.handleAddTag, onFocusLost: this.handleAddTag, onCancel: this.handleCancel, onChipRemoved: this.handleRemoveTag, filterFunc: this.handleTagInput })), this.props.onSubmit || this.props.onCancel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "tag-manager-buttons", className: "dialog-buttons panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "outline", onClick: this.handleCancel }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_cancel", defaultMessage: [{ "type": 0, "value": "Cancel" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "primary", onClick: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_ok", defaultMessage: [{ "type": 0, "value": "OK" }] }))) : null) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "quoted" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "flat-button", onClick: e => { e.preventDefault(); this.setState({ activated: true }); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "edit"), " \xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "title_manage_tags", defaultMessage: [{ "type": 0, "value": "Manage" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, tags))); } } ; /***/ }), /***/ "./src/widgets/topic-common.jsx": /*!**************************************!*\ !*** ./src/widgets/topic-common.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ TopicCommon) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/avatar-upload.jsx */ "./src/widgets/avatar-upload.jsx"); /* harmony import */ var _widgets_topic_desc_edit_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/topic-desc-edit.jsx */ "./src/widgets/topic-desc-edit.jsx"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); class TopicCommon extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); const topic = this.props.tinode.getTopic(this.props.topic); const acs = topic.getAccessMode(); this.state = { isMe: this.props.topic == 'me', owner: acs && acs.isOwner(), credentials: (topic.getCredentials ? topic.getCredentials() : null) || [], addCredActive: false, addCredInvalid: false, newCred: '', tags: [] }; this.previousTagsUpdated = undefined; this.onTagsUpdated = this.onTagsUpdated.bind(this); this.handleTagsUpdated = this.handleTagsUpdated.bind(this); this.tnCredsUpdated = this.tnCredsUpdated.bind(this); this.handleCredChange = this.handleCredChange.bind(this); this.handleCredKeyDown = this.handleCredKeyDown.bind(this); this.handleCredEntered = this.handleCredEntered.bind(this); } componentDidUpdate(props) { const topic = this.props.tinode.getTopic(props.topic); if (!topic) { return; } topic.onCredsUpdated = this.tnCredsUpdated; if (topic.onTagsUpdated != this.onTagsUpdated) { if (topic.getType() == 'grp') { this.previousTagsUpdated = topic.onTagsUpdated; topic.onTagsUpdated = this.onTagsUpdated; } else { this.previousTagsUpdated = undefined; } } if (this.state.topic != props.topic) { this.setState({ topic: props.topic }); } } componentWillUnmount() { const topic = this.props.tinode.getTopic(this.props.topic); topic.onCredsUpdated = undefined; topic.onTagsUpdated = this.previousTagsUpdated; } tnCredsUpdated(creds) { this.setState({ credentials: creds || [] }); } handleCredChange(e) { this.setState({ newCred: e.target.value, addCredInvalid: false }); } handleCredKeyDown(e) { if (e.keyCode === 27) { this.setState({ newCred: '', addCredActive: false }); } else if (e.keyCode === 13) { this.handleCredEntered(e); } } handleCredEntered(e) { const value = this.state.newCred.trim(); if (!value) { this.setState({ addCredActive: false, addCredInvalid: false }); return; } let val = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_4__.asPhone)(value); let method; if (val) { method = 'tel'; } else { val = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_4__.asEmail)(value); if (val) { method = 'email'; } } if (method) { this.props.onCredAdd(method, val); this.setState({ addCredActive: false, newCred: '' }); } else { this.setState({ addCredInvalid: true }); } } onTagsUpdated(tags) { this.setState({ tags: tags }); if (this.previousTagsUpdated && this.previousTagsUpdated != this.onTagsUpdated) { this.previousTagsUpdated(tags); } } handleTagsUpdated(tags) { if (!(0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_4__.arrayEqual)(this.state.tags.slice(0), tags.slice(0))) { this.props.onTopicTagsUpdateRequest(this.props.topic, tags); } } render() { const credentials = []; if (this.state.isMe) { this.state.credentials.map(cred => { credentials.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { key: cred.meth + ":" + cred.val + ":" + cred.done }, cred.meth, ": ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", null, cred.val), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, " ", !cred.done ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onCredConfirm(cred.meth, cred.val); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "validate_credential_action", defaultMessage: [{ "type": 0, "value": "confirm" }] })) : null, " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onCredDelete(cred.meth, cred.val); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, "delete_outline"))))); }); } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "scrollable-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_topic_desc_edit_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, topic: this.props.topic, onUpdateTopicDesc: this.props.onUpdateTopicDesc, onUpdateTags: this.handleTagsUpdated, onError: this.props.onError }), this.state.isMe ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_user_contacts", defaultMessage: [{ "type": 0, "value": "Contacts:" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "quoted" }, credentials, this.state.addCredActive ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", value: this.state.value, className: this.state.addCredInvalid ? 'invalid' : null, placeholder: "Phone number or email", required: "required", autoFocus: true, onChange: this.handleCredChange, onKeyDown: this.handleCredKeyDown, onBlur: this.handleCredEntered }) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.setState({ addCredActive: true }); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "add"), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_add_another", defaultMessage: [{ "type": 0, "value": "Add another" }] })))))) : null); } } ; /***/ }), /***/ "./src/widgets/topic-desc-edit.jsx": /*!*****************************************!*\ !*** ./src/widgets/topic-desc-edit.jsx ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ TopicDescEdit) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _avatar_crop_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./avatar-crop.jsx */ "./src/widgets/avatar-crop.jsx"); /* harmony import */ var _avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./avatar-upload.jsx */ "./src/widgets/avatar-upload.jsx"); /* harmony import */ var _in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./in-place-edit.jsx */ "./src/widgets/in-place-edit.jsx"); /* harmony import */ var _tag_manager_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./tag-manager.jsx */ "./src/widgets/tag-manager.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); class TopicDescEdit extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); const topic = this.props.tinode.getTopic(this.props.topic); const acs = topic.getAccessMode(); this.state = { isMe: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isMeTopicName(this.props.topic), owner: acs && acs.isOwner(), fullName: topic.public ? topic.public.fn : undefined, private: topic.private ? topic.private.comment : null, description: topic.public ? topic.public.note : undefined, avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_8__.makeImageUrl)(topic.public ? topic.public.photo : null), tags: topic.tags() || [], newAvatar: null, newAvatarMime: null }; this.previousOnTags = null; this.tnNewTags = this.tnNewTags.bind(this); this.handleFullNameUpdate = this.handleFullNameUpdate.bind(this); this.handleImageUpdated = this.handleImageUpdated.bind(this); this.handleAvatarCropped = this.handleAvatarCropped.bind(this); this.handlePrivateUpdate = this.handlePrivateUpdate.bind(this); this.handleDescriptionUpdate = this.handleDescriptionUpdate.bind(this); this.uploadAvatar = this.uploadAvatar.bind(this); this.handleAvatarCropCancel = this.handleAvatarCropCancel.bind(this); this.handleTagsUpdated = this.handleTagsUpdated.bind(this); } componentDidMount() { const topic = this.props.tinode.getTopic(this.props.topic); this.previousOnTags = topic.onTagsUpdated; topic.onTagsUpdated = this.tnNewTags; } componentWillUnmount() { const topic = this.props.tinode.getTopic(this.props.topic); topic.onTagsUpdated = this.previousOnTags; } tnNewTags(tags) { this.setState({ tags: tags }); } handleFullNameUpdate(fn) { fn = fn.trim().substring(0, _config_js__WEBPACK_IMPORTED_MODULE_7__.MAX_TITLE_LENGTH); if (fn && this.state.fullName !== fn) { this.setState({ fullName: fn }); this.props.onUpdateTopicDesc(this.props.topic, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_9__.theCard)(fn, null)); } } handlePrivateUpdate(comment) { comment = comment.trim().substring(0, _config_js__WEBPACK_IMPORTED_MODULE_7__.MAX_TITLE_LENGTH); if (this.state.private !== comment) { this.setState({ private: comment }); this.props.onUpdateTopicDesc(this.props.topic, null, comment || tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.DEL_CHAR); } } handleDescriptionUpdate(desc) { desc = desc.trim().substring(0, _config_js__WEBPACK_IMPORTED_MODULE_7__.MAX_TOPIC_DESCRIPTION_LENGTH); if (desc) { this.setState({ description: desc }); this.props.onUpdateTopicDesc(this.props.topic, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_9__.theCard)(null, null, null, desc)); } } handleImageUpdated(mime, img) { this.setState({ newAvatar: img, newAvatarMime: mime }); if (!img) { this.setState({ avatar: null }); this.props.onUpdateTopicDesc(this.props.topic, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_9__.theCard)(null, tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.DEL_CHAR)); } } handleAvatarCropped(mime, blob, width, height) { const url = blob ? URL.createObjectURL(blob) : null; this.setState({ avatar: url, newAvatar: null, newAvatarMime: null }); if (blob) { this.uploadAvatar(mime, blob, width, height); } } uploadAvatar(mime, blob, width, height) { const readyToUpload = image => { let { mime, blob } = image; if (blob.size > _config_js__WEBPACK_IMPORTED_MODULE_7__.MAX_AVATAR_BYTES) { const uploader = this.props.tinode.getLargeFileHelper(); this.setState({ uploading: true }); uploader.upload(blob).then(url => { this.props.onUpdateTopicDesc(this.props.topic, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_9__.theCard)(null, url)); }).catch(err => { this.props.onError(err, 'err'); }).finally(() => { this.setState({ uploading: false }); }); } else { this.setState({ uploading: true }); (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_8__.blobToBase64)(blob).then(b64 => { const du = (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_8__.makeImageUrl)({ data: b64.bits, type: mime }); this.setState({ source: du }); this.props.onUpdateTopicDesc(this.props.topic, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_9__.theCard)(null, du)); this.setState({ uploading: false }); }); } }; if (width > _config_js__WEBPACK_IMPORTED_MODULE_7__.AVATAR_SIZE || height > _config_js__WEBPACK_IMPORTED_MODULE_7__.AVATAR_SIZE || width != height) { (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_8__.imageScaled)(blob, _config_js__WEBPACK_IMPORTED_MODULE_7__.AVATAR_SIZE, _config_js__WEBPACK_IMPORTED_MODULE_7__.AVATAR_SIZE, _config_js__WEBPACK_IMPORTED_MODULE_7__.MAX_EXTERN_ATTACHMENT_SIZE, true).then(scaled => readyToUpload(scaled)).catch(err => this.props.onError(err, 'err')); } else { readyToUpload({ mime: mime, blob: blob, width: width, height: height }); } } handleAvatarCropCancel(img) { this.setState({ newAvatar: null, newAvatarMime: null }); } handleTagsUpdated(tags) { if ((0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_9__.arrayEqual)(this.state.tags.slice(0), tags.slice(0))) { return; } this.props.onUpdateTags(tags); } render() { if (this.state.newAvatar) { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_avatar_crop_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { avatar: this.state.newAvatar, mime: this.state.newAvatarMime, onSubmit: this.handleAvatarCropped, onCancel: this.handleAvatarCropCancel, onError: this.props.onError }); } const editable = this.state.isMe || this.state.owner; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("center", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { tinode: this.props.tinode, avatar: this.state.avatar, readOnly: !editable, uid: this.props.topic, title: this.state.fullName, onImageUpdated: this.handleImageUpdated, onError: this.props.onError })), this.state.isMe ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_your_name", defaultMessage: [{ "type": 0, "value": "Your name" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "full_name_prompt", defaultMessage: [{ "type": 0, "value": "Full name, e.g. John Doe" }] }, full_name_placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { placeholder: full_name_placeholder, value: this.state.fullName, required: true, onFinished: this.handleFullNameUpdate })))) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_topic_name", defaultMessage: [{ "type": 0, "value": "Name" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "topic_name_editing_placeholder", defaultMessage: [{ "type": 0, "value": "Freeform name of the group" }] }, group_name_placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { placeholder: group_name_placeholder, readOnly: !editable, value: this.state.fullName, required: true, onFinished: this.handleFullNameUpdate })))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_private", defaultMessage: [{ "type": 0, "value": "Private comment" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "private_editing_placeholder", defaultMessage: [{ "type": 0, "value": "Visible to you only" }] }, private_placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { placeholder: private_placeholder, value: this.state.private, onFinished: this.handlePrivateUpdate }))))), editable || this.state.description ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_description", defaultMessage: [{ "type": 0, "value": "Description" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "description_editing_placeholder", defaultMessage: [{ "type": 0, "value": "Description (optional)" }] }, private_placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { placeholder: private_placeholder, readOnly: !editable, value: this.state.description, multiline: 2, onFinished: this.handleDescriptionUpdate })))) : null), editable ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "title_tag_manager", defaultMessage: [{ "type": 0, "value": "Tags (search & discovery)" }] }, title_tag_manager => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_tag_manager_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], { tinode: this.props.tinode, title: title_tag_manager, activated: false, tags: this.state.tags, onSubmit: this.handleTagsUpdated }))) : null); } } ; /***/ }), /***/ "./src/widgets/topic-security.jsx": /*!****************************************!*\ !*** ./src/widgets/topic-security.jsx ***! \****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./in-place-edit.jsx */ "./src/widgets/in-place-edit.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ clear_messages: { id: "action_clear_messages", defaultMessage: [{ "type": 0, "value": "Clear Messages" }] }, clear_messages_warning: { id: "clear_messages_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to clear all messages? It cannot be undone." }] }, delete_messages: { id: "action_delete_messages", defaultMessage: [{ "type": 0, "value": "Clear Messages for All" }] }, delete_messages_warning: { id: "delete_messages_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to delete all messages for everyone? It cannot be undone." }] }, topic_delete: { id: "topic_delete", defaultMessage: [{ "type": 0, "value": "Delete Conversation" }] }, topic_delete_warning: { id: "topic_delete_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to delete this conversation? It cannot be undone." }] }, leave_chat: { id: "action_leave_chat", defaultMessage: [{ "type": 0, "value": "Leave Conversation" }] }, leave_chat_warning: { id: "leave_chat_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to leave this conversation?" }] }, block_contact: { id: "action_block_contact", defaultMessage: [{ "type": 0, "value": "Block Contact" }] }, block_contact_warning: { id: "block_contact_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to block this contact?" }] }, report_chat: { id: "action_report_chat", defaultMessage: [{ "type": 0, "value": "Report Conversation" }] }, report_chat_warning: { id: "report_chat_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to block and report this conversation?" }] }, other_user: { id: "label_other_user", defaultMessage: [{ "type": 0, "value": "Other" }] } }); class TopicSecurity extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleDeleteTopic = this.handleDeleteTopic.bind(this); this.handleDeleteMessages = this.handleDeleteMessages.bind(this); this.handleLeave = this.handleLeave.bind(this); this.handleBlock = this.handleBlock.bind(this); this.handleReport = this.handleReport.bind(this); } handleDeleteTopic(e) { e.preventDefault(); const { formatMessage } = this.props.intl; this.props.onShowAlert(formatMessage(messages.topic_delete), formatMessage(messages.topic_delete_warning), () => { this.props.onDeleteTopic(this.props.topic); }, null, true, null); } handleDeleteMessages(e) { e.preventDefault(); const { formatMessage } = this.props.intl; this.props.onShowAlert(formatMessage(this.props.deleter ? messages.delete_messages : messages.clear_messages), formatMessage(this.props.deleter ? messages.delete_messages_warning : messages.clear_messages_warning), () => { this.props.onDeleteMessages(this.props.topic); }, null, true, null); } handleLeave(e) { e.preventDefault(); const { formatMessage } = this.props.intl; this.props.onShowAlert(formatMessage(messages.leave_chat), formatMessage(messages.leave_chat_warning), () => { this.props.onLeaveTopic(this.props.topic); }, null, true, null); } handleBlock(e) { e.preventDefault(); const { formatMessage } = this.props.intl; this.props.onShowAlert(formatMessage(messages.block_contact), formatMessage(messages.block_contact_warning), () => { this.props.onBlockTopic(this.props.topic); }, null, true, null); } handleReport(e) { e.preventDefault(); const { formatMessage } = this.props.intl; this.props.onShowAlert(formatMessage(messages.report_chat), formatMessage(messages.report_chat_warning), _ => { this.props.onReportTopic(this.props.topic); }, null, true, null); } render() { const { formatMessage } = this.props.intl; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "scrollable-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, !this.props.channel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "flat-button", onClick: this.handleDeleteMessages }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "delete_outline"), " \xA0", formatMessage(this.props.deleter ? messages.delete_messages : messages.clear_messages)) : null, this.props.owner ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "danger flat-button", onClick: this.handleDeleteTopic }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "delete"), " \xA0", formatMessage(messages.topic_delete)) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "danger flat-button", onClick: this.handleLeave }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "exit_to_app"), " \xA0", formatMessage(messages.leave_chat)), !this.props.groupTopic ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "danger flat-button", onClick: this.handleBlock }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "block"), " \xA0", formatMessage(messages.block_contact)) : null, !this.props.owner ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "danger flat-button", onClick: this.handleReport }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "report"), " \xA0", formatMessage(messages.report_chat)) : null), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, this.props.groupTopic ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_your_permissions", defaultMessage: [{ "type": 0, "value": "Your permissions:" }] })), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", { className: "clickable", onClick: e => { e.preventDefault(); this.props.onLaunchPermissionsEditor('want'); } }, this.props.access)), !this.props.channel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_default_access_mode", defaultMessage: [{ "type": 0, "value": "Default access mode:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "quoted" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, "Auth: ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", { className: this.props.owner ? 'clickable' : null, onClick: e => { e.preventDefault(); if (this.props.owner) { this.props.onLaunchPermissionsEditor('auth'); } } }, this.props.auth)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, "Anon: ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", { className: this.props.owner ? 'clickable' : null, onClick: e => { e.preventDefault(); if (this.props.owner) { this.props.onLaunchPermissionsEditor('anon'); } } }, this.props.anon)))) : null) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_permissions", defaultMessage: [{ "type": 0, "value": "Permissions:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "quoted" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_you", defaultMessage: [{ "type": 0, "value": "You:" }] }), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", { className: "clickable", onClick: e => { e.preventDefault(); this.props.onLaunchPermissionsEditor('want'); } }, this.props.access)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, this.props.fullName ? this.props.fullName : formatMessage(messages.other_user), ": \xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", { className: "clickable", onClick: e => { e.preventDefault(); this.props.onLaunchPermissionsEditor('given'); } }, this.props.modeGiven2)))))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(TopicSecurity)); /***/ }), /***/ "./src/widgets/unread-badge.jsx": /*!**************************************!*\ !*** ./src/widgets/unread-badge.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ UnreadBadge) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class UnreadBadge extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return this.props.count > 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "unread" }, this.props.count > 9 ? "9+" : this.props.count) : null; } } ; /***/ }), /***/ "./src/widgets/uploading-image.jsx": /*!*****************************************!*\ !*** ./src/widgets/uploading-image.jsx ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ UploadingImage) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _file_progress_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./file-progress.jsx */ "./src/widgets/file-progress.jsx"); class UploadingImage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "inline-image" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement('img', this.props), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "rounded-container" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_file_progress_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { progress: this.props.progress, onCancel: this.props.onCancelUpload }))); } } ; /***/ }), /***/ "./src/widgets/visible-password.jsx": /*!******************************************!*\ !*** ./src/widgets/visible-password.jsx ***! \******************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ VisiblePassword) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class VisiblePassword extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { value: this.props.value, visible: false }; this.handleVisibility = this.handleVisibility.bind(this); this.handeTextChange = this.handeTextChange.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); this.handleEditingFinished = this.handleEditingFinished.bind(this); } handeTextChange(e) { this.setState({ value: e.target.value }); if (this.props.onChange) { this.props.onChange(e); } } handleVisibility(e) { e.preventDefault(); this.setState({ visible: !this.state.visible }); } handleKeyDown(e) { if (e.keyCode == 27) { this.setState({ value: this.props.value, visible: false }); if (this.props.onFinished) { this.props.onFinished(); } } else if (e.keyCode == 13) { this.handleEditingFinished(); } } handleEditingFinished(e) { if (e) { let currentTarget = e.currentTarget; setTimeout(() => { if (!currentTarget.contains(document.activeElement)) { if (this.props.onFinished) { this.props.onFinished(this.state.value); } } }, 0); } else if (this.props.onFinished) { this.props.onFinished(this.state.value.trim()); } } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { tabIndex: "-1", className: "group-focus", onBlur: this.handleEditingFinished }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { className: "with-visibility", type: this.state.visible ? "text" : "password", value: this.state.value, placeholder: this.props.placeholder, required: this.props.required ? 'required' : '', autoFocus: this.props.autoFocus ? 'autoFocus' : '', autoComplete: this.props.autoComplete, onChange: this.handeTextChange, onKeyDown: this.handleKeyDown }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { onClick: this.handleVisibility }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons clickable light-gray" }, this.state.visible ? 'visibility' : 'visibility_off'))); } } /***/ }), /***/ "./node_modules/firebase/app/dist/index.esm.js": /*!*****************************************************!*\ !*** ./node_modules/firebase/app/dist/index.esm.js ***! \*****************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "FirebaseError": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.FirebaseError), /* harmony export */ "SDK_VERSION": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.SDK_VERSION), /* harmony export */ "_DEFAULT_ENTRY_NAME": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._DEFAULT_ENTRY_NAME), /* harmony export */ "_addComponent": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._addComponent), /* harmony export */ "_addOrOverwriteComponent": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._addOrOverwriteComponent), /* harmony export */ "_apps": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._apps), /* harmony export */ "_clearComponents": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._clearComponents), /* harmony export */ "_components": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._components), /* harmony export */ "_getProvider": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._getProvider), /* harmony export */ "_registerComponent": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._registerComponent), /* harmony export */ "_removeServiceInstance": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._removeServiceInstance), /* harmony export */ "deleteApp": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.deleteApp), /* harmony export */ "getApp": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.getApp), /* harmony export */ "getApps": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.getApps), /* harmony export */ "initializeApp": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.initializeApp), /* harmony export */ "onLog": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.onLog), /* harmony export */ "registerVersion": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.registerVersion), /* harmony export */ "setLogLevel": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.setLogLevel) /* harmony export */ }); /* harmony import */ var _firebase_app__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @firebase/app */ "./node_modules/@firebase/app/dist/esm/index.esm2017.js"); var name = "firebase"; var version = "9.8.1"; /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__.registerVersion)(name, version, 'app'); //# sourceMappingURL=index.esm.js.map /***/ }), /***/ "./node_modules/firebase/messaging/dist/index.esm.js": /*!***********************************************************!*\ !*** ./node_modules/firebase/messaging/dist/index.esm.js ***! \***********************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "deleteToken": () => (/* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.deleteToken), /* harmony export */ "getMessaging": () => (/* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.getMessaging), /* harmony export */ "getToken": () => (/* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.getToken), /* harmony export */ "isSupported": () => (/* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.isSupported), /* harmony export */ "onMessage": () => (/* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.onMessage) /* harmony export */ }); /* harmony import */ var _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @firebase/messaging */ "./node_modules/@firebase/messaging/dist/esm/index.esm2017.js"); //# sourceMappingURL=index.esm.js.map /***/ }), /***/ "./node_modules/fix-webm-duration/fix-webm-duration.js": /*!*************************************************************!*\ !*** ./node_modules/fix-webm-duration/fix-webm-duration.js ***! \*************************************************************/ /***/ ((module, exports, __webpack_require__) => { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (name, definition) { if (true) { // RequireJS / AMD !(__WEBPACK_AMD_DEFINE_FACTORY__ = (definition), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); } else {} })('fix-webm-duration', function () { /* * This is the list of possible WEBM file sections by their IDs. * Possible types: Container, Binary, Uint, Int, String, Float, Date */ var sections = { 0xa45dfa3: { name: 'EBML', type: 'Container' }, 0x286: { name: 'EBMLVersion', type: 'Uint' }, 0x2f7: { name: 'EBMLReadVersion', type: 'Uint' }, 0x2f2: { name: 'EBMLMaxIDLength', type: 'Uint' }, 0x2f3: { name: 'EBMLMaxSizeLength', type: 'Uint' }, 0x282: { name: 'DocType', type: 'String' }, 0x287: { name: 'DocTypeVersion', type: 'Uint' }, 0x285: { name: 'DocTypeReadVersion', type: 'Uint' }, 0x6c: { name: 'Void', type: 'Binary' }, 0x3f: { name: 'CRC-32', type: 'Binary' }, 0xb538667: { name: 'SignatureSlot', type: 'Container' }, 0x3e8a: { name: 'SignatureAlgo', type: 'Uint' }, 0x3e9a: { name: 'SignatureHash', type: 'Uint' }, 0x3ea5: { name: 'SignaturePublicKey', type: 'Binary' }, 0x3eb5: { name: 'Signature', type: 'Binary' }, 0x3e5b: { name: 'SignatureElements', type: 'Container' }, 0x3e7b: { name: 'SignatureElementList', type: 'Container' }, 0x2532: { name: 'SignedElement', type: 'Binary' }, 0x8538067: { name: 'Segment', type: 'Container' }, 0x14d9b74: { name: 'SeekHead', type: 'Container' }, 0xdbb: { name: 'Seek', type: 'Container' }, 0x13ab: { name: 'SeekID', type: 'Binary' }, 0x13ac: { name: 'SeekPosition', type: 'Uint' }, 0x549a966: { name: 'Info', type: 'Container' }, 0x33a4: { name: 'SegmentUID', type: 'Binary' }, 0x3384: { name: 'SegmentFilename', type: 'String' }, 0x1cb923: { name: 'PrevUID', type: 'Binary' }, 0x1c83ab: { name: 'PrevFilename', type: 'String' }, 0x1eb923: { name: 'NextUID', type: 'Binary' }, 0x1e83bb: { name: 'NextFilename', type: 'String' }, 0x444: { name: 'SegmentFamily', type: 'Binary' }, 0x2924: { name: 'ChapterTranslate', type: 'Container' }, 0x29fc: { name: 'ChapterTranslateEditionUID', type: 'Uint' }, 0x29bf: { name: 'ChapterTranslateCodec', type: 'Uint' }, 0x29a5: { name: 'ChapterTranslateID', type: 'Binary' }, 0xad7b1: { name: 'TimecodeScale', type: 'Uint' }, 0x489: { name: 'Duration', type: 'Float' }, 0x461: { name: 'DateUTC', type: 'Date' }, 0x3ba9: { name: 'Title', type: 'String' }, 0xd80: { name: 'MuxingApp', type: 'String' }, 0x1741: { name: 'WritingApp', type: 'String' }, // 0xf43b675: { name: 'Cluster', type: 'Container' }, 0x67: { name: 'Timecode', type: 'Uint' }, 0x1854: { name: 'SilentTracks', type: 'Container' }, 0x18d7: { name: 'SilentTrackNumber', type: 'Uint' }, 0x27: { name: 'Position', type: 'Uint' }, 0x2b: { name: 'PrevSize', type: 'Uint' }, 0x23: { name: 'SimpleBlock', type: 'Binary' }, 0x20: { name: 'BlockGroup', type: 'Container' }, 0x21: { name: 'Block', type: 'Binary' }, 0x22: { name: 'BlockVirtual', type: 'Binary' }, 0x35a1: { name: 'BlockAdditions', type: 'Container' }, 0x26: { name: 'BlockMore', type: 'Container' }, 0x6e: { name: 'BlockAddID', type: 'Uint' }, 0x25: { name: 'BlockAdditional', type: 'Binary' }, 0x1b: { name: 'BlockDuration', type: 'Uint' }, 0x7a: { name: 'ReferencePriority', type: 'Uint' }, 0x7b: { name: 'ReferenceBlock', type: 'Int' }, 0x7d: { name: 'ReferenceVirtual', type: 'Int' }, 0x24: { name: 'CodecState', type: 'Binary' }, 0x35a2: { name: 'DiscardPadding', type: 'Int' }, 0xe: { name: 'Slices', type: 'Container' }, 0x68: { name: 'TimeSlice', type: 'Container' }, 0x4c: { name: 'LaceNumber', type: 'Uint' }, 0x4d: { name: 'FrameNumber', type: 'Uint' }, 0x4b: { name: 'BlockAdditionID', type: 'Uint' }, 0x4e: { name: 'Delay', type: 'Uint' }, 0x4f: { name: 'SliceDuration', type: 'Uint' }, 0x48: { name: 'ReferenceFrame', type: 'Container' }, 0x49: { name: 'ReferenceOffset', type: 'Uint' }, 0x4a: { name: 'ReferenceTimeCode', type: 'Uint' }, 0x2f: { name: 'EncryptedBlock', type: 'Binary' }, 0x654ae6b: { name: 'Tracks', type: 'Container' }, 0x2e: { name: 'TrackEntry', type: 'Container' }, 0x57: { name: 'TrackNumber', type: 'Uint' }, 0x33c5: { name: 'TrackUID', type: 'Uint' }, 0x3: { name: 'TrackType', type: 'Uint' }, 0x39: { name: 'FlagEnabled', type: 'Uint' }, 0x8: { name: 'FlagDefault', type: 'Uint' }, 0x15aa: { name: 'FlagForced', type: 'Uint' }, 0x1c: { name: 'FlagLacing', type: 'Uint' }, 0x2de7: { name: 'MinCache', type: 'Uint' }, 0x2df8: { name: 'MaxCache', type: 'Uint' }, 0x3e383: { name: 'DefaultDuration', type: 'Uint' }, 0x34e7a: { name: 'DefaultDecodedFieldDuration', type: 'Uint' }, 0x3314f: { name: 'TrackTimecodeScale', type: 'Float' }, 0x137f: { name: 'TrackOffset', type: 'Int' }, 0x15ee: { name: 'MaxBlockAdditionID', type: 'Uint' }, 0x136e: { name: 'Name', type: 'String' }, 0x2b59c: { name: 'Language', type: 'String' }, 0x6: { name: 'CodecID', type: 'String' }, 0x23a2: { name: 'CodecPrivate', type: 'Binary' }, 0x58688: { name: 'CodecName', type: 'String' }, 0x3446: { name: 'AttachmentLink', type: 'Uint' }, 0x1a9697: { name: 'CodecSettings', type: 'String' }, 0x1b4040: { name: 'CodecInfoURL', type: 'String' }, 0x6b240: { name: 'CodecDownloadURL', type: 'String' }, 0x2a: { name: 'CodecDecodeAll', type: 'Uint' }, 0x2fab: { name: 'TrackOverlay', type: 'Uint' }, 0x16aa: { name: 'CodecDelay', type: 'Uint' }, 0x16bb: { name: 'SeekPreRoll', type: 'Uint' }, 0x2624: { name: 'TrackTranslate', type: 'Container' }, 0x26fc: { name: 'TrackTranslateEditionUID', type: 'Uint' }, 0x26bf: { name: 'TrackTranslateCodec', type: 'Uint' }, 0x26a5: { name: 'TrackTranslateTrackID', type: 'Binary' }, 0x60: { name: 'Video', type: 'Container' }, 0x1a: { name: 'FlagInterlaced', type: 'Uint' }, 0x13b8: { name: 'StereoMode', type: 'Uint' }, 0x13c0: { name: 'AlphaMode', type: 'Uint' }, 0x13b9: { name: 'OldStereoMode', type: 'Uint' }, 0x30: { name: 'PixelWidth', type: 'Uint' }, 0x3a: { name: 'PixelHeight', type: 'Uint' }, 0x14aa: { name: 'PixelCropBottom', type: 'Uint' }, 0x14bb: { name: 'PixelCropTop', type: 'Uint' }, 0x14cc: { name: 'PixelCropLeft', type: 'Uint' }, 0x14dd: { name: 'PixelCropRight', type: 'Uint' }, 0x14b0: { name: 'DisplayWidth', type: 'Uint' }, 0x14ba: { name: 'DisplayHeight', type: 'Uint' }, 0x14b2: { name: 'DisplayUnit', type: 'Uint' }, 0x14b3: { name: 'AspectRatioType', type: 'Uint' }, 0xeb524: { name: 'ColourSpace', type: 'Binary' }, 0xfb523: { name: 'GammaValue', type: 'Float' }, 0x383e3: { name: 'FrameRate', type: 'Float' }, 0x61: { name: 'Audio', type: 'Container' }, 0x35: { name: 'SamplingFrequency', type: 'Float' }, 0x38b5: { name: 'OutputSamplingFrequency', type: 'Float' }, 0x1f: { name: 'Channels', type: 'Uint' }, 0x3d7b: { name: 'ChannelPositions', type: 'Binary' }, 0x2264: { name: 'BitDepth', type: 'Uint' }, 0x62: { name: 'TrackOperation', type: 'Container' }, 0x63: { name: 'TrackCombinePlanes', type: 'Container' }, 0x64: { name: 'TrackPlane', type: 'Container' }, 0x65: { name: 'TrackPlaneUID', type: 'Uint' }, 0x66: { name: 'TrackPlaneType', type: 'Uint' }, 0x69: { name: 'TrackJoinBlocks', type: 'Container' }, 0x6d: { name: 'TrackJoinUID', type: 'Uint' }, 0x40: { name: 'TrickTrackUID', type: 'Uint' }, 0x41: { name: 'TrickTrackSegmentUID', type: 'Binary' }, 0x46: { name: 'TrickTrackFlag', type: 'Uint' }, 0x47: { name: 'TrickMasterTrackUID', type: 'Uint' }, 0x44: { name: 'TrickMasterTrackSegmentUID', type: 'Binary' }, 0x2d80: { name: 'ContentEncodings', type: 'Container' }, 0x2240: { name: 'ContentEncoding', type: 'Container' }, 0x1031: { name: 'ContentEncodingOrder', type: 'Uint' }, 0x1032: { name: 'ContentEncodingScope', type: 'Uint' }, 0x1033: { name: 'ContentEncodingType', type: 'Uint' }, 0x1034: { name: 'ContentCompression', type: 'Container' }, 0x254: { name: 'ContentCompAlgo', type: 'Uint' }, 0x255: { name: 'ContentCompSettings', type: 'Binary' }, 0x1035: { name: 'ContentEncryption', type: 'Container' }, 0x7e1: { name: 'ContentEncAlgo', type: 'Uint' }, 0x7e2: { name: 'ContentEncKeyID', type: 'Binary' }, 0x7e3: { name: 'ContentSignature', type: 'Binary' }, 0x7e4: { name: 'ContentSigKeyID', type: 'Binary' }, 0x7e5: { name: 'ContentSigAlgo', type: 'Uint' }, 0x7e6: { name: 'ContentSigHashAlgo', type: 'Uint' }, 0xc53bb6b: { name: 'Cues', type: 'Container' }, 0x3b: { name: 'CuePoint', type: 'Container' }, 0x33: { name: 'CueTime', type: 'Uint' }, 0x37: { name: 'CueTrackPositions', type: 'Container' }, 0x77: { name: 'CueTrack', type: 'Uint' }, 0x71: { name: 'CueClusterPosition', type: 'Uint' }, 0x70: { name: 'CueRelativePosition', type: 'Uint' }, 0x32: { name: 'CueDuration', type: 'Uint' }, 0x1378: { name: 'CueBlockNumber', type: 'Uint' }, 0x6a: { name: 'CueCodecState', type: 'Uint' }, 0x5b: { name: 'CueReference', type: 'Container' }, 0x16: { name: 'CueRefTime', type: 'Uint' }, 0x17: { name: 'CueRefCluster', type: 'Uint' }, 0x135f: { name: 'CueRefNumber', type: 'Uint' }, 0x6b: { name: 'CueRefCodecState', type: 'Uint' }, 0x941a469: { name: 'Attachments', type: 'Container' }, 0x21a7: { name: 'AttachedFile', type: 'Container' }, 0x67e: { name: 'FileDescription', type: 'String' }, 0x66e: { name: 'FileName', type: 'String' }, 0x660: { name: 'FileMimeType', type: 'String' }, 0x65c: { name: 'FileData', type: 'Binary' }, 0x6ae: { name: 'FileUID', type: 'Uint' }, 0x675: { name: 'FileReferral', type: 'Binary' }, 0x661: { name: 'FileUsedStartTime', type: 'Uint' }, 0x662: { name: 'FileUsedEndTime', type: 'Uint' }, 0x43a770: { name: 'Chapters', type: 'Container' }, 0x5b9: { name: 'EditionEntry', type: 'Container' }, 0x5bc: { name: 'EditionUID', type: 'Uint' }, 0x5bd: { name: 'EditionFlagHidden', type: 'Uint' }, 0x5db: { name: 'EditionFlagDefault', type: 'Uint' }, 0x5dd: { name: 'EditionFlagOrdered', type: 'Uint' }, 0x36: { name: 'ChapterAtom', type: 'Container' }, 0x33c4: { name: 'ChapterUID', type: 'Uint' }, 0x1654: { name: 'ChapterStringUID', type: 'String' }, 0x11: { name: 'ChapterTimeStart', type: 'Uint' }, 0x12: { name: 'ChapterTimeEnd', type: 'Uint' }, 0x18: { name: 'ChapterFlagHidden', type: 'Uint' }, 0x598: { name: 'ChapterFlagEnabled', type: 'Uint' }, 0x2e67: { name: 'ChapterSegmentUID', type: 'Binary' }, 0x2ebc: { name: 'ChapterSegmentEditionUID', type: 'Uint' }, 0x23c3: { name: 'ChapterPhysicalEquiv', type: 'Uint' }, 0xf: { name: 'ChapterTrack', type: 'Container' }, 0x9: { name: 'ChapterTrackNumber', type: 'Uint' }, 0x0: { name: 'ChapterDisplay', type: 'Container' }, 0x5: { name: 'ChapString', type: 'String' }, 0x37c: { name: 'ChapLanguage', type: 'String' }, 0x37e: { name: 'ChapCountry', type: 'String' }, 0x2944: { name: 'ChapProcess', type: 'Container' }, 0x2955: { name: 'ChapProcessCodecID', type: 'Uint' }, 0x50d: { name: 'ChapProcessPrivate', type: 'Binary' }, 0x2911: { name: 'ChapProcessCommand', type: 'Container' }, 0x2922: { name: 'ChapProcessTime', type: 'Uint' }, 0x2933: { name: 'ChapProcessData', type: 'Binary' }, 0x254c367: { name: 'Tags', type: 'Container' }, 0x3373: { name: 'Tag', type: 'Container' }, 0x23c0: { name: 'Targets', type: 'Container' }, 0x28ca: { name: 'TargetTypeValue', type: 'Uint' }, 0x23ca: { name: 'TargetType', type: 'String' }, 0x23c5: { name: 'TagTrackUID', type: 'Uint' }, 0x23c9: { name: 'TagEditionUID', type: 'Uint' }, 0x23c4: { name: 'TagChapterUID', type: 'Uint' }, 0x23c6: { name: 'TagAttachmentUID', type: 'Uint' }, 0x27c8: { name: 'SimpleTag', type: 'Container' }, 0x5a3: { name: 'TagName', type: 'String' }, 0x47a: { name: 'TagLanguage', type: 'String' }, 0x484: { name: 'TagDefault', type: 'Uint' }, 0x487: { name: 'TagString', type: 'String' }, 0x485: { name: 'TagBinary', type: 'Binary' } }; function doInherit(newClass, baseClass) { newClass.prototype = Object.create(baseClass.prototype); newClass.prototype.constructor = newClass; } function WebmBase(name, type) { this.name = name || 'Unknown'; this.type = type || 'Unknown'; } WebmBase.prototype.updateBySource = function() { }; WebmBase.prototype.setSource = function(source) { this.source = source; this.updateBySource(); }; WebmBase.prototype.updateByData = function() { }; WebmBase.prototype.setData = function(data) { this.data = data; this.updateByData(); }; function WebmUint(name, type) { WebmBase.call(this, name, type || 'Uint'); } doInherit(WebmUint, WebmBase); function padHex(hex) { return hex.length % 2 === 1 ? '0' + hex : hex; } WebmUint.prototype.updateBySource = function() { // use hex representation of a number instead of number value this.data = ''; for (var i = 0; i < this.source.length; i++) { var hex = this.source[i].toString(16); this.data += padHex(hex); } }; WebmUint.prototype.updateByData = function() { var length = this.data.length / 2; this.source = new Uint8Array(length); for (var i = 0; i < length; i++) { var hex = this.data.substr(i * 2, 2); this.source[i] = parseInt(hex, 16); } }; WebmUint.prototype.getValue = function() { return parseInt(this.data, 16); }; WebmUint.prototype.setValue = function(value) { this.setData(padHex(value.toString(16))); }; function WebmFloat(name, type) { WebmBase.call(this, name, type || 'Float'); } doInherit(WebmFloat, WebmBase); WebmFloat.prototype.getFloatArrayType = function() { return this.source && this.source.length === 4 ? Float32Array : Float64Array; }; WebmFloat.prototype.updateBySource = function() { var byteArray = this.source.reverse(); var floatArrayType = this.getFloatArrayType(); var floatArray = new floatArrayType(byteArray.buffer); this.data = floatArray[0]; }; WebmFloat.prototype.updateByData = function() { var floatArrayType = this.getFloatArrayType(); var floatArray = new floatArrayType([ this.data ]); var byteArray = new Uint8Array(floatArray.buffer); this.source = byteArray.reverse(); }; WebmFloat.prototype.getValue = function() { return this.data; }; WebmFloat.prototype.setValue = function(value) { this.setData(value); }; function WebmContainer(name, type) { WebmBase.call(this, name, type || 'Container'); } doInherit(WebmContainer, WebmBase); WebmContainer.prototype.readByte = function() { return this.source[this.offset++]; }; WebmContainer.prototype.readUint = function() { var firstByte = this.readByte(); var bytes = 8 - firstByte.toString(2).length; var value = firstByte - (1 << (7 - bytes)); for (var i = 0; i < bytes; i++) { // don't use bit operators to support x86 value *= 256; value += this.readByte(); } return value; }; WebmContainer.prototype.updateBySource = function() { this.data = []; for (this.offset = 0; this.offset < this.source.length; this.offset = end) { var id = this.readUint(); var len = this.readUint(); var end = Math.min(this.offset + len, this.source.length); var data = this.source.slice(this.offset, end); var info = sections[id] || { name: 'Unknown', type: 'Unknown' }; var ctr = WebmBase; switch (info.type) { case 'Container': ctr = WebmContainer; break; case 'Uint': ctr = WebmUint; break; case 'Float': ctr = WebmFloat; break; } var section = new ctr(info.name, info.type); section.setSource(data); this.data.push({ id: id, idHex: id.toString(16), data: section }); } }; WebmContainer.prototype.writeUint = function(x, draft) { for (var bytes = 1, flag = 0x80; x >= flag && bytes < 8; bytes++, flag *= 0x80) { } if (!draft) { var value = flag + x; for (var i = bytes - 1; i >= 0; i--) { // don't use bit operators to support x86 var c = value % 256; this.source[this.offset + i] = c; value = (value - c) / 256; } } this.offset += bytes; }; WebmContainer.prototype.writeSections = function(draft) { this.offset = 0; for (var i = 0; i < this.data.length; i++) { var section = this.data[i], content = section.data.source, contentLength = content.length; this.writeUint(section.id, draft); this.writeUint(contentLength, draft); if (!draft) { this.source.set(content, this.offset); } this.offset += contentLength; } return this.offset; }; WebmContainer.prototype.updateByData = function() { // run without accessing this.source to determine total length - need to know it to create Uint8Array var length = this.writeSections('draft'); this.source = new Uint8Array(length); // now really write data this.writeSections(); }; WebmContainer.prototype.getSectionById = function(id) { for (var i = 0; i < this.data.length; i++) { var section = this.data[i]; if (section.id === id) { return section.data; } } return null; }; function WebmFile(source) { WebmContainer.call(this, 'File', 'File'); this.setSource(source); } doInherit(WebmFile, WebmContainer); WebmFile.prototype.fixDuration = function(duration, options) { var logger = options && options.logger; if (logger === undefined) { logger = function(message) { console.log(message); }; } else if (!logger) { logger = function() { }; } var segmentSection = this.getSectionById(0x8538067); if (!segmentSection) { logger('[fix-webm-duration] Segment section is missing'); return false; } var infoSection = segmentSection.getSectionById(0x549a966); if (!infoSection) { logger('[fix-webm-duration] Info section is missing'); return false; } var timeScaleSection = infoSection.getSectionById(0xad7b1); if (!timeScaleSection) { logger('[fix-webm-duration] TimecodeScale section is missing'); return false; } var durationSection = infoSection.getSectionById(0x489); if (durationSection) { if (durationSection.getValue() <= 0) { logger('[fix-webm-duration] Duration section is present, but the value is empty'); durationSection.setValue(duration); } else { logger('[fix-webm-duration] Duration section is present'); return false; } } else { logger('[fix-webm-duration] Duration section is missing'); // append Duration section durationSection = new WebmFloat('Duration', 'Float'); durationSection.setValue(duration); infoSection.data.push({ id: 0x489, data: durationSection }); } // set default time scale to 1 millisecond (1000000 nanoseconds) timeScaleSection.setValue(1000000); infoSection.updateByData(); segmentSection.updateByData(); this.updateByData(); return true; }; WebmFile.prototype.toBlob = function(mimeType) { return new Blob([ this.source.buffer ], { type: mimeType || 'video/webm' }); }; function fixWebmDuration(blob, duration, callback, options) { // The callback may be omitted - then the third argument is options if (typeof callback === "object") { options = callback; callback = undefined; } if (!callback) { return new Promise(function(resolve) { fixWebmDuration(blob, duration, resolve, options); }); } try { var reader = new FileReader(); reader.onloadend = function() { try { var file = new WebmFile(new Uint8Array(reader.result)); if (file.fixDuration(duration, options)) { blob = file.toBlob(blob.type); } } catch (ex) { // ignore } callback(blob); }; reader.readAsArrayBuffer(blob); } catch (ex) { callback(blob); } } // Support AMD import default fixWebmDuration.default = fixWebmDuration; return fixWebmDuration; }); /***/ }), /***/ "react": /*!************************!*\ !*** external "React" ***! \************************/ /***/ ((module) => { "use strict"; module.exports = React; /***/ }), /***/ "react-dom": /*!***************************!*\ !*** external "ReactDOM" ***! \***************************/ /***/ ((module) => { "use strict"; module.exports = ReactDOM; /***/ }), /***/ "react-intl": /*!****************************!*\ !*** external "ReactIntl" ***! \****************************/ /***/ ((module) => { "use strict"; module.exports = ReactIntl; /***/ }), /***/ "tinode-sdk": /*!*************************!*\ !*** external "Tinode" ***! \*************************/ /***/ ((module) => { "use strict"; module.exports = Tinode; /***/ }), /***/ "./node_modules/@firebase/app/dist/esm/index.esm2017.js": /*!**************************************************************!*\ !*** ./node_modules/@firebase/app/dist/esm/index.esm2017.js ***! \**************************************************************/ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "FirebaseError": () => (/* reexport safe */ _firebase_util__WEBPACK_IMPORTED_MODULE_2__.FirebaseError), /* harmony export */ "SDK_VERSION": () => (/* binding */ SDK_VERSION), /* harmony export */ "_DEFAULT_ENTRY_NAME": () => (/* binding */ DEFAULT_ENTRY_NAME), /* harmony export */ "_addComponent": () => (/* binding */ _addComponent), /* harmony export */ "_addOrOverwriteComponent": () => (/* binding */ _addOrOverwriteComponent), /* harmony export */ "_apps": () => (/* binding */ _apps), /* harmony export */ "_clearComponents": () => (/* binding */ _clearComponents), /* harmony export */ "_components": () => (/* binding */ _components), /* harmony export */ "_getProvider": () => (/* binding */ _getProvider), /* harmony export */ "_registerComponent": () => (/* binding */ _registerComponent), /* harmony export */ "_removeServiceInstance": () => (/* binding */ _removeServiceInstance), /* harmony export */ "deleteApp": () => (/* binding */ deleteApp), /* harmony export */ "getApp": () => (/* binding */ getApp), /* harmony export */ "getApps": () => (/* binding */ getApps), /* harmony export */ "initializeApp": () => (/* binding */ initializeApp), /* harmony export */ "onLog": () => (/* binding */ onLog), /* harmony export */ "registerVersion": () => (/* binding */ registerVersion), /* harmony export */ "setLogLevel": () => (/* binding */ setLogLevel) /* harmony export */ }); /* harmony import */ var _firebase_component__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @firebase/component */ "./node_modules/@firebase/component/dist/esm/index.esm2017.js"); /* harmony import */ var _firebase_logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @firebase/logger */ "./node_modules/@firebase/logger/dist/esm/index.esm2017.js"); /* harmony import */ var _firebase_util__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @firebase/util */ "./node_modules/@firebase/util/dist/index.esm2017.js"); /* harmony import */ var idb__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! idb */ "./node_modules/idb/build/index.js"); /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class PlatformLoggerServiceImpl { constructor(container) { this.container = container; } // In initial implementation, this will be called by installations on // auth token refresh, and installations will send this string. getPlatformInfoString() { const providers = this.container.getProviders(); // Loop through providers and get library/version pairs from any that are // version components. return providers .map(provider => { if (isVersionServiceProvider(provider)) { const service = provider.getImmediate(); return `${service.library}/${service.version}`; } else { return null; } }) .filter(logString => logString) .join(' '); } } /** * * @param provider check if this provider provides a VersionService * * NOTE: Using Provider<'app-version'> is a hack to indicate that the provider * provides VersionService. The provider is not necessarily a 'app-version' * provider. */ function isVersionServiceProvider(provider) { const component = provider.getComponent(); return (component === null || component === void 0 ? void 0 : component.type) === "VERSION" /* VERSION */; } const name$o = "@firebase/app"; const version$1 = "0.7.24"; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const logger = new _firebase_logger__WEBPACK_IMPORTED_MODULE_1__.Logger('@firebase/app'); const name$n = "@firebase/app-compat"; const name$m = "@firebase/analytics-compat"; const name$l = "@firebase/analytics"; const name$k = "@firebase/app-check-compat"; const name$j = "@firebase/app-check"; const name$i = "@firebase/auth"; const name$h = "@firebase/auth-compat"; const name$g = "@firebase/database"; const name$f = "@firebase/database-compat"; const name$e = "@firebase/functions"; const name$d = "@firebase/functions-compat"; const name$c = "@firebase/installations"; const name$b = "@firebase/installations-compat"; const name$a = "@firebase/messaging"; const name$9 = "@firebase/messaging-compat"; const name$8 = "@firebase/performance"; const name$7 = "@firebase/performance-compat"; const name$6 = "@firebase/remote-config"; const name$5 = "@firebase/remote-config-compat"; const name$4 = "@firebase/storage"; const name$3 = "@firebase/storage-compat"; const name$2 = "@firebase/firestore"; const name$1 = "@firebase/firestore-compat"; const name = "firebase"; const version = "9.8.1"; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * The default app name * * @internal */ const DEFAULT_ENTRY_NAME = '[DEFAULT]'; const PLATFORM_LOG_STRING = { [name$o]: 'fire-core', [name$n]: 'fire-core-compat', [name$l]: 'fire-analytics', [name$m]: 'fire-analytics-compat', [name$j]: 'fire-app-check', [name$k]: 'fire-app-check-compat', [name$i]: 'fire-auth', [name$h]: 'fire-auth-compat', [name$g]: 'fire-rtdb', [name$f]: 'fire-rtdb-compat', [name$e]: 'fire-fn', [name$d]: 'fire-fn-compat', [name$c]: 'fire-iid', [name$b]: 'fire-iid-compat', [name$a]: 'fire-fcm', [name$9]: 'fire-fcm-compat', [name$8]: 'fire-perf', [name$7]: 'fire-perf-compat', [name$6]: 'fire-rc', [name$5]: 'fire-rc-compat', [name$4]: 'fire-gcs', [name$3]: 'fire-gcs-compat', [name$2]: 'fire-fst', [name$1]: 'fire-fst-compat', 'fire-js': 'fire-js', [name]: 'fire-js-all' }; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @internal */ const _apps = new Map(); /** * Registered components. * * @internal */ // eslint-disable-next-line @typescript-eslint/no-explicit-any const _components = new Map(); /** * @param component - the component being added to this app's container * * @internal */ function _addComponent(app, component) { try { app.container.addComponent(component); } catch (e) { logger.debug(`Component ${component.name} failed to register with FirebaseApp ${app.name}`, e); } } /** * * @internal */ function _addOrOverwriteComponent(app, component) { app.container.addOrOverwriteComponent(component); } /** * * @param component - the component to register * @returns whether or not the component is registered successfully * * @internal */ function _registerComponent(component) { const componentName = component.name; if (_components.has(componentName)) { logger.debug(`There were multiple attempts to register component ${componentName}.`); return false; } _components.set(componentName, component); // add the component to existing app instances for (const app of _apps.values()) { _addComponent(app, component); } return true; } /** * * @param app - FirebaseApp instance * @param name - service name * * @returns the provider for the service with the matching name * * @internal */ function _getProvider(app, name) { const heartbeatController = app.container .getProvider('heartbeat') .getImmediate({ optional: true }); if (heartbeatController) { void heartbeatController.triggerHeartbeat(); } return app.container.getProvider(name); } /** * * @param app - FirebaseApp instance * @param name - service name * @param instanceIdentifier - service instance identifier in case the service supports multiple instances * * @internal */ function _removeServiceInstance(app, name, instanceIdentifier = DEFAULT_ENTRY_NAME) { _getProvider(app, name).clearInstance(instanceIdentifier); } /** * Test only * * @internal */ function _clearComponents() { _components.clear(); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const ERRORS = { ["no-app" /* NO_APP */]: "No Firebase App '{$appName}' has been created - " + 'call Firebase App.initializeApp()', ["bad-app-name" /* BAD_APP_NAME */]: "Illegal App name: '{$appName}", ["duplicate-app" /* DUPLICATE_APP */]: "Firebase App named '{$appName}' already exists with different options or config", ["app-deleted" /* APP_DELETED */]: "Firebase App named '{$appName}' already deleted", ["invalid-app-argument" /* INVALID_APP_ARGUMENT */]: 'firebase.{$appName}() takes either no argument or a ' + 'Firebase App instance.', ["invalid-log-argument" /* INVALID_LOG_ARGUMENT */]: 'First argument to `onLog` must be null or a function.', ["storage-open" /* STORAGE_OPEN */]: 'Error thrown when opening storage. Original error: {$originalErrorMessage}.', ["storage-get" /* STORAGE_GET */]: 'Error thrown when reading from storage. Original error: {$originalErrorMessage}.', ["storage-set" /* STORAGE_WRITE */]: 'Error thrown when writing to storage. Original error: {$originalErrorMessage}.', ["storage-delete" /* STORAGE_DELETE */]: 'Error thrown when deleting from storage. Original error: {$originalErrorMessage}.' }; const ERROR_FACTORY = new _firebase_util__WEBPACK_IMPORTED_MODULE_2__.ErrorFactory('app', 'Firebase', ERRORS); /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class FirebaseAppImpl { constructor(options, config, container) { this._isDeleted = false; this._options = Object.assign({}, options); this._config = Object.assign({}, config); this._name = config.name; this._automaticDataCollectionEnabled = config.automaticDataCollectionEnabled; this._container = container; this.container.addComponent(new _firebase_component__WEBPACK_IMPORTED_MODULE_0__.Component('app', () => this, "PUBLIC" /* PUBLIC */)); } get automaticDataCollectionEnabled() { this.checkDestroyed(); return this._automaticDataCollectionEnabled; } set automaticDataCollectionEnabled(val) { this.checkDestroyed(); this._automaticDataCollectionEnabled = val; } get name() { this.checkDestroyed(); return this._name; } get options() { this.checkDestroyed(); return this._options; } get config() { this.checkDestroyed(); return this._config; } get container() { return this._container; } get isDeleted() { return this._isDeleted; } set isDeleted(val) { this._isDeleted = val; } /** * This function will throw an Error if the App has already been deleted - * use before performing API actions on the App. */ checkDestroyed() { if (this.isDeleted) { throw ERROR_FACTORY.create("app-deleted" /* APP_DELETED */, { appName: this._name }); } } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * The current SDK version. * * @public */ const SDK_VERSION = version; function initializeApp(options, rawConfig = {}) { if (typeof rawConfig !== 'object') { const name = rawConfig; rawConfig = { name }; } const config = Object.assign({ name: DEFAULT_ENTRY_NAME, automaticDataCollectionEnabled: false }, rawConfig); const name = config.name; if (typeof name !== 'string' || !name) { throw ERROR_FACTORY.create("bad-app-name" /* BAD_APP_NAME */, { appName: String(name) }); } const existingApp = _apps.get(name); if (existingApp) { // return the existing app if options and config deep equal the ones in the existing app. if ((0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.deepEqual)(options, existingApp.options) && (0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.deepEqual)(config, existingApp.config)) { return existingApp; } else { throw ERROR_FACTORY.create("duplicate-app" /* DUPLICATE_APP */, { appName: name }); } } const container = new _firebase_component__WEBPACK_IMPORTED_MODULE_0__.ComponentContainer(name); for (const component of _components.values()) { container.addComponent(component); } const newApp = new FirebaseAppImpl(options, config, container); _apps.set(name, newApp); return newApp; } /** * Retrieves a {@link @firebase/app#FirebaseApp} instance. * * When called with no arguments, the default app is returned. When an app name * is provided, the app corresponding to that name is returned. * * An exception is thrown if the app being retrieved has not yet been * initialized. * * @example * ```javascript * // Return the default app * const app = getApp(); * ``` * * @example * ```javascript * // Return a named app * const otherApp = getApp("otherApp"); * ``` * * @param name - Optional name of the app to return. If no name is * provided, the default is `"[DEFAULT]"`. * * @returns The app corresponding to the provided app name. * If no app name is provided, the default app is returned. * * @public */ function getApp(name = DEFAULT_ENTRY_NAME) { const app = _apps.get(name); if (!app) { throw ERROR_FACTORY.create("no-app" /* NO_APP */, { appName: name }); } return app; } /** * A (read-only) array of all initialized apps. * @public */ function getApps() { return Array.from(_apps.values()); } /** * Renders this app unusable and frees the resources of all associated * services. * * @example * ```javascript * deleteApp(app) * .then(function() { * console.log("App deleted successfully"); * }) * .catch(function(error) { * console.log("Error deleting app:", error); * }); * ``` * * @public */ async function deleteApp(app) { const name = app.name; if (_apps.has(name)) { _apps.delete(name); await Promise.all(app.container .getProviders() .map(provider => provider.delete())); app.isDeleted = true; } } /** * Registers a library's name and version for platform logging purposes. * @param library - Name of 1p or 3p library (e.g. firestore, angularfire) * @param version - Current version of that library. * @param variant - Bundle variant, e.g., node, rn, etc. * * @public */ function registerVersion(libraryKeyOrName, version, variant) { var _a; // TODO: We can use this check to whitelist strings when/if we set up // a good whitelist system. let library = (_a = PLATFORM_LOG_STRING[libraryKeyOrName]) !== null && _a !== void 0 ? _a : libraryKeyOrName; if (variant) { library += `-${variant}`; } const libraryMismatch = library.match(/\s|\//); const versionMismatch = version.match(/\s|\//); if (libraryMismatch || versionMismatch) { const warning = [ `Unable to register library "${library}" with version "${version}":` ]; if (libraryMismatch) { warning.push(`library name "${library}" contains illegal characters (whitespace or "/")`); } if (libraryMismatch && versionMismatch) { warning.push('and'); } if (versionMismatch) { warning.push(`version name "${version}" contains illegal characters (whitespace or "/")`); } logger.warn(warning.join(' ')); return; } _registerComponent(new _firebase_component__WEBPACK_IMPORTED_MODULE_0__.Component(`${library}-version`, () => ({ library, version }), "VERSION" /* VERSION */)); } /** * Sets log handler for all Firebase SDKs. * @param logCallback - An optional custom log handler that executes user code whenever * the Firebase SDK makes a logging call. * * @public */ function onLog(logCallback, options) { if (logCallback !== null && typeof logCallback !== 'function') { throw ERROR_FACTORY.create("invalid-log-argument" /* INVALID_LOG_ARGUMENT */); } (0,_firebase_logger__WEBPACK_IMPORTED_MODULE_1__.setUserLogHandler)(logCallback, options); } /** * Sets log level for all Firebase SDKs. * * All of the log types above the current log level are captured (i.e. if * you set the log level to `info`, errors are logged, but `debug` and * `verbose` logs are not). * * @public */ function setLogLevel(logLevel) { (0,_firebase_logger__WEBPACK_IMPORTED_MODULE_1__.setLogLevel)(logLevel); } /** * @license * Copyright 2021 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const DB_NAME = 'firebase-heartbeat-database'; const DB_VERSION = 1; const STORE_NAME = 'firebase-heartbeat-store'; let dbPromise = null; function getDbPromise() { if (!dbPromise) { dbPromise = (0,idb__WEBPACK_IMPORTED_MODULE_3__.openDB)(DB_NAME, DB_VERSION, { upgrade: (db, oldVersion) => { // We don't use 'break' in this switch statement, the fall-through // behavior is what we want, because if there are multiple versions between // the old version and the current version, we want ALL the migrations // that correspond to those versions to run, not only the last one. // eslint-disable-next-line default-case switch (oldVersion) { case 0: db.createObjectStore(STORE_NAME); } } }).catch(e => { throw ERROR_FACTORY.create("storage-open" /* STORAGE_OPEN */, { originalErrorMessage: e.message }); }); } return dbPromise; } async function readHeartbeatsFromIndexedDB(app) { try { const db = await getDbPromise(); return db .transaction(STORE_NAME) .objectStore(STORE_NAME) .get(computeKey(app)); } catch (e) { throw ERROR_FACTORY.create("storage-get" /* STORAGE_GET */, { originalErrorMessage: e.message }); } } async function writeHeartbeatsToIndexedDB(app, heartbeatObject) { try { const db = await getDbPromise(); const tx = db.transaction(STORE_NAME, 'readwrite'); const objectStore = tx.objectStore(STORE_NAME); await objectStore.put(heartbeatObject, computeKey(app)); return tx.done; } catch (e) { throw ERROR_FACTORY.create("storage-set" /* STORAGE_WRITE */, { originalErrorMessage: e.message }); } } function computeKey(app) { return `${app.name}!${app.options.appId}`; } /** * @license * Copyright 2021 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const MAX_HEADER_BYTES = 1024; // 30 days const STORED_HEARTBEAT_RETENTION_MAX_MILLIS = 30 * 24 * 60 * 60 * 1000; class HeartbeatServiceImpl { constructor(container) { this.container = container; /** * In-memory cache for heartbeats, used by getHeartbeatsHeader() to generate * the header string. * Stores one record per date. This will be consolidated into the standard * format of one record per user agent string before being sent as a header. * Populated from indexedDB when the controller is instantiated and should * be kept in sync with indexedDB. * Leave public for easier testing. */ this._heartbeatsCache = null; const app = this.container.getProvider('app').getImmediate(); this._storage = new HeartbeatStorageImpl(app); this._heartbeatsCachePromise = this._storage.read().then(result => { this._heartbeatsCache = result; return result; }); } /** * Called to report a heartbeat. The function will generate * a HeartbeatsByUserAgent object, update heartbeatsCache, and persist it * to IndexedDB. * Note that we only store one heartbeat per day. So if a heartbeat for today is * already logged, subsequent calls to this function in the same day will be ignored. */ async triggerHeartbeat() { const platformLogger = this.container .getProvider('platform-logger') .getImmediate(); // This is the "Firebase user agent" string from the platform logger // service, not the browser user agent. const agent = platformLogger.getPlatformInfoString(); const date = getUTCDateString(); if (this._heartbeatsCache === null) { this._heartbeatsCache = await this._heartbeatsCachePromise; } // Do not store a heartbeat if one is already stored for this day // or if a header has already been sent today. if (this._heartbeatsCache.lastSentHeartbeatDate === date || this._heartbeatsCache.heartbeats.some(singleDateHeartbeat => singleDateHeartbeat.date === date)) { return; } else { // There is no entry for this date. Create one. this._heartbeatsCache.heartbeats.push({ date, agent }); } // Remove entries older than 30 days. this._heartbeatsCache.heartbeats = this._heartbeatsCache.heartbeats.filter(singleDateHeartbeat => { const hbTimestamp = new Date(singleDateHeartbeat.date).valueOf(); const now = Date.now(); return now - hbTimestamp <= STORED_HEARTBEAT_RETENTION_MAX_MILLIS; }); return this._storage.overwrite(this._heartbeatsCache); } /** * Returns a base64 encoded string which can be attached to the heartbeat-specific header directly. * It also clears all heartbeats from memory as well as in IndexedDB. * * NOTE: Consuming product SDKs should not send the header if this method * returns an empty string. */ async getHeartbeatsHeader() { if (this._heartbeatsCache === null) { await this._heartbeatsCachePromise; } // If it's still null or the array is empty, there is no data to send. if (this._heartbeatsCache === null || this._heartbeatsCache.heartbeats.length === 0) { return ''; } const date = getUTCDateString(); // Extract as many heartbeats from the cache as will fit under the size limit. const { heartbeatsToSend, unsentEntries } = extractHeartbeatsForHeader(this._heartbeatsCache.heartbeats); const headerString = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.base64urlEncodeWithoutPadding)(JSON.stringify({ version: 2, heartbeats: heartbeatsToSend })); // Store last sent date to prevent another being logged/sent for the same day. this._heartbeatsCache.lastSentHeartbeatDate = date; if (unsentEntries.length > 0) { // Store any unsent entries if they exist. this._heartbeatsCache.heartbeats = unsentEntries; // This seems more likely than emptying the array (below) to lead to some odd state // since the cache isn't empty and this will be called again on the next request, // and is probably safest if we await it. await this._storage.overwrite(this._heartbeatsCache); } else { this._heartbeatsCache.heartbeats = []; // Do not wait for this, to reduce latency. void this._storage.overwrite(this._heartbeatsCache); } return headerString; } } function getUTCDateString() { const today = new Date(); // Returns date format 'YYYY-MM-DD' return today.toISOString().substring(0, 10); } function extractHeartbeatsForHeader(heartbeatsCache, maxSize = MAX_HEADER_BYTES) { // Heartbeats grouped by user agent in the standard format to be sent in // the header. const heartbeatsToSend = []; // Single date format heartbeats that are not sent. let unsentEntries = heartbeatsCache.slice(); for (const singleDateHeartbeat of heartbeatsCache) { // Look for an existing entry with the same user agent. const heartbeatEntry = heartbeatsToSend.find(hb => hb.agent === singleDateHeartbeat.agent); if (!heartbeatEntry) { // If no entry for this user agent exists, create one. heartbeatsToSend.push({ agent: singleDateHeartbeat.agent, dates: [singleDateHeartbeat.date] }); if (countBytes(heartbeatsToSend) > maxSize) { // If the header would exceed max size, remove the added heartbeat // entry and stop adding to the header. heartbeatsToSend.pop(); break; } } else { heartbeatEntry.dates.push(singleDateHeartbeat.date); // If the header would exceed max size, remove the added date // and stop adding to the header. if (countBytes(heartbeatsToSend) > maxSize) { heartbeatEntry.dates.pop(); break; } } // Pop unsent entry from queue. (Skipped if adding the entry exceeded // quota and the loop breaks early.) unsentEntries = unsentEntries.slice(1); } return { heartbeatsToSend, unsentEntries }; } class HeartbeatStorageImpl { constructor(app) { this.app = app; this._canUseIndexedDBPromise = this.runIndexedDBEnvironmentCheck(); } async runIndexedDBEnvironmentCheck() { if (!(0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.isIndexedDBAvailable)()) { return false; } else { return (0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.validateIndexedDBOpenable)() .then(() => true) .catch(() => false); } } /** * Read all heartbeats. */ async read() { const canUseIndexedDB = await this._canUseIndexedDBPromise; if (!canUseIndexedDB) { return { heartbeats: [] }; } else { const idbHeartbeatObject = await readHeartbeatsFromIndexedDB(this.app); return idbHeartbeatObject || { heartbeats: [] }; } } // overwrite the storage with the provided heartbeats async overwrite(heartbeatsObject) { var _a; const canUseIndexedDB = await this._canUseIndexedDBPromise; if (!canUseIndexedDB) { return; } else { const existingHeartbeatsObject = await this.read(); return writeHeartbeatsToIndexedDB(this.app, { lastSentHeartbeatDate: (_a = heartbeatsObject.lastSentHeartbeatDate) !== null && _a !== void 0 ? _a : existingHeartbeatsObject.lastSentHeartbeatDate, heartbeats: heartbeatsObject.heartbeats }); } } // add heartbeats async add(heartbeatsObject) { var _a; const canUseIndexedDB = await this._canUseIndexedDBPromise; if (!canUseIndexedDB) { return; } else { const existingHeartbeatsObject = await this.read(); return writeHeartbeatsToIndexedDB(this.app, { lastSentHeartbeatDate: (_a = heartbeatsObject.lastSentHeartbeatDate) !== null && _a !== void 0 ? _a : existingHeartbeatsObject.lastSentHeartbeatDate, heartbeats: [ ...existingHeartbeatsObject.heartbeats, ...heartbeatsObject.heartbeats ] }); } } } /** * Calculate bytes of a HeartbeatsByUserAgent array after being wrapped * in a platform logging header JSON object, stringified, and converted * to base 64. */ function countBytes(heartbeatsCache) { // base64 has a restricted set of characters, all of which should be 1 byte. return (0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.base64urlEncodeWithoutPadding)( // heartbeatsCache wrapper properties JSON.stringify({ version: 2, heartbeats: heartbeatsCache })).length; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function registerCoreComponents(variant) { _registerComponent(new _firebase_component__WEBPACK_IMPORTED_MODULE_0__.Component('platform-logger', container => new PlatformLoggerServiceImpl(container), "PRIVATE" /* PRIVATE */)); _registerComponent(new _firebase_component__WEBPACK_IMPORTED_MODULE_0__.Component('heartbeat', container => new HeartbeatServiceImpl(container), "PRIVATE" /* PRIVATE */)); // Register `app` package. registerVersion(name$o, version$1, variant); // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation registerVersion(name$o, version$1, 'esm2017'); // Register platform SDK identifier (no version). registerVersion('fire-js', ''); } /** * Firebase App * * @remarks This package coordinates the communication between the different Firebase components * @packageDocumentation */ registerCoreComponents(''); //# sourceMappingURL=index.esm2017.js.map /***/ }), /***/ "./node_modules/@firebase/component/dist/esm/index.esm2017.js": /*!********************************************************************!*\ !*** ./node_modules/@firebase/component/dist/esm/index.esm2017.js ***! \********************************************************************/ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Component": () => (/* binding */ Component), /* harmony export */ "ComponentContainer": () => (/* binding */ ComponentContainer), /* harmony export */ "Provider": () => (/* binding */ Provider) /* harmony export */ }); /* harmony import */ var _firebase_util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @firebase/util */ "./node_modules/@firebase/util/dist/index.esm2017.js"); /** * Component for service name T, e.g. `auth`, `auth-internal` */ class Component { /** * * @param name The public service name, e.g. app, auth, firestore, database * @param instanceFactory Service factory responsible for creating the public interface * @param type whether the service provided by the component is public or private */ constructor(name, instanceFactory, type) { this.name = name; this.instanceFactory = instanceFactory; this.type = type; this.multipleInstances = false; /** * Properties to be added to the service namespace */ this.serviceProps = {}; this.instantiationMode = "LAZY" /* LAZY */; this.onInstanceCreated = null; } setInstantiationMode(mode) { this.instantiationMode = mode; return this; } setMultipleInstances(multipleInstances) { this.multipleInstances = multipleInstances; return this; } setServiceProps(props) { this.serviceProps = props; return this; } setInstanceCreatedCallback(callback) { this.onInstanceCreated = callback; return this; } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const DEFAULT_ENTRY_NAME = '[DEFAULT]'; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Provider for instance for service name T, e.g. 'auth', 'auth-internal' * NameServiceMapping[T] is an alias for the type of the instance */ class Provider { constructor(name, container) { this.name = name; this.container = container; this.component = null; this.instances = new Map(); this.instancesDeferred = new Map(); this.instancesOptions = new Map(); this.onInitCallbacks = new Map(); } /** * @param identifier A provider can provide mulitple instances of a service * if this.component.multipleInstances is true. */ get(identifier) { // if multipleInstances is not supported, use the default name const normalizedIdentifier = this.normalizeInstanceIdentifier(identifier); if (!this.instancesDeferred.has(normalizedIdentifier)) { const deferred = new _firebase_util__WEBPACK_IMPORTED_MODULE_0__.Deferred(); this.instancesDeferred.set(normalizedIdentifier, deferred); if (this.isInitialized(normalizedIdentifier) || this.shouldAutoInitialize()) { // initialize the service if it can be auto-initialized try { const instance = this.getOrInitializeService({ instanceIdentifier: normalizedIdentifier }); if (instance) { deferred.resolve(instance); } } catch (e) { // when the instance factory throws an exception during get(), it should not cause // a fatal error. We just return the unresolved promise in this case. } } } return this.instancesDeferred.get(normalizedIdentifier).promise; } getImmediate(options) { var _a; // if multipleInstances is not supported, use the default name const normalizedIdentifier = this.normalizeInstanceIdentifier(options === null || options === void 0 ? void 0 : options.identifier); const optional = (_a = options === null || options === void 0 ? void 0 : options.optional) !== null && _a !== void 0 ? _a : false; if (this.isInitialized(normalizedIdentifier) || this.shouldAutoInitialize()) { try { return this.getOrInitializeService({ instanceIdentifier: normalizedIdentifier }); } catch (e) { if (optional) { return null; } else { throw e; } } } else { // In case a component is not initialized and should/can not be auto-initialized at the moment, return null if the optional flag is set, or throw if (optional) { return null; } else { throw Error(`Service ${this.name} is not available`); } } } getComponent() { return this.component; } setComponent(component) { if (component.name !== this.name) { throw Error(`Mismatching Component ${component.name} for Provider ${this.name}.`); } if (this.component) { throw Error(`Component for ${this.name} has already been provided`); } this.component = component; // return early without attempting to initialize the component if the component requires explicit initialization (calling `Provider.initialize()`) if (!this.shouldAutoInitialize()) { return; } // if the service is eager, initialize the default instance if (isComponentEager(component)) { try { this.getOrInitializeService({ instanceIdentifier: DEFAULT_ENTRY_NAME }); } catch (e) { // when the instance factory for an eager Component throws an exception during the eager // initialization, it should not cause a fatal error. // TODO: Investigate if we need to make it configurable, because some component may want to cause // a fatal error in this case? } } // Create service instances for the pending promises and resolve them // NOTE: if this.multipleInstances is false, only the default instance will be created // and all promises with resolve with it regardless of the identifier. for (const [instanceIdentifier, instanceDeferred] of this.instancesDeferred.entries()) { const normalizedIdentifier = this.normalizeInstanceIdentifier(instanceIdentifier); try { // `getOrInitializeService()` should always return a valid instance since a component is guaranteed. use ! to make typescript happy. const instance = this.getOrInitializeService({ instanceIdentifier: normalizedIdentifier }); instanceDeferred.resolve(instance); } catch (e) { // when the instance factory throws an exception, it should not cause // a fatal error. We just leave the promise unresolved. } } } clearInstance(identifier = DEFAULT_ENTRY_NAME) { this.instancesDeferred.delete(identifier); this.instancesOptions.delete(identifier); this.instances.delete(identifier); } // app.delete() will call this method on every provider to delete the services // TODO: should we mark the provider as deleted? async delete() { const services = Array.from(this.instances.values()); await Promise.all([ ...services .filter(service => 'INTERNAL' in service) // legacy services // eslint-disable-next-line @typescript-eslint/no-explicit-any .map(service => service.INTERNAL.delete()), ...services .filter(service => '_delete' in service) // modularized services // eslint-disable-next-line @typescript-eslint/no-explicit-any .map(service => service._delete()) ]); } isComponentSet() { return this.component != null; } isInitialized(identifier = DEFAULT_ENTRY_NAME) { return this.instances.has(identifier); } getOptions(identifier = DEFAULT_ENTRY_NAME) { return this.instancesOptions.get(identifier) || {}; } initialize(opts = {}) { const { options = {} } = opts; const normalizedIdentifier = this.normalizeInstanceIdentifier(opts.instanceIdentifier); if (this.isInitialized(normalizedIdentifier)) { throw Error(`${this.name}(${normalizedIdentifier}) has already been initialized`); } if (!this.isComponentSet()) { throw Error(`Component ${this.name} has not been registered yet`); } const instance = this.getOrInitializeService({ instanceIdentifier: normalizedIdentifier, options }); // resolve any pending promise waiting for the service instance for (const [instanceIdentifier, instanceDeferred] of this.instancesDeferred.entries()) { const normalizedDeferredIdentifier = this.normalizeInstanceIdentifier(instanceIdentifier); if (normalizedIdentifier === normalizedDeferredIdentifier) { instanceDeferred.resolve(instance); } } return instance; } /** * * @param callback - a function that will be invoked after the provider has been initialized by calling provider.initialize(). * The function is invoked SYNCHRONOUSLY, so it should not execute any longrunning tasks in order to not block the program. * * @param identifier An optional instance identifier * @returns a function to unregister the callback */ onInit(callback, identifier) { var _a; const normalizedIdentifier = this.normalizeInstanceIdentifier(identifier); const existingCallbacks = (_a = this.onInitCallbacks.get(normalizedIdentifier)) !== null && _a !== void 0 ? _a : new Set(); existingCallbacks.add(callback); this.onInitCallbacks.set(normalizedIdentifier, existingCallbacks); const existingInstance = this.instances.get(normalizedIdentifier); if (existingInstance) { callback(existingInstance, normalizedIdentifier); } return () => { existingCallbacks.delete(callback); }; } /** * Invoke onInit callbacks synchronously * @param instance the service instance` */ invokeOnInitCallbacks(instance, identifier) { const callbacks = this.onInitCallbacks.get(identifier); if (!callbacks) { return; } for (const callback of callbacks) { try { callback(instance, identifier); } catch (_a) { // ignore errors in the onInit callback } } } getOrInitializeService({ instanceIdentifier, options = {} }) { let instance = this.instances.get(instanceIdentifier); if (!instance && this.component) { instance = this.component.instanceFactory(this.container, { instanceIdentifier: normalizeIdentifierForFactory(instanceIdentifier), options }); this.instances.set(instanceIdentifier, instance); this.instancesOptions.set(instanceIdentifier, options); /** * Invoke onInit listeners. * Note this.component.onInstanceCreated is different, which is used by the component creator, * while onInit listeners are registered by consumers of the provider. */ this.invokeOnInitCallbacks(instance, instanceIdentifier); /** * Order is important * onInstanceCreated() should be called after this.instances.set(instanceIdentifier, instance); which * makes `isInitialized()` return true. */ if (this.component.onInstanceCreated) { try { this.component.onInstanceCreated(this.container, instanceIdentifier, instance); } catch (_a) { // ignore errors in the onInstanceCreatedCallback } } } return instance || null; } normalizeInstanceIdentifier(identifier = DEFAULT_ENTRY_NAME) { if (this.component) { return this.component.multipleInstances ? identifier : DEFAULT_ENTRY_NAME; } else { return identifier; // assume multiple instances are supported before the component is provided. } } shouldAutoInitialize() { return (!!this.component && this.component.instantiationMode !== "EXPLICIT" /* EXPLICIT */); } } // undefined should be passed to the service factory for the default instance function normalizeIdentifierForFactory(identifier) { return identifier === DEFAULT_ENTRY_NAME ? undefined : identifier; } function isComponentEager(component) { return component.instantiationMode === "EAGER" /* EAGER */; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * ComponentContainer that provides Providers for service name T, e.g. `auth`, `auth-internal` */ class ComponentContainer { constructor(name) { this.name = name; this.providers = new Map(); } /** * * @param component Component being added * @param overwrite When a component with the same name has already been registered, * if overwrite is true: overwrite the existing component with the new component and create a new * provider with the new component. It can be useful in tests where you want to use different mocks * for different tests. * if overwrite is false: throw an exception */ addComponent(component) { const provider = this.getProvider(component.name); if (provider.isComponentSet()) { throw new Error(`Component ${component.name} has already been registered with ${this.name}`); } provider.setComponent(component); } addOrOverwriteComponent(component) { const provider = this.getProvider(component.name); if (provider.isComponentSet()) { // delete the existing provider from the container, so we can register the new component this.providers.delete(component.name); } this.addComponent(component); } /** * getProvider provides a type safe interface where it can only be called with a field name * present in NameServiceMapping interface. * * Firebase SDKs providing services should extend NameServiceMapping interface to register * themselves. */ getProvider(name) { if (this.providers.has(name)) { return this.providers.get(name); } // create a Provider for a service that hasn't registered with Firebase const provider = new Provider(name, this); this.providers.set(name, provider); return provider; } getProviders() { return Array.from(this.providers.values()); } } //# sourceMappingURL=index.esm2017.js.map /***/ }), /***/ "./node_modules/@firebase/installations/dist/esm/index.esm2017.js": /*!************************************************************************!*\ !*** ./node_modules/@firebase/installations/dist/esm/index.esm2017.js ***! \************************************************************************/ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "deleteInstallations": () => (/* binding */ deleteInstallations), /* harmony export */ "getId": () => (/* binding */ getId), /* harmony export */ "getInstallations": () => (/* binding */ getInstallations), /* harmony export */ "getToken": () => (/* binding */ getToken), /* harmony export */ "onIdChange": () => (/* binding */ onIdChange) /* harmony export */ }); /* harmony import */ var _firebase_app__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @firebase/app */ "./node_modules/@firebase/app/dist/esm/index.esm2017.js"); /* harmony import */ var _firebase_component__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @firebase/component */ "./node_modules/@firebase/component/dist/esm/index.esm2017.js"); /* harmony import */ var _firebase_util__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @firebase/util */ "./node_modules/@firebase/util/dist/index.esm2017.js"); /* harmony import */ var idb__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! idb */ "./node_modules/idb/build/index.js"); const name = "@firebase/installations"; const version = "0.5.9"; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const PENDING_TIMEOUT_MS = 10000; const PACKAGE_VERSION = `w:${version}`; const INTERNAL_AUTH_VERSION = 'FIS_v2'; const INSTALLATIONS_API_URL = 'https://firebaseinstallations.googleapis.com/v1'; const TOKEN_EXPIRATION_BUFFER = 60 * 60 * 1000; // One hour const SERVICE = 'installations'; const SERVICE_NAME = 'Installations'; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const ERROR_DESCRIPTION_MAP = { ["missing-app-config-values" /* MISSING_APP_CONFIG_VALUES */]: 'Missing App configuration value: "{$valueName}"', ["not-registered" /* NOT_REGISTERED */]: 'Firebase Installation is not registered.', ["installation-not-found" /* INSTALLATION_NOT_FOUND */]: 'Firebase Installation not found.', ["request-failed" /* REQUEST_FAILED */]: '{$requestName} request failed with error "{$serverCode} {$serverStatus}: {$serverMessage}"', ["app-offline" /* APP_OFFLINE */]: 'Could not process request. Application offline.', ["delete-pending-registration" /* DELETE_PENDING_REGISTRATION */]: "Can't delete installation while there is a pending registration request." }; const ERROR_FACTORY = new _firebase_util__WEBPACK_IMPORTED_MODULE_2__.ErrorFactory(SERVICE, SERVICE_NAME, ERROR_DESCRIPTION_MAP); /** Returns true if error is a FirebaseError that is based on an error from the server. */ function isServerError(error) { return (error instanceof _firebase_util__WEBPACK_IMPORTED_MODULE_2__.FirebaseError && error.code.includes("request-failed" /* REQUEST_FAILED */)); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function getInstallationsEndpoint({ projectId }) { return `${INSTALLATIONS_API_URL}/projects/${projectId}/installations`; } function extractAuthTokenInfoFromResponse(response) { return { token: response.token, requestStatus: 2 /* COMPLETED */, expiresIn: getExpiresInFromResponseExpiresIn(response.expiresIn), creationTime: Date.now() }; } async function getErrorFromResponse(requestName, response) { const responseJson = await response.json(); const errorData = responseJson.error; return ERROR_FACTORY.create("request-failed" /* REQUEST_FAILED */, { requestName, serverCode: errorData.code, serverMessage: errorData.message, serverStatus: errorData.status }); } function getHeaders({ apiKey }) { return new Headers({ 'Content-Type': 'application/json', Accept: 'application/json', 'x-goog-api-key': apiKey }); } function getHeadersWithAuth(appConfig, { refreshToken }) { const headers = getHeaders(appConfig); headers.append('Authorization', getAuthorizationHeader(refreshToken)); return headers; } /** * Calls the passed in fetch wrapper and returns the response. * If the returned response has a status of 5xx, re-runs the function once and * returns the response. */ async function retryIfServerError(fn) { const result = await fn(); if (result.status >= 500 && result.status < 600) { // Internal Server Error. Retry request. return fn(); } return result; } function getExpiresInFromResponseExpiresIn(responseExpiresIn) { // This works because the server will never respond with fractions of a second. return Number(responseExpiresIn.replace('s', '000')); } function getAuthorizationHeader(refreshToken) { return `${INTERNAL_AUTH_VERSION} ${refreshToken}`; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function createInstallationRequest({ appConfig, heartbeatServiceProvider }, { fid }) { const endpoint = getInstallationsEndpoint(appConfig); const headers = getHeaders(appConfig); // If heartbeat service exists, add the heartbeat string to the header. const heartbeatService = heartbeatServiceProvider.getImmediate({ optional: true }); if (heartbeatService) { const heartbeatsHeader = await heartbeatService.getHeartbeatsHeader(); if (heartbeatsHeader) { headers.append('x-firebase-client', heartbeatsHeader); } } const body = { fid, authVersion: INTERNAL_AUTH_VERSION, appId: appConfig.appId, sdkVersion: PACKAGE_VERSION }; const request = { method: 'POST', headers, body: JSON.stringify(body) }; const response = await retryIfServerError(() => fetch(endpoint, request)); if (response.ok) { const responseValue = await response.json(); const registeredInstallationEntry = { fid: responseValue.fid || fid, registrationStatus: 2 /* COMPLETED */, refreshToken: responseValue.refreshToken, authToken: extractAuthTokenInfoFromResponse(responseValue.authToken) }; return registeredInstallationEntry; } else { throw await getErrorFromResponse('Create Installation', response); } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** Returns a promise that resolves after given time passes. */ function sleep(ms) { return new Promise(resolve => { setTimeout(resolve, ms); }); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function bufferToBase64UrlSafe(array) { const b64 = btoa(String.fromCharCode(...array)); return b64.replace(/\+/g, '-').replace(/\//g, '_'); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const VALID_FID_PATTERN = /^[cdef][\w-]{21}$/; const INVALID_FID = ''; /** * Generates a new FID using random values from Web Crypto API. * Returns an empty string if FID generation fails for any reason. */ function generateFid() { try { // A valid FID has exactly 22 base64 characters, which is 132 bits, or 16.5 // bytes. our implementation generates a 17 byte array instead. const fidByteArray = new Uint8Array(17); const crypto = self.crypto || self.msCrypto; crypto.getRandomValues(fidByteArray); // Replace the first 4 random bits with the constant FID header of 0b0111. fidByteArray[0] = 0b01110000 + (fidByteArray[0] % 0b00010000); const fid = encode(fidByteArray); return VALID_FID_PATTERN.test(fid) ? fid : INVALID_FID; } catch (_a) { // FID generation errored return INVALID_FID; } } /** Converts a FID Uint8Array to a base64 string representation. */ function encode(fidByteArray) { const b64String = bufferToBase64UrlSafe(fidByteArray); // Remove the 23rd character that was added because of the extra 4 bits at the // end of our 17 byte array, and the '=' padding. return b64String.substr(0, 22); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** Returns a string key that can be used to identify the app. */ function getKey(appConfig) { return `${appConfig.appName}!${appConfig.appId}`; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const fidChangeCallbacks = new Map(); /** * Calls the onIdChange callbacks with the new FID value, and broadcasts the * change to other tabs. */ function fidChanged(appConfig, fid) { const key = getKey(appConfig); callFidChangeCallbacks(key, fid); broadcastFidChange(key, fid); } function addCallback(appConfig, callback) { // Open the broadcast channel if it's not already open, // to be able to listen to change events from other tabs. getBroadcastChannel(); const key = getKey(appConfig); let callbackSet = fidChangeCallbacks.get(key); if (!callbackSet) { callbackSet = new Set(); fidChangeCallbacks.set(key, callbackSet); } callbackSet.add(callback); } function removeCallback(appConfig, callback) { const key = getKey(appConfig); const callbackSet = fidChangeCallbacks.get(key); if (!callbackSet) { return; } callbackSet.delete(callback); if (callbackSet.size === 0) { fidChangeCallbacks.delete(key); } // Close broadcast channel if there are no more callbacks. closeBroadcastChannel(); } function callFidChangeCallbacks(key, fid) { const callbacks = fidChangeCallbacks.get(key); if (!callbacks) { return; } for (const callback of callbacks) { callback(fid); } } function broadcastFidChange(key, fid) { const channel = getBroadcastChannel(); if (channel) { channel.postMessage({ key, fid }); } closeBroadcastChannel(); } let broadcastChannel = null; /** Opens and returns a BroadcastChannel if it is supported by the browser. */ function getBroadcastChannel() { if (!broadcastChannel && 'BroadcastChannel' in self) { broadcastChannel = new BroadcastChannel('[Firebase] FID Change'); broadcastChannel.onmessage = e => { callFidChangeCallbacks(e.data.key, e.data.fid); }; } return broadcastChannel; } function closeBroadcastChannel() { if (fidChangeCallbacks.size === 0 && broadcastChannel) { broadcastChannel.close(); broadcastChannel = null; } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const DATABASE_NAME = 'firebase-installations-database'; const DATABASE_VERSION = 1; const OBJECT_STORE_NAME = 'firebase-installations-store'; let dbPromise = null; function getDbPromise() { if (!dbPromise) { dbPromise = (0,idb__WEBPACK_IMPORTED_MODULE_3__.openDB)(DATABASE_NAME, DATABASE_VERSION, { upgrade: (db, oldVersion) => { // We don't use 'break' in this switch statement, the fall-through // behavior is what we want, because if there are multiple versions between // the old version and the current version, we want ALL the migrations // that correspond to those versions to run, not only the last one. // eslint-disable-next-line default-case switch (oldVersion) { case 0: db.createObjectStore(OBJECT_STORE_NAME); } } }); } return dbPromise; } /** Assigns or overwrites the record for the given key with the given value. */ async function set(appConfig, value) { const key = getKey(appConfig); const db = await getDbPromise(); const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); const objectStore = tx.objectStore(OBJECT_STORE_NAME); const oldValue = (await objectStore.get(key)); await objectStore.put(value, key); await tx.done; if (!oldValue || oldValue.fid !== value.fid) { fidChanged(appConfig, value.fid); } return value; } /** Removes record(s) from the objectStore that match the given key. */ async function remove(appConfig) { const key = getKey(appConfig); const db = await getDbPromise(); const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); await tx.objectStore(OBJECT_STORE_NAME).delete(key); await tx.done; } /** * Atomically updates a record with the result of updateFn, which gets * called with the current value. If newValue is undefined, the record is * deleted instead. * @return Updated value */ async function update(appConfig, updateFn) { const key = getKey(appConfig); const db = await getDbPromise(); const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); const store = tx.objectStore(OBJECT_STORE_NAME); const oldValue = (await store.get(key)); const newValue = updateFn(oldValue); if (newValue === undefined) { await store.delete(key); } else { await store.put(newValue, key); } await tx.done; if (newValue && (!oldValue || oldValue.fid !== newValue.fid)) { fidChanged(appConfig, newValue.fid); } return newValue; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Updates and returns the InstallationEntry from the database. * Also triggers a registration request if it is necessary and possible. */ async function getInstallationEntry(installations) { let registrationPromise; const installationEntry = await update(installations.appConfig, oldEntry => { const installationEntry = updateOrCreateInstallationEntry(oldEntry); const entryWithPromise = triggerRegistrationIfNecessary(installations, installationEntry); registrationPromise = entryWithPromise.registrationPromise; return entryWithPromise.installationEntry; }); if (installationEntry.fid === INVALID_FID) { // FID generation failed. Waiting for the FID from the server. return { installationEntry: await registrationPromise }; } return { installationEntry, registrationPromise }; } /** * Creates a new Installation Entry if one does not exist. * Also clears timed out pending requests. */ function updateOrCreateInstallationEntry(oldEntry) { const entry = oldEntry || { fid: generateFid(), registrationStatus: 0 /* NOT_STARTED */ }; return clearTimedOutRequest(entry); } /** * If the Firebase Installation is not registered yet, this will trigger the * registration and return an InProgressInstallationEntry. * * If registrationPromise does not exist, the installationEntry is guaranteed * to be registered. */ function triggerRegistrationIfNecessary(installations, installationEntry) { if (installationEntry.registrationStatus === 0 /* NOT_STARTED */) { if (!navigator.onLine) { // Registration required but app is offline. const registrationPromiseWithError = Promise.reject(ERROR_FACTORY.create("app-offline" /* APP_OFFLINE */)); return { installationEntry, registrationPromise: registrationPromiseWithError }; } // Try registering. Change status to IN_PROGRESS. const inProgressEntry = { fid: installationEntry.fid, registrationStatus: 1 /* IN_PROGRESS */, registrationTime: Date.now() }; const registrationPromise = registerInstallation(installations, inProgressEntry); return { installationEntry: inProgressEntry, registrationPromise }; } else if (installationEntry.registrationStatus === 1 /* IN_PROGRESS */) { return { installationEntry, registrationPromise: waitUntilFidRegistration(installations) }; } else { return { installationEntry }; } } /** This will be executed only once for each new Firebase Installation. */ async function registerInstallation(installations, installationEntry) { try { const registeredInstallationEntry = await createInstallationRequest(installations, installationEntry); return set(installations.appConfig, registeredInstallationEntry); } catch (e) { if (isServerError(e) && e.customData.serverCode === 409) { // Server returned a "FID can not be used" error. // Generate a new ID next time. await remove(installations.appConfig); } else { // Registration failed. Set FID as not registered. await set(installations.appConfig, { fid: installationEntry.fid, registrationStatus: 0 /* NOT_STARTED */ }); } throw e; } } /** Call if FID registration is pending in another request. */ async function waitUntilFidRegistration(installations) { // Unfortunately, there is no way of reliably observing when a value in // IndexedDB changes (yet, see https://github.com/WICG/indexed-db-observers), // so we need to poll. let entry = await updateInstallationRequest(installations.appConfig); while (entry.registrationStatus === 1 /* IN_PROGRESS */) { // createInstallation request still in progress. await sleep(100); entry = await updateInstallationRequest(installations.appConfig); } if (entry.registrationStatus === 0 /* NOT_STARTED */) { // The request timed out or failed in a different call. Try again. const { installationEntry, registrationPromise } = await getInstallationEntry(installations); if (registrationPromise) { return registrationPromise; } else { // if there is no registrationPromise, entry is registered. return installationEntry; } } return entry; } /** * Called only if there is a CreateInstallation request in progress. * * Updates the InstallationEntry in the DB based on the status of the * CreateInstallation request. * * Returns the updated InstallationEntry. */ function updateInstallationRequest(appConfig) { return update(appConfig, oldEntry => { if (!oldEntry) { throw ERROR_FACTORY.create("installation-not-found" /* INSTALLATION_NOT_FOUND */); } return clearTimedOutRequest(oldEntry); }); } function clearTimedOutRequest(entry) { if (hasInstallationRequestTimedOut(entry)) { return { fid: entry.fid, registrationStatus: 0 /* NOT_STARTED */ }; } return entry; } function hasInstallationRequestTimedOut(installationEntry) { return (installationEntry.registrationStatus === 1 /* IN_PROGRESS */ && installationEntry.registrationTime + PENDING_TIMEOUT_MS < Date.now()); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function generateAuthTokenRequest({ appConfig, heartbeatServiceProvider }, installationEntry) { const endpoint = getGenerateAuthTokenEndpoint(appConfig, installationEntry); const headers = getHeadersWithAuth(appConfig, installationEntry); // If heartbeat service exists, add the heartbeat string to the header. const heartbeatService = heartbeatServiceProvider.getImmediate({ optional: true }); if (heartbeatService) { const heartbeatsHeader = await heartbeatService.getHeartbeatsHeader(); if (heartbeatsHeader) { headers.append('x-firebase-client', heartbeatsHeader); } } const body = { installation: { sdkVersion: PACKAGE_VERSION, appId: appConfig.appId } }; const request = { method: 'POST', headers, body: JSON.stringify(body) }; const response = await retryIfServerError(() => fetch(endpoint, request)); if (response.ok) { const responseValue = await response.json(); const completedAuthToken = extractAuthTokenInfoFromResponse(responseValue); return completedAuthToken; } else { throw await getErrorFromResponse('Generate Auth Token', response); } } function getGenerateAuthTokenEndpoint(appConfig, { fid }) { return `${getInstallationsEndpoint(appConfig)}/${fid}/authTokens:generate`; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Returns a valid authentication token for the installation. Generates a new * token if one doesn't exist, is expired or about to expire. * * Should only be called if the Firebase Installation is registered. */ async function refreshAuthToken(installations, forceRefresh = false) { let tokenPromise; const entry = await update(installations.appConfig, oldEntry => { if (!isEntryRegistered(oldEntry)) { throw ERROR_FACTORY.create("not-registered" /* NOT_REGISTERED */); } const oldAuthToken = oldEntry.authToken; if (!forceRefresh && isAuthTokenValid(oldAuthToken)) { // There is a valid token in the DB. return oldEntry; } else if (oldAuthToken.requestStatus === 1 /* IN_PROGRESS */) { // There already is a token request in progress. tokenPromise = waitUntilAuthTokenRequest(installations, forceRefresh); return oldEntry; } else { // No token or token expired. if (!navigator.onLine) { throw ERROR_FACTORY.create("app-offline" /* APP_OFFLINE */); } const inProgressEntry = makeAuthTokenRequestInProgressEntry(oldEntry); tokenPromise = fetchAuthTokenFromServer(installations, inProgressEntry); return inProgressEntry; } }); const authToken = tokenPromise ? await tokenPromise : entry.authToken; return authToken; } /** * Call only if FID is registered and Auth Token request is in progress. * * Waits until the current pending request finishes. If the request times out, * tries once in this thread as well. */ async function waitUntilAuthTokenRequest(installations, forceRefresh) { // Unfortunately, there is no way of reliably observing when a value in // IndexedDB changes (yet, see https://github.com/WICG/indexed-db-observers), // so we need to poll. let entry = await updateAuthTokenRequest(installations.appConfig); while (entry.authToken.requestStatus === 1 /* IN_PROGRESS */) { // generateAuthToken still in progress. await sleep(100); entry = await updateAuthTokenRequest(installations.appConfig); } const authToken = entry.authToken; if (authToken.requestStatus === 0 /* NOT_STARTED */) { // The request timed out or failed in a different call. Try again. return refreshAuthToken(installations, forceRefresh); } else { return authToken; } } /** * Called only if there is a GenerateAuthToken request in progress. * * Updates the InstallationEntry in the DB based on the status of the * GenerateAuthToken request. * * Returns the updated InstallationEntry. */ function updateAuthTokenRequest(appConfig) { return update(appConfig, oldEntry => { if (!isEntryRegistered(oldEntry)) { throw ERROR_FACTORY.create("not-registered" /* NOT_REGISTERED */); } const oldAuthToken = oldEntry.authToken; if (hasAuthTokenRequestTimedOut(oldAuthToken)) { return Object.assign(Object.assign({}, oldEntry), { authToken: { requestStatus: 0 /* NOT_STARTED */ } }); } return oldEntry; }); } async function fetchAuthTokenFromServer(installations, installationEntry) { try { const authToken = await generateAuthTokenRequest(installations, installationEntry); const updatedInstallationEntry = Object.assign(Object.assign({}, installationEntry), { authToken }); await set(installations.appConfig, updatedInstallationEntry); return authToken; } catch (e) { if (isServerError(e) && (e.customData.serverCode === 401 || e.customData.serverCode === 404)) { // Server returned a "FID not found" or a "Invalid authentication" error. // Generate a new ID next time. await remove(installations.appConfig); } else { const updatedInstallationEntry = Object.assign(Object.assign({}, installationEntry), { authToken: { requestStatus: 0 /* NOT_STARTED */ } }); await set(installations.appConfig, updatedInstallationEntry); } throw e; } } function isEntryRegistered(installationEntry) { return (installationEntry !== undefined && installationEntry.registrationStatus === 2 /* COMPLETED */); } function isAuthTokenValid(authToken) { return (authToken.requestStatus === 2 /* COMPLETED */ && !isAuthTokenExpired(authToken)); } function isAuthTokenExpired(authToken) { const now = Date.now(); return (now < authToken.creationTime || authToken.creationTime + authToken.expiresIn < now + TOKEN_EXPIRATION_BUFFER); } /** Returns an updated InstallationEntry with an InProgressAuthToken. */ function makeAuthTokenRequestInProgressEntry(oldEntry) { const inProgressAuthToken = { requestStatus: 1 /* IN_PROGRESS */, requestTime: Date.now() }; return Object.assign(Object.assign({}, oldEntry), { authToken: inProgressAuthToken }); } function hasAuthTokenRequestTimedOut(authToken) { return (authToken.requestStatus === 1 /* IN_PROGRESS */ && authToken.requestTime + PENDING_TIMEOUT_MS < Date.now()); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Creates a Firebase Installation if there isn't one for the app and * returns the Installation ID. * @param installations - The `Installations` instance. * * @public */ async function getId(installations) { const installationsImpl = installations; const { installationEntry, registrationPromise } = await getInstallationEntry(installationsImpl); if (registrationPromise) { registrationPromise.catch(console.error); } else { // If the installation is already registered, update the authentication // token if needed. refreshAuthToken(installationsImpl).catch(console.error); } return installationEntry.fid; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Returns a Firebase Installations auth token, identifying the current * Firebase Installation. * @param installations - The `Installations` instance. * @param forceRefresh - Force refresh regardless of token expiration. * * @public */ async function getToken(installations, forceRefresh = false) { const installationsImpl = installations; await completeInstallationRegistration(installationsImpl); // At this point we either have a Registered Installation in the DB, or we've // already thrown an error. const authToken = await refreshAuthToken(installationsImpl, forceRefresh); return authToken.token; } async function completeInstallationRegistration(installations) { const { registrationPromise } = await getInstallationEntry(installations); if (registrationPromise) { // A createInstallation request is in progress. Wait until it finishes. await registrationPromise; } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function deleteInstallationRequest(appConfig, installationEntry) { const endpoint = getDeleteEndpoint(appConfig, installationEntry); const headers = getHeadersWithAuth(appConfig, installationEntry); const request = { method: 'DELETE', headers }; const response = await retryIfServerError(() => fetch(endpoint, request)); if (!response.ok) { throw await getErrorFromResponse('Delete Installation', response); } } function getDeleteEndpoint(appConfig, { fid }) { return `${getInstallationsEndpoint(appConfig)}/${fid}`; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Deletes the Firebase Installation and all associated data. * @param installations - The `Installations` instance. * * @public */ async function deleteInstallations(installations) { const { appConfig } = installations; const entry = await update(appConfig, oldEntry => { if (oldEntry && oldEntry.registrationStatus === 0 /* NOT_STARTED */) { // Delete the unregistered entry without sending a deleteInstallation request. return undefined; } return oldEntry; }); if (entry) { if (entry.registrationStatus === 1 /* IN_PROGRESS */) { // Can't delete while trying to register. throw ERROR_FACTORY.create("delete-pending-registration" /* DELETE_PENDING_REGISTRATION */); } else if (entry.registrationStatus === 2 /* COMPLETED */) { if (!navigator.onLine) { throw ERROR_FACTORY.create("app-offline" /* APP_OFFLINE */); } else { await deleteInstallationRequest(appConfig, entry); await remove(appConfig); } } } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Sets a new callback that will get called when Installation ID changes. * Returns an unsubscribe function that will remove the callback when called. * @param installations - The `Installations` instance. * @param callback - The callback function that is invoked when FID changes. * @returns A function that can be called to unsubscribe. * * @public */ function onIdChange(installations, callback) { const { appConfig } = installations; addCallback(appConfig, callback); return () => { removeCallback(appConfig, callback); }; } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Returns an instance of {@link Installations} associated with the given * {@link @firebase/app#FirebaseApp} instance. * @param app - The {@link @firebase/app#FirebaseApp} instance. * * @public */ function getInstallations(app = (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__.getApp)()) { const installationsImpl = (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__._getProvider)(app, 'installations').getImmediate(); return installationsImpl; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function extractAppConfig(app) { if (!app || !app.options) { throw getMissingValueError('App Configuration'); } if (!app.name) { throw getMissingValueError('App Name'); } // Required app config keys const configKeys = [ 'projectId', 'apiKey', 'appId' ]; for (const keyName of configKeys) { if (!app.options[keyName]) { throw getMissingValueError(keyName); } } return { appName: app.name, projectId: app.options.projectId, apiKey: app.options.apiKey, appId: app.options.appId }; } function getMissingValueError(valueName) { return ERROR_FACTORY.create("missing-app-config-values" /* MISSING_APP_CONFIG_VALUES */, { valueName }); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const INSTALLATIONS_NAME = 'installations'; const INSTALLATIONS_NAME_INTERNAL = 'installations-internal'; const publicFactory = (container) => { const app = container.getProvider('app').getImmediate(); // Throws if app isn't configured properly. const appConfig = extractAppConfig(app); const heartbeatServiceProvider = (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__._getProvider)(app, 'heartbeat'); const installationsImpl = { app, appConfig, heartbeatServiceProvider, _delete: () => Promise.resolve() }; return installationsImpl; }; const internalFactory = (container) => { const app = container.getProvider('app').getImmediate(); // Internal FIS instance relies on public FIS instance. const installations = (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__._getProvider)(app, INSTALLATIONS_NAME).getImmediate(); const installationsInternal = { getId: () => getId(installations), getToken: (forceRefresh) => getToken(installations, forceRefresh) }; return installationsInternal; }; function registerInstallations() { (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__._registerComponent)(new _firebase_component__WEBPACK_IMPORTED_MODULE_1__.Component(INSTALLATIONS_NAME, publicFactory, "PUBLIC" /* PUBLIC */)); (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__._registerComponent)(new _firebase_component__WEBPACK_IMPORTED_MODULE_1__.Component(INSTALLATIONS_NAME_INTERNAL, internalFactory, "PRIVATE" /* PRIVATE */)); } /** * Firebase Installations * * @packageDocumentation */ registerInstallations(); (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__.registerVersion)(name, version); // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__.registerVersion)(name, version, 'esm2017'); //# sourceMappingURL=index.esm2017.js.map /***/ }), /***/ "./node_modules/@firebase/logger/dist/esm/index.esm2017.js": /*!*****************************************************************!*\ !*** ./node_modules/@firebase/logger/dist/esm/index.esm2017.js ***! \*****************************************************************/ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "LogLevel": () => (/* binding */ LogLevel), /* harmony export */ "Logger": () => (/* binding */ Logger), /* harmony export */ "setLogLevel": () => (/* binding */ setLogLevel), /* harmony export */ "setUserLogHandler": () => (/* binding */ setUserLogHandler) /* harmony export */ }); /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * A container for all of the Logger instances */ const instances = []; /** * The JS SDK supports 5 log levels and also allows a user the ability to * silence the logs altogether. * * The order is a follows: * DEBUG < VERBOSE < INFO < WARN < ERROR * * All of the log types above the current log level will be captured (i.e. if * you set the log level to `INFO`, errors will still be logged, but `DEBUG` and * `VERBOSE` logs will not) */ var LogLevel; (function (LogLevel) { LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG"; LogLevel[LogLevel["VERBOSE"] = 1] = "VERBOSE"; LogLevel[LogLevel["INFO"] = 2] = "INFO"; LogLevel[LogLevel["WARN"] = 3] = "WARN"; LogLevel[LogLevel["ERROR"] = 4] = "ERROR"; LogLevel[LogLevel["SILENT"] = 5] = "SILENT"; })(LogLevel || (LogLevel = {})); const levelStringToEnum = { 'debug': LogLevel.DEBUG, 'verbose': LogLevel.VERBOSE, 'info': LogLevel.INFO, 'warn': LogLevel.WARN, 'error': LogLevel.ERROR, 'silent': LogLevel.SILENT }; /** * The default log level */ const defaultLogLevel = LogLevel.INFO; /** * By default, `console.debug` is not displayed in the developer console (in * chrome). To avoid forcing users to have to opt-in to these logs twice * (i.e. once for firebase, and once in the console), we are sending `DEBUG` * logs to the `console.log` function. */ const ConsoleMethod = { [LogLevel.DEBUG]: 'log', [LogLevel.VERBOSE]: 'log', [LogLevel.INFO]: 'info', [LogLevel.WARN]: 'warn', [LogLevel.ERROR]: 'error' }; /** * The default log handler will forward DEBUG, VERBOSE, INFO, WARN, and ERROR * messages on to their corresponding console counterparts (if the log method * is supported by the current log level) */ const defaultLogHandler = (instance, logType, ...args) => { if (logType < instance.logLevel) { return; } const now = new Date().toISOString(); const method = ConsoleMethod[logType]; if (method) { console[method](`[${now}] ${instance.name}:`, ...args); } else { throw new Error(`Attempted to log a message with an invalid logType (value: ${logType})`); } }; class Logger { /** * Gives you an instance of a Logger to capture messages according to * Firebase's logging scheme. * * @param name The name that the logs will be associated with */ constructor(name) { this.name = name; /** * The log level of the given Logger instance. */ this._logLevel = defaultLogLevel; /** * The main (internal) log handler for the Logger instance. * Can be set to a new function in internal package code but not by user. */ this._logHandler = defaultLogHandler; /** * The optional, additional, user-defined log handler for the Logger instance. */ this._userLogHandler = null; /** * Capture the current instance for later use */ instances.push(this); } get logLevel() { return this._logLevel; } set logLevel(val) { if (!(val in LogLevel)) { throw new TypeError(`Invalid value "${val}" assigned to \`logLevel\``); } this._logLevel = val; } // Workaround for setter/getter having to be the same type. setLogLevel(val) { this._logLevel = typeof val === 'string' ? levelStringToEnum[val] : val; } get logHandler() { return this._logHandler; } set logHandler(val) { if (typeof val !== 'function') { throw new TypeError('Value assigned to `logHandler` must be a function'); } this._logHandler = val; } get userLogHandler() { return this._userLogHandler; } set userLogHandler(val) { this._userLogHandler = val; } /** * The functions below are all based on the `console` interface */ debug(...args) { this._userLogHandler && this._userLogHandler(this, LogLevel.DEBUG, ...args); this._logHandler(this, LogLevel.DEBUG, ...args); } log(...args) { this._userLogHandler && this._userLogHandler(this, LogLevel.VERBOSE, ...args); this._logHandler(this, LogLevel.VERBOSE, ...args); } info(...args) { this._userLogHandler && this._userLogHandler(this, LogLevel.INFO, ...args); this._logHandler(this, LogLevel.INFO, ...args); } warn(...args) { this._userLogHandler && this._userLogHandler(this, LogLevel.WARN, ...args); this._logHandler(this, LogLevel.WARN, ...args); } error(...args) { this._userLogHandler && this._userLogHandler(this, LogLevel.ERROR, ...args); this._logHandler(this, LogLevel.ERROR, ...args); } } function setLogLevel(level) { instances.forEach(inst => { inst.setLogLevel(level); }); } function setUserLogHandler(logCallback, options) { for (const instance of instances) { let customLogLevel = null; if (options && options.level) { customLogLevel = levelStringToEnum[options.level]; } if (logCallback === null) { instance.userLogHandler = null; } else { instance.userLogHandler = (instance, level, ...args) => { const message = args .map(arg => { if (arg == null) { return null; } else if (typeof arg === 'string') { return arg; } else if (typeof arg === 'number' || typeof arg === 'boolean') { return arg.toString(); } else if (arg instanceof Error) { return arg.message; } else { try { return JSON.stringify(arg); } catch (ignored) { return null; } } }) .filter(arg => arg) .join(' '); if (level >= (customLogLevel !== null && customLogLevel !== void 0 ? customLogLevel : instance.logLevel)) { logCallback({ level: LogLevel[level].toLowerCase(), message, args, type: instance.name }); } }; } } } //# sourceMappingURL=index.esm2017.js.map /***/ }), /***/ "./node_modules/@firebase/messaging/dist/esm/index.esm2017.js": /*!********************************************************************!*\ !*** ./node_modules/@firebase/messaging/dist/esm/index.esm2017.js ***! \********************************************************************/ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "deleteToken": () => (/* binding */ deleteToken), /* harmony export */ "getMessaging": () => (/* binding */ getMessagingInWindow), /* harmony export */ "getToken": () => (/* binding */ getToken), /* harmony export */ "isSupported": () => (/* binding */ isWindowSupported), /* harmony export */ "onMessage": () => (/* binding */ onMessage) /* harmony export */ }); /* harmony import */ var _firebase_installations__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @firebase/installations */ "./node_modules/@firebase/installations/dist/esm/index.esm2017.js"); /* harmony import */ var _firebase_component__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @firebase/component */ "./node_modules/@firebase/component/dist/esm/index.esm2017.js"); /* harmony import */ var idb__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! idb */ "./node_modules/idb/build/index.js"); /* harmony import */ var _firebase_util__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @firebase/util */ "./node_modules/@firebase/util/dist/index.esm2017.js"); /* harmony import */ var _firebase_app__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @firebase/app */ "./node_modules/@firebase/app/dist/esm/index.esm2017.js"); /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const DEFAULT_SW_PATH = '/firebase-messaging-sw.js'; const DEFAULT_SW_SCOPE = '/firebase-cloud-messaging-push-scope'; const DEFAULT_VAPID_KEY = 'BDOU99-h67HcA6JeFXHbSNMu7e2yNNu3RzoMj8TM4W88jITfq7ZmPvIM1Iv-4_l2LxQcYwhqby2xGpWwzjfAnG4'; const ENDPOINT = 'https://fcmregistrations.googleapis.com/v1'; const CONSOLE_CAMPAIGN_ID = 'google.c.a.c_id'; const CONSOLE_CAMPAIGN_NAME = 'google.c.a.c_l'; const CONSOLE_CAMPAIGN_TIME = 'google.c.a.ts'; /** Set to '1' if Analytics is enabled for the campaign */ const CONSOLE_CAMPAIGN_ANALYTICS_ENABLED = 'google.c.a.e'; var MessageType$1; (function (MessageType) { MessageType[MessageType["DATA_MESSAGE"] = 1] = "DATA_MESSAGE"; MessageType[MessageType["DISPLAY_NOTIFICATION"] = 3] = "DISPLAY_NOTIFICATION"; })(MessageType$1 || (MessageType$1 = {})); /** * @license * Copyright 2018 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ var MessageType; (function (MessageType) { MessageType["PUSH_RECEIVED"] = "push-received"; MessageType["NOTIFICATION_CLICKED"] = "notification-clicked"; })(MessageType || (MessageType = {})); /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function arrayToBase64(array) { const uint8Array = new Uint8Array(array); const base64String = btoa(String.fromCharCode(...uint8Array)); return base64String.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); } function base64ToArray(base64String) { const padding = '='.repeat((4 - (base64String.length % 4)) % 4); const base64 = (base64String + padding) .replace(/\-/g, '+') .replace(/_/g, '/'); const rawData = atob(base64); const outputArray = new Uint8Array(rawData.length); for (let i = 0; i < rawData.length; ++i) { outputArray[i] = rawData.charCodeAt(i); } return outputArray; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const OLD_DB_NAME = 'fcm_token_details_db'; /** * The last DB version of 'fcm_token_details_db' was 4. This is one higher, so that the upgrade * callback is called for all versions of the old DB. */ const OLD_DB_VERSION = 5; const OLD_OBJECT_STORE_NAME = 'fcm_token_object_Store'; async function migrateOldDatabase(senderId) { if ('databases' in indexedDB) { // indexedDb.databases() is an IndexedDB v3 API and does not exist in all browsers. TODO: Remove // typecast when it lands in TS types. const databases = await indexedDB.databases(); const dbNames = databases.map(db => db.name); if (!dbNames.includes(OLD_DB_NAME)) { // old DB didn't exist, no need to open. return null; } } let tokenDetails = null; const db = await (0,idb__WEBPACK_IMPORTED_MODULE_2__.openDB)(OLD_DB_NAME, OLD_DB_VERSION, { upgrade: async (db, oldVersion, newVersion, upgradeTransaction) => { var _a; if (oldVersion < 2) { // Database too old, skip migration. return; } if (!db.objectStoreNames.contains(OLD_OBJECT_STORE_NAME)) { // Database did not exist. Nothing to do. return; } const objectStore = upgradeTransaction.objectStore(OLD_OBJECT_STORE_NAME); const value = await objectStore.index('fcmSenderId').get(senderId); await objectStore.clear(); if (!value) { // No entry in the database, nothing to migrate. return; } if (oldVersion === 2) { const oldDetails = value; if (!oldDetails.auth || !oldDetails.p256dh || !oldDetails.endpoint) { return; } tokenDetails = { token: oldDetails.fcmToken, createTime: (_a = oldDetails.createTime) !== null && _a !== void 0 ? _a : Date.now(), subscriptionOptions: { auth: oldDetails.auth, p256dh: oldDetails.p256dh, endpoint: oldDetails.endpoint, swScope: oldDetails.swScope, vapidKey: typeof oldDetails.vapidKey === 'string' ? oldDetails.vapidKey : arrayToBase64(oldDetails.vapidKey) } }; } else if (oldVersion === 3) { const oldDetails = value; tokenDetails = { token: oldDetails.fcmToken, createTime: oldDetails.createTime, subscriptionOptions: { auth: arrayToBase64(oldDetails.auth), p256dh: arrayToBase64(oldDetails.p256dh), endpoint: oldDetails.endpoint, swScope: oldDetails.swScope, vapidKey: arrayToBase64(oldDetails.vapidKey) } }; } else if (oldVersion === 4) { const oldDetails = value; tokenDetails = { token: oldDetails.fcmToken, createTime: oldDetails.createTime, subscriptionOptions: { auth: arrayToBase64(oldDetails.auth), p256dh: arrayToBase64(oldDetails.p256dh), endpoint: oldDetails.endpoint, swScope: oldDetails.swScope, vapidKey: arrayToBase64(oldDetails.vapidKey) } }; } } }); db.close(); // Delete all old databases. await (0,idb__WEBPACK_IMPORTED_MODULE_2__.deleteDB)(OLD_DB_NAME); await (0,idb__WEBPACK_IMPORTED_MODULE_2__.deleteDB)('fcm_vapid_details_db'); await (0,idb__WEBPACK_IMPORTED_MODULE_2__.deleteDB)('undefined'); return checkTokenDetails(tokenDetails) ? tokenDetails : null; } function checkTokenDetails(tokenDetails) { if (!tokenDetails || !tokenDetails.subscriptionOptions) { return false; } const { subscriptionOptions } = tokenDetails; return (typeof tokenDetails.createTime === 'number' && tokenDetails.createTime > 0 && typeof tokenDetails.token === 'string' && tokenDetails.token.length > 0 && typeof subscriptionOptions.auth === 'string' && subscriptionOptions.auth.length > 0 && typeof subscriptionOptions.p256dh === 'string' && subscriptionOptions.p256dh.length > 0 && typeof subscriptionOptions.endpoint === 'string' && subscriptionOptions.endpoint.length > 0 && typeof subscriptionOptions.swScope === 'string' && subscriptionOptions.swScope.length > 0 && typeof subscriptionOptions.vapidKey === 'string' && subscriptionOptions.vapidKey.length > 0); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Exported for tests. const DATABASE_NAME = 'firebase-messaging-database'; const DATABASE_VERSION = 1; const OBJECT_STORE_NAME = 'firebase-messaging-store'; let dbPromise = null; function getDbPromise() { if (!dbPromise) { dbPromise = (0,idb__WEBPACK_IMPORTED_MODULE_2__.openDB)(DATABASE_NAME, DATABASE_VERSION, { upgrade: (upgradeDb, oldVersion) => { // We don't use 'break' in this switch statement, the fall-through behavior is what we want, // because if there are multiple versions between the old version and the current version, we // want ALL the migrations that correspond to those versions to run, not only the last one. // eslint-disable-next-line default-case switch (oldVersion) { case 0: upgradeDb.createObjectStore(OBJECT_STORE_NAME); } } }); } return dbPromise; } /** Gets record(s) from the objectStore that match the given key. */ async function dbGet(firebaseDependencies) { const key = getKey(firebaseDependencies); const db = await getDbPromise(); const tokenDetails = (await db .transaction(OBJECT_STORE_NAME) .objectStore(OBJECT_STORE_NAME) .get(key)); if (tokenDetails) { return tokenDetails; } else { // Check if there is a tokenDetails object in the old DB. const oldTokenDetails = await migrateOldDatabase(firebaseDependencies.appConfig.senderId); if (oldTokenDetails) { await dbSet(firebaseDependencies, oldTokenDetails); return oldTokenDetails; } } } /** Assigns or overwrites the record for the given key with the given value. */ async function dbSet(firebaseDependencies, tokenDetails) { const key = getKey(firebaseDependencies); const db = await getDbPromise(); const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); await tx.objectStore(OBJECT_STORE_NAME).put(tokenDetails, key); await tx.done; return tokenDetails; } /** Removes record(s) from the objectStore that match the given key. */ async function dbRemove(firebaseDependencies) { const key = getKey(firebaseDependencies); const db = await getDbPromise(); const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); await tx.objectStore(OBJECT_STORE_NAME).delete(key); await tx.done; } function getKey({ appConfig }) { return appConfig.appId; } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const ERROR_MAP = { ["missing-app-config-values" /* MISSING_APP_CONFIG_VALUES */]: 'Missing App configuration value: "{$valueName}"', ["only-available-in-window" /* AVAILABLE_IN_WINDOW */]: 'This method is available in a Window context.', ["only-available-in-sw" /* AVAILABLE_IN_SW */]: 'This method is available in a service worker context.', ["permission-default" /* PERMISSION_DEFAULT */]: 'The notification permission was not granted and dismissed instead.', ["permission-blocked" /* PERMISSION_BLOCKED */]: 'The notification permission was not granted and blocked instead.', ["unsupported-browser" /* UNSUPPORTED_BROWSER */]: "This browser doesn't support the API's required to use the Firebase SDK.", ["indexed-db-unsupported" /* INDEXED_DB_UNSUPPORTED */]: "This browser doesn't support indexedDb.open() (ex. Safari iFrame, Firefox Private Browsing, etc)", ["failed-service-worker-registration" /* FAILED_DEFAULT_REGISTRATION */]: 'We are unable to register the default service worker. {$browserErrorMessage}', ["token-subscribe-failed" /* TOKEN_SUBSCRIBE_FAILED */]: 'A problem occurred while subscribing the user to FCM: {$errorInfo}', ["token-subscribe-no-token" /* TOKEN_SUBSCRIBE_NO_TOKEN */]: 'FCM returned no token when subscribing the user to push.', ["token-unsubscribe-failed" /* TOKEN_UNSUBSCRIBE_FAILED */]: 'A problem occurred while unsubscribing the ' + 'user from FCM: {$errorInfo}', ["token-update-failed" /* TOKEN_UPDATE_FAILED */]: 'A problem occurred while updating the user from FCM: {$errorInfo}', ["token-update-no-token" /* TOKEN_UPDATE_NO_TOKEN */]: 'FCM returned no token when updating the user to push.', ["use-sw-after-get-token" /* USE_SW_AFTER_GET_TOKEN */]: 'The useServiceWorker() method may only be called once and must be ' + 'called before calling getToken() to ensure your service worker is used.', ["invalid-sw-registration" /* INVALID_SW_REGISTRATION */]: 'The input to useServiceWorker() must be a ServiceWorkerRegistration.', ["invalid-bg-handler" /* INVALID_BG_HANDLER */]: 'The input to setBackgroundMessageHandler() must be a function.', ["invalid-vapid-key" /* INVALID_VAPID_KEY */]: 'The public VAPID key must be a string.', ["use-vapid-key-after-get-token" /* USE_VAPID_KEY_AFTER_GET_TOKEN */]: 'The usePublicVapidKey() method may only be called once and must be ' + 'called before calling getToken() to ensure your VAPID key is used.' }; const ERROR_FACTORY = new _firebase_util__WEBPACK_IMPORTED_MODULE_3__.ErrorFactory('messaging', 'Messaging', ERROR_MAP); /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function requestGetToken(firebaseDependencies, subscriptionOptions) { const headers = await getHeaders(firebaseDependencies); const body = getBody(subscriptionOptions); const subscribeOptions = { method: 'POST', headers, body: JSON.stringify(body) }; let responseData; try { const response = await fetch(getEndpoint(firebaseDependencies.appConfig), subscribeOptions); responseData = await response.json(); } catch (err) { throw ERROR_FACTORY.create("token-subscribe-failed" /* TOKEN_SUBSCRIBE_FAILED */, { errorInfo: err }); } if (responseData.error) { const message = responseData.error.message; throw ERROR_FACTORY.create("token-subscribe-failed" /* TOKEN_SUBSCRIBE_FAILED */, { errorInfo: message }); } if (!responseData.token) { throw ERROR_FACTORY.create("token-subscribe-no-token" /* TOKEN_SUBSCRIBE_NO_TOKEN */); } return responseData.token; } async function requestUpdateToken(firebaseDependencies, tokenDetails) { const headers = await getHeaders(firebaseDependencies); const body = getBody(tokenDetails.subscriptionOptions); const updateOptions = { method: 'PATCH', headers, body: JSON.stringify(body) }; let responseData; try { const response = await fetch(`${getEndpoint(firebaseDependencies.appConfig)}/${tokenDetails.token}`, updateOptions); responseData = await response.json(); } catch (err) { throw ERROR_FACTORY.create("token-update-failed" /* TOKEN_UPDATE_FAILED */, { errorInfo: err }); } if (responseData.error) { const message = responseData.error.message; throw ERROR_FACTORY.create("token-update-failed" /* TOKEN_UPDATE_FAILED */, { errorInfo: message }); } if (!responseData.token) { throw ERROR_FACTORY.create("token-update-no-token" /* TOKEN_UPDATE_NO_TOKEN */); } return responseData.token; } async function requestDeleteToken(firebaseDependencies, token) { const headers = await getHeaders(firebaseDependencies); const unsubscribeOptions = { method: 'DELETE', headers }; try { const response = await fetch(`${getEndpoint(firebaseDependencies.appConfig)}/${token}`, unsubscribeOptions); const responseData = await response.json(); if (responseData.error) { const message = responseData.error.message; throw ERROR_FACTORY.create("token-unsubscribe-failed" /* TOKEN_UNSUBSCRIBE_FAILED */, { errorInfo: message }); } } catch (err) { throw ERROR_FACTORY.create("token-unsubscribe-failed" /* TOKEN_UNSUBSCRIBE_FAILED */, { errorInfo: err }); } } function getEndpoint({ projectId }) { return `${ENDPOINT}/projects/${projectId}/registrations`; } async function getHeaders({ appConfig, installations }) { const authToken = await installations.getToken(); return new Headers({ 'Content-Type': 'application/json', Accept: 'application/json', 'x-goog-api-key': appConfig.apiKey, 'x-goog-firebase-installations-auth': `FIS ${authToken}` }); } function getBody({ p256dh, auth, endpoint, vapidKey }) { const body = { web: { endpoint, auth, p256dh } }; if (vapidKey !== DEFAULT_VAPID_KEY) { body.web.applicationPubKey = vapidKey; } return body; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // UpdateRegistration will be called once every week. const TOKEN_EXPIRATION_MS = 7 * 24 * 60 * 60 * 1000; // 7 days async function getTokenInternal(messaging) { const pushSubscription = await getPushSubscription(messaging.swRegistration, messaging.vapidKey); const subscriptionOptions = { vapidKey: messaging.vapidKey, swScope: messaging.swRegistration.scope, endpoint: pushSubscription.endpoint, auth: arrayToBase64(pushSubscription.getKey('auth')), p256dh: arrayToBase64(pushSubscription.getKey('p256dh')) }; const tokenDetails = await dbGet(messaging.firebaseDependencies); if (!tokenDetails) { // No token, get a new one. return getNewToken(messaging.firebaseDependencies, subscriptionOptions); } else if (!isTokenValid(tokenDetails.subscriptionOptions, subscriptionOptions)) { // Invalid token, get a new one. try { await requestDeleteToken(messaging.firebaseDependencies, tokenDetails.token); } catch (e) { // Suppress errors because of #2364 console.warn(e); } return getNewToken(messaging.firebaseDependencies, subscriptionOptions); } else if (Date.now() >= tokenDetails.createTime + TOKEN_EXPIRATION_MS) { // Weekly token refresh return updateToken(messaging, { token: tokenDetails.token, createTime: Date.now(), subscriptionOptions }); } else { // Valid token, nothing to do. return tokenDetails.token; } } /** * This method deletes the token from the database, unsubscribes the token from FCM, and unregisters * the push subscription if it exists. */ async function deleteTokenInternal(messaging) { const tokenDetails = await dbGet(messaging.firebaseDependencies); if (tokenDetails) { await requestDeleteToken(messaging.firebaseDependencies, tokenDetails.token); await dbRemove(messaging.firebaseDependencies); } // Unsubscribe from the push subscription. const pushSubscription = await messaging.swRegistration.pushManager.getSubscription(); if (pushSubscription) { return pushSubscription.unsubscribe(); } // If there's no SW, consider it a success. return true; } async function updateToken(messaging, tokenDetails) { try { const updatedToken = await requestUpdateToken(messaging.firebaseDependencies, tokenDetails); const updatedTokenDetails = Object.assign(Object.assign({}, tokenDetails), { token: updatedToken, createTime: Date.now() }); await dbSet(messaging.firebaseDependencies, updatedTokenDetails); return updatedToken; } catch (e) { await deleteTokenInternal(messaging); throw e; } } async function getNewToken(firebaseDependencies, subscriptionOptions) { const token = await requestGetToken(firebaseDependencies, subscriptionOptions); const tokenDetails = { token, createTime: Date.now(), subscriptionOptions }; await dbSet(firebaseDependencies, tokenDetails); return tokenDetails.token; } /** * Gets a PushSubscription for the current user. */ async function getPushSubscription(swRegistration, vapidKey) { const subscription = await swRegistration.pushManager.getSubscription(); if (subscription) { return subscription; } return swRegistration.pushManager.subscribe({ userVisibleOnly: true, // Chrome <= 75 doesn't support base64-encoded VAPID key. For backward compatibility, VAPID key // submitted to pushManager#subscribe must be of type Uint8Array. applicationServerKey: base64ToArray(vapidKey) }); } /** * Checks if the saved tokenDetails object matches the configuration provided. */ function isTokenValid(dbOptions, currentOptions) { const isVapidKeyEqual = currentOptions.vapidKey === dbOptions.vapidKey; const isEndpointEqual = currentOptions.endpoint === dbOptions.endpoint; const isAuthEqual = currentOptions.auth === dbOptions.auth; const isP256dhEqual = currentOptions.p256dh === dbOptions.p256dh; return isVapidKeyEqual && isEndpointEqual && isAuthEqual && isP256dhEqual; } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function externalizePayload(internalPayload) { const payload = { from: internalPayload.from, // eslint-disable-next-line camelcase collapseKey: internalPayload.collapse_key, // eslint-disable-next-line camelcase messageId: internalPayload.fcmMessageId }; propagateNotificationPayload(payload, internalPayload); propagateDataPayload(payload, internalPayload); propagateFcmOptions(payload, internalPayload); return payload; } function propagateNotificationPayload(payload, messagePayloadInternal) { if (!messagePayloadInternal.notification) { return; } payload.notification = {}; const title = messagePayloadInternal.notification.title; if (!!title) { payload.notification.title = title; } const body = messagePayloadInternal.notification.body; if (!!body) { payload.notification.body = body; } const image = messagePayloadInternal.notification.image; if (!!image) { payload.notification.image = image; } } function propagateDataPayload(payload, messagePayloadInternal) { if (!messagePayloadInternal.data) { return; } payload.data = messagePayloadInternal.data; } function propagateFcmOptions(payload, messagePayloadInternal) { if (!messagePayloadInternal.fcmOptions) { return; } payload.fcmOptions = {}; const link = messagePayloadInternal.fcmOptions.link; if (!!link) { payload.fcmOptions.link = link; } // eslint-disable-next-line camelcase const analyticsLabel = messagePayloadInternal.fcmOptions.analytics_label; if (!!analyticsLabel) { payload.fcmOptions.analyticsLabel = analyticsLabel; } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function isConsoleMessage(data) { // This message has a campaign ID, meaning it was sent using the Firebase Console. return typeof data === 'object' && !!data && CONSOLE_CAMPAIGN_ID in data; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ _mergeStrings('hts/frbslgigp.ogepscmv/ieo/eaylg', 'tp:/ieaeogn-agolai.o/1frlglgc/o'); _mergeStrings('AzSCbw63g1R0nCw85jG8', 'Iaya3yLKwmgvh7cF0q4'); function _mergeStrings(s1, s2) { const resultArray = []; for (let i = 0; i < s1.length; i++) { resultArray.push(s1.charAt(i)); if (i < s2.length) { resultArray.push(s2.charAt(i)); } } return resultArray.join(''); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function extractAppConfig(app) { if (!app || !app.options) { throw getMissingValueError('App Configuration Object'); } if (!app.name) { throw getMissingValueError('App Name'); } // Required app config keys const configKeys = [ 'projectId', 'apiKey', 'appId', 'messagingSenderId' ]; const { options } = app; for (const keyName of configKeys) { if (!options[keyName]) { throw getMissingValueError(keyName); } } return { appName: app.name, projectId: options.projectId, apiKey: options.apiKey, appId: options.appId, senderId: options.messagingSenderId }; } function getMissingValueError(valueName) { return ERROR_FACTORY.create("missing-app-config-values" /* MISSING_APP_CONFIG_VALUES */, { valueName }); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class MessagingService { constructor(app, installations, analyticsProvider) { // logging is only done with end user consent. Default to false. this.deliveryMetricsExportedToBigQueryEnabled = false; this.onBackgroundMessageHandler = null; this.onMessageHandler = null; this.logEvents = []; this.isLogServiceStarted = false; const appConfig = extractAppConfig(app); this.firebaseDependencies = { app, appConfig, installations, analyticsProvider }; } _delete() { return Promise.resolve(); } } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function registerDefaultSw(messaging) { try { messaging.swRegistration = await navigator.serviceWorker.register(DEFAULT_SW_PATH, { scope: DEFAULT_SW_SCOPE }); // The timing when browser updates sw when sw has an update is unreliable from experiment. It // leads to version conflict when the SDK upgrades to a newer version in the main page, but sw // is stuck with the old version. For example, // https://github.com/firebase/firebase-js-sdk/issues/2590 The following line reliably updates // sw if there was an update. messaging.swRegistration.update().catch(() => { /* it is non blocking and we don't care if it failed */ }); } catch (e) { throw ERROR_FACTORY.create("failed-service-worker-registration" /* FAILED_DEFAULT_REGISTRATION */, { browserErrorMessage: e.message }); } } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function updateSwReg(messaging, swRegistration) { if (!swRegistration && !messaging.swRegistration) { await registerDefaultSw(messaging); } if (!swRegistration && !!messaging.swRegistration) { return; } if (!(swRegistration instanceof ServiceWorkerRegistration)) { throw ERROR_FACTORY.create("invalid-sw-registration" /* INVALID_SW_REGISTRATION */); } messaging.swRegistration = swRegistration; } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function updateVapidKey(messaging, vapidKey) { if (!!vapidKey) { messaging.vapidKey = vapidKey; } else if (!messaging.vapidKey) { messaging.vapidKey = DEFAULT_VAPID_KEY; } } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function getToken$1(messaging, options) { if (!navigator) { throw ERROR_FACTORY.create("only-available-in-window" /* AVAILABLE_IN_WINDOW */); } if (Notification.permission === 'default') { await Notification.requestPermission(); } if (Notification.permission !== 'granted') { throw ERROR_FACTORY.create("permission-blocked" /* PERMISSION_BLOCKED */); } await updateVapidKey(messaging, options === null || options === void 0 ? void 0 : options.vapidKey); await updateSwReg(messaging, options === null || options === void 0 ? void 0 : options.serviceWorkerRegistration); return getTokenInternal(messaging); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function logToScion(messaging, messageType, data) { const eventType = getEventType(messageType); const analytics = await messaging.firebaseDependencies.analyticsProvider.get(); analytics.logEvent(eventType, { /* eslint-disable camelcase */ message_id: data[CONSOLE_CAMPAIGN_ID], message_name: data[CONSOLE_CAMPAIGN_NAME], message_time: data[CONSOLE_CAMPAIGN_TIME], message_device_time: Math.floor(Date.now() / 1000) /* eslint-enable camelcase */ }); } function getEventType(messageType) { switch (messageType) { case MessageType.NOTIFICATION_CLICKED: return 'notification_open'; case MessageType.PUSH_RECEIVED: return 'notification_foreground'; default: throw new Error(); } } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function messageEventListener(messaging, event) { const internalPayload = event.data; if (!internalPayload.isFirebaseMessaging) { return; } if (messaging.onMessageHandler && internalPayload.messageType === MessageType.PUSH_RECEIVED) { if (typeof messaging.onMessageHandler === 'function') { messaging.onMessageHandler(externalizePayload(internalPayload)); } else { messaging.onMessageHandler.next(externalizePayload(internalPayload)); } } // Log to Scion if applicable const dataPayload = internalPayload.data; if (isConsoleMessage(dataPayload) && dataPayload[CONSOLE_CAMPAIGN_ANALYTICS_ENABLED] === '1') { await logToScion(messaging, internalPayload.messageType, dataPayload); } } const name = "@firebase/messaging"; const version = "0.9.13"; /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const WindowMessagingFactory = (container) => { const messaging = new MessagingService(container.getProvider('app').getImmediate(), container.getProvider('installations-internal').getImmediate(), container.getProvider('analytics-internal')); navigator.serviceWorker.addEventListener('message', e => messageEventListener(messaging, e)); return messaging; }; const WindowMessagingInternalFactory = (container) => { const messaging = container .getProvider('messaging') .getImmediate(); const messagingInternal = { getToken: (options) => getToken$1(messaging, options) }; return messagingInternal; }; function registerMessagingInWindow() { (0,_firebase_app__WEBPACK_IMPORTED_MODULE_4__._registerComponent)(new _firebase_component__WEBPACK_IMPORTED_MODULE_1__.Component('messaging', WindowMessagingFactory, "PUBLIC" /* PUBLIC */)); (0,_firebase_app__WEBPACK_IMPORTED_MODULE_4__._registerComponent)(new _firebase_component__WEBPACK_IMPORTED_MODULE_1__.Component('messaging-internal', WindowMessagingInternalFactory, "PRIVATE" /* PRIVATE */)); (0,_firebase_app__WEBPACK_IMPORTED_MODULE_4__.registerVersion)(name, version); // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation (0,_firebase_app__WEBPACK_IMPORTED_MODULE_4__.registerVersion)(name, version, 'esm2017'); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Checks if all required APIs exist in the browser. * @returns a Promise that resolves to a boolean. * * @public */ async function isWindowSupported() { try { // This throws if open() is unsupported, so adding it to the conditional // statement below can cause an uncaught error. await (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.validateIndexedDBOpenable)(); } catch (e) { return false; } // firebase-js-sdk/issues/2393 reveals that idb#open in Safari iframe and Firefox private browsing // might be prohibited to run. In these contexts, an error would be thrown during the messaging // instantiating phase, informing the developers to import/call isSupported for special handling. return (typeof window !== 'undefined' && (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.isIndexedDBAvailable)() && (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.areCookiesEnabled)() && 'serviceWorker' in navigator && 'PushManager' in window && 'Notification' in window && 'fetch' in window && ServiceWorkerRegistration.prototype.hasOwnProperty('showNotification') && PushSubscription.prototype.hasOwnProperty('getKey')); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function deleteToken$1(messaging) { if (!navigator) { throw ERROR_FACTORY.create("only-available-in-window" /* AVAILABLE_IN_WINDOW */); } if (!messaging.swRegistration) { await registerDefaultSw(messaging); } return deleteTokenInternal(messaging); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function onMessage$1(messaging, nextOrObserver) { if (!navigator) { throw ERROR_FACTORY.create("only-available-in-window" /* AVAILABLE_IN_WINDOW */); } messaging.onMessageHandler = nextOrObserver; return () => { messaging.onMessageHandler = null; }; } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Retrieves a Firebase Cloud Messaging instance. * * @returns The Firebase Cloud Messaging instance associated with the provided firebase app. * * @public */ function getMessagingInWindow(app = (0,_firebase_app__WEBPACK_IMPORTED_MODULE_4__.getApp)()) { // Conscious decision to make this async check non-blocking during the messaging instance // initialization phase for performance consideration. An error would be thrown latter for // developer's information. Developers can then choose to import and call `isSupported` for // special handling. isWindowSupported().then(isSupported => { // If `isWindowSupported()` resolved, but returned false. if (!isSupported) { throw ERROR_FACTORY.create("unsupported-browser" /* UNSUPPORTED_BROWSER */); } }, _ => { // If `isWindowSupported()` rejected. throw ERROR_FACTORY.create("indexed-db-unsupported" /* INDEXED_DB_UNSUPPORTED */); }); return (0,_firebase_app__WEBPACK_IMPORTED_MODULE_4__._getProvider)((0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.getModularInstance)(app), 'messaging').getImmediate(); } /** * Subscribes the {@link Messaging} instance to push notifications. Returns an Firebase Cloud * Messaging registration token that can be used to send push messages to that {@link Messaging} * instance. * * If a notification permission isn't already granted, this method asks the user for permission. The * returned promise rejects if the user does not allow the app to show notifications. * * @param messaging - The {@link Messaging} instance. * @param options - Provides an optional vapid key and an optinoal service worker registration * * @returns The promise resolves with an FCM registration token. * * @public */ async function getToken(messaging, options) { messaging = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.getModularInstance)(messaging); return getToken$1(messaging, options); } /** * Deletes the registration token associated with this {@link Messaging} instance and unsubscribes * the {@link Messaging} instance from the push subscription. * * @param messaging - The {@link Messaging} instance. * * @returns The promise resolves when the token has been successfully deleted. * * @public */ function deleteToken(messaging) { messaging = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.getModularInstance)(messaging); return deleteToken$1(messaging); } /** * When a push message is received and the user is currently on a page for your origin, the * message is passed to the page and an `onMessage()` event is dispatched with the payload of * the push message. * * * @param messaging - The {@link Messaging} instance. * @param nextOrObserver - This function, or observer object with `next` defined, * is called when a message is received and the user is currently viewing your page. * @returns To stop listening for messages execute this returned function. * * @public */ function onMessage(messaging, nextOrObserver) { messaging = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.getModularInstance)(messaging); return onMessage$1(messaging, nextOrObserver); } /** * Firebase Cloud Messaging * * @packageDocumentation */ registerMessagingInWindow(); //# sourceMappingURL=index.esm2017.js.map /***/ }), /***/ "./node_modules/idb/build/index.js": /*!*****************************************!*\ !*** ./node_modules/idb/build/index.js ***! \*****************************************/ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "deleteDB": () => (/* binding */ deleteDB), /* harmony export */ "openDB": () => (/* binding */ openDB), /* harmony export */ "unwrap": () => (/* reexport safe */ _wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.u), /* harmony export */ "wrap": () => (/* reexport safe */ _wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.w) /* harmony export */ }); /* harmony import */ var _wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./wrap-idb-value.js */ "./node_modules/idb/build/wrap-idb-value.js"); /** * Open a database. * * @param name Name of the database. * @param version Schema version. * @param callbacks Additional callbacks. */ function openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) { const request = indexedDB.open(name, version); const openPromise = (0,_wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.w)(request); if (upgrade) { request.addEventListener('upgradeneeded', (event) => { upgrade((0,_wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.w)(request.result), event.oldVersion, event.newVersion, (0,_wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.w)(request.transaction)); }); } if (blocked) request.addEventListener('blocked', () => blocked()); openPromise .then((db) => { if (terminated) db.addEventListener('close', () => terminated()); if (blocking) db.addEventListener('versionchange', () => blocking()); }) .catch(() => { }); return openPromise; } /** * Delete a database. * * @param name Name of the database. */ function deleteDB(name, { blocked } = {}) { const request = indexedDB.deleteDatabase(name); if (blocked) request.addEventListener('blocked', () => blocked()); return (0,_wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.w)(request).then(() => undefined); } const readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count']; const writeMethods = ['put', 'add', 'delete', 'clear']; const cachedMethods = new Map(); function getMethod(target, prop) { if (!(target instanceof IDBDatabase && !(prop in target) && typeof prop === 'string')) { return; } if (cachedMethods.get(prop)) return cachedMethods.get(prop); const targetFuncName = prop.replace(/FromIndex$/, ''); const useIndex = prop !== targetFuncName; const isWrite = writeMethods.includes(targetFuncName); if ( // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge. !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) || !(isWrite || readMethods.includes(targetFuncName))) { return; } const method = async function (storeName, ...args) { // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :( const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly'); let target = tx.store; if (useIndex) target = target.index(args.shift()); // Must reject if op rejects. // If it's a write operation, must reject if tx.done rejects. // Must reject with op rejection first. // Must resolve with op value. // Must handle both promises (no unhandled rejections) return (await Promise.all([ target[targetFuncName](...args), isWrite && tx.done, ]))[0]; }; cachedMethods.set(prop, method); return method; } (0,_wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.r)((oldTraps) => ({ ...oldTraps, get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver), has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop), })); /***/ }), /***/ "./node_modules/idb/build/wrap-idb-value.js": /*!**************************************************!*\ !*** ./node_modules/idb/build/wrap-idb-value.js ***! \**************************************************/ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "a": () => (/* binding */ reverseTransformCache), /* harmony export */ "i": () => (/* binding */ instanceOfAny), /* harmony export */ "r": () => (/* binding */ replaceTraps), /* harmony export */ "u": () => (/* binding */ unwrap), /* harmony export */ "w": () => (/* binding */ wrap) /* harmony export */ }); const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c); let idbProxyableTypes; let cursorAdvanceMethods; // This is a function to prevent it throwing up in node environments. function getIdbProxyableTypes() { return (idbProxyableTypes || (idbProxyableTypes = [ IDBDatabase, IDBObjectStore, IDBIndex, IDBCursor, IDBTransaction, ])); } // This is a function to prevent it throwing up in node environments. function getCursorAdvanceMethods() { return (cursorAdvanceMethods || (cursorAdvanceMethods = [ IDBCursor.prototype.advance, IDBCursor.prototype.continue, IDBCursor.prototype.continuePrimaryKey, ])); } const cursorRequestMap = new WeakMap(); const transactionDoneMap = new WeakMap(); const transactionStoreNamesMap = new WeakMap(); const transformCache = new WeakMap(); const reverseTransformCache = new WeakMap(); function promisifyRequest(request) { const promise = new Promise((resolve, reject) => { const unlisten = () => { request.removeEventListener('success', success); request.removeEventListener('error', error); }; const success = () => { resolve(wrap(request.result)); unlisten(); }; const error = () => { reject(request.error); unlisten(); }; request.addEventListener('success', success); request.addEventListener('error', error); }); promise .then((value) => { // Since cursoring reuses the IDBRequest (*sigh*), we cache it for later retrieval // (see wrapFunction). if (value instanceof IDBCursor) { cursorRequestMap.set(value, request); } // Catching to avoid "Uncaught Promise exceptions" }) .catch(() => { }); // This mapping exists in reverseTransformCache but doesn't doesn't exist in transformCache. This // is because we create many promises from a single IDBRequest. reverseTransformCache.set(promise, request); return promise; } function cacheDonePromiseForTransaction(tx) { // Early bail if we've already created a done promise for this transaction. if (transactionDoneMap.has(tx)) return; const done = new Promise((resolve, reject) => { const unlisten = () => { tx.removeEventListener('complete', complete); tx.removeEventListener('error', error); tx.removeEventListener('abort', error); }; const complete = () => { resolve(); unlisten(); }; const error = () => { reject(tx.error || new DOMException('AbortError', 'AbortError')); unlisten(); }; tx.addEventListener('complete', complete); tx.addEventListener('error', error); tx.addEventListener('abort', error); }); // Cache it for later retrieval. transactionDoneMap.set(tx, done); } let idbProxyTraps = { get(target, prop, receiver) { if (target instanceof IDBTransaction) { // Special handling for transaction.done. if (prop === 'done') return transactionDoneMap.get(target); // Polyfill for objectStoreNames because of Edge. if (prop === 'objectStoreNames') { return target.objectStoreNames || transactionStoreNamesMap.get(target); } // Make tx.store return the only store in the transaction, or undefined if there are many. if (prop === 'store') { return receiver.objectStoreNames[1] ? undefined : receiver.objectStore(receiver.objectStoreNames[0]); } } // Else transform whatever we get back. return wrap(target[prop]); }, set(target, prop, value) { target[prop] = value; return true; }, has(target, prop) { if (target instanceof IDBTransaction && (prop === 'done' || prop === 'store')) { return true; } return prop in target; }, }; function replaceTraps(callback) { idbProxyTraps = callback(idbProxyTraps); } function wrapFunction(func) { // Due to expected object equality (which is enforced by the caching in `wrap`), we // only create one new func per func. // Edge doesn't support objectStoreNames (booo), so we polyfill it here. if (func === IDBDatabase.prototype.transaction && !('objectStoreNames' in IDBTransaction.prototype)) { return function (storeNames, ...args) { const tx = func.call(unwrap(this), storeNames, ...args); transactionStoreNamesMap.set(tx, storeNames.sort ? storeNames.sort() : [storeNames]); return wrap(tx); }; } // Cursor methods are special, as the behaviour is a little more different to standard IDB. In // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense // with real promises, so each advance methods returns a new promise for the cursor object, or // undefined if the end of the cursor has been reached. if (getCursorAdvanceMethods().includes(func)) { return function (...args) { // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use // the original object. func.apply(unwrap(this), args); return wrap(cursorRequestMap.get(this)); }; } return function (...args) { // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use // the original object. return wrap(func.apply(unwrap(this), args)); }; } function transformCachableValue(value) { if (typeof value === 'function') return wrapFunction(value); // This doesn't return, it just creates a 'done' promise for the transaction, // which is later returned for transaction.done (see idbObjectHandler). if (value instanceof IDBTransaction) cacheDonePromiseForTransaction(value); if (instanceOfAny(value, getIdbProxyableTypes())) return new Proxy(value, idbProxyTraps); // Return the same value back if we're not going to transform it. return value; } function wrap(value) { // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached. if (value instanceof IDBRequest) return promisifyRequest(value); // If we've already transformed this value before, reuse the transformed value. // This is faster, but it also provides object equality. if (transformCache.has(value)) return transformCache.get(value); const newValue = transformCachableValue(value); // Not all types are transformed. // These may be primitive types, so they can't be WeakMap keys. if (newValue !== value) { transformCache.set(value, newValue); reverseTransformCache.set(newValue, value); } return newValue; } const unwrap = (value) => reverseTransformCache.get(value); /***/ }), /***/ "./src/messages.json": /*!***************************!*\ !*** ./src/messages.json ***! \***************************/ /***/ ((module) => { "use strict"; module.exports = JSON.parse('{"de":{"action_block_contact":"Kontakt blockieren","action_cancel":"Abbrechen","action_clear_messages":"Nachrichten leeren","action_delete_messages":"Nachrichten für alle löschen","action_leave_chat":"Unterhaltung verlassen","action_report_chat":"Unterhaltung melden","archived_contacts":"Archivierte Kontakte ({count})","badge_danger":"Verdächtig","badge_owner":"Besitzer","badge_staff":"Verwaltung","badge_verified":"Verifiziert","badge_you":"Sie","block_contact_warning":"Möchten Sie diesen Kontakt wirklich blockieren?","blocked_contacts_link":"Blockierte Kontakte ({count})","button_add_another":"Hinzufügen","button_add_members":"Mitglieder hinzufügen","button_cancel":"Abbrechen","button_confirm":"Bestätigen","button_create":"Erstellen","button_delete_account":"Konto löschen","button_edit":"Bearbeiten","button_logout":"Abmelden","button_ok":"OK","button_reset":"Zurücksetzen","button_send_request":"Anfrage senden","button_sign_in":"Anmelden","button_sign_up":"Anmelden","button_subscribe":"Abbonieren","button_update":"Aktualisieren","cannot_initiate_file_upload":"Datei kann nicht hochgeladen werden.","channel":"Sender","channel_prompt":"Dies ist ein Sender","chat_invitation":"Sie sind eingeladen, an einem neuen Chat teilzunehmen. Was möchten Sie tun?","chat_invitation_accept":"Akzeptieren","chat_invitation_block":"Blockieren","chat_invitation_ignore":"Ignorieren","clear_messages_warning":"Sind Sie sicher, dass Sie diese Unterhaltung für alle leeren wollen? Das kann nicht rückgängig gemacht werden.","code_doesnot_match":"Code stimmt nicht überein","contacts_not_found":"Sie haben keine Unterhaltungen
¯∖_(ツ)_/¯","contacts_not_found_short":"Keine Kontakte für \'\'{query}\'\'","credential_email_prompt":"E-Mail Adresse für Registrierung","delete_account":"Konto löschen","delete_account_warning":"Möchten Sie das Konto wirklich löschen? Das kann nicht rückgängig gemacht werden","delete_messages_warning":"Sind Sie sicher, dass Sie diese Unterhaltung für alle löschen wollen? Das kann nicht rückgängig gemacht werden.","deleted_content":"Inhalt gelöscht","download_action":"herunterladen","drafty_attachment":"Dateianhang","drafty_form":"Formular:","drafty_image":"Bild","email_dative":"E-Mail","email_prompt":"E-Mail, z.B. lisam@beispiel.de","enable_peers_messaging":"Aktivieren","enter_confirmation_code_prompt":"Geben Sie den Bestätigungscode ein, der per {method} geschickt wurde:","error_invalid_id":"ungültige ID","file_attachment_too_large":"Die Dateigröße {size} überschreitet das Limit von {limit}.","forgot_password_link":"Passwort vergessen?","full_name_prompt":"Vollständiger Name, z.B. Lisa Musterfrau","granted_permissions":"Erteilt","group_has_no_members":"Keine Mitglieder","group_user_id_prompt":"Gruppe oder Benutzer ID","image_caption_prompt":"Bildunterschrift","invalid_content":"ungültiger Inhalt","invalid_security_token":"Ungültiger Sicherheitsschlüssel","label_client":"Client:","label_content_type":"Inhaltsart:","label_default_access_mode":"Standard Zugriffsmodus:","label_file_name":"Dateiname:","label_group_members":"Gruppenmitglieder:","label_incognito_mode":"inkognito-Modus:","label_message_sound":"Benachrichtigungston:","label_muting_topic":"Stumm geschaltet:","label_other_user":"Andere","label_password":"Passwort","label_permissions":"Berechtigungen:","label_private":"Privater Kommentar","label_push_notifications":"Benachrichtigungsmeldungen:","label_push_notifications_disabled":"Benachrichtigungsmeldungen (erfordert HTTPS):","label_reset_password":"Passwort per E-Mail wiederherstellen:","label_sdk":"SDK:","label_server":"Server:","label_server_address":"Server Adresse:","label_server_to_use":"Server verwenden:","label_size":"Größe:","label_topic_name":"Name","label_user_contacts":"Kontakte:","label_user_id":"ID:","label_wire_transport":"Übertragung per Kabel:","label_you":"Sie:","label_your_name":"Ihr Name","label_your_permissions":"Ihre Berechtigungen:","last_seen_timestamp":"Zuletzt gesehen","leave_chat_warning":"Möchten Sie diese Unterhaltung wirklich verlassen?","link_contact_us":"Kontakt","link_privacy_policy":"Datenschutzerklärung","link_terms_of_service":"Nutzungsbedingungen","login_prompt":"Anmelden","menu_item_archive_topic":"Archivieren","menu_item_block":"Blockieren","menu_item_clear_messages":"Nachrichten leeren","menu_item_clear_messages_for_all":"Für alle leeren","menu_item_delete":"Löschen","menu_item_delete_for_all":"Für alle löschen","menu_item_delete_topic":"Entfernen","menu_item_edit_permissions":"Berechtigungen ändern","menu_item_info":"Info","menu_item_member_delete":"Entfernen","menu_item_mute":"Unterhaltung stumm schalten","menu_item_restore_topic":"Wiederherstellen","menu_item_send_retry":"Wiederholen","menu_item_unblock":"Blockierung aufheben","menu_item_unmute":"Stumm schalten beenden","message_sending":"wird gesendet...","message_sending_failed":"fehlgeschlagen","messages_not_readable":"Neue Nachrichten können nicht gelesen werden","messaging_disabled_prompt":"Nachrichtenübermittlung deaktiviert","more_online_members":"+{overflow} mehr","new_message_prompt":"Neue Nachricht","new_password_placeholder":"Geben Sie ein neues Passwort ein","no_connection":"Keine Verbindung","no_contacts":"Sie haben keine Kontakte :-(","numeric_confirmation_code_prompt":"Nur zahlen","online_now":"jetzt online","password_prompt":"Passwort","password_unchanged_prompt":"unverändert","peers_messaging_disabled":"Gruppennachrichten sind deaktiviert","permission_admin":"Bestätigen ({val})","permission_delete":"Entfernen ({val})","permission_join":"Beitreten ({val})","permission_owner":"Besitzer ({val})","permission_pres":"Benachrichtigt werden ({val})","permission_read":"Lesen ({val})","permission_share":"Teilen ({val})","permission_write":"Schreiben ({val})","phone_dative":"Telefon","private_editing_placeholder":"Nur für Sie sichtbar","push_init_failed":"Initialisierung von Push-Benachrichtigungen fehlgeschlagen","reconnect_countdown":"Getrennt. Wiederverbinden in {seconds}…","reconnect_now":"Jetzt probieren","reload_update":"Neu laden","report_chat_warning":"Möchten Sie diese Unterhaltung wirklich blockieren und melden?","requested_permissions":"Angefordert","save_attachment":"Speichern","search_for_contacts":"Nutzen Sie die Suche um Kontakte zu finden","search_no_results":"Die Suche hatte keine Ergebnisse","search_placeholder":"Liste: email:lisa@beispiel.de, tel:17025550003...","sidepanel_title_acc_notifications":"Benachrichtigungen","sidepanel_title_acc_support":"Unterstützung","sidepanel_title_account_settings":"Konto-Einstellungen","sidepanel_title_archive":"Archivierte Unterhaltungen","sidepanel_title_blocked":"Blockierte Unterhaltungen","sidepanel_title_cred":"Anmeldeinformationen bestätigen","sidepanel_title_login":"Anmelden","sidepanel_title_newtpk":"Neue Unterhaltung starten","sidepanel_title_register":"Konto erstellen","sidepanel_title_reset":"Passwort zurücksetzen","sidepanel_title_settings":"Einstellungen","stay_logged_in":"Angemeldet bleiben","tabtitle_find_user":"Suchen","tabtitle_group_by_id":"nach ID","tabtitle_new_group":"Neue Gruppe","tags_editor_no_tags":"Schlagworte hinzufügen","tags_not_found":"Keine Schlagworte definiert. Erstellen Sie welche.","title_all_contacts":"Alle Kontakte","title_group_members":"Gruppenmitglieder","panel_title_info":"Info","title_manage_tags":"Verwalten","title_not_found":"Nicht gefunden","title_permissions":"Berechtigungen","title_tag_manager":"Schlagworte (Nutzer entdecken)","topic_block_warning":"Möchten Sie diese Unterhaltung wirklich blockieren?","topic_delete_warning":"Möchten Sie diese Unterhaltung wirklich löschen?","topic_name_editing_placeholder":"Freiform Name der Gruppe","unnamed_topic":"Unbenannt","update_available":"Aktualisierung verfügbar.","upload_finishing":"wird abgeschlossen...","user_not_found":"Nicht gefunden","validate_credential_action":"bestätigen","description_editing_placeholder":"Beschreibung (optional)","label_description":"Beschreibung","button_security":"Sicherheit","panel_title_general":"Allgemein","panel_title_security":"Sicherheit","panel_title_crop":"Zum Anpassen ziehen","panel_title_members":"Mitglieder","permissions_anonymous":"Anonym","permissions_authenticated":"Authentifiziert","topic_delete":"Chat löschen","permissions_user":"Benutzerberechtigungen","password_reset_email_sent":"Eine E-Mail wurde an {email} gesendet. Folgen Sie den Anweisungen in der E-Mail, um Ihr Passwort zurückzusetzen.","label_unarchive_topic":"Archiviert:","menu_item_reply":"Antwort","menu_item_forward":"Nach vorne","forward_to":"Weiterleiten","forward_to_search_placeholder":"Kontakte durchsuchen","label_new_password":"Neues Kennwort","drafty_unknown":"Nicht unterstützt"},"en":{"action_block_contact":"Block Contact","action_cancel":"cancel","action_clear_messages":"Clear Messages","action_delete_messages":"Clear Messages for All","action_leave_chat":"Leave Conversation","action_report_chat":"Report Conversation","archived_contacts":"Archived contacts ({count})","badge_danger":"Untrustworthy","badge_owner":"owner","badge_staff":"Staff-managed","badge_verified":"Verified/official","badge_you":"you","block_contact_warning":"Are you sure you want to block this contact?","blocked_contacts_link":"Blocked contacts ({count})","button_add_another":"Add another","button_add_members":"Add members","button_cancel":"Cancel","button_confirm":"Confirm","button_create":"Create","button_delete_account":"Delete account","button_edit":"Edit","button_logout":"Logout","button_ok":"OK","button_reset":"Reset","button_send_request":"Send request","button_sign_in":"Sign in","button_sign_up":"Sign up","button_subscribe":"Subscribe","button_update":"Update","cannot_initiate_file_upload":"Cannot initiate file upload.","channel":"channel","channel_prompt":"This is a channel","chat_invitation":"You are invited to start a new chat. What would you like to do?","chat_invitation_accept":"Accept","chat_invitation_block":"Block","chat_invitation_ignore":"Ignore","clear_messages_warning":"Are you sure you want to clear all messages? It cannot be undone.","code_doesnot_match":"Code does not match","contacts_not_found":"You have no chats
¯∖_(ツ)_/¯","contacts_not_found_short":"No contacts match \'\'{query}\'\'","credential_email_prompt":"Your registration email","delete_account":"Delete account","delete_account_warning":"Are you sure you want to delete your account? It cannot be undone.","delete_messages_warning":"Are you sure you want to delete all messages for everyone? It cannot be undone.","deleted_content":"content deleted","download_action":"download","drafty_attachment":"Attachment","drafty_form":"Form:","drafty_image":"Picture","email_dative":"email","email_prompt":"Email, e.g. jdoe@example.com","enable_peers_messaging":"Enable","enter_confirmation_code_prompt":"Enter confirmation code sent to you by {method}:","error_invalid_id":"Invalid ID","file_attachment_too_large":"The file size {size} exceeds the {limit} limit.","forgot_password_link":"Forgot password?","full_name_prompt":"Full name, e.g. John Doe","granted_permissions":"Granted","group_has_no_members":"No members","group_user_id_prompt":"Group or User ID","image_caption_prompt":"Image caption","invalid_content":"invalid content","invalid_security_token":"Invalid security token","label_client":"Client:","label_content_type":"Content type:","label_default_access_mode":"Default access mode:","label_file_name":"File name:","label_group_members":"Group members:","label_incognito_mode":"Incognito mode:","label_message_sound":"Message sound:","label_muting_topic":"Muted:","label_other_user":"Other","label_password":"Password","label_permissions":"Permissions:","label_private":"Private comment","label_push_notifications":"Notification alerts:","label_push_notifications_disabled":"Notification alerts (requires HTTPS):","label_reset_password":"Send a password reset email:","label_sdk":"SDK:","label_server":"Server:","label_server_address":"Server address:","label_server_to_use":"Server to use:","label_size":"Size:","label_topic_name":"Name","label_user_contacts":"Contacts:","label_user_id":"ID:","label_wire_transport":"Wire transport:","label_you":"You:","label_your_name":"Your name","label_your_permissions":"Your permissions:","last_seen_timestamp":"Last seen","leave_chat_warning":"Are you sure you want to leave this conversation?","link_contact_us":"Contact Us","link_privacy_policy":"Privacy Policy","link_terms_of_service":"Terms of Service","login_prompt":"Login","menu_item_archive_topic":"Archive","menu_item_block":"Block","menu_item_clear_messages":"Clear messages","menu_item_clear_messages_for_all":"Clear for All","menu_item_delete":"Delete","menu_item_delete_for_all":"Delete for All","menu_item_delete_topic":"Delete","menu_item_edit_permissions":"Edit permissions","menu_item_info":"Info","menu_item_member_delete":"Remove","menu_item_mute":"Mute","menu_item_reply":"Reply","menu_item_restore_topic":"Restore","menu_item_send_retry":"Retry","menu_item_unblock":"Unblock","menu_item_unmute":"Unmute","message_sending":"sending...","message_sending_failed":"failed","messages_not_readable":"no access to messages","messaging_disabled_prompt":"Messaging disabled","more_online_members":"+{overflow} more","new_message_prompt":"New message","new_password_placeholder":"Enter new password","no_connection":"No connection","no_contacts":"You have no contacts :-(","numeric_confirmation_code_prompt":"Numbers only","online_now":"online now","password_prompt":"Password","password_unchanged_prompt":"Unchanged","peers_messaging_disabled":"Peer\'s messaging is disabled.","permission_admin":"Approve ({val})","permission_delete":"Delete ({val})","permission_join":"Join ({val})","permission_owner":"Owner ({val})","permission_pres":"Get notified ({val})","permission_read":"Read ({val})","permission_share":"Share ({val})","permission_write":"Write ({val})","phone_dative":"phone","private_editing_placeholder":"Visible to you only","push_init_failed":"Failed to initialize push notifications","reconnect_countdown":"Disconnected. Reconnecting in {seconds}…","reconnect_now":"Try now","reload_update":"Reload","report_chat_warning":"Are you sure you want to block and report this conversation?","requested_permissions":"Requested","save_attachment":"save","search_for_contacts":"Use search to find contacts","search_no_results":"Search returned no results","search_placeholder":"List like email:alice@example.com, tel:17025550003...","sidepanel_title_acc_notifications":"Notifications","sidepanel_title_acc_support":"Support","sidepanel_title_account_settings":"Account Settings","sidepanel_title_archive":"Archived Chats","sidepanel_title_blocked":"Blocked Chats","sidepanel_title_cred":"Confirm Credentials","sidepanel_title_login":"Sign In","sidepanel_title_newtpk":"Start New Chat","sidepanel_title_register":"Create Account","sidepanel_title_reset":"Reset Password","sidepanel_title_settings":"Settings","stay_logged_in":"Stay logged in","tabtitle_find_user":"find","tabtitle_group_by_id":"by id","tabtitle_new_group":"new group","tags_editor_no_tags":"Add some tags","tags_not_found":"No tags defined. Add some.","title_all_contacts":"All Contacts","title_group_members":"Group Members","title_manage_tags":"Manage","title_not_found":"Not found","title_permissions":"Permissions","title_tag_manager":"Tags (search & discovery)","topic_block_warning":"Are you sure you want to block this conversation?","topic_delete_warning":"Are you sure you want to delete this conversation?","topic_name_editing_placeholder":"Freeform name of the group","unnamed_topic":"Unnamed","update_available":"Update available.","upload_finishing":"finishing...","user_not_found":"Not found","validate_credential_action":"confirm","description_editing_placeholder":"Optional description","label_description":"Description","button_security":"Security","panel_title_crop":"Drag to Adjust","panel_title_general":"General","panel_title_members":"Members","panel_title_security":"Security","panel_title_info":"Info","permissions_anonymous":"Anonymous","permissions_authenticated":"Authenticated","topic_delete":"Delete Conversation","permissions_user":"User\'s Permissions","password_reset_email_sent":"An email has been sent to {email}. Follow the directions in the email to reset your password.","label_unarchive_topic":"Archived:","menu_item_forward":"Forward","forward_to":"Forward to","forward_to_search_placeholder":"Search contacts","label_new_password":"New password","drafty_unknown":"Unsupported","calls_incoming":"Incoming Call","calls_incoming_title":"Incoming Call","calls_outgoing":"Outgoing Call","calls_you_label":"You","menu_item_video_call":"Video Call","already_in_call":"You already in an ongoing call!"},"es":{"action_block_contact":"Bloquear contacto","action_cancel":"cancelar","action_clear_messages":"Borrar mensajes","action_delete_messages":"Borrar mensajes para todos","action_leave_chat":"Dejar conversación","action_report_chat":"Reportar conversación","archived_contacts":"Contactos archivados ({count})","badge_danger":"Suspicaz","badge_owner":"propietario","badge_staff":"Administración","badge_verified":"Verificado","badge_you":"tú","block_contact_warning":"¿Estás seguro de que quieres bloquear a este contacto?","blocked_contacts_link":"Contactos bloqueados ({count})","button_add_another":"Añadir contacto","button_add_members":"Añadir miembros","button_cancel":"Cancelar","button_confirm":"Confirmar","button_create":"Crear","button_delete_account":"Eliminar cuenta","button_edit":"Editar","button_logout":"Cerrar sesión","button_ok":"OK","button_reset":"Restablecer","button_send_request":"Enviar petición","button_sign_in":"Entrar","button_sign_up":"Regístrate","button_subscribe":"Suscribirse","button_update":"Actualizar","cannot_initiate_file_upload":"No se pudo iniciar la carga del archivo.","channel":"canal","channel_prompt":"Este es un canal","chat_invitation":"Estás invitado a participar en un nuevo chat. ¿Qué te gustaría hacer?","chat_invitation_accept":"Aceptar","chat_invitation_block":"Bloquear","chat_invitation_ignore":"Ignorar","clear_messages_warning":"¿Estás seguro de que quieres eliminar todos los mensajes? Esta acción es irreversible.","code_doesnot_match":"El código no coincide","contacts_not_found":"No tienes chats
¯∖_(ツ)_/¯","contacts_not_found_short":"Ningún contacto coincide con \'\'{query}\'\'","credential_email_prompt":"Tu correo electrónico de registro","delete_account":"Eliminar cuenta","delete_account_warning":"¿Estás seguro de que deseas eliminar permanentemente tu cuenta? Esta acción es irreversible.","delete_messages_warning":"¿Estás seguro de que quieres eliminar todos los mensajes para todos? Esta acción es irreversible.","deleted_content":"este mensaje fue eliminado","download_action":"descargar","drafty_attachment":"Archivo","drafty_form":"Formulario:","drafty_image":"Imagen","email_dative":"correo electrónico","email_prompt":"Correo electrónico, p.ej. juan@example.com","enable_peers_messaging":"Habilitar","enter_confirmation_code_prompt":"Introduzca el código de confirmación enviado a tu {method}:","error_invalid_id":"ID inválido","file_attachment_too_large":"El tamaño del archivo {size} excede el límite de {limit}.","forgot_password_link":"¿Olvidaste tu contraseña?","full_name_prompt":"Nombre completo, p.ej. Juan González Hernández","granted_permissions":"Otorgados","group_has_no_members":"No hay miembros","group_user_id_prompt":"ID del grupo o usuario","image_caption_prompt":"Añade un comentario","invalid_content":"contenido inválido","invalid_security_token":"Token de seguridad inválido","label_client":"Cliente:","label_content_type":"Tipo de contenido:","label_default_access_mode":"Modo de acceso predeterminado:","label_file_name":"Nombre del archivo:","label_group_members":"Miembros del grupo:","label_incognito_mode":"Modo incógnito:","label_message_sound":"Sonido de mensaje:","label_muting_topic":"Silenciado:","label_other_user":"Otros","label_password":"Contraseña","label_permissions":"Permisos:","label_private":"Comentario privado","label_push_notifications":"Alertas de notificaciones:","label_push_notifications_disabled":"Alertas de notificaciones (requiere HTTPS):","label_reset_password":"Enviar un correo electrónico de restablecimiento de contraseña:","label_sdk":"SDK:","label_server":"Servidor:","label_server_address":"Dirección del servidor:","label_server_to_use":"Servidor para usar:","label_size":"Tamaño:","label_topic_name":"Nombre del tema","label_user_contacts":"Contactos:","label_user_id":"ID:","label_wire_transport":"Transporte de alambre:","label_you":"Tú:","label_your_name":"Tu nombre","label_your_permissions":"Tus permisos:","last_seen_timestamp":"Últ. vez","leave_chat_warning":"¿Estás seguro de que quieres dejar esta conversación?","link_contact_us":"Contáctanos","link_privacy_policy":"Política de privacidad","link_terms_of_service":"Términos de uso","login_prompt":"Nombre de usuario","menu_item_archive_topic":"Archivar","menu_item_block":"Bloquear","menu_item_clear_messages":"Borrar mensajes","menu_item_clear_messages_for_all":"Borrar para todos","menu_item_delete":"Eliminar","menu_item_delete_for_all":"Eliminar para todos","menu_item_delete_topic":"Eliminar","menu_item_edit_permissions":"Editar permisos","menu_item_info":"Información","menu_item_member_delete":"Eliminar","menu_item_mute":"Silenciar","menu_item_restore_topic":"Restaurar","menu_item_send_retry":"Inténtalo de nuevo","menu_item_unblock":"Desbloquear","menu_item_unmute":"Anular el silencio","message_sending":"enviando...","message_sending_failed":"no se pudo enviar el mensaje","messages_not_readable":"sin acceso a mensajes","messaging_disabled_prompt":"El envío de mensajes está deshabilitado","more_online_members":"+{overflow} más","new_message_prompt":"Nuevo mensaje","new_password_placeholder":"Introduzca una nueva contraseña","no_connection":"Sin conexión","no_contacts":"No tienes contactos :-(","numeric_confirmation_code_prompt":"Sólo números","online_now":"en línea","password_prompt":"Contraseña","password_unchanged_prompt":"Sin cambios","peers_messaging_disabled":"La mensajería Peer está deshabilitada.","permission_admin":"Approbar ({val})","permission_delete":"Eliminar ({val})","permission_join":"Unirse ({val})","permission_owner":"Propietario ({val})","permission_pres":"Ser notificado ({val})","permission_read":"Leer ({val})","permission_share":"Compartir ({val})","permission_write":"Escribir ({val})","phone_dative":"teléfono","private_editing_placeholder":"Sólo visible para tí","push_init_failed":"Error al inicializar las notificaciones push","reconnect_countdown":"Desconectado. Reconectando en {seconds}…","reconnect_now":"Reintentar","reload_update":"Recargar","report_chat_warning":"¿Estás seguro de que quieres bloquear y reportar a esta conversación?","requested_permissions":"Solicitados","save_attachment":"guardar","search_for_contacts":"Usa la búsqueda para encontrar contactos","search_no_results":"La búsqueda no arrojó resultados","search_placeholder":"Ej. email:alice@example.com, tel:17025550003...","sidepanel_title_acc_notifications":"Notificaciones","sidepanel_title_acc_support":"Soporte","sidepanel_title_account_settings":"Ajustes de la cuenta","sidepanel_title_archive":"Chats archivados","sidepanel_title_blocked":"Chats bloqueados","sidepanel_title_cred":"Confirmar credenciales","sidepanel_title_login":"Iniciar sesión","sidepanel_title_newtpk":"Iniciar un nuevo chat","sidepanel_title_register":"Crear cuenta","sidepanel_title_reset":"Restablecer contraseña","sidepanel_title_settings":"Ajustes","stay_logged_in":"Permanecer conectado","tabtitle_find_user":"encontrar","tabtitle_group_by_id":"por ID","tabtitle_new_group":"nuevo grupo","tags_editor_no_tags":"Añadir etiquetas","tags_not_found":"No hay etiquetas definidas. Añade unas.","title_all_contacts":"Todos los contactos","title_group_members":"Miembros del grupo","title_manage_tags":"Gestionar","title_not_found":"No encontrado","title_permissions":"Permisos","title_tag_manager":"Etiquetas (descubrimiento de usuarios)","topic_block_warning":"¿Estás seguro de que quieres bloquear esta conversación","topic_delete_warning":"¿Estás seguro de que quieres eliminar esta conversación?","topic_name_editing_placeholder":"Nombre del grupo","unnamed_topic":"Sin nombre","update_available":"Actualización disponible.","upload_finishing":"terminando...","user_not_found":"Usuario no encontrado","validate_credential_action":"confirmar","description_editing_placeholder":"Descripción (opcional)","label_description":"Descripción","button_security":"Seguridad","panel_title_crop":"Arrastra para ajustar","panel_title_general":"General","panel_title_members":"Miembros","panel_title_security":"Seguridad","panel_title_info":"Información","permissions_anonymous":"Anónimo","permissions_authenticated":"Autenticado","topic_delete":"Eliminar chat","permissions_user":"Permisos del usuario","password_reset_email_sent":"Se ha enviado un correo electrónico a {email}. Siga las instrucciones del correo electrónico para restablecer su contraseña.","label_unarchive_topic":"Archivado:","menu_item_reply":"Respuesta","menu_item_forward":"Reenviar","forward_to":"Reenviar a","forward_to_search_placeholder":"Buscar contactos","label_new_password":"Nueva contraseña","drafty_unknown":"No soportado"},"ko":{"action_block_contact":"연락차단","action_cancel":"취소","action_clear_messages":"메시지지우기","action_delete_messages":"모든메시지지우기","action_leave_chat":"대화나누기","action_report_chat":"대화기록","archived_contacts":"보관된연락처({수})","badge_danger":"의심 많은","badge_owner":"소유자","badge_staff":"직원 관리하에","badge_verified":"확인 됨","badge_you":"당신","block_contact_warning":"이연락처를차단하시겠습니까?","blocked_contacts_link":"차단된연락처({수})","button_add_another":"다른항목추가","button_add_members":"회원추가","button_cancel":"취소","button_confirm":"확인","button_create":"작성","button_delete_account":"계정삭제","button_edit":"편집","button_logout":"로그아웃","button_ok":"OK","button_reset":"재설정","button_send_request":"요청보내기","button_sign_in":"로그인","button_sign_up":"가입","button_subscribe":"구독","button_update":"업데이트","cannot_initiate_file_upload":"파일업로드를시작할수없습니다.","channel":"채널","channel_prompt":"이 채널입니다","chat_invitation":"새로운대화를시작하도록초대되었습니다.무엇을하시겠습니까?","chat_invitation_accept":"수락","chat_invitation_block":"차단","chat_invitation_ignore":"무시","clear_messages_warning":"모든메시지를지우시겠습니까?실행취소할수없습니다.","code_doesnot_match":"코드가일치하지않습니다","contacts_not_found":"채팅이없습니다
¯∖_(ツ)_/¯","contacts_not_found_short":"\'{문의}\'와일치하는연락처가없습니다.","credential_email_prompt":"등록이메일","delete_account":"계정삭제","delete_account_warning":"계정을삭제하시겠습니까?실행취소할수없습니다.","delete_messages_warning":"모든사람의모든메시지를삭제하시겠습니까?실행취소할수없습니다.","deleted_content":"내용이 삭제되었습니다","download_action":"다운로드","drafty_attachment":"부착","drafty_form":"형태:","drafty_image":"이미지","email_dative":"이메일","email_prompt":"이메일(예:hong@example.com)","enable_peers_messaging":"활성화","enter_confirmation_code_prompt":"{방법}으로보낸확인코드를입력하십시오:","error_invalid_id":"잘못된ID","file_attachment_too_large":"파일크기{크기}이(가){제한}제한을초과합니다.","forgot_password_link":"비밀번호를잊으셨습니까?","full_name_prompt":"전체이름(예:홍길동)","granted_permissions":"승낙하다","group_has_no_members":"회원없음","group_user_id_prompt":"그룹또는사용자ID","image_caption_prompt":"이미지설명","invalid_content":"잘못된내용","invalid_security_token":"유효하지않은보안토큰","label_client":"클라이언트: ","label_content_type":"컨텐츠유형: ","label_default_access_mode":"기본액세스모드: ","label_file_name":"파일이름: ","label_group_members":"그룹회원: ","label_incognito_mode":"시크릿모드: ","label_message_sound":"메시지소리: ","label_muting_topic":"음소거: ","label_other_user":"기타","label_password":"비밀번호","label_permissions":"권한: ","label_private":"개인코멘트","label_push_notifications":"통지경보: ","label_push_notifications_disabled":"통지경보(HTTPS필요): ","label_reset_password":"비밀번호재설정이메일보내기: ","label_sdk":"SDK:","label_server":"서버: ","label_server_address":"서버주소: ","label_server_to_use":"사용할서버:","label_size":"크기: ","label_topic_name":"이름","label_user_contacts":"연락처: ","label_user_id":"ID:","label_wire_transport":"와이어수송:","label_you":"당신: ","label_your_name":"이름","label_your_permissions":"권한: ","last_seen_timestamp":"마지막으로본","leave_chat_warning":"이대화를나가시겠습니까?","link_contact_us":"문의처","link_privacy_policy":"개인정보보호정책","link_terms_of_service":"서비스약관","login_prompt":"로그인","menu_item_archive_topic":"보관","menu_item_block":"차단","menu_item_clear_messages":"메시지지우기","menu_item_clear_messages_for_all":"모두지우기","menu_item_delete":"삭제","menu_item_delete_for_all":"모두삭제","menu_item_delete_topic":"삭제","menu_item_edit_permissions":"편집권한","menu_item_info":"정보","menu_item_member_delete":"제거","menu_item_mute":"음소거","menu_item_restore_topic":"복원","menu_item_send_retry":"다시시도","menu_item_unblock":"차단해제","menu_item_unmute":"음소거해제","message_sending":"보내기...","message_sending_failed":"실패","messages_not_readable":"메시지에 액세스 할 수 없습니다","messaging_disabled_prompt":"메시지비활성화","more_online_members":"+{넘침}더보기","new_message_prompt":"새메시지","new_password_placeholder":"새비밀번호입력","no_connection":"연결없음","no_contacts":"연락처가없습니다 (._.)","numeric_confirmation_code_prompt":"숫자만","online_now":"현재접속중","password_prompt":"비밀번호","password_unchanged_prompt":"변경되지않음","peers_messaging_disabled":"동료의메시지가비활성화되었습니다.","permission_admin":"승인({val})","permission_delete":"삭제({val})","permission_join":"참여({val})","permission_owner":"소유자({val})","permission_pres":"알림받기({val})","permission_read":"읽기({val})","permission_share":"공유({val})","permission_write":"쓰기({val})","phone_dative":"전화","private_editing_placeholder":"나만볼수있습니다","push_init_failed":"푸시알림을초기화하지못했습니다","reconnect_countdown":"연결이끊어졌습니다.다시연결하는중{초}…","reconnect_now":"지금시도","reload_update":"재로드","report_chat_warning":"이대화를차단하고기록하시겠습니까?","requested_permissions":"요청","save_attachment":"저장","search_for_contacts":"검색을사용하여연락처찾기","search_no_results":"검색결과가없습니다","search_placeholder":"email:alice@example.com,tel:17025550003...와같은목록","sidepanel_title_acc_notifications":"알림","sidepanel_title_acc_support":"지원","sidepanel_title_account_settings":"계정설정","sidepanel_title_archive":"보관된채팅","sidepanel_title_blocked":"차단된채팅","sidepanel_title_cred":"자격증명확인","sidepanel_title_login":"로그인","sidepanel_title_newtpk":"새채팅시작","sidepanel_title_register":"계정만들기","sidepanel_title_reset":"비밀번호재설정","sidepanel_title_settings":"설정","stay_logged_in":"로그인상태유지","tabtitle_find_user":"찾기","tabtitle_group_by_id":"id로","tabtitle_new_group":"새그룹","tags_editor_no_tags":"일부태그추가","tags_not_found":"태그가정의되지않았습니다.일부를추가하십시오.","title_all_contacts":"모든연락처","title_group_members":"그룹구성원","title_manage_tags":"관리","title_not_found":"찾을수없음","title_permissions":"권한","title_tag_manager":"태그(사용자검색)","topic_block_warning":"이대화를차단하시겠습니까?","topic_delete_warning":"이대화를삭제하시겠습니까?","topic_name_editing_placeholder":"그룹의자유형이름","unnamed_topic":"이름없는","update_available":"업데이트가능.","upload_finishing":"마무리...","user_not_found":"찾을수없음","validate_credential_action":"확인","description_editing_placeholder":"설명(선택 사항)","label_description":"설명","button_security":"보안","panel_title_crop":"드래그하여 조정","panel_title_general":"일반","panel_title_members":"구성원","panel_title_security":"보안","panel_title_info":"정보","permissions_anonymous":"익명","permissions_authenticated":"인증됨","topic_delete":"채팅 삭제","permissions_user":"사용자 권한","password_reset_email_sent":"이메일이 {email}(으)로 전송되었습니다. 이메일의 지침에 따라 비밀번호를 재설정하세요.","label_unarchive_topic":"보관됨:","menu_item_reply":"회신하다","menu_item_forward":"리디렉션","forward_to":"메시지를 리디렉션","forward_to_search_placeholder":"연락처 검색","label_new_password":"새 비밀번호","drafty_unknown":"지원되지 않음"},"ro":{"action_block_contact":"Blochează contact","action_cancel":"anulează","action_clear_messages":"Șterge mesajele","action_delete_messages":"Șterge toate mesajele","action_leave_chat":"Ieși din conversație","action_report_chat":"Raportează conversația","archived_contacts":"Contacte arhivate ({count})","badge_danger":"Suspicios","badge_owner":"owner","badge_staff":"Administrare","badge_verified":"Verificat","badge_you":"tu","block_contact_warning":"Ești sigur că dorești să blochezi acest contact?","blocked_contacts_link":"Contact blocate ({count})","button_add_another":"Adaugă","button_add_members":"Adaugă persoane","button_cancel":"Anulează","button_confirm":"Confirmă","button_create":"Creează","button_delete_account":"Șterge cont","button_edit":"Editează","button_logout":"Deconectare","button_ok":"OK","button_reset":"Resetează","button_send_request":"Trimite cerere","button_sign_in":"Conectează-te","button_sign_up":"Creează cont","button_subscribe":"Subscribe","button_update":"Actualizează","cannot_initiate_file_upload":"Nu se poate face încărcarea.","channel":"canal","channel_prompt":"Acesta este un canal","chat_invitation":"Ai primit invitație într-o conversație. Accepți?","chat_invitation_accept":"Da, accept","chat_invitation_block":"Blochează","chat_invitation_ignore":"Ignoră","clear_messages_warning":"Ești sigur că dorești să ștergi mesajele? Acestea nu pot fi recuperate.","code_doesnot_match":"Codul furnizat nu este valid","contacts_not_found":"Nu ai contacte salvate
¯∖_(ツ)_/¯","contacts_not_found_short":"Niciun contact găsit după criteriile \'\'{query}\'\'","credential_email_prompt":"Adresa de e-mail","delete_account":"Șterge contul","delete_account_warning":"Ești sigur că dorești să ștergi contul? Acesta nu va putea fi recuperat.","delete_messages_warning":"Ești sigur că dorești să șterge mesajele din toate conversațiile? Acestea nu pot fi recuperate.","deleted_content":"conținut șters","download_action":"download","drafty_attachment":"Atasament","drafty_form":"Formă:","drafty_image":"Imagine","email_dative":"email","email_prompt":"Adresa de e-mail","enable_peers_messaging":"Activează","enter_confirmation_code_prompt":"Introu codul de confirmare trimis pe {method}:","error_invalid_id":"ID Invalid","file_attachment_too_large":"Dimensiunea fișiterului {size} depășește limita de {limit}.","forgot_password_link":"Ți-ai uitat parola?","full_name_prompt":"Numele tău","granted_permissions":"Oferite","group_has_no_members":"În acest grup nu se află persoane","group_user_id_prompt":"Grup sau user ID","image_caption_prompt":"Titlul imaginii","invalid_content":"conținut invalid","invalid_security_token":"Codul de securitate este invalid","label_client":"Client:","label_content_type":"Tip conținut:","label_default_access_mode":"Default access mode:","label_file_name":"Nume fișier:","label_group_members":"Membrii grupului:","label_incognito_mode":"Mod incognito:","label_message_sound":"Sunet de mesaj:","label_muting_topic":"Mod silențios (muted):","label_other_user":"Altele","label_password":"Parola","label_permissions":"Permisiuni:","label_private":"Comentariu privat","label_push_notifications":"Alerte de notificare:","label_push_notifications_disabled":"Alerte de notificare (necesită HTTPS):","label_reset_password":"Resetează parola:","label_sdk":"SDK:","label_server":"Server:","label_server_address":"Adresa serverului:","label_server_to_use":"Server de utilizat:","label_size":"Size:","label_topic_name":"Nume","label_user_contacts":"Contacte:","label_user_id":"ID:","label_wire_transport":"Transportul legat:","label_you":"Tu:","label_your_name":"Numele tău","label_your_permissions":"Permisiuniile tale:","last_seen_timestamp":"Văzut ultima dată","leave_chat_warning":"Ești sigur că dorești să ieși din conersație?","link_contact_us":"Contactează-ne","link_privacy_policy":"Politica de Confidențialitate","link_terms_of_service":"Termenii Serviciului","login_prompt":"Conectează-te","menu_item_archive_topic":"Arhivează","menu_item_block":"Blochează","menu_item_clear_messages":"Șterge mesajele","menu_item_clear_messages_for_all":"Ștergele pe toate","menu_item_delete":"Șterge","menu_item_delete_for_all":"Ștergele pe toate","menu_item_delete_topic":"Șterge","menu_item_edit_permissions":"Editează permisiuni","menu_item_info":"Info","menu_item_member_delete":"Șterge persoană","menu_item_mute":"Mute","menu_item_restore_topic":"Restabili","menu_item_send_retry":"Reîncearcă","menu_item_unblock":"Deblochează","menu_item_unmute":"Unmute","message_sending":"se trimite...","message_sending_failed":"eroare","messages_not_readable":"Mesajele nu pot fi citite","messaging_disabled_prompt":"Mesageria este dezactivată","more_online_members":"+{overflow} mai mult","new_message_prompt":"Mesaj nou","new_password_placeholder":"Introdu parolă","no_connection":"Nu există conexiune","no_contacts":"Nu ai contacte adăugate :-(","numeric_confirmation_code_prompt":"Doar cifre","online_now":"online acum","password_prompt":"Parola","password_unchanged_prompt":"Neschimbată","peers_messaging_disabled":"Mesageria de tip Peer este dezactivată.","permission_admin":"Aprobare ({val})","permission_delete":"Ștergere ({val})","permission_join":"Participare ({val})","permission_owner":"Deținător ({val})","permission_pres":"Notificare ({val})","permission_read":"Citire ({val})","permission_share":"Distribuire ({val})","permission_write":"Scriere ({val})","phone_dative":"telefon","private_editing_placeholder":"Vizibil doar ție","push_init_failed":"Nu s-a reușit inițializarea tip push notifications","reconnect_countdown":"Deconectat. Se încearcă conectarea în {seconds}…","reconnect_now":"Încearcă din nou","reload_update":"Reîncarcă","report_chat_warning":"Ești sigur că dorești să blochezi și să raportezi această conversație?","requested_permissions":"Necesare","save_attachment":"salvează","search_for_contacts":"Caută în contacte","search_no_results":"Nu s-au găsit rezultate","search_placeholder":"Caută după e-mail sau număr telefon...","sidepanel_title_acc_notifications":"Notificări","sidepanel_title_acc_support":"Ajutor","sidepanel_title_account_settings":"Setările Contului","sidepanel_title_archive":"Conversații Arhivate","sidepanel_title_blocked":"Conversații Blocate","sidepanel_title_cred":"Confirmă credențiale","sidepanel_title_login":"Conectează-te","sidepanel_title_newtpk":"Creeză un nou Chat","sidepanel_title_register":"Creează Cont","sidepanel_title_reset":"Resetează Parola","sidepanel_title_settings":"Setări","stay_logged_in":"Rămâi conectat","tabtitle_find_user":"caută","tabtitle_group_by_id":"după id","tabtitle_new_group":"grup nou","tags_editor_no_tags":"Adaugă tag-uri","tags_not_found":"Niciun tag definit. Adaugă.","title_all_contacts":"Toate Contactele","title_group_members":"Persoanele din grup","title_manage_tags":"Administrează","title_not_found":"Nu a fost găsit","title_permissions":"Permisiuni","title_tag_manager":"Tag-uri (user discovery)","topic_block_warning":"Ești sigur că dorești să blochezi această conversație?","topic_delete_warning":"Ești sigur că dorești să șterge această conversație?","topic_name_editing_placeholder":"Numele grupului","unnamed_topic":"Nedenumit","update_available":"Actualizare disponibilă.","upload_finishing":"se încarcă...","user_not_found":"Utilizatorul nu a fost găsit","validate_credential_action":"confirmă","description_editing_placeholder":"Descriere (opțional)","label_description":"Descriere","button_security":"Securitate","panel_title_crop":"Trageți pentru a ajusta","panel_title_general":"Generale","panel_title_members":"Membri","panel_title_security":"Securitate","panel_title_info":"Info","permissions_anonymous":"Anonim","permissions_authenticated":"Autentificat","topic_delete":"Ștergeți Chat","permissions_user":"Permisiunile utilizatorului","password_reset_email_sent":"Un e-mail a fost trimis către {email}. Urmați instrucțiunile din e-mail pentru a vă reseta parola.","label_unarchive_topic":"Arhivat:","menu_item_reply":"A raspunde","menu_item_forward":"Redirecţiona","forward_to":"Redirecționați către","forward_to_search_placeholder":"Căutați contacte","label_new_password":"Parolă Nouă","drafty_unknown":"Neacceptat"},"ru":{"action_block_contact":"Заблокировать контакт","action_cancel":"отменить","action_clear_messages":"Удалить сообщения","action_delete_messages":"Удалить сообщения","action_leave_chat":"Уйти из чата","action_report_chat":"Сообщить о нарушении","archived_contacts":"Чаты в архиве ({count})","badge_danger":"Подозрительный","badge_owner":"влад.","badge_staff":"Администрация","badge_verified":"Верифицированный","badge_you":"вы","block_contact_warning":"Вы действительно заблокировать этот контакт?","blocked_contacts_link":"Заблокированные ({count})","button_add_another":"Добавить","button_add_members":"Добавить","button_cancel":"Отменить","button_confirm":"Подтвердить","button_create":"Создать","button_delete_account":"Удалить аккаунт","button_edit":"Редактировать","button_logout":"Выйти","button_ok":"OK","button_reset":"Изменить","button_send_request":"Отправить","button_sign_in":"Войти","button_sign_up":"Создать аккаунт","button_subscribe":"Подписаться","button_update":"Применить","cannot_initiate_file_upload":"Ошибка загрузки файла.","channel":"канал","channel_prompt":"Создать канал","chat_invitation":"Вас пригласили начать новый чат. Как вы хотите поступить?","chat_invitation_accept":"Принять","chat_invitation_block":"Заблокировать","chat_invitation_ignore":"Игнорировать","clear_messages_warning":"Вы действительно хотите удалить все сообщения в чате? Их будет невозможно восстановить.","code_doesnot_match":"Код не совпадает","contacts_not_found":"Чатов нет
¯∖_(ツ)_/¯","contacts_not_found_short":"Нет контактов для запроса \'\'{query}\'\'","credential_email_prompt":"Регистрационный емейл","delete_account":"Удалить аккаунт","delete_account_warning":"Вы уверены, что ходите удалить свой аккаунт? Его невозможно будет восстановить.","delete_messages_warning":"Вы действительно хотите удалить все сообщения?","deleted_content":"удалено","download_action":"скачать","drafty_attachment":"Аттачмент","drafty_form":"Форма:","drafty_image":"Картинка","email_dative":"емейлу","email_prompt":"Email, напр. ivan@example.com","enable_peers_messaging":"Разблокировать.","enter_confirmation_code_prompt":"Код подтверждения, полученный по {method}:","error_invalid_id":"Неверный ID","file_attachment_too_large":"Размер файла {size} превышает {limit} лимит.","forgot_password_link":"Напомнить пароль","full_name_prompt":"Полное имя, напр. Иван Петров","granted_permissions":"Получены","group_has_no_members":"Нет участников","group_user_id_prompt":"ID чата или пользователя","image_caption_prompt":"Подпись к фото","invalid_content":"сообщение не читается","invalid_security_token":"Токен некорректен","label_client":"Клиент:","label_content_type":"Тип:","label_default_access_mode":"Доступ по умолчанию:","label_file_name":"Имя файла:","label_group_members":"Участники чата:","label_incognito_mode":"Режим инкогнито:","label_message_sound":"Звук нового сообщения:","label_muting_topic":"Без уведомлений","label_other_user":"Второй","label_password":"Пароль","label_permissions":"Права доступа:","label_private":"Комментарий","label_push_notifications":"Уведомления:","label_push_notifications_disabled":"Уведомления (требуют HTTPS):","label_reset_password":"Отправить емейл для смены пароля:","label_sdk":"SDK:","label_server":"Сервер:","label_server_address":"Адрес сервера:","label_server_to_use":"Использовать сервер:","label_size":"Размер:","label_topic_name":"Название","label_user_contacts":"Конакты:","label_user_id":"ID:","label_wire_transport":"Соединение:","label_you":"Вы:","label_your_name":"Ваше имя","label_your_permissions":"Ваши права доступа:","last_seen_timestamp":"Был активен","leave_chat_warning":"Вы действительно хотите покинуть этот чат?","link_contact_us":"Связаться с нами","link_privacy_policy":"Политика конфиденциальности","link_terms_of_service":"Условия сервиса","login_prompt":"Логин","menu_item_archive_topic":"В архив","menu_item_block":"Заблокировать","menu_item_clear_messages":"Удалить сообщения","menu_item_clear_messages_for_all":"Удалить для всех","menu_item_delete":"Удалить","menu_item_delete_for_all":"Удалить для всех","menu_item_delete_topic":"Удалить чат","menu_item_edit_permissions":"Права доступа","menu_item_info":"Информация","menu_item_member_delete":"Отписать","menu_item_mute":"Не уведомлять","menu_item_restore_topic":"Разархивировать","menu_item_send_retry":"Отправить заново","menu_item_unblock":"Разблокировать","menu_item_unmute":"Уведомлять","message_sending":"в пути...","message_sending_failed":"ошибка","messages_not_readable":"нет доступа к сообщениям","messaging_disabled_prompt":"Отправка недоступна","more_online_members":"+еще {overflow}","new_message_prompt":"Новое сообщение","new_password_placeholder":"Введите новый пароль","no_connection":"Нет связи","no_contacts":"Ничего нет :-(","numeric_confirmation_code_prompt":"Только цифры","online_now":"онлайн","password_prompt":"Пароль","password_unchanged_prompt":"Не изменен","peers_messaging_disabled":"Чат заблокирован у корреспондента.","permission_admin":"Подтверждать ({val})","permission_delete":"Удалять ({val})","permission_join":"Подписываться ({val})","permission_owner":"Владелец ({val})","permission_pres":"Уведомлять ({val})","permission_read":"Читать ({val})","permission_share":"Приглашать ({val})","permission_write":"Писать ({val})","phone_dative":"телефону","private_editing_placeholder":"Виден только вам","push_init_failed":"Ошибка инициализации пуш уведомлений","reconnect_countdown":"Нет связи. Подключение через {seconds}…","reconnect_now":"Подключить сейчас.","reload_update":"Обновить","report_chat_warning":"Вы действительно хотите сообщить о нарушении и заблокировать этот чат?","requested_permissions":"Требуются","save_attachment":"сохранить","search_for_contacts":"Поиск контактов","search_no_results":"Ничего не найдено","search_placeholder":"Список, напр. email:alice@example.com, tel:+17025550003...","sidepanel_title_acc_notifications":"Уведомления","sidepanel_title_acc_support":"Поддержка","sidepanel_title_account_settings":"Настройки аккаунта","sidepanel_title_archive":"Архив чатов","sidepanel_title_blocked":"Заблокированные чаты","sidepanel_title_cred":"Подтвердить","sidepanel_title_login":"Авторизация","sidepanel_title_newtpk":"Новый чат","sidepanel_title_register":"Зарегистрироваться","sidepanel_title_reset":"Сменить пароль","sidepanel_title_settings":"Настройки","stay_logged_in":"Запомнить","tabtitle_find_user":"найти","tabtitle_group_by_id":"по id","tabtitle_new_group":"создать","tags_editor_no_tags":"Добавьте теги","tags_not_found":"Тегов нет. Добавьте","title_all_contacts":"Все контакты","title_group_members":"Участники","title_manage_tags":"Редактировать","title_not_found":"Не найден","title_permissions":"Права доступа","title_tag_manager":"Теги для поиска","topic_block_warning":"Вы действительно хотите заблокировать этот чат?","topic_delete_warning":"Вы действительно хотите удалить этот чат?","topic_name_editing_placeholder":"Название чата","unnamed_topic":"Без названия","update_available":"Есть новая версия приложения.","upload_finishing":"завершение...","user_not_found":"Не найден","validate_credential_action":"подтвердить","description_editing_placeholder":"Описание (не обязательно)","label_description":"Описание","button_security":"Безопасность","panel_title_crop":"Обрезать картинку","panel_title_general":"Общие настройки","panel_title_members":"Участники","panel_title_security":"Безопасность","panel_title_info":"Подробности","permissions_anonymous":"Анонимный","permissions_authenticated":"Авторизованный","topic_delete":"Удалить чат","permissions_user":"Права доступа","password_reset_email_sent":"Сообщение было отправлено на адрес {email}. Следуйте инструкциям в сообщении, чтобы изменить пароль.","label_unarchive_topic":"Архивирован:","menu_item_reply":"Ответить","menu_item_forward":"Переслать","forward_to":"Переслать","forward_to_search_placeholder":"Поиск контактов","label_new_password":"Новый пароль","drafty_unknown":"Не поддерживается"},"zh-TW":{"action_block_contact":"封鎖聯絡人","action_cancel":"取消","action_clear_messages":"清除訊息","action_delete_messages":"為所有人清除訊息","action_leave_chat":"離開對話","action_report_chat":"檢舉對話","archived_contacts":"已封存的聯絡人 ({count})","badge_danger":"不可信","badge_owner":"擁有者","badge_staff":"員工管理","badge_verified":"已驗證/官方","badge_you":"您","block_contact_warning":"您確定要封鎖此聯絡人嗎?","blocked_contacts_link":"已封鎖的聯絡人 ({count})","button_add_another":"新增其他人","button_add_members":"新增成員","button_cancel":"取消","button_confirm":"確認","button_create":"建立","button_delete_account":"刪除帳號","button_edit":"編輯","button_logout":"登出","button_ok":"OK","button_reset":"重設","button_send_request":"傳送要求","button_sign_in":"登入","button_sign_up":"註冊","button_subscribe":"訂閱","button_update":"更新","cannot_initiate_file_upload":"無法為檔案上傳初始化。","channel":"頻道","channel_prompt":"這是頻道","chat_invitation":"您已被邀請開始新對話。您接下來要做什麼呢?","chat_invitation_accept":"接受","chat_invitation_block":"封鎖","chat_invitation_ignore":"忽略","clear_messages_warning":"您確定要清除所有訊息嗎?此操作無法復原。","code_doesnot_match":"代碼不相符","contacts_not_found":"您沒有任何對話
¯∖_(ツ)_/¯","contacts_not_found_short":"沒有符合 \'\'{query}\'\' 的聯絡人","credential_email_prompt":"您的註冊電子郵件地址","delete_account":"刪除帳號","delete_account_warning":"您確定要刪除您的帳戶嗎?此操作無法撤消。","delete_messages_warning":"您確定要為所有人刪除所有訊息嗎?此操作無法復原。","deleted_content":"內容已被刪除","download_action":"下載","drafty_attachment":"附加檔案","drafty_form":"表單:","drafty_image":"圖片","email_dative":"電子郵件地址","email_prompt":"電子郵件地址,例如:jdoe@example.com","enable_peers_messaging":"啟用","enter_confirmation_code_prompt":"輸入透過 {method} 傳送給您的確認碼:","error_invalid_id":"ID 無效","file_attachment_too_large":"檔案大小 {size} 超出 {limit} 限制。","forgot_password_link":"忘記密碼?","full_name_prompt":"全名,例如:王小明","granted_permissions":"已授權","group_has_no_members":"無成員","group_user_id_prompt":"群組或使用者 ID","image_caption_prompt":"圖片說明","invalid_content":"內容無效","invalid_security_token":"安全權杖無效","label_client":"客戶端:","label_content_type":"類型:","label_default_access_mode":"預設存取模式:","label_file_name":"檔名:","label_group_members":"群組成員:","label_incognito_mode":"無痕模式:","label_message_sound":"訊息提示聲:","label_muting_topic":"靜音:","label_other_user":"其他","label_password":"密碼","label_permissions":"權限:","label_private":"私人留言","label_push_notifications":"通知:","label_push_notifications_disabled":"通知 (需要 HTTPS):","label_reset_password":"傳送重設密碼郵件:","label_sdk":"SDK:","label_server":"伺服器:","label_server_address":"伺服器位址:","label_server_to_use":"使用的伺服器:","label_size":"大小:","label_topic_name":"名稱","label_user_contacts":"聯絡人:","label_user_id":"ID:","label_wire_transport":"Wire transport:","label_you":"您:","label_your_name":"您的名字","label_your_permissions":"您的權限:","last_seen_timestamp":"最後上線","leave_chat_warning":"您確定要離開此對話嗎?","link_contact_us":"聯絡我們","link_privacy_policy":"隱私權政策","link_terms_of_service":"服務條款","login_prompt":"登入","menu_item_archive_topic":"封存","menu_item_block":"封鎖","menu_item_clear_messages":"清除訊息","menu_item_clear_messages_for_all":"為所有人清除訊息","menu_item_delete":"刪除","menu_item_delete_for_all":"為所有人刪除","menu_item_delete_topic":"刪除","menu_item_edit_permissions":"編輯權限","menu_item_info":"Info","menu_item_member_delete":"移除","menu_item_mute":"靜音","menu_item_restore_topic":"恢復","menu_item_send_retry":"重試","menu_item_unblock":"解除封鎖","menu_item_unmute":"解除靜音","message_sending":"正在傳送...","message_sending_failed":"失敗","messages_not_readable":"沒有存取訊息的權限","messaging_disabled_prompt":"停用訊息","more_online_members":"+{overflow}","new_message_prompt":"新訊息","new_password_placeholder":"輸入新的密碼","no_connection":"無連線","no_contacts":"您沒有任何聯絡人 :-(","numeric_confirmation_code_prompt":"僅數字","online_now":"上線中","password_prompt":"密碼","password_unchanged_prompt":"未修改","peers_messaging_disabled":"Peer 已停用訊息。","permission_admin":"核可 ({val})","permission_delete":"刪除 ({val})","permission_join":"加入 ({val})","permission_owner":"擁有者 ({val})","permission_pres":"收到通知 ({val})","permission_read":"讀取 ({val})","permission_share":"分享 ({val})","permission_write":"撰寫 ({val})","phone_dative":"phone","private_editing_placeholder":"僅您可見","push_init_failed":"初始化通知失敗。","reconnect_countdown":"已斷線。將在 {seconds} 秒後重新連線…","reconnect_now":"現在重試","reload_update":"重新載入","report_chat_warning":"您確定要封鎖並檢舉此對話嗎?","requested_permissions":"重新請求","save_attachment":"儲存","search_for_contacts":"使用搜尋來尋找聯絡人","search_no_results":"搜尋無結果","search_placeholder":"例如 email:alice@example.com, tel:17025550003... 的清單","sidepanel_title_acc_notifications":"通知","sidepanel_title_acc_support":"支援","sidepanel_title_account_settings":"帳號設定","sidepanel_title_archive":"已封存的對話","sidepanel_title_blocked":"已封鎖的對話","sidepanel_title_cred":"確認認證","sidepanel_title_login":"登入","sidepanel_title_newtpk":"開始新對話","sidepanel_title_register":"建立帳號","sidepanel_title_reset":"重設密碼","sidepanel_title_settings":"設定","stay_logged_in":"保持登入","tabtitle_find_user":"尋找","tabtitle_group_by_id":"以 id","tabtitle_new_group":"新群組","tags_editor_no_tags":"新增一些標籤","tags_not_found":"未定義任何標籤。請新增一些標籤。","title_all_contacts":"所有聯絡人","title_group_members":"群組成員","title_manage_tags":"管理","title_not_found":"找不到","title_permissions":"權限","title_tag_manager":"標籤 (使用者探索)","topic_block_warning":"您確定要封鎖此對話嗎?","topic_delete_warning":"您確定要刪除此對話嗎?","topic_name_editing_placeholder":"群組的任意名稱","unnamed_topic":"未命名","update_available":"有可用的更新。","upload_finishing":"正在完成...","user_not_found":"找不到","validate_credential_action":"確認","description_editing_placeholder":"說明(可選)","label_description":"說明","button_security":"安全性","panel_title_crop":"拖動調整","panel_title_general":"一般","panel_title_members":"成員","panel_title_security":"安全性","panel_title_info":"資訊","permissions_anonymous":"匿名","permissions_authenticated":"已認證","topic_delete":"刪除聊天","permissions_user":"用戶權限","password_reset_email_sent":"一封電子郵件已發送至 {email}。按照電子郵件中的說明重置密碼。","label_unarchive_topic":"存檔聊天:","menu_item_reply":"回答","menu_item_forward":"重定向","forward_to":"重定向消息","forward_to_search_placeholder":"搜索聯繫人","label_new_password":"新密碼","drafty_unknown":"不支持"},"zh":{"action_block_contact":"屏蔽联系人","action_cancel":"取消","action_clear_messages":"删除讯息","action_delete_messages":"删除所有帖子","action_leave_chat":"离开","action_report_chat":"检举垃圾邮件","archived_contacts":"已归档联系人 ({count})","badge_danger":"可疑的","badge_owner":"所有者","badge_staff":"在员工管理下","badge_verified":"值得信赖","badge_you":"你","block_contact_warning":"您确定要阻止此联系人吗?","blocked_contacts_link":"封锁的联络人 ({count})","button_add_another":"加上另一个","button_add_members":"添加成员","button_cancel":"取消","button_confirm":"确认","button_create":"创建","button_delete_account":"删除帐户","button_edit":"编辑","button_logout":"登出","button_ok":"好","button_reset":"重置","button_send_request":"发送请求","button_sign_in":"登录","button_sign_up":"注册","button_subscribe":"订阅","button_update":"更新","cannot_initiate_file_upload":"无法初始化文件上传。","channel":"频道","channel_prompt":"这是一个频道","chat_invitation":"你受邀开始新会话。你想怎么做?","chat_invitation_accept":"接受","chat_invitation_block":"屏蔽","chat_invitation_ignore":"忽略","clear_messages_warning":"您确定要清除所有消息吗?无法撤消。","code_doesnot_match":"代码不匹配","contacts_not_found":"你尚无会话
¯∖_(ツ)_/¯","contacts_not_found_short":"无联系人匹配\'\'{query}\'\'","credential_email_prompt":"你的注册邮箱","delete_account":"删除帐户","delete_account_warning":"您确定要删除您的帐户吗?无法撤消。","delete_messages_warning":"您确定要删除所有消息吗?无法撤消。","deleted_content":"内容已删除","download_action":"下载","drafty_attachment":"附件","drafty_form":"形式:","drafty_image":"图像","email_dative":"电子邮件","email_prompt":"电子邮件,例如 zhang@example.com","enable_peers_messaging":"启用","enter_confirmation_code_prompt":"输入通过{method}发送的验证码:","error_invalid_id":"无效 ID","file_attachment_too_large":"文件大小 {size} 超过 {limit} 限制。","forgot_password_link":"忘记密码?","full_name_prompt":"全名,例如张伟","granted_permissions":"已授予","group_has_no_members":"无成员","group_user_id_prompt":"群组或用户 ID","image_caption_prompt":"图片标题","invalid_content":"无效内容","invalid_security_token":"无效的安全令牌","label_client":"客户端:","label_content_type":"内容类型:","label_default_access_mode":"蓦然访问模式:","label_file_name":"文件名:","label_group_members":"群组成员:","label_incognito_mode":"无痕模式:","label_message_sound":"消息提示音:","label_muting_topic":"已静音:","label_other_user":"其他","label_password":"密码","label_permissions":"权限:","label_private":"私人评论","label_push_notifications":"通知提醒:","label_push_notifications_disabled":"通知提醒(需要 HTTPS):","label_reset_password":"发送密码重置邮件:","label_sdk":"开发包:","label_server":"服务器:","label_server_address":"服务器地址:","label_server_to_use":"使用的服务器:","label_size":"大小:","label_topic_name":"名称","label_user_contacts":"往来:","label_user_id":"地址:","label_wire_transport":"线路传输:","label_you":"你:","label_your_name":"你的姓名","label_your_permissions":"你的权限:","last_seen_timestamp":"最后可见","leave_chat_warning":"您确定要退出此对话吗?","link_contact_us":"联系我们","link_privacy_policy":"隐私政策","link_terms_of_service":"条款和条件","login_prompt":"登录","menu_item_archive_topic":"归档","menu_item_block":"屏蔽","menu_item_clear_messages":"清空消息","menu_item_clear_messages_for_all":"全部清除","menu_item_delete":"删除","menu_item_delete_for_all":"全部删除","menu_item_delete_topic":"删除","menu_item_edit_permissions":"编辑权限","menu_item_info":"信息","menu_item_member_delete":"移除","menu_item_mute":"静音","menu_item_restore_topic":"从存档中恢复","menu_item_send_retry":"重试","menu_item_unblock":"取消屏蔽","menu_item_unmute":"取消静音","message_sending":"正在发送...","message_sending_failed":"发送失败","messages_not_readable":"无消息访问权限","messaging_disabled_prompt":"消息已禁用","more_online_members":"还有{overflow}个","new_message_prompt":"新消息","new_password_placeholder":"输入新密码","no_connection":"无连接","no_contacts":"你尚无联系人 (._.)","numeric_confirmation_code_prompt":"仅数字","online_now":"在线","password_prompt":"密码","password_unchanged_prompt":"未改变","peers_messaging_disabled":"成员间消息已禁用。","permission_admin":"批准 ({val})","permission_delete":"删除 ({val})","permission_join":"加入 ({val})","permission_owner":"所有者 ({val})","permission_pres":"获取通知 ({val})","permission_read":"读取 ({val})","permission_share":"分享 ({val})","permission_write":"写入 ({val})","phone_dative":"电话","private_editing_placeholder":"仅自己可见","push_init_failed":"初始化推送通知失败","reconnect_countdown":"连接已断开。{seconds} 秒后重新连接…","reconnect_now":"立即尝试","reload_update":"重新载入","report_chat_warning":"您确定要停止并报告此对话吗?","requested_permissions":"已请求","save_attachment":"保存","search_for_contacts":"使用搜索寻找联系人","search_no_results":"搜索返回任何结果","search_placeholder":"列表如 email:alice@example.com, tel:+17025550003...","sidepanel_title_acc_notifications":"通知","sidepanel_title_acc_support":"支持","sidepanel_title_account_settings":"帐号设定","sidepanel_title_archive":"已存档会话","sidepanel_title_blocked":"被阻止的聊天","sidepanel_title_cred":"确认凭据","sidepanel_title_login":"登录","sidepanel_title_newtpk":"开始新会话","sidepanel_title_register":"创建账户","sidepanel_title_reset":"重置密码","sidepanel_title_settings":"设置","stay_logged_in":"保持登录","tabtitle_find_user":"搜索","tabtitle_group_by_id":"通过 id","tabtitle_new_group":"新群组","tags_editor_no_tags":"添加一些标签","tags_not_found":"尚未定义标签。添加一些。","title_all_contacts":"全部联系人","title_group_members":"群组成员","title_manage_tags":"管理标签","title_not_found":"无法找到","title_permissions":"权限","title_tag_manager":"标签(用户发现)","topic_block_warning":"您确定要阻止此对话吗?","topic_delete_warning":"您确定要删除此对话吗?","topic_name_editing_placeholder":"群组自由格式名称","unnamed_topic":"未命名","update_available":"更新可用。","upload_finishing":"正在结束...","user_not_found":"未找到","validate_credential_action":"确认","description_editing_placeholder":"说明(可选)","label_description":"说明","button_security":"安全","panel_title_crop":"拖动调整","panel_title_general":"常用设定","panel_title_members":"成员","panel_title_security":"安全","panel_title_info":"信息","permissions_anonymous":"匿名","permissions_authenticated":"已认证","topic_delete":"删除聊天","permissions_user":"用户权限","password_reset_email_sent":"一封电子邮件已发送至 {email}。按照电子邮件中的说明重置密码。","label_unarchive_topic":"存档:","menu_item_reply":"回复","menu_item_forward":"重定向","forward_to":"重定向消息","forward_to_search_placeholder":"搜索联系人","label_new_password":"新密码","drafty_unknown":"不支持"}}'); /***/ }) /******/ }); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ var cachedModule = __webpack_module_cache__[moduleId]; /******/ if (cachedModule !== undefined) { /******/ return cachedModule.exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = __webpack_module_cache__[moduleId] = { /******/ // no module.id needed /******/ // no module.loaded needed /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /************************************************************************/ /******/ /* webpack/runtime/compat get default export */ /******/ (() => { /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = (module) => { /******/ var getter = module && module.__esModule ? /******/ () => (module['default']) : /******/ () => (module); /******/ __webpack_require__.d(getter, { a: getter }); /******/ return getter; /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports /******/ __webpack_require__.d = (exports, definition) => { /******/ for(var key in definition) { /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/global */ /******/ (() => { /******/ __webpack_require__.g = (function() { /******/ if (typeof globalThis === 'object') return globalThis; /******/ try { /******/ return this || new Function('return this')(); /******/ } catch (e) { /******/ if (typeof window === 'object') return window; /******/ } /******/ })(); /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ (() => { /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) /******/ })(); /******/ /******/ /* webpack/runtime/make namespace object */ /******/ (() => { /******/ // define __esModule on exports /******/ __webpack_require__.r = (exports) => { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ })(); /******/ /************************************************************************/ var __webpack_exports__ = {}; // This entry need to be wrapped in an IIFE because it need to be in strict mode. (() => { "use strict"; /*!**********************!*\ !*** ./src/index.js ***! \**********************/ __webpack_require__.r(__webpack_exports__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-dom */ "react-dom"); /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _messages_json__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./messages.json */ "./src/messages.json"); /* harmony import */ var _views_tinode_web_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./views/tinode-web.jsx */ "./src/views/tinode-web.jsx"); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./lib/navigation.js */ "./src/lib/navigation.js"); const { params } = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_5__["default"].parseUrlHash(window.location.hash); const language = params && params.hl || navigator.languages && navigator.languages[0] || navigator.language || navigator.userLanguage || 'en'; const baseLanguage = language.toLowerCase().split(/[-_]/)[0]; const htmlLang = _messages_json__WEBPACK_IMPORTED_MODULE_3__[language] ? language : _messages_json__WEBPACK_IMPORTED_MODULE_3__[baseLanguage] ? baseLanguage : 'en'; const messages = _messages_json__WEBPACK_IMPORTED_MODULE_3__[htmlLang]; document.getElementsByTagName('html')[0].setAttribute('lang', htmlLang); react_dom__WEBPACK_IMPORTED_MODULE_1___default().render(react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().StrictMode), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_2__.IntlProvider, { locale: language, messages: messages, textComponent: (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment) }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_views_tinode_web_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], null))), document.getElementById('mountPoint')); })(); /******/ })() ; //# sourceMappingURL=index.dev.js.map