push notifications seem to work in FF and Chrome

This commit is contained in:
or-else
2018-09-19 17:38:30 +03:00
parent 242b30cee0
commit c567a2678a
3 changed files with 145 additions and 107 deletions
BIN
View File
Binary file not shown.
+23
View File
@@ -0,0 +1,23 @@
// Must be located at the root.
'use strict';
importScripts("https://unpkg.com/firebase@5.5.0/firebase-app.js");
importScripts("https://unpkg.com/firebase@5.5.0/firebase-messaging.js");
const FIREBASE_PUBLIC_API_KEY = "AIzaSyD6X4ULR-RUsobvs1zZ2bHdJuPz39q2tbQ";
const FIREBASE_SENDER_ID = "114126160546";
firebase.initializeApp({
apiKey: FIREBASE_PUBLIC_API_KEY,
messagingSenderId: FIREBASE_SENDER_ID
});
firebase.messaging().setBackgroundMessageHandler(function(payload) {
let title = payload.notification.title || "New message";
let options = {
body: payload.notification.body || "",
icon: '/img/logo96.png'
};
return self.registration.showNotification(title, options);
});
+122 -107
View File
@@ -30,7 +30,7 @@ const API_KEY = "AQEAAAABAAD_rAp4DJh05a1HAwFT3A6K";
// Firebase is used for desktop alerts (push notifications). // Firebase is used for desktop alerts (push notifications).
// If you deploy your own server, you must change these FIREBASE_... values to your own. // If you deploy your own server, you must change these FIREBASE_... values to your own.
const FIREBASE_VAPID_KEY = "BOgQVPOMzIMXUpsYGpbVkZoEBc0ifKY_f2kSU5DNDGYI6i6CoKqqxDd7w7PJ3FaGRBgVGJffldETumOx831jl58"; const FIREBASE_VAPID_KEY = "BOgQVPOMzIMXUpsYGpbVkZoEBc0ifKY_f2kSU5DNDGYI6i6CoKqqxDd7w7PJ3FaGRBgVGJffldETumOx831jl58";
const FIREBASE_API_KEY = "AIzaSyD6X4ULR-RUsobvs1zZ2bHdJuPz39q2tbQ"; const FIREBASE_PUBLIC_API_KEY = "AIzaSyD6X4ULR-RUsobvs1zZ2bHdJuPz39q2tbQ";
const FIREBASE_SENDER_ID = "114126160546"; const FIREBASE_SENDER_ID = "114126160546";
// Minimum time between two keypress notifications, milliseconds. // Minimum time between two keypress notifications, milliseconds.
@@ -422,6 +422,13 @@ function isSecureConnection() {
return false; return false;
} }
function isLocalHost() {
if (typeof window.location == 'object') {
return window.location.hostname == 'localhost';
}
return false;
}
// Create VCard which represents topic 'public' info // Create VCard which represents topic 'public' info
function vcard(fn, imageDataUrl) { function vcard(fn, imageDataUrl) {
var card = null; var card = null;
@@ -4326,6 +4333,8 @@ class TinodeWeb extends React.Component {
this.handleSettings = this.handleSettings.bind(this); this.handleSettings = this.handleSettings.bind(this);
this.handleGlobalSettings = this.handleGlobalSettings.bind(this); this.handleGlobalSettings = this.handleGlobalSettings.bind(this);
this.initDesktopAlerts = this.initDesktopAlerts.bind(this); this.initDesktopAlerts = this.initDesktopAlerts.bind(this);
this.togglePushToken = this.togglePushToken.bind(this);
this.requestPushToken = this.requestPushToken.bind(this);
this.handleSidepanelCancel = this.handleSidepanelCancel.bind(this); this.handleSidepanelCancel = this.handleSidepanelCancel.bind(this);
this.handleNewTopic = this.handleNewTopic.bind(this); this.handleNewTopic = this.handleNewTopic.bind(this);
this.handleNewTopicRequest = this.handleNewTopicRequest.bind(this); this.handleNewTopicRequest = this.handleNewTopicRequest.bind(this);
@@ -4349,7 +4358,6 @@ class TinodeWeb extends React.Component {
let settings = localStorage.getObject("settings") || {}; let settings = localStorage.getObject("settings") || {};
return { return {
tinode: null,
connected: false, connected: false,
transport: settings.transport || null, transport: settings.transport || null,
serverAddress: settings.serverAddress || detectServerAddress(), serverAddress: settings.serverAddress || detectServerAddress(),
@@ -4357,7 +4365,9 @@ class TinodeWeb extends React.Component {
// "On" is the default, so saving the "off" state. // "On" is the default, so saving the "off" state.
messageSounds: !settings.messageSoundsOff, messageSounds: !settings.messageSoundsOff,
desktopAlerts: settings.desktopAlerts, desktopAlerts: settings.desktopAlerts,
desktopAlertsEnabled: !isSecureConnection() && (typeof firebase != 'undefined') && (typeof navigator != 'undefined'), desktopAlertsEnabled: (isSecureConnection() || isLocalHost()) &&
(typeof firebase != 'undefined') && (typeof navigator != 'undefined'),
firebaseToken: localStorage.getObject("firebase-token"),
errorText: '', errorText: '',
errorLevel: null, errorLevel: null,
@@ -4408,29 +4418,40 @@ class TinodeWeb extends React.Component {
this.setState({viewportWidth: document.documentElement.clientWidth}); this.setState({viewportWidth: document.documentElement.clientWidth});
let tinode = TinodeWeb.tnSetup(this.state.serverAddress, this.state.transport); this.tinode = TinodeWeb.tnSetup(this.state.serverAddress, this.state.transport);
this.setState({tinode: tinode});
// Initialize desktop alerts.
if (this.state.desktopAlertsEnabled) { if (this.state.desktopAlertsEnabled) {
let app = firebase.initializeApp({ try {
apiKey: FIREBASE_API_KEY, this.fbPush = firebase.initializeApp({
messagingSenderId: FIREBASE_SENDER_ID, apiKey: FIREBASE_PUBLIC_API_KEY,
}, APP_NAME); messagingSenderId: FIREBASE_SENDER_ID,
let fbPush = app.messaging(); }, APP_NAME).messaging();
fbPush.usePublicVapidKey(FIREBASE_VAPID_KEY); this.fbPush.usePublicVapidKey(FIREBASE_VAPID_KEY);
navigator.serviceWorker.register('/service-worker.js').then((reg) => { navigator.serviceWorker.register('/service-worker.js').then((reg) => {
// Registration was successful this.fbPush.useServiceWorker(reg);
this.initDesktopAlerts(fbPush, this.state.desktopAlerts, reg); this.initDesktopAlerts();
}, (err) => { if (this.state.desktopAlerts) {
// registration failed :( if (!this.state.firebaseToken) {
console.log('Failed to register service worker:', err); this.togglePushToken(true, null);
}); } else {
this.tinode.setDeviceToken(this.state.firebaseToken);
}
}
}).catch((err) => {
// registration failed :(
console.log("Failed to register service worker:", err);
});
} catch (err) {
this.handleError("Failed to initialize push notifications", "err");
console.log("Failed to initialize push notifications", err);
this.setState({desktopAlertsEnabled: false});
}
} }
tinode.enableLogging(true, true); this.tinode.enableLogging(true, true);
tinode.onConnect = this.handleConnected; this.tinode.onConnect = this.handleConnected;
tinode.onDisconnect = this.handleDisconnect; this.tinode.onDisconnect = this.handleDisconnect;
let token, firebasePushToken; let token, firebasePushToken;
if (localStorage.getObject("keep-logged-in")) { if (localStorage.getObject("keep-logged-in")) {
token = localStorage.getObject("auth-token"); token = localStorage.getObject("auth-token");
@@ -4439,8 +4460,8 @@ class TinodeWeb extends React.Component {
if (token) { if (token) {
// When reading from storage, date is returned as string. // When reading from storage, date is returned as string.
token.expires = new Date(token.expires); token.expires = new Date(token.expires);
tinode.setAuthToken(token); this.tinode.setAuthToken(token);
tinode.connect().catch((err) => { this.tinode.connect().catch((err) => {
// Socket error // Socket error
this.handleError(err.message, "err"); this.handleError(err.message, "err");
}); });
@@ -4554,10 +4575,10 @@ class TinodeWeb extends React.Component {
this.setState({loginDisabled: true, login: login, password: password}); this.setState({loginDisabled: true, login: login, password: password});
this.handleError("", null); this.handleError("", null);
if (this.state.tinode.isConnected()) { if (this.tinode.isConnected()) {
this.doLogin(login, password, {meth: this.state.credMethod, resp: this.state.credCode}); this.doLogin(login, password, {meth: this.state.credMethod, resp: this.state.credCode});
} else { } else {
this.state.tinode.connect().catch((err) => { this.tinode.connect().catch((err) => {
// Socket error // Socket error
this.setState({loginDisabled: false}); this.setState({loginDisabled: false});
this.handleError(err.message, "err"); this.handleError(err.message, "err");
@@ -4567,7 +4588,7 @@ class TinodeWeb extends React.Component {
// Connection succeeded. // Connection succeeded.
handleConnected() { handleConnected() {
var params = this.state.tinode.getServerInfo(); var params = this.tinode.getServerInfo();
this.setState({ this.setState({
serverVersion: params.ver + " " + (params.build ? params.build : "none") + "; " serverVersion: params.ver + " " + (params.build ? params.build : "none") + "; "
}); });
@@ -4575,7 +4596,7 @@ class TinodeWeb extends React.Component {
} }
doLogin(login, password, cred) { doLogin(login, password, cred) {
if (this.state.tinode.isAuthenticated()) { if (this.tinode.isAuthenticated()) {
// Already logged in. Go to default screen. // Already logged in. Go to default screen.
navigateTo(""); navigateTo("");
return; return;
@@ -4584,12 +4605,12 @@ class TinodeWeb extends React.Component {
cred = Tinode.credential(cred); cred = Tinode.credential(cred);
// Try to login with login/password. If they are not available, try token. If no token, ask for login/password. // Try to login with login/password. If they are not available, try token. If no token, ask for login/password.
let promise = null; let promise = null;
let token = this.state.tinode.getAuthToken(); let token = this.tinode.getAuthToken();
if (login && password) { if (login && password) {
this.setState({password: null}); this.setState({password: null});
promise = this.state.tinode.loginBasic(login, password, cred); promise = this.tinode.loginBasic(login, password, cred);
} else if (token) { } else if (token) {
promise = this.state.tinode.loginToken(token.token, cred); promise = this.tinode.loginToken(token.token, cred);
} }
if (promise) { if (promise) {
@@ -4629,10 +4650,10 @@ class TinodeWeb extends React.Component {
// Refresh authentication token. // Refresh authentication token.
if (localStorage.getObject("keep-logged-in")) { if (localStorage.getObject("keep-logged-in")) {
localStorage.setObject("auth-token", this.state.tinode.getAuthToken()); localStorage.setObject("auth-token", this.tinode.getAuthToken());
} }
// Logged in fine, subscribe to 'me' attaching callbacks from the contacts view. // Logged in fine, subscribe to 'me' attaching callbacks from the contacts view.
var me = this.state.tinode.getMeTopic(); var me = this.tinode.getMeTopic();
me.onMetaDesc = this.tnMeMetaDesc; me.onMetaDesc = this.tnMeMetaDesc;
me.onContactUpdate = this.tnMeContactUpdate; me.onContactUpdate = this.tnMeContactUpdate;
me.onSubsUpdated = this.tnMeSubsUpdated; me.onSubsUpdated = this.tnMeSubsUpdated;
@@ -4640,7 +4661,7 @@ class TinodeWeb extends React.Component {
connected: true, connected: true,
credMethod: undefined, credMethod: undefined,
credCode: undefined, credCode: undefined,
myUserId: this.state.tinode.getCurrentUserID() myUserId: this.tinode.getCurrentUserID()
}); });
// Subscribe, fetch topic desc, the list of subscriptions. Messages are not fetched. // Subscribe, fetch topic desc, the list of subscriptions. Messages are not fetched.
me.subscribe( me.subscribe(
@@ -4761,7 +4782,7 @@ class TinodeWeb extends React.Component {
let newState = { let newState = {
chatList: [] chatList: []
}; };
this.state.tinode.getMeTopic().contacts((c) => { this.tinode.getMeTopic().contacts((c) => {
newState.chatList.push(c); newState.chatList.push(c);
if (this.state.topicSelected == c.topic) { if (this.state.topicSelected == c.topic) {
newState.topicSelectedOnline = c.online; newState.topicSelectedOnline = c.online;
@@ -4775,7 +4796,7 @@ class TinodeWeb extends React.Component {
// Sending "received" notifications // Sending "received" notifications
tnData(data) { tnData(data) {
let topic = this.state.tinode.getTopic(data.topic); let topic = this.tinode.getTopic(data.topic);
if (topic.msgStatus(data) > Tinode.MESSAGE_STATUS_SENDING) { if (topic.msgStatus(data) > Tinode.MESSAGE_STATUS_SENDING) {
clearTimeout(this.receivedTimer); clearTimeout(this.receivedTimer);
this.receivedTimer = setTimeout(() => { this.receivedTimer = setTimeout(() => {
@@ -4787,7 +4808,7 @@ class TinodeWeb extends React.Component {
/* Fnd topic: find contacts by tokens */ /* Fnd topic: find contacts by tokens */
tnInitFind() { tnInitFind() {
let fnd = this.state.tinode.getFndTopic(); let fnd = this.tinode.getFndTopic();
if (fnd.isSubscribed()) { if (fnd.isSubscribed()) {
this.setState({contactsSearchQuery: ''}); this.setState({contactsSearchQuery: ''});
this.tnFndSubsUpdated(); this.tnFndSubsUpdated();
@@ -4802,7 +4823,7 @@ class TinodeWeb extends React.Component {
tnFndSubsUpdated() { tnFndSubsUpdated() {
let foundContacts = []; let foundContacts = [];
// Don't attempt to create P2P topics which already exist. Server will reject the duplicates. // Don't attempt to create P2P topics which already exist. Server will reject the duplicates.
this.state.tinode.getFndTopic().contacts((s) => { this.tinode.getFndTopic().contacts((s) => {
foundContacts.push(s); foundContacts.push(s);
}); });
this.setState({ this.setState({
@@ -4815,7 +4836,7 @@ class TinodeWeb extends React.Component {
@param query {Array} is an array of contacts to search for @param query {Array} is an array of contacts to search for
*/ */
handleSearchContacts(query) { handleSearchContacts(query) {
var fnd = this.state.tinode.getFndTopic(); var fnd = this.tinode.getFndTopic();
this.setState({contactsSearchQuery: query == Tinode.DEL_CHAR ? '' : query}); this.setState({contactsSearchQuery: query == Tinode.DEL_CHAR ? '' : query});
fnd.setMeta({desc: {public: query}}).then((ctrl) => { fnd.setMeta({desc: {public: query}}).then((ctrl) => {
return fnd.getMeta(fnd.startMetaQuery().withSub().build()); return fnd.getMeta(fnd.startMetaQuery().withSub().build());
@@ -4866,7 +4887,7 @@ class TinodeWeb extends React.Component {
// User is sending a message, either plain text or a drafty object, possibly // User is sending a message, either plain text or a drafty object, possibly
// with attachments. // with attachments.
handleSendMessage(msg, promise, uploader) { handleSendMessage(msg, promise, uploader) {
let topic = this.state.tinode.getTopic(this.state.topicSelected); let topic = this.tinode.getTopic(this.state.topicSelected);
msg = topic.createMessage(msg, false); msg = topic.createMessage(msg, false);
// The uploader is used to show progress. // The uploader is used to show progress.
@@ -4898,9 +4919,9 @@ class TinodeWeb extends React.Component {
// Actual registration of a new account. // Actual registration of a new account.
handleNewAccountRequest(login_, password_, public_, cred_, tags_) { handleNewAccountRequest(login_, password_, public_, cred_, tags_) {
this.state.tinode.connect(this.state.serverAddress) this.tinode.connect(this.state.serverAddress)
.then(() => { .then(() => {
return this.state.tinode.createAccountBasic(login_, password_, return this.tinode.createAccountBasic(login_, password_,
{public: public_, tags: tags_, cred: Tinode.credential(cred_)}); {public: public_, tags: tags_, cred: Tinode.credential(cred_)});
}).then((ctrl) => { }).then((ctrl) => {
if (ctrl.code >= 300 && ctrl.text === "validate credentials") { if (ctrl.code >= 300 && ctrl.text === "validate credentials") {
@@ -4915,19 +4936,19 @@ class TinodeWeb extends React.Component {
handleUpdateAccountRequest(password, pub, priv) { handleUpdateAccountRequest(password, pub, priv) {
if (pub || priv) { if (pub || priv) {
this.state.tinode.getMeTopic().setMeta({desc: {public: pub, private: priv}}).catch((err) => { this.tinode.getMeTopic().setMeta({desc: {public: pub, private: priv}}).catch((err) => {
this.handleError(err.message, "err"); this.handleError(err.message, "err");
}); });
} }
if (password) { if (password) {
this.state.tinode.updateAccountBasic(null, this.state.tinode.getCurrentLogin(), password).catch((err) => { this.tinode.updateAccountBasic(null, this.tinode.getCurrentLogin(), password).catch((err) => {
this.handleError(err.message, "err"); this.handleError(err.message, "err");
}); });
} }
} }
handleUpdateAccountTagsRequest(tags) { handleUpdateAccountTagsRequest(tags) {
this.state.tinode.getFndTopic().setMeta({tags: tags}) this.tinode.getFndTopic().setMeta({tags: tags})
.catch((err) => { .catch((err) => {
this.handleError(err.message, "err"); this.handleError(err.message, "err");
}); });
@@ -4940,90 +4961,84 @@ class TinodeWeb extends React.Component {
// User updated global parameters. // User updated global parameters.
handleGlobalSettings(settings) { handleGlobalSettings(settings) {
console.log("handleGlobalSettings", settings);
let serverAddress = settings.serverAddress || this.state.serverAddress; let serverAddress = settings.serverAddress || this.state.serverAddress;
let transport = settings.transport || this.state.transport; let transport = settings.transport || this.state.transport;
let messageSounds = (typeof settings.messageSounds == 'boolean') ? settings.messageSounds : this.state.messageSounds; let messageSounds = (typeof settings.messageSounds == 'boolean') ? settings.messageSounds : this.state.messageSounds;
let desktopAlerts = settings.desktopAlerts;
if (settings.desktopAlerts != this.state.desktopAlerts) {
this.togglePushToken(settings.desktopAlerts, this.state.firebaseToken);
}
this.setState({ this.setState({
serverAddress: serverAddress, serverAddress: serverAddress,
transport: transport, transport: transport,
messageSounds: messageSounds, messageSounds: messageSounds,
desktopAlerts: desktopAlerts, desktopAlerts: settings.desktopAlerts,
tinode: TinodeWeb.tnSetup(serverAddress, transport), tinode: TinodeWeb.tnSetup(serverAddress, transport),
}); });
localStorage.setObject({ localStorage.setObject("settings", {
serverAddress: serverAddress, serverAddress: serverAddress,
messageSoundsOff: !messageSounds, messageSoundsOff: !messageSounds,
transport: this.state.transport, transport: transport,
desktopAlerts: desktopAlerts desktopAlerts: settings.desktopAlerts,
}); });
navigateTo(setUrlSidePanel(window.location.hash, '')); navigateTo(setUrlSidePanel(window.location.hash, ''));
} }
// Initialize desktop alerts = push notifications. // Initialize desktop alerts = push notifications.
initDesktopAlerts(fbPush, enabled, reg) { initDesktopAlerts() {
let oldToken = localStorage.getObject("firebase-token"); // Google could not be bothered to mention that
// onTokenRefresh is never called.
this.fbPush.onTokenRefresh(() => {
this.requestPushToken(this.state.firebaseToken, true);
});
this.fbPush.onMessage((payload) => {
// No need to do anything about it.
// All the magic happends in the service worker.
});
}
togglePushToken(enabled, oldToken) {
if (enabled) { if (enabled) {
fbPush.useServiceWorker(reg);
if (!oldToken) { if (!oldToken) {
fbPush.requestPermission().then(() => { this.fbPush.requestPermission().then(() => {
console.log("firebase: permission granted"); this.requestPushToken(oldToken);
// Token will be received in onTokenRefresh. }).catch((err) => {
}).catch(function(err) {
this.handleError(err.message, "err"); this.handleError(err.message, "err");
this.setState({desktopAlerts: false, firebaseToken: null}); this.setState({desktopAlerts: false, firebaseToken: null});
console.log("Failed to get permission to notify.", err); console.log("Failed to get permission to notify.", err);
}); });
} else {
this.setState({"firebaseToken": oldToken});
} }
} else if (oldToken) { } else if (oldToken) {
FirebasePush.deleteToken(oldToken).then(function() { this.fbPush.deleteToken(oldToken).then(() => {
console.log('Token deleted.'); let settings = localStorage.getObject("settings");
settings.desktopAlerts = false;
localStorage.setObject("settings", settings);
localStorage.removeItem("firebase-token"); localStorage.removeItem("firebase-token");
this.setState({desktopAlerts: false, firebaseToken: null}); this.setState({desktopAlerts: false, firebaseToken: null});
}).catch(function(err) { }).catch((err) => {
console.log('Unable to delete token. ', err); console.log("Unable to delete token.", err);
}); });
} else {
this.setState({desktopAlerts: false, firebaseToken: null});
} }
}
fbPush.onTokenRefresh(() => { requestPushToken(oldToken, sendToServer) {
fbPush.getToken().then((refreshedToken) => { this.fbPush.getToken().then((refreshedToken) => {
this.setState({"firebaseToken": refreshedToken}); this.setState({"firebaseToken": refreshedToken});
if (refreshedToken != oldToken) { if (refreshedToken != oldToken) {
localStorage.save("firebase-token", refreshedToken); localStorage.setObject("firebase-token", refreshedToken);
console.log("send new token to server", refreshedToken); this.tinode.setDeviceToken(refreshedToken, sendToServer);
} }
}).catch(function(err) { }).catch((err) => {
this.handleError(err.message, "err"); this.handleError(err.message, "err");
console.log("Failed to retrieve firebase token", err); console.log("Failed to retrieve firebase token", err);
});
});
fbPush.onMessage(function(payload) {
console.log('Message received. ', payload);
}); });
} }
requestPermission() {
console.log('Requesting permission...');
// [START request_permission]
FirebasePush.requestPermission().then(function() {
console.log('Notification permission granted.');
// TODO(developer): Retrieve an Instance ID token for use with FCM.
// [START_EXCLUDE]
// In many cases once an app has been granted notification permission, it
// should update its UI reflecting this.
resetUI();
// [END_EXCLUDE]
}).catch(function(err) {
console.log('Unable to get permission to notify.', err);
});
// [END request_permission]
}
// User clicked Cancel button in Setting or Sign Up panel. // User clicked Cancel button in Setting or Sign Up panel.
handleSidepanelCancel() { handleSidepanelCancel() {
var parsed = parseUrlHash(window.location.hash); var parsed = parseUrlHash(window.location.hash);
@@ -5044,7 +5059,7 @@ class TinodeWeb extends React.Component {
// Request to start a new topic. New P2P topic requires peer's name. // Request to start a new topic. New P2P topic requires peer's name.
handleNewTopicRequest(peerName, pub, priv, tags) { handleNewTopicRequest(peerName, pub, priv, tags) {
var topicName = peerName || this.state.tinode.newGroupTopicName(); var topicName = peerName || this.tinode.newGroupTopicName();
if (!peerName) { if (!peerName) {
this.setState( this.setState(
{newGroupTopicParams: {desc: {public: pub, private: {comment: priv}}, tags: tags}}, {newGroupTopicParams: {desc: {public: pub, private: {comment: priv}}, tags: tags}},
@@ -5066,7 +5081,7 @@ class TinodeWeb extends React.Component {
} }
handleTopicUpdateRequest(topicName, pub, priv, permissions) { handleTopicUpdateRequest(topicName, pub, priv, permissions) {
var topic = this.state.tinode.getTopic(topicName); var topic = this.tinode.getTopic(topicName);
if (topic) { if (topic) {
var params = {}; var params = {};
if (pub) { if (pub) {
@@ -5085,7 +5100,7 @@ class TinodeWeb extends React.Component {
} }
handleChangePermissions(topicName, mode, uid) { handleChangePermissions(topicName, mode, uid) {
var topic = this.state.tinode.getTopic(topicName); var topic = this.tinode.getTopic(topicName);
if (topic) { if (topic) {
var am = topic.getAccessMode(); var am = topic.getAccessMode();
if (uid) { if (uid) {
@@ -5102,7 +5117,7 @@ class TinodeWeb extends React.Component {
} }
handleTagsUpdated(topicName, tags) { handleTagsUpdated(topicName, tags) {
var topic = this.state.tinode.getTopic(topicName); var topic = this.tinode.getTopic(topicName);
if (topic) { if (topic) {
var instance = this; var instance = this;
topic.setMeta({tags: tags}).catch((err) => { topic.setMeta({tags: tags}).catch((err) => {
@@ -5119,7 +5134,7 @@ class TinodeWeb extends React.Component {
} }
handleLeaveUnsubRequest(topicName) { handleLeaveUnsubRequest(topicName) {
var topic = this.state.tinode.getTopic(topicName); var topic = this.tinode.getTopic(topicName);
if (!topic) { if (!topic) {
return; return;
} }
@@ -5148,7 +5163,7 @@ class TinodeWeb extends React.Component {
defaultTopicContextMenu(topicName) { defaultTopicContextMenu(topicName) {
var muted = false, blocked = false, subscribed = false, deleter = false; var muted = false, blocked = false, subscribed = false, deleter = false;
var topic = this.state.tinode.getTopic(topicName); var topic = this.tinode.getTopic(topicName);
if (topic) { if (topic) {
if (topic.isSubscribed()) { if (topic.isSubscribed()) {
subscribed = true; subscribed = true;
@@ -5193,7 +5208,7 @@ class TinodeWeb extends React.Component {
return; return;
} }
var topic = this.state.tinode.getTopic(topicName); var topic = this.tinode.getTopic(topicName);
if (!topic) { if (!topic) {
return; return;
} }
@@ -5225,7 +5240,7 @@ class TinodeWeb extends React.Component {
<div id="app-container"> <div id="app-container">
{this.state.contextMenuVisible ? {this.state.contextMenuVisible ?
<ContextMenu <ContextMenu
tinode={this.state.tinode} tinode={this.tinode}
bounds={this.state.contextMenuBounds} bounds={this.state.contextMenuBounds}
clickAt={this.state.contextMenuClickAt} clickAt={this.state.contextMenuClickAt}
params={this.state.contextMenuParams} params={this.state.contextMenuParams}
@@ -5238,7 +5253,7 @@ class TinodeWeb extends React.Component {
} }
<SidepanelView <SidepanelView
tinode={this.state.tinode} tinode={this.tinode}
connected={this.state.connected} connected={this.state.connected}
displayMobile={this.state.displayMobile} displayMobile={this.state.displayMobile}
hideSelf={this.state.displayMobile && this.state.mobilePanel !== 'sidepanel'} hideSelf={this.state.displayMobile && this.state.mobilePanel !== 'sidepanel'}
@@ -5284,7 +5299,7 @@ class TinodeWeb extends React.Component {
showContextMenu={this.handleShowContextMenu} /> showContextMenu={this.handleShowContextMenu} />
<MessagesView <MessagesView
tinode={this.state.tinode} tinode={this.tinode}
connected={this.state.connected} connected={this.state.connected}
online={this.state.topicSelectedOnline} online={this.state.topicSelectedOnline}
acs={this.state.topicSelectedAcs} acs={this.state.topicSelectedAcs}
@@ -5310,7 +5325,7 @@ class TinodeWeb extends React.Component {
{this.state.showInfoPanel ? {this.state.showInfoPanel ?
<InfoView <InfoView
tinode={this.state.tinode} tinode={this.tinode}
connected={this.state.connected} connected={this.state.connected}
displayMobile={this.state.displayMobile} displayMobile={this.state.displayMobile}
topic={this.state.topicSelected} topic={this.state.topicSelected}