
* Updated config, added types and classes for messaging tab * Working app with tabs and servers * Remainder of logic * Make base tab abstract class * Account for new app case * Merge'd * PR feedback
213 lines
6.6 KiB
JavaScript
213 lines
6.6 KiB
JavaScript
// Copyright (c) 2015-2016 Yuya Ochiai
|
|
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
'use strict';
|
|
|
|
/* eslint-disable no-magic-numbers */
|
|
|
|
import {ipcRenderer, webFrame} from 'electron';
|
|
import log from 'electron-log';
|
|
|
|
import {NOTIFY_MENTION, IS_UNREAD, UNREAD_RESULT, SESSION_EXPIRED, SET_VIEW_NAME, REACT_APP_INITIALIZED, USER_ACTIVITY_UPDATE, CLOSE_TEAMS_DROPDOWN} from 'common/communication';
|
|
|
|
const UNREAD_COUNT_INTERVAL = 1000;
|
|
const CLEAR_CACHE_INTERVAL = 6 * 60 * 60 * 1000; // 6 hours
|
|
|
|
Reflect.deleteProperty(global.Buffer); // http://electron.atom.io/docs/tutorial/security/#buffer-global
|
|
|
|
let appVersion;
|
|
let appName;
|
|
let sessionExpired;
|
|
let viewName;
|
|
|
|
log.info('Initializing preload');
|
|
|
|
ipcRenderer.invoke('get-app-version').then(({name, version}) => {
|
|
appVersion = version;
|
|
appName = name;
|
|
});
|
|
|
|
function isReactAppInitialized() {
|
|
const initializedRoot =
|
|
document.querySelector('#root.channel-view') || // React 16 webapp
|
|
document.querySelector('#root .signup-team__container') || // React 16 login
|
|
document.querySelector('div[data-reactroot]'); // Older React apps
|
|
if (initializedRoot === null) {
|
|
return false;
|
|
}
|
|
return initializedRoot.children.length !== 0;
|
|
}
|
|
|
|
function watchReactAppUntilInitialized(callback) {
|
|
let count = 0;
|
|
const interval = 500;
|
|
const timeout = 30000;
|
|
const timer = setInterval(() => {
|
|
count += interval;
|
|
if (isReactAppInitialized() || count >= timeout) { // assumed as webapp has been initialized.
|
|
clearTimeout(timer);
|
|
callback();
|
|
}
|
|
}, interval);
|
|
}
|
|
|
|
window.addEventListener('load', () => {
|
|
if (document.getElementById('root') === null) {
|
|
console.log('The guest is not assumed as mattermost-webapp');
|
|
return;
|
|
}
|
|
watchReactAppUntilInitialized(() => {
|
|
ipcRenderer.send(REACT_APP_INITIALIZED, viewName);
|
|
});
|
|
});
|
|
|
|
const parentTag = (target) => {
|
|
if (target.parentNode && target.parentNode.tagName) {
|
|
return target.parentNode.tagName.toUpperCase();
|
|
}
|
|
return null;
|
|
};
|
|
|
|
document.addEventListener('mouseover', (event) => {
|
|
if (event.target && (event.target.tagName === 'A')) {
|
|
ipcRenderer.send('update-target-url', event.target.href);
|
|
} else if (event.target && (parentTag(event.target) === 'A')) {
|
|
ipcRenderer.send('update-target-url', event.target.parentNode.href);
|
|
}
|
|
});
|
|
|
|
document.addEventListener('mouseout', (event) => {
|
|
if (event.target && event.target.tagName === 'A') {
|
|
ipcRenderer.send('delete-target-url', event.target.href);
|
|
}
|
|
});
|
|
|
|
// listen for messages from the webapp
|
|
window.addEventListener('message', ({origin, data = {}} = {}) => {
|
|
const {type, message = {}} = data;
|
|
if (origin !== window.location.origin) {
|
|
return;
|
|
}
|
|
switch (type) {
|
|
case 'webapp-ready': {
|
|
// register with the webapp to enable custom integration functionality
|
|
console.log(`registering ${appName} v${appVersion} with the server`);
|
|
window.postMessage(
|
|
{
|
|
type: 'register-desktop',
|
|
message: {
|
|
version: appVersion,
|
|
name: appName,
|
|
},
|
|
},
|
|
window.location.origin || '*',
|
|
);
|
|
break;
|
|
}
|
|
case 'register-desktop':
|
|
// it will be captured by itself too
|
|
break;
|
|
case 'dispatch-notification': {
|
|
const {title, body, channel, teamId, silent, data: messageData} = message;
|
|
ipcRenderer.send(NOTIFY_MENTION, title, body, channel, teamId, silent, messageData);
|
|
break;
|
|
}
|
|
default:
|
|
if (typeof type === 'undefined') {
|
|
console.log('ignoring message of undefined type:');
|
|
console.log(data);
|
|
} else {
|
|
console.log(`ignored message of type: ${type}`);
|
|
}
|
|
}
|
|
});
|
|
|
|
const handleNotificationClick = ({channel, teamId}) => {
|
|
window.postMessage(
|
|
{
|
|
type: 'notification-clicked',
|
|
message: {
|
|
channel,
|
|
teamId,
|
|
},
|
|
},
|
|
window.location.origin,
|
|
);
|
|
};
|
|
|
|
ipcRenderer.on('notification-clicked', (event, data) => {
|
|
handleNotificationClick(data);
|
|
});
|
|
|
|
const findUnread = (favicon) => {
|
|
const classes = ['team-container unreads', 'SidebarChannel unread', 'sidebar-item unread-title'];
|
|
const isUnread = classes.some((classPair) => {
|
|
const result = document.getElementsByClassName(classPair);
|
|
return result && result.length > 0;
|
|
});
|
|
ipcRenderer.send(UNREAD_RESULT, favicon, viewName, isUnread);
|
|
};
|
|
|
|
ipcRenderer.on(IS_UNREAD, (event, favicon, server) => {
|
|
if (typeof viewName === 'undefined') {
|
|
viewName = server;
|
|
}
|
|
if (isReactAppInitialized()) {
|
|
findUnread(favicon);
|
|
} else {
|
|
watchReactAppUntilInitialized(() => {
|
|
findUnread(favicon);
|
|
});
|
|
}
|
|
});
|
|
|
|
ipcRenderer.on(SET_VIEW_NAME, (_, name) => {
|
|
viewName = name;
|
|
});
|
|
|
|
function getUnreadCount() {
|
|
// LHS not found => Log out => Count should be 0, but session may be expired.
|
|
if (typeof viewName !== 'undefined') {
|
|
let isExpired;
|
|
if (document.getElementById('sidebar-left') === null) {
|
|
const extraParam = (new URLSearchParams(window.location.search)).get('extra');
|
|
isExpired = extraParam === 'expired';
|
|
} else {
|
|
isExpired = false;
|
|
}
|
|
if (isExpired !== sessionExpired) {
|
|
sessionExpired = isExpired;
|
|
ipcRenderer.send(SESSION_EXPIRED, sessionExpired, viewName);
|
|
}
|
|
}
|
|
}
|
|
setInterval(getUnreadCount, UNREAD_COUNT_INTERVAL);
|
|
|
|
// push user activity updates to the webapp
|
|
ipcRenderer.on(USER_ACTIVITY_UPDATE, (event, {userIsActive, isSystemEvent}) => {
|
|
if (window.location.origin !== 'null') {
|
|
window.postMessage({type: USER_ACTIVITY_UPDATE, message: {userIsActive, manual: isSystemEvent}}, window.location.origin);
|
|
}
|
|
});
|
|
|
|
// exit fullscreen embedded elements like youtube - https://mattermost.atlassian.net/browse/MM-19226
|
|
ipcRenderer.on('exit-fullscreen', () => {
|
|
if (document.fullscreenElement && document.fullscreenElement.nodeName.toLowerCase() === 'iframe') {
|
|
document.exitFullscreen();
|
|
}
|
|
});
|
|
|
|
// mattermost-webapp is SPA. So cache is not cleared due to no navigation.
|
|
// We needed to manually clear cache to free memory in long-term-use.
|
|
// http://seenaburns.com/debugging-electron-memory-usage/
|
|
setInterval(() => {
|
|
webFrame.clearCache();
|
|
}, CLEAR_CACHE_INTERVAL);
|
|
|
|
window.addEventListener('click', () => {
|
|
ipcRenderer.send(CLOSE_TEAMS_DROPDOWN);
|
|
});
|
|
|
|
/* eslint-enable no-magic-numbers */
|