Import log instead of using it off of window
This commit is contained in:
parent
8eb0dd3116
commit
65ddf0a9e8
155 changed files with 3654 additions and 3433 deletions
|
@ -11,7 +11,7 @@
|
|||
window.Whisper.Database.nolog = true;
|
||||
|
||||
Whisper.Database.handleDOMException = (prefix, error, reject) => {
|
||||
window.log.error(
|
||||
window.SignalWindow.log.error(
|
||||
`${prefix}:`,
|
||||
error && error.name,
|
||||
error && error.message,
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
/* global $: false */
|
||||
/* global Whisper: false */
|
||||
|
||||
$(document).on('keydown', e => {
|
||||
if (e.keyCode === 27) {
|
||||
|
@ -16,5 +15,5 @@ $body.addClass(`${window.theme}-theme`);
|
|||
// got.js appears to need this to successfully submit debug logs to the cloud
|
||||
window.setImmediate = window.nodeSetImmediate;
|
||||
|
||||
window.view = new Whisper.DebugLogView();
|
||||
window.view = new window.Whisper.DebugLogView();
|
||||
window.view.$el.appendTo($body);
|
||||
|
|
|
@ -13,11 +13,13 @@
|
|||
|
||||
async function destroyExpiredMessages() {
|
||||
try {
|
||||
window.log.info('destroyExpiredMessages: Loading messages...');
|
||||
window.SignalWindow.log.info(
|
||||
'destroyExpiredMessages: Loading messages...'
|
||||
);
|
||||
const messages = await window.Signal.Data.getExpiredMessages({
|
||||
MessageCollection: Whisper.MessageCollection,
|
||||
});
|
||||
window.log.info(
|
||||
window.SignalWindow.log.info(
|
||||
`destroyExpiredMessages: found ${messages.length} messages to expire`
|
||||
);
|
||||
|
||||
|
@ -38,7 +40,7 @@
|
|||
await Promise.all(messageCleanup);
|
||||
|
||||
inMemoryMessages.forEach(message => {
|
||||
window.log.info('Message expired', {
|
||||
window.SignalWindow.log.info('Message expired', {
|
||||
sentAt: message.get('sent_at'),
|
||||
});
|
||||
|
||||
|
@ -50,23 +52,27 @@
|
|||
}
|
||||
});
|
||||
} catch (error) {
|
||||
window.log.error(
|
||||
window.SignalWindow.log.error(
|
||||
'destroyExpiredMessages: Error deleting expired messages',
|
||||
error && error.stack ? error.stack : error
|
||||
);
|
||||
}
|
||||
|
||||
window.log.info('destroyExpiredMessages: complete');
|
||||
window.SignalWindow.log.info('destroyExpiredMessages: complete');
|
||||
checkExpiringMessages();
|
||||
}
|
||||
|
||||
let timeout;
|
||||
async function checkExpiringMessages() {
|
||||
window.log.info('checkExpiringMessages: checking for expiring messages');
|
||||
window.SignalWindow.log.info(
|
||||
'checkExpiringMessages: checking for expiring messages'
|
||||
);
|
||||
|
||||
const soonestExpiry = await window.Signal.Data.getSoonestMessageExpiry();
|
||||
if (!soonestExpiry) {
|
||||
window.log.info('checkExpiringMessages: found no messages to expire');
|
||||
window.SignalWindow.log.info(
|
||||
'checkExpiringMessages: found no messages to expire'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -82,7 +88,7 @@
|
|||
wait = 2147483647;
|
||||
}
|
||||
|
||||
window.log.info(
|
||||
window.SignalWindow.log.info(
|
||||
`checkExpiringMessages: next message expires ${new Date(
|
||||
soonestExpiry
|
||||
).toISOString()}; waiting ${wait} ms before clearing`
|
||||
|
|
|
@ -13,7 +13,9 @@
|
|||
|
||||
async function eraseTapToViewMessages() {
|
||||
try {
|
||||
window.log.info('eraseTapToViewMessages: Loading messages...');
|
||||
window.SignalWindow.log.info(
|
||||
'eraseTapToViewMessages: Loading messages...'
|
||||
);
|
||||
const messages = await window.Signal.Data.getTapToViewMessagesNeedingErase(
|
||||
{
|
||||
MessageCollection: Whisper.MessageCollection,
|
||||
|
@ -24,7 +26,7 @@
|
|||
messages.map(async fromDB => {
|
||||
const message = MessageController.register(fromDB.id, fromDB);
|
||||
|
||||
window.log.info(
|
||||
window.SignalWindow.log.info(
|
||||
'eraseTapToViewMessages: message data erased',
|
||||
message.idForLogging()
|
||||
);
|
||||
|
@ -33,13 +35,13 @@
|
|||
})
|
||||
);
|
||||
} catch (error) {
|
||||
window.log.error(
|
||||
window.SignalWindow.log.error(
|
||||
'eraseTapToViewMessages: Error erasing messages',
|
||||
error && error.stack ? error.stack : error
|
||||
);
|
||||
}
|
||||
|
||||
window.log.info('eraseTapToViewMessages: complete');
|
||||
window.SignalWindow.log.info('eraseTapToViewMessages: complete');
|
||||
}
|
||||
|
||||
let timeout;
|
||||
|
@ -57,7 +59,7 @@
|
|||
const nextCheck = receivedAt + THIRTY_DAYS;
|
||||
|
||||
Whisper.TapToViewMessagesListener.nextCheck = nextCheck;
|
||||
window.log.info(
|
||||
window.SignalWindow.log.info(
|
||||
'checkTapToViewMessages: next check at',
|
||||
new Date(nextCheck).toISOString()
|
||||
);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
/* eslint-env node */
|
||||
/* global log, Signal */
|
||||
/* global Signal, window */
|
||||
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
@ -58,7 +58,7 @@ exports.createConversation = async ({
|
|||
await Promise.all(
|
||||
range(0, numMessages).map(async index => {
|
||||
await sleep(index * 100);
|
||||
log.info(`Create message ${index + 1}`);
|
||||
window.SignalWindow.log.info(`Create message ${index + 1}`);
|
||||
const message = await createRandomMessage({ conversationId });
|
||||
return Signal.Data.saveMessage(message);
|
||||
})
|
||||
|
@ -108,7 +108,10 @@ const createRandomMessage = async ({ conversationId } = {}) => {
|
|||
};
|
||||
|
||||
const message = _createMessage({ commonProperties, conversationId, type });
|
||||
return Message.initializeSchemaVersion({ message, logger: log });
|
||||
return Message.initializeSchemaVersion({
|
||||
message,
|
||||
logger: window.SignalWindow.log,
|
||||
});
|
||||
};
|
||||
|
||||
const _createMessage = ({ commonProperties, conversationId, type } = {}) => {
|
||||
|
|
|
@ -3,9 +3,6 @@
|
|||
|
||||
/* eslint-env node, browser */
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
const log = typeof window !== 'undefined' ? window.log : console;
|
||||
|
||||
exports.setup = (locale, messages) => {
|
||||
if (!locale) {
|
||||
throw new Error('i18n: locale parameter is required');
|
||||
|
@ -15,6 +12,10 @@ exports.setup = (locale, messages) => {
|
|||
}
|
||||
|
||||
function getMessage(key, substitutions) {
|
||||
// eslint-disable-next-line no-console
|
||||
const log =
|
||||
typeof window !== 'undefined' ? window.SignalWindow.log : console;
|
||||
|
||||
const entry = messages[key];
|
||||
if (!entry) {
|
||||
log.error(
|
||||
|
|
|
@ -16,7 +16,7 @@ class IdleDetector extends EventEmitter {
|
|||
}
|
||||
|
||||
start() {
|
||||
window.log.info('Start idle detector');
|
||||
window.SignalWindow.log.info('Start idle detector');
|
||||
this._scheduleNextCallback();
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ class IdleDetector extends EventEmitter {
|
|||
return;
|
||||
}
|
||||
|
||||
window.log.info('Stop idle detector');
|
||||
window.SignalWindow.log.info('Stop idle detector');
|
||||
this._clearScheduledCallbacks();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,9 @@ module.exports = {
|
|||
};
|
||||
|
||||
async function doesDatabaseExist() {
|
||||
window.log.info('Checking for the existence of IndexedDB data...');
|
||||
window.SignalWindow.log.info(
|
||||
'Checking for the existence of IndexedDB data...'
|
||||
);
|
||||
return new Promise((resolve, reject) => {
|
||||
const { id } = Whisper.Database;
|
||||
const req = window.indexedDB.open(id);
|
||||
|
@ -20,7 +22,7 @@ async function doesDatabaseExist() {
|
|||
let existed = true;
|
||||
|
||||
setTimeout(() => {
|
||||
window.log.warn(
|
||||
window.SignalWindow.log.warn(
|
||||
'doesDatabaseExist: Timed out attempting to check IndexedDB status'
|
||||
);
|
||||
return resolve(false);
|
||||
|
@ -41,6 +43,8 @@ async function doesDatabaseExist() {
|
|||
}
|
||||
|
||||
function removeDatabase() {
|
||||
window.log.info(`Deleting IndexedDB database '${Whisper.Database.id}'`);
|
||||
window.SignalWindow.log.info(
|
||||
`Deleting IndexedDB database '${Whisper.Database.id}'`
|
||||
);
|
||||
window.indexedDB.deleteDatabase(Whisper.Database.id);
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ exports.processNext = async ({
|
|||
}
|
||||
);
|
||||
} catch (error) {
|
||||
window.log.error(
|
||||
window.SignalWindow.log.error(
|
||||
'processNext error:',
|
||||
error && error.stack ? error.stack : error
|
||||
);
|
||||
|
|
|
@ -53,7 +53,7 @@ function buildAvatarUpdater({ field }) {
|
|||
const { hash, path } = avatar;
|
||||
const exists = await doesAttachmentExist(path);
|
||||
if (!exists) {
|
||||
window.log.warn(
|
||||
window.SignalWindow.log.warn(
|
||||
`Conversation.buildAvatarUpdater: attachment ${path} did not exist`
|
||||
);
|
||||
}
|
||||
|
|
|
@ -133,7 +133,7 @@
|
|||
}
|
||||
|
||||
if (status.type !== 'ok') {
|
||||
window.log.info(
|
||||
window.SignalWindow.log.info(
|
||||
`Not updating notifications; notification status is ${status.type}. ${
|
||||
status.shouldClearNotifications ? 'Also clearing notifications' : ''
|
||||
}`
|
||||
|
@ -145,7 +145,7 @@
|
|||
|
||||
return;
|
||||
}
|
||||
window.log.info('Showing a notification');
|
||||
window.SignalWindow.log.info('Showing a notification');
|
||||
|
||||
let notificationTitle;
|
||||
let notificationMessage;
|
||||
|
@ -191,7 +191,7 @@
|
|||
}
|
||||
} else {
|
||||
if (userSetting !== SettingNames.NO_NAME_OR_MESSAGE) {
|
||||
window.log.error(
|
||||
window.SignalWindow.log.error(
|
||||
`Error: Unknown user notification setting: '${userSetting}'`
|
||||
);
|
||||
}
|
||||
|
@ -216,7 +216,7 @@
|
|||
);
|
||||
},
|
||||
clear() {
|
||||
window.log.info('Removing notification');
|
||||
window.SignalWindow.log.info('Removing notification');
|
||||
this.notificationData = null;
|
||||
this.update();
|
||||
},
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
a2 = args[1],
|
||||
a3 = args[2];
|
||||
const logError = function (error) {
|
||||
window.log.error(
|
||||
window.SignalWindow.log.error(
|
||||
'Model caught error triggering',
|
||||
name,
|
||||
'event:',
|
||||
|
|
|
@ -21,13 +21,13 @@
|
|||
}
|
||||
|
||||
async function run() {
|
||||
window.log.info('Rotating signed prekey...');
|
||||
window.SignalWindow.log.info('Rotating signed prekey...');
|
||||
try {
|
||||
await getAccountManager().rotateSignedPreKey();
|
||||
scheduleNextRotation();
|
||||
setTimeoutForNextRun();
|
||||
} catch (error) {
|
||||
window.log.error(
|
||||
window.SignalWindow.log.error(
|
||||
'rotateSignedPrekey() failed. Trying again in five minutes'
|
||||
);
|
||||
setTimeout(setTimeoutForNextRun, 5 * 60 * 1000);
|
||||
|
@ -38,7 +38,7 @@
|
|||
if (navigator.onLine) {
|
||||
run();
|
||||
} else {
|
||||
window.log.info(
|
||||
window.SignalWindow.log.info(
|
||||
'We are offline; keys will be rotated when we are next online'
|
||||
);
|
||||
const listener = () => {
|
||||
|
@ -53,7 +53,7 @@
|
|||
const now = Date.now();
|
||||
const time = storage.get('nextSignedKeyRotationTime', now);
|
||||
|
||||
window.log.info(
|
||||
window.SignalWindow.log.info(
|
||||
'Next signed key rotation scheduled for',
|
||||
new Date(time).toISOString()
|
||||
);
|
||||
|
@ -71,7 +71,9 @@
|
|||
Whisper.RotateSignedPreKeyListener = {
|
||||
init(events, newVersion) {
|
||||
if (initComplete) {
|
||||
window.log.info('Rotate signed prekey listener: Already initialized');
|
||||
window.SignalWindow.log.info(
|
||||
'Rotate signed prekey listener: Already initialized'
|
||||
);
|
||||
return;
|
||||
}
|
||||
initComplete = true;
|
||||
|
|
|
@ -1,201 +0,0 @@
|
|||
// Copyright 2015-2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
/* global i18n, Whisper, $ */
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
(function () {
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
// This enum-like object describes the load state of `DebugLogView`. It's designed to be
|
||||
// unidirectional; `NotStarted` → `Started` → `LogsFetchedButNotInTextarea`, etc.
|
||||
const LoadState = {
|
||||
NotStarted: 0,
|
||||
Started: 1,
|
||||
LogsFetchedButNotInTextarea: 2,
|
||||
PuttingLogsInTextarea: 3,
|
||||
LogsInTextarea: 4,
|
||||
};
|
||||
|
||||
Whisper.LoadingFullLogsToast = Whisper.ToastView.extend({
|
||||
render_attributes() {
|
||||
return { toastMessage: i18n('loading') };
|
||||
},
|
||||
});
|
||||
|
||||
Whisper.LinkedCopiedToast = Whisper.ToastView.extend({
|
||||
render_attributes() {
|
||||
return { toastMessage: i18n('debugLogLinkCopied') };
|
||||
},
|
||||
});
|
||||
|
||||
Whisper.DebugLogLinkView = Whisper.View.extend({
|
||||
template: () => $('#debug-log-link').html(),
|
||||
initialize(options) {
|
||||
this.url = options.url;
|
||||
},
|
||||
events: {
|
||||
'click .copy': 'copy',
|
||||
},
|
||||
render_attributes() {
|
||||
return {
|
||||
url: this.url,
|
||||
reportIssue: i18n('reportIssue'),
|
||||
debugLogCopy: i18n('debugLogCopy'),
|
||||
debugLogCopyAlt: i18n('debugLogCopyAlt'),
|
||||
};
|
||||
},
|
||||
copy(e) {
|
||||
e.preventDefault();
|
||||
window.copyText(e.currentTarget.href);
|
||||
Whisper.ToastView.show(Whisper.LinkedCopiedToast, document.body);
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* The bulk of the logic in this view involves grabbing the logs from disk and putting
|
||||
* them in a `<textarea>`. The first part isn't instant but is reasonably fast; setting
|
||||
* the textarea's `value` takes a long time.
|
||||
*
|
||||
* After loading the logs into memory, we only put a small number of lines into the
|
||||
* textarea. If the user clicks or scrolls the textarea, we pull the full logs, which
|
||||
* can cause the system to lock up for a bit.
|
||||
*
|
||||
* Ideally, we'd only show a sampling of the logs and allow the user to download and
|
||||
* edit them in their own editor. This is mostly a stopgap solution.
|
||||
*/
|
||||
Whisper.DebugLogView = Whisper.View.extend({
|
||||
template: () => $('#debug-log').html(),
|
||||
className: 'debug-log modal',
|
||||
initialize() {
|
||||
this.render();
|
||||
|
||||
this.textarea = this.$('.textarea').get(0);
|
||||
if (!this.textarea) {
|
||||
throw new Error('textarea not found');
|
||||
}
|
||||
this.textarea.setAttribute('readonly', '');
|
||||
|
||||
this.loadState = LoadState.NotStarted;
|
||||
this.putFullLogsInTextareaPlease = false;
|
||||
|
||||
this.fetchLogs();
|
||||
},
|
||||
events: {
|
||||
'click .textarea': 'putFullLogsInTextarea',
|
||||
'scroll .textarea': 'putFullLogsInTextarea',
|
||||
'wheel .textarea': 'putFullLogsInTextarea',
|
||||
'click .submit': 'submit',
|
||||
'click .close': 'close',
|
||||
},
|
||||
render_attributes: {
|
||||
title: i18n('submitDebugLog'),
|
||||
cancel: i18n('cancel'),
|
||||
submit: i18n('submit'),
|
||||
close: i18n('gotIt'),
|
||||
debugLogExplanation: i18n('debugLogExplanation'),
|
||||
},
|
||||
async fetchLogs() {
|
||||
if (this.loadState !== LoadState.NotStarted) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadState = LoadState.Started;
|
||||
this.textarea.value = i18n('loading');
|
||||
this.$('.submit').attr('disabled', 'disabled');
|
||||
|
||||
this.logText = await window.log.fetch();
|
||||
this.loadState = LoadState.LogsFetchedButNotInTextarea;
|
||||
|
||||
// This number is somewhat arbitrary; we want to show enough that it's clear that
|
||||
// we need to scroll, but not so many that things get slow.
|
||||
const linesToShow = Math.ceil(Math.min(window.innerHeight, 2000) / 5);
|
||||
this.textarea.value = this.logText
|
||||
.split(/\n/g, linesToShow)
|
||||
.concat(['', i18n('loading')])
|
||||
.join('\n');
|
||||
|
||||
this.$('.submit').removeAttr('disabled');
|
||||
|
||||
if (this.putFullLogsInTextareaPlease) {
|
||||
this.putFullLogsInTextarea();
|
||||
}
|
||||
},
|
||||
putFullLogsInTextarea() {
|
||||
switch (this.loadState) {
|
||||
case LoadState.NotStarted:
|
||||
case LoadState.Started:
|
||||
this.putFullLogsInTextareaPlease = true;
|
||||
break;
|
||||
case LoadState.LogsInTextarea:
|
||||
case LoadState.PuttingLogsInTextarea:
|
||||
break;
|
||||
case LoadState.LogsFetchedButNotInTextarea:
|
||||
if (!this.logText) {
|
||||
throw new Error('Expected log text to be present');
|
||||
}
|
||||
this.loadState = LoadState.PuttingLogsInTextarea;
|
||||
Whisper.ToastView.show(Whisper.LoadingFullLogsToast, document.body);
|
||||
setTimeout(() => {
|
||||
this.textarea.value = this.logText;
|
||||
this.textarea.removeAttribute('readonly');
|
||||
this.loadState = LoadState.LogsInTextarea;
|
||||
}, 0);
|
||||
break;
|
||||
default:
|
||||
// When we can, we should make this throw a `missingCaseError`.
|
||||
break;
|
||||
}
|
||||
},
|
||||
close() {
|
||||
window.closeDebugLog();
|
||||
},
|
||||
async submit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
let text;
|
||||
switch (this.loadState) {
|
||||
case LoadState.NotStarted:
|
||||
case LoadState.Started:
|
||||
return;
|
||||
case LoadState.LogsFetchedButNotInTextarea:
|
||||
text = this.logText;
|
||||
break;
|
||||
case LoadState.LogsInTextarea:
|
||||
text = this.textarea.value;
|
||||
break;
|
||||
default:
|
||||
// When we can, we should make this throw a `missingCaseError`.
|
||||
return;
|
||||
}
|
||||
|
||||
if (text.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$('.buttons, .textarea').remove();
|
||||
this.$('.result').addClass('loading');
|
||||
|
||||
try {
|
||||
const publishedLogURL = await window.log.publish(
|
||||
text,
|
||||
window.getVersion()
|
||||
);
|
||||
const view = new Whisper.DebugLogLinkView({
|
||||
url: publishedLogURL,
|
||||
el: this.$('.result'),
|
||||
});
|
||||
this.$('.loading').removeClass('loading');
|
||||
view.render();
|
||||
this.$('.link').focus().select();
|
||||
} catch (error) {
|
||||
window.log.error(
|
||||
'DebugLogView error:',
|
||||
error && error.stack ? error.stack : error
|
||||
);
|
||||
this.$('.loading').removeClass('loading');
|
||||
this.$('.result').text(i18n('debugLogError'));
|
||||
}
|
||||
},
|
||||
});
|
||||
})();
|
|
@ -1,242 +0,0 @@
|
|||
// Copyright 2014-2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
/* global
|
||||
ConversationController,
|
||||
i18n,
|
||||
Whisper,
|
||||
Signal,
|
||||
$
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
(function () {
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
Whisper.StickerPackInstallFailedToast = Whisper.ToastView.extend({
|
||||
render_attributes() {
|
||||
return { toastMessage: i18n('stickers--toast--InstallFailed') };
|
||||
},
|
||||
});
|
||||
|
||||
Whisper.ConversationStack = Whisper.View.extend({
|
||||
className: 'conversation-stack',
|
||||
lastConversation: null,
|
||||
open(conversation, messageId) {
|
||||
const id = `conversation-${conversation.cid}`;
|
||||
if (id !== this.el.lastChild.id) {
|
||||
const view = new Whisper.ConversationView({
|
||||
model: conversation,
|
||||
});
|
||||
this.listenTo(conversation, 'unload', () =>
|
||||
this.onUnload(conversation)
|
||||
);
|
||||
view.$el.appendTo(this.el);
|
||||
|
||||
if (this.lastConversation && this.lastConversation !== conversation) {
|
||||
this.lastConversation.trigger(
|
||||
'unload',
|
||||
'opened another conversation'
|
||||
);
|
||||
this.stopListening(this.lastConversation);
|
||||
this.lastConversation = null;
|
||||
}
|
||||
|
||||
this.lastConversation = conversation;
|
||||
conversation.trigger('opened', messageId);
|
||||
} else if (messageId) {
|
||||
conversation.trigger('scroll-to-message', messageId);
|
||||
}
|
||||
|
||||
// Make sure poppers are positioned properly
|
||||
window.dispatchEvent(new Event('resize'));
|
||||
},
|
||||
unload() {
|
||||
const { lastConversation } = this;
|
||||
if (!lastConversation) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastConversation.trigger('unload', 'force unload requested');
|
||||
},
|
||||
onUnload(conversation) {
|
||||
if (this.lastConversation === conversation) {
|
||||
this.stopListening(this.lastConversation);
|
||||
this.lastConversation = null;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Whisper.AppLoadingScreen = Whisper.View.extend({
|
||||
template: () => $('#app-loading-screen').html(),
|
||||
className: 'app-loading-screen',
|
||||
updateProgress(count) {
|
||||
if (count > 0) {
|
||||
const message = i18n('loadingMessages', [count.toString()]);
|
||||
this.$('.message').text(message);
|
||||
}
|
||||
},
|
||||
render_attributes: {
|
||||
message: i18n('loading'),
|
||||
},
|
||||
});
|
||||
|
||||
Whisper.InboxView = Whisper.View.extend({
|
||||
template: () => $('#two-column').html(),
|
||||
className: 'inbox index',
|
||||
initialize(options = {}) {
|
||||
this.ready = false;
|
||||
this.render();
|
||||
|
||||
this.conversation_stack = new Whisper.ConversationStack({
|
||||
el: this.$('.conversation-stack'),
|
||||
model: { window: options.window },
|
||||
});
|
||||
|
||||
this.renderWhatsNew();
|
||||
|
||||
Whisper.events.on('refreshConversation', ({ oldId, newId }) => {
|
||||
const convo = this.conversation_stack.lastConversation;
|
||||
if (convo && convo.get('id') === oldId) {
|
||||
this.conversation_stack.open(newId);
|
||||
}
|
||||
});
|
||||
|
||||
// Close current opened conversation to reload the group information once
|
||||
// linked.
|
||||
Whisper.events.on('setupAsNewDevice', () => {
|
||||
this.conversation_stack.unload();
|
||||
});
|
||||
|
||||
window.Whisper.events.on('showConversation', async (id, messageId) => {
|
||||
const conversation = await ConversationController.getOrCreateAndWait(
|
||||
id,
|
||||
'private'
|
||||
);
|
||||
|
||||
conversation.setMarkedUnread(false);
|
||||
|
||||
const { openConversationExternal } = window.reduxActions.conversations;
|
||||
if (openConversationExternal) {
|
||||
openConversationExternal(conversation.id, messageId);
|
||||
}
|
||||
|
||||
this.conversation_stack.open(conversation, messageId);
|
||||
this.focusConversation();
|
||||
});
|
||||
|
||||
window.Whisper.events.on('loadingProgress', count => {
|
||||
const view = this.appLoadingScreen;
|
||||
if (view) {
|
||||
view.updateProgress(count);
|
||||
}
|
||||
});
|
||||
|
||||
if (!options.initialLoadComplete) {
|
||||
this.appLoadingScreen = new Whisper.AppLoadingScreen();
|
||||
this.appLoadingScreen.render();
|
||||
this.appLoadingScreen.$el.prependTo(this.el);
|
||||
this.startConnectionListener();
|
||||
} else {
|
||||
this.setupLeftPane();
|
||||
}
|
||||
|
||||
Whisper.events.on('pack-install-failed', () => {
|
||||
const toast = new Whisper.StickerPackInstallFailedToast();
|
||||
toast.$el.appendTo(this.$el);
|
||||
toast.render();
|
||||
});
|
||||
},
|
||||
render_attributes: {
|
||||
welcomeToSignal: i18n('welcomeToSignal'),
|
||||
// TODO DESKTOP-1451: add back the selectAContact message
|
||||
selectAContact: '',
|
||||
},
|
||||
events: {
|
||||
click: 'onClick',
|
||||
},
|
||||
renderWhatsNew() {
|
||||
if (this.whatsNewView) {
|
||||
return;
|
||||
}
|
||||
this.whatsNewView = new Whisper.ReactWrapperView({
|
||||
Component: window.Signal.Components.WhatsNew,
|
||||
props: {
|
||||
i18n: window.i18n,
|
||||
},
|
||||
});
|
||||
this.$('.whats-new-placeholder').append(this.whatsNewView.el);
|
||||
},
|
||||
setupLeftPane() {
|
||||
if (this.leftPaneView) {
|
||||
return;
|
||||
}
|
||||
this.leftPaneView = new Whisper.ReactWrapperView({
|
||||
className: 'left-pane-wrapper',
|
||||
JSX: Signal.State.Roots.createLeftPane(window.reduxStore),
|
||||
});
|
||||
|
||||
this.$('.left-pane-placeholder').append(this.leftPaneView.el);
|
||||
},
|
||||
startConnectionListener() {
|
||||
this.interval = setInterval(() => {
|
||||
const status = window.getSocketStatus();
|
||||
switch (status) {
|
||||
case 'CONNECTING':
|
||||
break;
|
||||
case 'OPEN':
|
||||
clearInterval(this.interval);
|
||||
// if we've connected, we can wait for real empty event
|
||||
this.interval = null;
|
||||
break;
|
||||
case 'CLOSING':
|
||||
case 'CLOSED':
|
||||
clearInterval(this.interval);
|
||||
this.interval = null;
|
||||
// if we failed to connect, we pretend we got an empty event
|
||||
this.onEmpty();
|
||||
break;
|
||||
default:
|
||||
window.log.warn(
|
||||
`startConnectionListener: Found unexpected socket status ${status}; calling onEmpty() manually.`
|
||||
);
|
||||
this.onEmpty();
|
||||
break;
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
onEmpty() {
|
||||
this.setupLeftPane();
|
||||
|
||||
const view = this.appLoadingScreen;
|
||||
if (view) {
|
||||
this.appLoadingScreen = null;
|
||||
view.remove();
|
||||
|
||||
const searchInput = document.querySelector(
|
||||
'.module-main-header__search__input'
|
||||
);
|
||||
if (searchInput && searchInput.focus) {
|
||||
searchInput.focus();
|
||||
}
|
||||
}
|
||||
},
|
||||
focusConversation(e) {
|
||||
if (e && this.$(e.target).closest('.placeholder').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$('#header, .gutter').addClass('inactive');
|
||||
this.$('.conversation-stack').removeClass('inactive');
|
||||
},
|
||||
closeRecording(e) {
|
||||
if (e && this.$(e.target).closest('.capture-audio').length > 0) {
|
||||
return;
|
||||
}
|
||||
this.$('.conversation:first .recorder').trigger('close');
|
||||
},
|
||||
onClick(e) {
|
||||
this.closeRecording(e);
|
||||
},
|
||||
});
|
||||
})();
|
|
@ -1,238 +0,0 @@
|
|||
// Copyright 2015-2020 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
/* global Whisper, i18n, getAccountManager, $, textsecure, QRCode */
|
||||
|
||||
/* eslint-disable more/no-then */
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
(function () {
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
const Steps = {
|
||||
INSTALL_SIGNAL: 2,
|
||||
SCAN_QR_CODE: 3,
|
||||
ENTER_NAME: 4,
|
||||
PROGRESS_BAR: 5,
|
||||
TOO_MANY_DEVICES: 'TooManyDevices',
|
||||
NETWORK_ERROR: 'NetworkError',
|
||||
};
|
||||
|
||||
const DEVICE_NAME_SELECTOR = 'input.device-name';
|
||||
const CONNECTION_ERROR = -1;
|
||||
const TOO_MANY_DEVICES = 411;
|
||||
const TOO_OLD = 409;
|
||||
|
||||
Whisper.InstallView = Whisper.View.extend({
|
||||
template: () => $('#link-flow-template').html(),
|
||||
className: 'main full-screen-flow',
|
||||
events: {
|
||||
'click .try-again': 'connect',
|
||||
'click .second': 'shutdown',
|
||||
// the actual next step happens in confirmNumber() on submit form #link-phone
|
||||
},
|
||||
initialize(options = {}) {
|
||||
window.readyForUpdates();
|
||||
|
||||
this.selectStep(Steps.SCAN_QR_CODE);
|
||||
this.connect();
|
||||
this.on('disconnected', this.reconnect);
|
||||
|
||||
// Keep data around if it's a re-link, or the middle of a light import
|
||||
this.shouldRetainData =
|
||||
window.Signal.Util.Registration.everDone() || options.hasExistingData;
|
||||
},
|
||||
render_attributes() {
|
||||
let errorMessage;
|
||||
let errorButton = i18n('installTryAgain');
|
||||
let errorSecondButton = null;
|
||||
|
||||
if (this.error) {
|
||||
if (
|
||||
this.error.name === 'HTTPError' &&
|
||||
this.error.code === TOO_MANY_DEVICES
|
||||
) {
|
||||
errorMessage = i18n('installTooManyDevices');
|
||||
} else if (
|
||||
this.error.name === 'HTTPError' &&
|
||||
this.error.code === TOO_OLD
|
||||
) {
|
||||
errorMessage = i18n('installTooOld');
|
||||
errorButton = i18n('upgrade');
|
||||
errorSecondButton = i18n('quit');
|
||||
} else if (
|
||||
this.error.name === 'HTTPError' &&
|
||||
this.error.code === CONNECTION_ERROR
|
||||
) {
|
||||
errorMessage = i18n('installConnectionFailed');
|
||||
} else if (this.error.message === 'websocket closed') {
|
||||
// AccountManager.registerSecondDevice uses this specific
|
||||
// 'websocket closed' error message
|
||||
errorMessage = i18n('installConnectionFailed');
|
||||
}
|
||||
|
||||
return {
|
||||
isError: true,
|
||||
errorHeader: i18n('installErrorHeader'),
|
||||
errorMessage,
|
||||
errorButton,
|
||||
errorSecondButton,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
isStep3: this.step === Steps.SCAN_QR_CODE,
|
||||
linkYourPhone: i18n('linkYourPhone'),
|
||||
signalSettings: i18n('signalSettings'),
|
||||
linkedDevices: i18n('linkedDevices'),
|
||||
androidFinalStep: i18n('plusButton'),
|
||||
appleFinalStep: i18n('linkNewDevice'),
|
||||
|
||||
isStep4: this.step === Steps.ENTER_NAME,
|
||||
chooseName: i18n('chooseDeviceName'),
|
||||
finishLinkingPhoneButton: i18n('finishLinkingPhone'),
|
||||
|
||||
isStep5: this.step === Steps.PROGRESS_BAR,
|
||||
syncing: i18n('initialSync'),
|
||||
};
|
||||
},
|
||||
selectStep(step) {
|
||||
this.step = step;
|
||||
this.render();
|
||||
},
|
||||
shutdown() {
|
||||
window.shutdown();
|
||||
},
|
||||
connect() {
|
||||
if (
|
||||
this.error &&
|
||||
this.error.name === 'HTTPError' &&
|
||||
this.error.code === TOO_OLD
|
||||
) {
|
||||
window.location = 'https://signal.org/download';
|
||||
return;
|
||||
}
|
||||
|
||||
this.error = null;
|
||||
this.selectStep(Steps.SCAN_QR_CODE);
|
||||
this.clearQR();
|
||||
if (this.timeout) {
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = null;
|
||||
}
|
||||
|
||||
const accountManager = getAccountManager();
|
||||
|
||||
accountManager
|
||||
.registerSecondDevice(
|
||||
this.setProvisioningUrl.bind(this),
|
||||
this.confirmNumber.bind(this)
|
||||
)
|
||||
.catch(this.handleDisconnect.bind(this));
|
||||
},
|
||||
handleDisconnect(error) {
|
||||
window.log.error(
|
||||
'provisioning failed',
|
||||
error && error.stack ? error.stack : error
|
||||
);
|
||||
|
||||
this.error = error;
|
||||
this.render();
|
||||
|
||||
if (error.message === 'websocket closed') {
|
||||
this.trigger('disconnected');
|
||||
} else if (
|
||||
error.name !== 'HTTPError' ||
|
||||
(error.code !== CONNECTION_ERROR && error.code !== TOO_MANY_DEVICES)
|
||||
) {
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
reconnect() {
|
||||
if (this.timeout) {
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = null;
|
||||
}
|
||||
this.timeout = setTimeout(this.connect.bind(this), 10000);
|
||||
},
|
||||
clearQR() {
|
||||
this.$('#qr img').remove();
|
||||
this.$('#qr canvas').remove();
|
||||
this.$('#qr .container').show();
|
||||
this.$('#qr').removeClass('ready');
|
||||
},
|
||||
setProvisioningUrl(url) {
|
||||
if ($('#qr').length === 0) {
|
||||
window.log.error('Did not find #qr element in the DOM!');
|
||||
return;
|
||||
}
|
||||
|
||||
this.clearQR();
|
||||
this.$('#qr .container').hide();
|
||||
this.qr = new QRCode(this.$('#qr')[0]).makeCode(url);
|
||||
this.$('#qr').removeAttr('title');
|
||||
this.$('#qr').addClass('ready');
|
||||
},
|
||||
setDeviceNameDefault() {
|
||||
const deviceName = textsecure.storage.user.getDeviceName();
|
||||
|
||||
this.$(DEVICE_NAME_SELECTOR).val(deviceName || window.getHostName());
|
||||
this.$(DEVICE_NAME_SELECTOR).focus();
|
||||
},
|
||||
confirmNumber() {
|
||||
const tsp = textsecure.storage.protocol;
|
||||
|
||||
window.removeSetupMenuItems();
|
||||
this.selectStep(Steps.ENTER_NAME);
|
||||
this.setDeviceNameDefault();
|
||||
|
||||
return new Promise(resolve => {
|
||||
const onDeviceName = name => {
|
||||
this.selectStep(Steps.PROGRESS_BAR);
|
||||
|
||||
const finish = () => {
|
||||
window.Signal.Util.postLinkExperience.start();
|
||||
return resolve(name);
|
||||
};
|
||||
|
||||
// Delete all data from database unless we're in the middle
|
||||
// of a re-link, or we are finishing a light import. Without this,
|
||||
// app restarts at certain times can cause weird things to happen,
|
||||
// like data from a previous incomplete light import showing up
|
||||
// after a new install.
|
||||
if (this.shouldRetainData) {
|
||||
return finish();
|
||||
}
|
||||
|
||||
return tsp.removeAllData().then(finish, error => {
|
||||
window.log.error(
|
||||
'confirmNumber: error clearing database',
|
||||
error && error.stack ? error.stack : error
|
||||
);
|
||||
return finish();
|
||||
});
|
||||
};
|
||||
|
||||
if (window.CI) {
|
||||
onDeviceName(window.CI.deviceName);
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line consistent-return
|
||||
this.$('#link-phone').submit(e => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
let name = this.$(DEVICE_NAME_SELECTOR).val();
|
||||
name = name.replace(/\0/g, ''); // strip unicode null
|
||||
if (name.trim().length === 0) {
|
||||
this.$(DEVICE_NAME_SELECTOR).focus();
|
||||
return null;
|
||||
}
|
||||
|
||||
onDeviceName(name);
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
})();
|
|
@ -1,40 +0,0 @@
|
|||
// Copyright 2015-2020 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
/* global libphonenumber, Whisper, $ */
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
(function () {
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
Whisper.PhoneInputView = Whisper.View.extend({
|
||||
tagName: 'div',
|
||||
className: 'phone-input',
|
||||
template: () => $('#phone-number').html(),
|
||||
initialize() {
|
||||
this.$('input.number').intlTelInput();
|
||||
},
|
||||
events: {
|
||||
change: 'validateNumber',
|
||||
keydown: 'validateNumber',
|
||||
},
|
||||
validateNumber() {
|
||||
const input = this.$('input.number');
|
||||
const regionCode = this.$('li.active')
|
||||
.attr('data-country-code')
|
||||
.toUpperCase();
|
||||
const number = input.val();
|
||||
|
||||
const parsedNumber = libphonenumber.util.parseNumber(number, regionCode);
|
||||
if (parsedNumber.isValidNumber) {
|
||||
this.$('.number-container').removeClass('invalid');
|
||||
this.$('.number-container').addClass('valid');
|
||||
} else {
|
||||
this.$('.number-container').removeClass('valid');
|
||||
}
|
||||
input.trigger('validation');
|
||||
|
||||
return parsedNumber.e164;
|
||||
},
|
||||
});
|
||||
})();
|
|
@ -49,7 +49,7 @@
|
|||
try {
|
||||
cb();
|
||||
} catch (error) {
|
||||
window.log.error(
|
||||
window.SignalWindow.log.error(
|
||||
'ReactWrapperView.update error:',
|
||||
error && error.stack ? error.stack : error
|
||||
);
|
||||
|
|
|
@ -1,149 +0,0 @@
|
|||
// Copyright 2016-2020 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
/* global $, Whisper, moment, WebAudioRecorder */
|
||||
|
||||
/* eslint-disable more/no-then */
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
(function () {
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
Whisper.RecorderView = Whisper.View.extend({
|
||||
className: 'recorder clearfix',
|
||||
template: () => $('#recorder').html(),
|
||||
initialize() {
|
||||
this.startTime = Date.now();
|
||||
this.interval = setInterval(this.updateTime.bind(this), 1000);
|
||||
|
||||
this.onSwitchAwayBound = this.onSwitchAway.bind(this);
|
||||
$(window).on('blur', this.onSwitchAwayBound);
|
||||
|
||||
this.handleKeyDownBound = this.handleKeyDown.bind(this);
|
||||
this.$el.on('keydown', this.handleKeyDownBound);
|
||||
|
||||
this.start();
|
||||
},
|
||||
events: {
|
||||
'click .close': 'remove',
|
||||
'click .finish': 'finish',
|
||||
close: 'remove',
|
||||
},
|
||||
onSwitchAway() {
|
||||
this.lostFocus = true;
|
||||
this.recorder.finishRecording();
|
||||
},
|
||||
handleKeyDown(event) {
|
||||
if (event.key === 'Escape') {
|
||||
this.remove();
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
},
|
||||
updateTime() {
|
||||
const duration = moment.duration(Date.now() - this.startTime, 'ms');
|
||||
const minutes = `${Math.trunc(duration.asMinutes())}`;
|
||||
let seconds = `${duration.seconds()}`;
|
||||
if (seconds.length < 2) {
|
||||
seconds = `0${seconds}`;
|
||||
}
|
||||
this.$('.time').text(`${minutes}:${seconds}`);
|
||||
},
|
||||
remove() {
|
||||
// Note: the 'close' event can be triggered by InboxView, when the user clicks
|
||||
// anywhere outside the recording pane.
|
||||
|
||||
if (this.recorder.isRecording()) {
|
||||
this.recorder.cancelRecording();
|
||||
}
|
||||
|
||||
// Reach in and terminate the web worker used by WebAudioRecorder, otherwise
|
||||
// it gets leaked due to a reference cycle with its onmessage listener
|
||||
this.recorder.worker.terminate();
|
||||
this.recorder = null;
|
||||
|
||||
if (this.interval) {
|
||||
clearInterval(this.interval);
|
||||
}
|
||||
this.interval = null;
|
||||
|
||||
if (this.source) {
|
||||
this.source.disconnect();
|
||||
}
|
||||
this.source = null;
|
||||
|
||||
if (this.context) {
|
||||
this.context.close().then(() => {
|
||||
window.log.info('audio context closed');
|
||||
});
|
||||
}
|
||||
this.context = null;
|
||||
|
||||
Whisper.View.prototype.remove.call(this);
|
||||
this.trigger('closed');
|
||||
|
||||
$(window).off('blur', this.onSwitchAwayBound);
|
||||
|
||||
this.$el.off('keydown', this.handleKeyDownBound);
|
||||
},
|
||||
finish() {
|
||||
this.clickedFinish = true;
|
||||
this.recorder.finishRecording();
|
||||
},
|
||||
handleBlob(recorder, blob) {
|
||||
if (blob && this.clickedFinish) {
|
||||
this.trigger('send', blob);
|
||||
} else if (blob) {
|
||||
this.trigger('confirm', blob, this.lostFocus);
|
||||
}
|
||||
this.remove();
|
||||
},
|
||||
start() {
|
||||
this.lostFocus = false;
|
||||
this.clickedFinish = false;
|
||||
this.context = new AudioContext();
|
||||
this.input = this.context.createGain();
|
||||
this.recorder = new WebAudioRecorder(this.input, {
|
||||
encoding: 'mp3',
|
||||
workerDir: 'js/', // must end with slash
|
||||
});
|
||||
this.recorder.onComplete = this.handleBlob.bind(this);
|
||||
this.recorder.onError = this.onError.bind(this);
|
||||
this.recorder.onTimeout = this.onTimeout.bind(this);
|
||||
navigator.webkitGetUserMedia(
|
||||
{ audio: true },
|
||||
stream => {
|
||||
this.source = this.context.createMediaStreamSource(stream);
|
||||
this.source.connect(this.input);
|
||||
},
|
||||
this.onError.bind(this)
|
||||
);
|
||||
this.recorder.startRecording();
|
||||
},
|
||||
onTimeout() {
|
||||
this.recorder.finishRecording();
|
||||
},
|
||||
onError(error) {
|
||||
// Protect against out-of-band errors, which can happen if the user revokes media
|
||||
// permissions after successfully accessing the microphone.
|
||||
if (!this.recorder) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.remove();
|
||||
|
||||
if (error && error.name === 'NotAllowedError') {
|
||||
window.log.warn(
|
||||
'RecorderView.onError: Microphone access is not allowed!'
|
||||
);
|
||||
window.showPermissionsPopup();
|
||||
} else {
|
||||
window.log.error(
|
||||
'RecorderView.onError:',
|
||||
error && error.stack ? error.stack : error
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
})();
|
|
@ -1,106 +0,0 @@
|
|||
// Copyright 2017-2020 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
/* global Whisper, $, getAccountManager, textsecure */
|
||||
|
||||
/* eslint-disable more/no-then */
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
(function () {
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
Whisper.StandaloneRegistrationView = Whisper.View.extend({
|
||||
template: () => $('#standalone').html(),
|
||||
className: 'full-screen-flow',
|
||||
initialize() {
|
||||
window.readyForUpdates();
|
||||
|
||||
this.accountManager = getAccountManager();
|
||||
|
||||
this.render();
|
||||
|
||||
const number = textsecure.storage.user.getNumber();
|
||||
if (number) {
|
||||
this.$('input.number').val(number);
|
||||
}
|
||||
this.phoneView = new Whisper.PhoneInputView({
|
||||
el: this.$('#phone-number-input'),
|
||||
});
|
||||
this.$('#error').hide();
|
||||
},
|
||||
events: {
|
||||
'validation input.number': 'onValidation',
|
||||
'click #request-voice': 'requestVoice',
|
||||
'click #request-sms': 'requestSMSVerification',
|
||||
'change #code': 'onChangeCode',
|
||||
'click #verifyCode': 'verifyCode',
|
||||
},
|
||||
verifyCode() {
|
||||
const number = this.phoneView.validateNumber();
|
||||
const verificationCode = $('#code').val().replace(/\D+/g, '');
|
||||
|
||||
this.accountManager
|
||||
.registerSingleDevice(number, verificationCode)
|
||||
.then(() => {
|
||||
this.$el.trigger('openInbox');
|
||||
})
|
||||
.catch(this.log.bind(this));
|
||||
},
|
||||
log(s) {
|
||||
window.log.info(s);
|
||||
this.$('#status').text(s);
|
||||
},
|
||||
validateCode() {
|
||||
const verificationCode = $('#code').val().replace(/\D/g, '');
|
||||
|
||||
if (verificationCode.length === 6) {
|
||||
return verificationCode;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
displayError(error) {
|
||||
this.$('#error').hide().text(error).addClass('in').fadeIn();
|
||||
},
|
||||
onValidation() {
|
||||
if (this.$('#number-container').hasClass('valid')) {
|
||||
this.$('#request-sms, #request-voice').removeAttr('disabled');
|
||||
} else {
|
||||
this.$('#request-sms, #request-voice').prop('disabled', 'disabled');
|
||||
}
|
||||
},
|
||||
onChangeCode() {
|
||||
if (!this.validateCode()) {
|
||||
this.$('#code').addClass('invalid');
|
||||
} else {
|
||||
this.$('#code').removeClass('invalid');
|
||||
}
|
||||
},
|
||||
requestVoice() {
|
||||
window.removeSetupMenuItems();
|
||||
this.$('#error').hide();
|
||||
const number = this.phoneView.validateNumber();
|
||||
if (number) {
|
||||
this.accountManager
|
||||
.requestVoiceVerification(number)
|
||||
.catch(this.displayError.bind(this));
|
||||
this.$('#step2').addClass('in').fadeIn();
|
||||
} else {
|
||||
this.$('#number-container').addClass('invalid');
|
||||
}
|
||||
},
|
||||
requestSMSVerification() {
|
||||
window.removeSetupMenuItems();
|
||||
$('#error').hide();
|
||||
const number = this.phoneView.validateNumber();
|
||||
if (number) {
|
||||
this.accountManager
|
||||
.requestSMSVerification(number)
|
||||
.catch(this.displayError.bind(this));
|
||||
this.$('#step2').addClass('in').fadeIn();
|
||||
} else {
|
||||
this.$('#number-container').addClass('invalid');
|
||||
}
|
||||
},
|
||||
});
|
||||
})();
|
Loading…
Add table
Add a link
Reference in a new issue