/**
* @file Contains all renderer code
* @author yafp
* @namespace renderer
*/
'use strict'
// ----------------------------------------------------------------------------
// REQUIRE: TTTH MODULES
// ----------------------------------------------------------------------------
const utils = require('./js/ttth/modules/utils.js')
const uscu = require('./js/ttth/modules/userServiceConfigUpdater.js')
// const crash = require('./js/ttth/modules/crashReporter.js') // crashReporter
const sentry = require('./js/ttth/modules/sentry.js') // sentry
const unhandled = require('./js/ttth/modules/unhandled.js') // electron-unhandled
// ----------------------------------------------------------------------------
// REQUIRE: 3rd PARTY
// ----------------------------------------------------------------------------
const customTitlebar = require('custom-electron-titlebar')
// ----------------------------------------------------------------------------
// VARIABLES
// ----------------------------------------------------------------------------
let myTitlebar
// const appWideUserAgentDefault = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) ttth Chrome/78.0.3904.130 Electron/7.1.8 Safari/537.36' // default agent
const appWideUserAgentDefault = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.130 Electron/7.1.8 Safari/537.36' // default agent
// ----------------------------------------------------------------------------
// ERROR HANDLING
// ----------------------------------------------------------------------------
// crash.initCrashReporter()
unhandled.initUnhandled()
// -----------------------------------------------------------------------------
// FUNCTIONS - TITLEBAR
// -----------------------------------------------------------------------------
/**
* @function titlebarInit
* @summary Init the titlebar for the frameless mainWindow
* @description Creates a custom titlebar for the mainWindow using custom-electron-titlebar (https://github.com/AlexTorresSk/custom-electron-titlebar).
* @memberof renderer
*/
function titlebarInit () {
myTitlebar = new customTitlebar.Titlebar({
titleHorizontalAlignment: 'center', // position of window title
icon: 'img/titlebar/icon_titlebar.png',
drag: true, // whether or not you can drag the window by holding the click on the title bar.
backgroundColor: customTitlebar.Color.fromHex('#171717'), // changes with each team
minimizable: true,
maximizable: true,
closeable: true,
unfocusEffect: false,
itemBackgroundColor: customTitlebar.Color.fromHex('#525252') // hover color - changes with each theme
})
// font size of custom-titlebar is set in /app/css/ttth/mainWindow.css
}
/**
* @function titlebarUpdateBackground
* @summary Update the color of the custom titlebar
* @description Update the color of the custom titlebar
* @memberof renderer
* @param {string} newColor - A hex color string
*/
function titlebarUpdateBackground (newColor) {
myTitlebar.updateBackground(customTitlebar.Color.fromHex(newColor))
utils.writeConsoleMsg('info', 'titlebarUpdateBackground ::: Updated the titlebar background')
}
/**
* @function titlebarUpdateItemBackGroundOnHover
* @summary Update the item background color of the custom titlebar
* @description Update the item background color of the custom titlebar
* @memberof renderer
* @param {string} newColor - A hex color string
*/
function titlebarUpdateItemBackgroundOnHover (newColor) {
myTitlebar.updateItemBGColor(customTitlebar.Color.fromHex(newColor))
utils.writeConsoleMsg('info', 'titlebarUpdateItemBackgroundOnHover ::: Updated the item background on hover')
}
/**
* @function titlebarDispose
* @summary Removes the custom titlbar
* @description Removes the custom titlbar. Shouldnt be used - as the UI looks broken then.
* @memberof renderer
*/
function titlebarDispose () { // eslint-disable-line no-unused-vars
myTitlebar.dispose()
utils.writeConsoleMsg('warn', 'titlebarDispose ::: Disposed the entire titlebar')
}
// -----------------------------------------------------------------------------
// FUNCTIONS
// -----------------------------------------------------------------------------
/**
* @function switchToService
* @summary Activates a given service tab
* @description Activates the tab of a given service. Needed for handling DefaultView setting.
* @memberof renderer
* @param {string} serviceName - Name of the service
*/
function switchToService (serviceName) {
$('#target_' + serviceName).trigger('click') // activate the related tab
utils.writeConsoleMsg('info', 'switchToService ::: Switched to tab: _' + serviceName + '_.')
}
/**
* @function writeLocalUserSetting
* @summary Write to electron-json-storage
* @description Writes a value for a given key to electron-json-storage
* @memberof renderer
* @param {string} key - Name of storage key
* @param {string} value - New value
*/
function writeLocalUserSetting (key, value) {
const storage = require('electron-json-storage')
utils.jsonStoragePathSet('Settings')
// write the user setting
storage.set(key, { setting: value }, function (error) {
if (error) {
utils.writeConsoleMsg('error', 'writeLocalUserSetting ::: Got an error while trying to write a user setting with key: _' + key + '_ and value: _' + value + '_. Error: ' + error)
throw error
}
utils.writeConsoleMsg('info', 'writeLocalUserSetting ::: key: _' + key + '_ - new value: _' + value + '_')
utils.globalObjectSet(key, value) // Update the global object (to be in sync)
})
}
/**
* @function loadDefaultView
* @summary Loads the default view
* @description Loads the default view. This is used on load of the .html
* @memberof renderer
* @param {string} newDefaultView - the view which is defined as default view
*/
function loadDefaultView (newDefaultView) {
utils.writeConsoleMsg('info', 'loadDefaultView ::: Found configured default view: _' + newDefaultView + '_.')
switchToService(newDefaultView)
}
/**
* @function settingDefaultViewReset
* @summary Reset the stored default view
* @description Deletes the localstorage key 'settingDefaultview'
* @memberof renderer
*/
function settingDefaultViewReset () {
writeLocalUserSetting('settingDefaultView', false)
$('#selectDefaultView').prop('selectedIndex', 0) // reset the selection of the select item
utils.writeConsoleMsg('info', 'settingDefaultViewReset ::: Did reset the default view')
}
/**
* @function settingActivateUserColorCss
* @summary Activates a css style
* @description Activates a css style / theme
* @memberof renderer
* @param {string} cssStyleName - Name of the css file
*/
function settingActivateUserColorCss (cssFile) {
utils.writeConsoleMsg('info', 'settingActivateUserColorCss ::: Loading css file: _' + cssFile + '_.')
// load custom css file
//
$('<link/>', {
rel: 'stylesheet',
type: 'text/css',
href: 'css/ttth/themes/' + cssFile
}).appendTo('head')
// update color of custom-titlebar - see #156
//
let titlebarBackGroundColor
let titlebarItemBackGroundColor
switch (cssFile) {
case 'mainWindow_dark.css':
titlebarBackGroundColor = '#171717'
titlebarItemBackGroundColor = '#FFFFFF'
break
case 'mainWindow_default.css':
titlebarBackGroundColor = '#171717'
titlebarItemBackGroundColor = '#32CD32'
break
case 'mainWindow_dracula.css':
titlebarBackGroundColor = '#282a36'
titlebarItemBackGroundColor = '#ff79c6'
break
case 'mainWindow_nord.css':
titlebarBackGroundColor = '#5e81ac'
titlebarItemBackGroundColor = '#FFFFFF'
break
case 'mainWindow_snazzy.css':
titlebarBackGroundColor = '#1a1c24'
titlebarItemBackGroundColor = '#5af78e'
break
case 'mainWindow_solarized_dark.css':
titlebarBackGroundColor = '#002b36'
titlebarItemBackGroundColor = '#FFFFFF'
break
case 'mainWindow_solarized_light.css':
titlebarBackGroundColor = '#eee8d5'
titlebarItemBackGroundColor = '#FFFFFF'
break
default:
titlebarBackGroundColor = '#171717'
titlebarItemBackGroundColor = '#FFFFFF'
}
titlebarUpdateBackground(titlebarBackGroundColor) // update the titlebar
titlebarUpdateItemBackgroundOnHover(titlebarItemBackGroundColor) // update the hover color for menu-items
}
/**
* @function settingThemeUpdate
* @summary Updates which theme is selected
* @description Sets the new theme and activates a css style / theme
* @memberof renderer
* @todo This functions gets ignored for eslint/standardx as it is only called from mainWindow.html
*/
function settingThemeUpdate () { // eslint-disable-line no-unused-vars
const currentSelectedTheme = $('#selectTheme').val() // id of selected theme
const currentSelectedThemeDisplayName = $('#selectTheme option:selected').text() // displayed theme name
settingActivateUserColorCss(currentSelectedTheme) // activate the theme
writeLocalUserSetting('settingTheme', currentSelectedTheme) // write Setting
utils.showNoty('success', "<i class='fas fa-toggle-on'></i> <b>Option:</b> <u>Theme</u> changed to " + currentSelectedThemeDisplayName + '.') // noty
utils.writeConsoleMsg('info', 'settingThemeUpdate ::: Updating user selected css file to: _' + currentSelectedTheme + '_.') // log
}
/**
* @function settingThemeReset
* @summary Resets the selected theme back to default
* @description Sets the new theme and activates a css style / theme
* @memberof renderer
* @todo This functions gets ignored for eslint/standardx as it is only called from mainWindow.html
*/
function settingThemeReset () { // eslint-disable-line no-unused-vars
$('#selectTheme').prop('selectedIndex', 0) // reset the selection of the select item back to default
const currentSelectedTheme = 'mainWindow_default.css'
settingActivateUserColorCss(currentSelectedTheme) // load default theme
writeLocalUserSetting('settingTheme', currentSelectedTheme) // write setting
utils.showNoty('success', "<i class='fas fa-toggle-on'></i> Changed <b>Option:</b> <u>Theme</u> back to default.") // noty
utils.writeConsoleMsg('info', 'settingThemeReset ::: Resetting user selected css file back to default: _' + currentSelectedTheme + '_.') // log
}
/**
* @function readLocalUserSetting
* @summary Read from local storage
* @description Reads a value stored in local storage (for a given key)
* @memberof renderer
* @param {string} key - Name of local storage key
* @param {boolean} [optional] - Boolean used for an ugly hack
*/
function readLocalUserSetting (key, optional = false) {
const storage = require('electron-json-storage')
utils.jsonStoragePathSet('Settings')
utils.writeConsoleMsg('info', 'readLocalUserSetting ::: Trying to read value of key: ' + key)
// read the json file
storage.get(key, function (error, data) {
if (error) {
utils.writeConsoleMsg('error', 'readLocalUserSetting ::: Got error while reading a json file with the name: _' + key + '_. Error: ' + error)
throw error
}
let value = data.setting // store the read value in a variable
utils.writeConsoleMsg('info', 'readLocalUserSetting ::: key: _' + key + '_ - got value: _' + value + '_')
// setting DefaultView (FIXME)
if (key === 'settingDefaultView') {
// no default view configured
if (value === null) {
utils.writeConsoleMsg('info', 'readLocalUserSetting ::: No default configured - Stay on settings-view')
} else {
utils.writeConsoleMsg('info', 'readLocalUserSetting ::: Found configured default view: ' + value)
// check if the configured service is enabled or not
let exists = false
utils.writeConsoleMsg('info', 'readLocalUserSetting ::: Check if configured default view is an enabled service or not')
// Check if Dropdown contains the defined default view as enabled service
$('#selectDefaultView option').each(function () {
if (this.value === value) {
exists = true
return false
}
})
// if it exists
if (exists) {
utils.writeConsoleMsg('info', 'readLocalUserSetting ::: Configured default view is valid')
$('#selectDefaultView').val(value) // Update UI select
loadDefaultView(value) // load the default view
} else {
utils.writeConsoleMsg('warning', 'readLocalUserSetting ::: Fallback to default (setting-view)')
$('#selectDefaultView').prop('selectedIndex', 0) // reset the selection of the select item
settingDefaultViewReset() // delete the localstorage entry for defaultview
}
}
utils.globalObjectSet('settingDefaultView', value) // update the global object
}
// Setting Theme
//
if (key === 'settingTheme') {
// there is no config yet - create one
if ((value === null) || (value === 'undefined') || (value === undefined)) {
value = 'mainWindow_default.css'
utils.writeConsoleMsg('warn', 'readLocalUserSetting ::: Setting Theme is undefined - going to fallback to default theme with the value: ' + value)
writeLocalUserSetting('settingTheme', 'mainWindow_default.css') // introduced with #154
} else {
utils.writeConsoleMsg('info', 'readLocalUserSetting ::: settingTheme is currently configured to: _' + value + '_.')
}
settingActivateUserColorCss(value)
utils.globalObjectSet('settingTheme', value) // update the global object
$('#selectTheme').val(value) // Update UI select
}
// End: Theme
// Setting Autostart
//
if (key === 'settingAutostart') {
// there is no config yet - create one
if (value === undefined) {
writeLocalUserSetting('settingAutostart', false)
} else {
if (value === true) {
utils.writeConsoleMsg('info', 'readLocalUserSetting ::: Setting Autostart is configured')
$('#checkboxSettingAutostart').prop('checked', true)
} else {
utils.writeConsoleMsg('info', 'readLocalUserSetting ::: Setting Autostart is not configured')
$('#checkboxSettingAutostart').prop('checked', false)
}
utils.globalObjectSet('settingAutostart', value) // update the global object
}
}
// End: Autostart
// Setting DisableTray (Linux specific)
//
if (key === 'settingDisableTray') {
// there is no config yet - create one
if (value === undefined) {
writeLocalUserSetting('settingDisableTray', false)
} else {
if (utils.isLinux()) {
if (value === true) {
const { ipcRenderer } = require('electron')
utils.writeConsoleMsg('info', 'readLocalUserSetting ::: Setting DisableTray is enabled')
$('#checkboxSettingDisableTray').prop('checked', true)
ipcRenderer.send('disableTray')
} else {
utils.writeConsoleMsg('info', 'readLocalUserSetting ::: Setting DisableTray is not enabled')
}
} else {
$('#settingsSectionDisableTray').hide() // hide the entire setting on settingspage
}
utils.globalObjectSet('settingDisableTray', value) // update the global object
}
}
// End DisableTRay
// Setting Urgent Window - #110
if (key === 'settingUrgentWindow') {
// there is no config yet - create one
if (value === undefined) {
writeLocalUserSetting('settingUrgentWindow', true)
} else {
if (value === true) {
const { ipcRenderer } = require('electron')
$('#checkboxSettingUrgentWindow').prop('checked', true)
if (optional === true) {
ipcRenderer.send('makeWindowUrgent')
}
utils.writeConsoleMsg('info', 'readLocalUserSetting ::: Setting UrgentWindow is enabled')
}
utils.globalObjectSet('settingUrgentWindow', value) // update the global object
}
}
// End: Urgent Window
// Setting: ErrorReporting
if (key === 'settingEnableErrorReporting') {
// there is no config yet - create one
if (value === undefined) {
writeLocalUserSetting('settingEnableErrorReporting', true)
} else {
if (value === false) {
$('#checkboxSettingErrorReporting').prop('checked', false)
sentry.disableSentry()
utils.writeConsoleMsg('info', 'readLocalUserSetting ::: Setting ErrorReporting is disabled')
} else {
$('#checkboxSettingErrorReporting').prop('checked', true)
sentry.enableSentry()
utils.writeConsoleMsg('info', 'readLocalUserSetting ::: Setting ErrorReporting is enabled')
}
utils.globalObjectSet('settingEnableErrorReporting', value) // update the global object
}
}
// End: ErrorReporting
// Setting: EnablePrereleases
if (key === 'settingEnablePrereleases') {
// there is no config yet - create one
if (value === undefined) {
writeLocalUserSetting('settingEnablePrereleases', false)
} else {
if (value === false) {
$('#checkboxSettingEnablePrereleases').prop('checked', false)
utils.writeConsoleMsg('info', 'readLocalUserSetting ::: Setting EnablePrereleases is disabled')
} else {
$('#checkboxSettingEnablePrereleases').prop('checked', true)
utils.writeConsoleMsg('info', 'readLocalUserSetting ::: Setting EnablePrereleases is enabled')
}
utils.globalObjectSet('settingEnablePrereleases', value) // update the global object
}
}
// End: EnablePrereleases
})
}
/**
* @function previewIcon
* @summary Generates a preview of the icon in the config-window
* @description Reads the content of the icon field and tries to show/preview the resulting FontAwesome icon
* @memberof renderer
*/
function previewIcon () {
const currentIconCode = $('#input_serviceIcon').val() // get content of field
$('#previewIcon').html("<i class='" + currentIconCode + " fa-lg'></i>") // try to load font-awesome icon
}
/**
* @function settingToggleDisableTray
* @summary Enables or disabled the Tray
* @description Updates the settings / option DisableTray
* @memberof renderer
* @todo This functions gets ignored for eslint/standardx as it is only called from mainWindow.html
*/
function settingToggleDisableTray () { // eslint-disable-line no-unused-vars
const { ipcRenderer } = require('electron')
// Handle depending on the checkbox state
if ($('#checkboxSettingDisableTray').prop('checked')) {
ipcRenderer.send('disableTray')
writeLocalUserSetting('settingDisableTray', true)
utils.showNoty('success', "<i class='fas fa-toggle-on'></i> <b>Option:</b> <u>Disable Tray</u> is now enabled.")
utils.writeConsoleMsg('info', 'settingToggleDisableTray ::: Finished enabling DisableTray')
} else {
ipcRenderer.send('recreateTray')
writeLocalUserSetting('settingDisableTray', false)
utils.showNoty('success', "<i class='fas fa-toggle-off'></i> <b>Option:</b> <u>Disable Tray</u> is now disabled.")
utils.writeConsoleMsg('info', 'settingToggleDisableTray ::: Finished re-enabling DisableTray')
}
}
/**
* @function settingToggleUrgentWindow
* @summary Enables or disabled the urgent window mode
* @description Updates the settings / option Urgentwindow
* @memberof renderer
* @todo This functions gets ignored for eslint/standardx as it is only called from mainWindow.html
*/
function settingToggleUrgentWindow () { // eslint-disable-line no-unused-vars
// Handle depending on the checkbox state
if ($('#checkboxSettingUrgentWindow').prop('checked')) {
writeLocalUserSetting('settingUrgentWindow', true)
utils.showNoty('success', "<i class='fas fa-toggle-on'></i> <b>Option:</b> <u>Urgent window</u> is now enabled.")
utils.writeConsoleMsg('info', 'settingToggleUrgentWindow ::: Finished enabling UrgentWindow')
} else {
writeLocalUserSetting('settingUrgentWindow', false)
utils.showNoty('success', "<i class='fas fa-toggle-off'></i> <b>Option:</b> <u>Urgent window</u> is now disabled.")
utils.writeConsoleMsg('info', 'settingToggleUrgentWindow ::: Finished re-enabling UrgentWindow')
}
}
/**
* @function settingsSelectServiceToAddChanged
* @summary Changes the add-service-template was selected and enables the button
* @description Changes the add-service-template was selected and enables the button
* @memberof renderer
* @todo This functions gets ignored for eslint/standardx as it is only called from mainWindow.html
*/
function settingsSelectServiceToAddChanged () { // eslint-disable-line no-unused-vars
const currentSelectedServiceTemplate = $('#select_availableServices').val()
utils.writeConsoleMsg('info', 'settingsSelectServiceToAddChanged ::: Value of service-template select has changed to: _' + currentSelectedServiceTemplate + '_.')
if (currentSelectedServiceTemplate !== '') {
$('#bt_addNewService').prop('disabled', false) // enable the add button
// change button type to success
$('#bt_addNewService').removeClass()
$('#bt_addNewService').addClass('btn btn-success btn-sm')
utils.writeConsoleMsg('info', 'settingsSelectServiceToAddChanged ::: Enabled the add-service button.')
}
}
/**
* @function showNotyAutostartMinimizedConfirm
* @summary Shows a dialog while configuring the autostart.
* @description Asks the user if the autostart should be minimized or not
* @memberof renderer
*/
function showNotyAutostartMinimizedConfirm () {
const AutoLaunch = require('auto-launch')
const Noty = require('noty')
const n = new Noty(
{
theme: 'bootstrap-v4',
layout: 'bottom',
type: 'information',
closeWith: [''], // to prevent closing the confirm-dialog by clicking something other then a confirm-dialog-button
text: 'Should autostart enable the minimize mode?',
buttons: [
Noty.button('Yes', 'btn btn-success', function () {
// enable start minimized
const ttthAutoLauncher = new AutoLaunch({
name: 'ttth',
isHidden: true,
useLaunchAgent: true
})
ttthAutoLauncher.enable()
writeLocalUserSetting('settingAutostart', true)
n.close()
utils.showNoty('success', "<i class='fas fa-toggle-on'></i> <b>Option:</b> <u>Minimized Autostart (on login)</u> is now enabled.")
},
{
id: 'button1', 'data-status': 'ok'
}),
Noty.button('No', 'btn btn-secondary float-right', function () {
const ttthAutoLauncher = new AutoLaunch({
name: 'ttth',
isHidden: false,
useLaunchAgent: true
})
ttthAutoLauncher.enable()
writeLocalUserSetting('settingAutostart', true)
n.close()
utils.showNoty('success', "<i class='fas fa-toggle-on'></i> <b>Option:</b> <u>Autostart (on login)</u> is now enabled.")
})
]
})
n.show() // show the noty dialog
}
/**
* @function openUserServicesConfigFolder
* @summary Opens the folder in filesystem which contains the service configurations of the current user
* @description Triggers a method in main.js which then opens the folder which contains all service configurations of the current user.
* @memberof renderer
* @todo This functions gets ignored for eslint/standardx as it is only called from mainWindow.html
*/
function openUserServicesConfigFolder () { // eslint-disable-line no-unused-vars
const { ipcRenderer } = require('electron')
ipcRenderer.send('openUserServicesConfigFolder')
utils.writeConsoleMsg('info', 'openUserServicesConfigFolder ::: Should try to open the folder which contains the user configured services.')
}
/**
* @function openUserSettingsConfigFolder
* @summary Opens the folder in filesystem which contains the user settings
* @description Triggers a method in main.js which then opens the folder which contains all user settings
* @memberof renderer
* @todo This functions gets ignored for eslint/standardx as it is only called from mainWindow.html
*/
function openUserSettingsConfigFolder () { // eslint-disable-line no-unused-vars
const { ipcRenderer } = require('electron')
ipcRenderer.send('openUserSettingsConfigFolder')
utils.writeConsoleMsg('info', 'openUserSettingsConfigFolder ::: Should try to open the folder which contains the user settings.')
}
/**
* @function updateTrayIconStatus
* @summary Updates the tray icon
* @description Checks the tabs of all services and fetches the content of the related batch. Based on the overall unread message account it triggers the update of the tray icon
* @memberof renderer
*/
function updateTrayIconStatus () {
let overallUnreadMessages = 0 // counts unread messages for all enabled services
let curServiceUnreadMessageCount = 0 // contains the unread-message count for a single service
let currentTabId
// loop over all tabs - count unread messages
$('#myTabs li a').each(function () {
currentTabId = $(this).attr('id')
// for all tabs - but NOT for the settings tab
if (currentTabId !== 'target_Settings') {
currentTabId = currentTabId.replace('target_', '')
curServiceUnreadMessageCount = 0 // reset to 0
curServiceUnreadMessageCount = $('#badge_' + currentTabId).html()
curServiceUnreadMessageCount = Number(curServiceUnreadMessageCount)
// if the current service has a significant unread message count -> log it and add it to overall counter
// if ((curServiceUnreadMessageCount !== 0) && (curServiceUnreadMessageCount !== '') && (curServiceUnreadMessageCount !== null)) {
// if ((curServiceUnreadMessageCount !== 0) && (curServiceUnreadMessageCount !== null)) {
if (curServiceUnreadMessageCount !== 0) {
overallUnreadMessages = overallUnreadMessages + curServiceUnreadMessageCount // increase the overall counter
}
if (curServiceUnreadMessageCount !== 0) { // only if there is something to report
utils.writeConsoleMsg('info', 'updateTrayIconStatus ::: Unread messages count of _' + currentTabId + '_ is: ' + curServiceUnreadMessageCount)
}
}
})
if (overallUnreadMessages !== 0) { // only if there is something to report
utils.writeConsoleMsg('info', 'updateTrayIconStatus ::: Overall unread message count for all enabled services is: _' + overallUnreadMessages + '_.')
}
const { ipcRenderer } = require('electron')
if ((overallUnreadMessages === '0') || (overallUnreadMessages === 0)) {
ipcRenderer.send('changeTrayIconToDefault') // tray should show the default icon
} else {
// tray should show that we got unread messages
ipcRenderer.send('changeTrayIconToUnreadMessages')
readLocalUserSetting('settingUrgentWindow', true)
}
// Update the badgeCount of the app. See #152
ipcRenderer.send('updateBadgeCount', overallUnreadMessages)
}
/**
* @function doAnimateServiceIcon
* @summary Starts or stops the animation of the service tab icon
* @description Adds or removes a class to the service icon in the related service tab. FontAwesome Animating icons: https://fontawesome.com/how-to-use/on-the-web/styling/animating-icons
* @memberof renderer
* @param {boolean} doOrDont - True = enable animation, false = stop the animation.
* @param {string} serviceId - The id of the related service
*/
function doAnimateServiceIcon (doOrDont, serviceId) {
if (doOrDont === true) {
$('#icon_' + serviceId).addClass('fa-spin') // start to spin the service icon in the tabmenu
utils.writeConsoleMsg('info', 'doAnimateServiceIcon ::: Animating the icon of service _' + serviceId + '_.')
} else {
$('#icon_' + serviceId).removeClass('fa-spin') // stop to spin the service icon in the tabmenu
utils.writeConsoleMsg('info', 'doAnimateServiceIcon ::: Stopped animating the icon of service _' + serviceId + '_.')
}
}
/**
* @function updateServiceBadge
* @summary Updates the badge in a tab of a single service
* @description gets the name of a service and its current unread message count. Updates the badge of the related service
* @memberof renderer
* @param {string} serviceId - ID of the service
* @param {number} count - Amount of unread messages
*/
function updateServiceBadge (serviceId, count) {
if (count !== '0') {
utils.writeConsoleMsg('info', 'updateServiceBadge ::: New unread count for service _' + serviceId + '_ is: _' + count + '_.')
}
// if count is < 1 - badge should show nothing
if ((count === null) || (count === 0) || (count === 'null') || (count === '0')) {
count = ''
}
$('#badge_' + serviceId).html(count) // update the badge
updateTrayIconStatus() // Update tray icon status if needed
}
/**
* @function eventListenerForSingleService
* @summary Adds several EventListeners to the webview of the service
* @description Defines several EventListeners to the webview of the service and starts a periodic request to check for unread messages
* @memberof renderer
* @param serviceId - the ID of the service
* @param enableUnreadMessageHandling - boolean - if unread message handler should be created
* @param enableLinkSupport - boolean - if link handler should be created
*/
function eventListenerForSingleService (serviceId, enableUnreadMessageHandling = true, enableLinkSupport = false) {
utils.writeConsoleMsg('info', 'eventListenerForSingleService ::: Adding event listeners for webview: _webview_' + serviceId + '_.')
const webview = document.getElementById('webview_' + serviceId) // get webview ( https://electronjs.org/docs/api/webview-tag )
// run it periodically
//
// 5.000 = 5 sec
// var intervalID = setInterval(function () { // CLEANME
setInterval(function () {
webview.send('request')
}, 3000) // 3.000 milliseconds = 3 sec
// TODO:
// add a network-connectivity check for each single service?
// -----------------------------------------
// adding general webview events (valid for all services)
// -----------------------------------------
// WebView Event: load-commit (https://electronjs.org/docs/api/webview-tag#event-load-commit)
// Fired when a load has committed. This includes navigation within the current document as well as subframe document-level loads, but does not include asynchronous resource loads.
/*
webview.addEventListener('load-commit', function () {
utils.writeConsoleMsg('info', 'eventListenerForSingleService ::: load-commit for: _' + serviceId + '_.')
// start to spin the service icon in the tabmenu
// doAnimateServiceIcon(true, serviceId);
})
*/
// WebView Event: did-fail-load (https://electronjs.org/docs/api/webview-tag#event-did-fail-load)
// This event is like did-finish-load, but fired when the load failed or was cancelled, e.g. window.stop() is invoked.
webview.addEventListener('did-fail-load', function () {
utils.writeConsoleMsg('error', 'eventListenerForSingleService ::: webview of service: _' + serviceId + '_ got a did-fail-load event.')
// stop to spin the service icon in the tabmenu
doAnimateServiceIcon(false, serviceId)
})
// WebView Event: crashed (https://electronjs.org/docs/api/webview-tag#event-crashed)
// Fired when the renderer process is crashed.
webview.addEventListener('crashed', function (event) {
doAnimateServiceIcon(false, serviceId) // stop to spin the service icon in the tabmenu
utils.writeConsoleMsg('error', 'eventListenerForSingleService ::: webview of service: _' + serviceId + '_ got a crashed event.')
utils.writeConsoleMsg('error', 'Error: ', event)
utils.showNoty('error', 'Ooops, the service <b>' + serviceId + '</b> just crashed.', 0)
// FIXME
// Idea: load an error page into the crashed webview
// webview.loadURL('file://' + __dirname + '/error.html')
// BUT
// this crashes the entire app - as it is sung the same code as reloadCurrentService
})
// WebView Event: page-title-updated (https://electronjs.org/docs/api/webview-tag#event-page-title-updated)
// Fired when page title is set during navigation. explicitSet is false when title is synthesized from file url.
/*
webview.addEventListener('page-title-updated', function () {
utils.writeConsoleMsg('info', 'eventListenerForSingleService ::: page-title-updated for: _' + serviceId + '_.')
})
*/
// WebView Event: plugin-crashed (https://electronjs.org/docs/api/webview-tag#event-plugin-crashed)
// Fired when a plugin process is crashed.
/*
webview.addEventListener('plugin-crashed', function () {
utils.writeConsoleMsg('error', 'eventListenerForSingleService ::: plugin-crashed for: _' + serviceId + '_.')
})
*/
// WebView Event: destroyed (https://electronjs.org/docs/api/webview-tag#event-destroyed)
// Fired when the WebContents is destroyed.
/*
webview.addEventListener('destroyed', function () {
utils.writeConsoleMsg('error', 'eventListenerForSingleService ::: destroyed for: _' + serviceId + '_.')
})
*/
// WebView Event: update-target-url (https://electronjs.org/docs/api/webview-tag#event-update-target-url)
// Emitted when mouse moves over a link or the keyboard moves the focus to a link.
/*
webview.addEventListener('update-target-url', function () {
utils.writeConsoleMsg('info', 'eventListenerForSingleService ::: update-target-url for: _' + serviceId + '_.')
})
*/
// WebView Event: devtools-opened (htps://electronjs.org/docs/api/webview-tag#event-devtools-opened)
// Emitted when DevTools is opened.
/*
webview.addEventListener('devtools-opened', function () {
utils.writeConsoleMsg('info', 'eventListenerForSingleService ::: devtools-opened for: _' + serviceId + '_.')
})
*/
// WebView Event: devtools closed (https://electronjs.org/docs/api/webview-tag#event-devtools-closed)
// Emitted when DevTools is closed.
/*
webview.addEventListener('devtools-closed', function () {
utils.writeConsoleMsg('info', 'eventListenerForSingleService ::: devtools closed for: _' + serviceId + '_.')
})
*/
// WebView Event: close (https://electronjs.org/docs/api/webview-tag#event-close)
// Fired when the guest page attempts to close itself.
/*
webview.addEventListener('close', function () {
utils.writeConsoleMsg('info', 'eventListenerForSingleService ::: close for: _' + serviceId + '_.')
})
*/
// WebView Event: console-message (https://electronjs.org/docs/api/webview-tag#event-console-message)
//
// webview.addEventListener("console-message", function()
// {
// utils.writeConsoleMsg("info", "eventListenerForSingleService ::: console-message");
// });
// WebView Event: did-start-loading
// Corresponds to the points in time when the spinner of the tab starts spinning.
webview.addEventListener('did-start-loading', function () {
utils.writeConsoleMsg('info', 'eventListenerForSingleService ::: webview of service: _' + serviceId + '_ got a did-start-loading event')
doAnimateServiceIcon(true, serviceId) // start to spin the service icon in the tabmenu
webview.send('request') // Triggering search for unread messages
// show the useragent of this webview
//
// var userAgent = webview.getUserAgent()
// utils.writeConsoleMsg('warn', 'UserAgent of service _'+ serviceId + '_ is set to _' + userAgent + '_.')
})
// WebView Event: did-finish-load
// Fired when the navigation is done, i.e. the spinner of the tab will stop spinning, and the onload event is dispatched.
webview.addEventListener('did-finish-load', function () {
utils.writeConsoleMsg('info', 'eventListenerForSingleService ::: webview of service: _' + serviceId + '_ got a did-finish-load event.')
doAnimateServiceIcon(false, serviceId) // stop to spin the service icon in the tabmenu
})
// WebView Event: did-frame-finish-load
// Fired when a frame has done navigation.
webview.addEventListener('did-frame-finish-load', function () {
utils.writeConsoleMsg('info', 'eventListenerForSingleService ::: webview of service: _' + serviceId + '_ got a did-frame-finish-load event.')
doAnimateServiceIcon(false, serviceId) // stop to spin the service icon in the tabmenu
})
// WebView Event: did-stop-loading
// Corresponds to the points in time when the spinner of the tab stops spinning.
webview.addEventListener('did-stop-loading', function () {
utils.writeConsoleMsg('info', 'eventListenerForSingleService ::: webview of service: _' + serviceId + '_ got a did-stop-loading event.')
doAnimateServiceIcon(false, serviceId) // stop to spin the service icon in the tabmenu
})
// WebView Event: dom-ready
// Fired when document in the given frame is loaded.
webview.addEventListener('dom-ready', function () {
utils.writeConsoleMsg('info', 'eventListenerForSingleService ::: webview of service: _' + serviceId + '_ got a DOM-Ready event.')
doAnimateServiceIcon(false, serviceId) // stop to spin the service icon in the tabmenu
})
// -----------------------------------------
// Specific WebView Events for UnreadMessageHandling
// -----------------------------------------
if (enableUnreadMessageHandling === true) {
// WebView Event: ipc-message
//
webview.addEventListener('ipc-message', (event) => {
// utils.writeConsoleMsg('info', 'eventListenerForSingleService ::: ipc-message for: _' + serviceId + '_.')
// update the badge
if (event.channel !== null) {
updateServiceBadge(serviceId, event.channel)
}
})
}
// /WebView Events for UnreadMessageHandling
// -----------------------------------------
// Specific WebView Event: new-window / clicking links
// -----------------------------------------
if (enableLinkSupport === true) {
webview.addEventListener('new-window', function (event) {
utils.writeConsoleMsg('info', 'eventListenerForSingleService ::: new-window for: _' + serviceId + '_.')
const shell = require('electron').shell
// const protocol = require('url').parse(event.url).protocol // 'url.parse' was deprecated since v11.0.0.
// const http = require('url')
const myURL = new URL(event.url)
const protocol = myURL.protocol
if (protocol === 'http:' || protocol === 'https:') {
// Display warning for http links - see: https://electronjs.org/docs/tutorial/security
if (protocol === 'http:') {
const Noty = require('noty')
const n = new Noty(
{
theme: 'bootstrap-v4',
layout: 'bottom',
type: 'information',
closeWith: [''], // to prevent closing the confirm-dialog by clicking something other then a confirm-dialog-button
text: 'Do you really want to open this potentially unsafe link (reason: not using https://) ?',
buttons: [
Noty.button('Yes', 'btn btn-danger', function () {
n.close()
utils.writeConsoleMsg('info', 'User confirmed to open non-https:// link: _' + event.url + '_.')
shell.openExternal(event.url)
},
{
id: 'button1', 'data-status': 'ok'
}),
Noty.button('No', 'btn btn-success float-right', function () {
n.close()
})
]
})
// show the noty dialog
n.show()
} else {
// its https://
shell.openExternal(event.url)
}
}
})
}
// /WebView Event: new-window / clicking links
utils.writeConsoleMsg('info', 'eventListenerForSingleService ::: End for service: _' + serviceId + '_.')
}
/**
* @function closeSingleServiceConfiguratationWindow
* @summary Triggers a function in main.js to close the single-service-configuration popup window
* @description Triggers a function in main.js to close the single-service-configuration popup window
* @memberof renderer
*/
function closeSingleServiceConfiguratationWindow () {
const { ipcRenderer } = require('electron')
ipcRenderer.send('closeConfigureSingleServiceWindow')
}
/**
* @function validateConfigSingleServiceForm
* @summary Validate the required input values from the config-single-service form
* @description Validate the required input values from the config-single-service form
* @memberof renderer
* @param {string} serviceName - The display name of the service
* @param {string} serviceIcon - The icon for this service
* @param {string} serviceUrl - The url of this service
* @return {boolean} true or false - depending on the actual form validation
*/
function validateConfigSingleServiceForm (serviceName, serviceIcon, serviceUrl) {
utils.writeConsoleMsg('info', 'validateConfigSingleServiceForm ::: Starting to validate the form.')
if ((serviceName === '') || (serviceIcon === '') || (serviceUrl === '')) {
utils.writeConsoleMsg('warn', 'validateConfigSingleServiceForm ::: Form is not valid.')
return false
} else {
utils.writeConsoleMsg('info', 'validateConfigSingleServiceForm ::: Form is valid.')
return true
}
}
/**
* @function createSingleServiceConfiguration
* @summary Fetches the input values from the single-service-configuration popup window and creates a related service config
* @description Fetches the input values from the single-service-configuration popup window and creates a related service config
* @memberof renderer
* @todo This functions gets ignored for eslint/standardx as it is only called from configWindow.html
*/
function createSingleServiceConfiguration () { // eslint-disable-line no-unused-vars
const storage = require('electron-json-storage')
utils.jsonStoragePathSet() // set default path
utils.writeConsoleMsg('info', 'createSingleServiceConfiguration ::: Starting to create a new service config')
// get values from configServiceWindow
const serviceId = $('#input_serviceId').val()
const serviceType = $('#input_serviceType').val() // hidden
const serviceName = $('#input_serviceName').val()
const serviceIcon = $('#input_serviceIcon').val()
const serviceUrl = $('#input_serviceUrl').val()
const serviceInjectCode = $('#input_serviceInjectCode').val() // hidden
const serviceUserAgentDefault = $('#input_serviceUserAgentDefault').val()
const serviceUserAgentCustom = $('#input_serviceUserAgentCustom').val()
const serviceEnableStatus = true
const isFormValid = validateConfigSingleServiceForm(serviceName, serviceIcon, serviceUrl)
if (isFormValid === true) {
// create a new config for the configured service
storage.set(serviceId, {
type: serviceType,
name: serviceName,
icon: serviceIcon,
url: serviceUrl,
injectCode: serviceInjectCode,
serviceEnableStatus: serviceEnableStatus,
userAgentDefault: serviceUserAgentDefault,
userAgentCustom: serviceUserAgentCustom
},
function (error) {
const { ipcRenderer } = require('electron')
ipcRenderer.send('reloadMainWindow') // reload the main window
closeSingleServiceConfiguratationWindow() // close aka hide the configWindow
utils.writeConsoleMsg('info', 'createSingleServiceConfiguration ::: Created a new service config for: _' + serviceId + '_.')
if (error) {
utils.writeConsoleMsg('error', 'createSingleServiceConfiguration ::: Error: ' + error)
throw error
}
})
}
}
/**
* @function updateSingleServiceConfiguration
* @summary Fetches the input values from the single-service-configuration popup window and updates the related service config
* @description Fetches the input values from the single-service-configuration popup window and updates the related service config
* @memberof renderer
* @todo This functions gets ignored for eslint/standardx as it is only called from configWindow.html
*/
function updateSingleServiceConfiguration () { // eslint-disable-line no-unused-vars
utils.writeConsoleMsg('info', 'updateSingleServiceConfiguration ::: Starting to update an existing service config')
const storage = require('electron-json-storage')
utils.jsonStoragePathSet() // set default path
// get values from configServiceWindow
const serviceId = $('#input_serviceId').val()
const serviceType = $('#input_serviceType').val() // hidden
const serviceName = $('#input_serviceName').val()
const serviceIcon = $('#input_serviceIcon').val()
const serviceUrl = $('#input_serviceUrl').val()
const serviceUserAgentDefault = $('#input_serviceUserAgentDefault').val()
const serviceUserAgentCustom = $('#input_serviceUserAgentCustom').val()
const serviceInjectCode = $('#input_serviceInjectCode').val() // hidden
let serviceEnableStatus = $('#input_serviceEnableStatus').val() // hidden
if (serviceEnableStatus === 'true') {
serviceEnableStatus = true
} else {
serviceEnableStatus = false
}
const isFormValid = validateConfigSingleServiceForm(serviceName, serviceIcon, serviceUrl)
if (isFormValid === true) {
// update the config of the configured service (status)
storage.set(serviceId, {
type: serviceType,
name: serviceName,
icon: serviceIcon,
url: serviceUrl,
injectCode: serviceInjectCode,
serviceEnableStatus: serviceEnableStatus,
userAgentDefault: serviceUserAgentDefault,
userAgentCustom: serviceUserAgentCustom
}, function (error) {
const { ipcRenderer } = require('electron')
ipcRenderer.send('reloadMainWindow') // reload the main window
closeSingleServiceConfiguratationWindow() // close aka hide the configWindow
utils.writeConsoleMsg('info', 'updateSingleServiceConfiguration ::: Updating service config: _' + serviceId + '_.')
if (error) {
utils.writeConsoleMsg('error', 'updateSingleServiceConfiguration ::: Error: ' + error)
throw error
}
})
}
}
/**
* @function configureSingleUserService
* @summary Triggers a function in main.js to open the single-service-configuration popup window
* @description Triggers a function in main.js to open the single-service-configuration popup window
* @memberof renderer
* @param {string} serviceId - id of the service
*/
function configureSingleUserService (serviceId) { // eslint-disable-line no-unused-vars
const { ipcRenderer } = require('electron')
utils.writeConsoleMsg('info', 'configureSingleUserService ::: Trying to open service configure window for service: _' + serviceId + '_.')
ipcRenderer.send('showConfigureSingleServiceWindow', serviceId) // send ipc to show service-configuration window
}
/**
* @function openDevTools
* @summary Toggles the DevConsole
* @description Opens or closes the Developer Console inside the app. Gets called from mainWindow.html
* @memberof renderer
*/
function openDevTools () { // eslint-disable-line no-unused-vars
const remote = require('electron').remote
utils.writeConsoleMsg('info', 'openDevTools ::: Opening Developer Console')
remote.getCurrentWindow().toggleDevTools()
}
/**
* @function settingToggleAutostart
* @summary Enables or disables the autostart
* @description Enables or disables the autostart
* @memberof renderer
* @todo This functions gets ignored for eslint/standardx as it is only called from mainWindow.html
*/
function settingToggleAutostart () { // eslint-disable-line no-unused-vars
const isDev = require('electron-is-dev')
if (isDev) {
utils.showNoty('warning', 'Configuring autostart is only supported in packaged builds.')
$('#checkboxSettingAutostart').prop('checked', false) // unselect the autostart checkbox
} else {
const AutoLaunch = require('auto-launch') // auto-launch - via: https://www.npmjs.com/package/auto-launch
const ttthAutoLauncher = new AutoLaunch({
name: 'ttth',
useLaunchAgent: true
})
// Handle depending on the checkbox state
// enabling the autostart
if ($('#checkboxSettingAutostart').prop('checked')) {
showNotyAutostartMinimizedConfirm()
} else {
ttthAutoLauncher.disable() // disabling the autostart
writeLocalUserSetting('settingAutostart', false)
utils.writeConsoleMsg('info', 'settingToggleAutostart ::: Finished disabling Autostart')
utils.showNoty('success', "<i class='fas fa-toggle-off'></i> <b>Option:</b> <u>Autostart (on login)</u> is now disabled.")
}
ttthAutoLauncher.isEnabled()
.then(function (isEnabled) {
if (isEnabled) {
return
}
ttthAutoLauncher.enable()
})
.catch(function (err) {
utils.writeConsoleMsg('error', 'settingToggleAutostart ::: Error: ' + err)
throw err
})
}
}
/**
* @function settingDefaultViewUpdate
* @summary Stores a new default view to local storage
* @description Users can define a default / startup view in settings. This method stores the users choice into local storage.
* @memberof renderer
* @todo This functions gets ignored for eslint/standardx as it is only called from mainWindow.html
*/
function settingDefaultViewUpdate () { // eslint-disable-line no-unused-vars
const newDefaultView = $('#selectDefaultView').val() // get currently selected value from select
if (newDefaultView !== null) {
utils.writeConsoleMsg('info', 'settingDefaultViewUpdate ::: New default view on start is set to: ' + newDefaultView)
writeLocalUserSetting('settingDefaultView', newDefaultView) // Store new default view in local storage
utils.showNoty('success', 'Set default view to <b>' + newDefaultView + '</b>.') // show noty
} else {
utils.showNoty('warning', 'Please <b>choose a service</b> to set a custom <b>default view</b>.') // user forgot to select a service for new default view
}
}
/**
* @function checkSupportedOperatingSystem
* @summary Checks if the operating system is supported or not
* @description Checks if the operating system is linux, windows or macOS. Those are supported - others are currently not.
* @memberof renderer
*/
function checkSupportedOperatingSystem () {
let supportedOperatingSystemMessage = ''
const userPlatform = process.platform // process.platform (works without require) vs os.platform
utils.writeConsoleMsg('info', 'checkSupportedOperatingSystem ::: Detected operating system as: ' + userPlatform)
switch (userPlatform) {
case 'win32':
case 'windows':
case 'linux':
case 'darwin':
case 'freebsd':
utils.writeConsoleMsg('info', 'checkSupportedOperatingSystem ::: Operating system ' + userPlatform + ' is fine.')
break
default:
// could be: sunos or whatever else
supportedOperatingSystemMessage = userPlatform + ' is currently not supported. Please contact devs.' // define message
utils.showNoty('warning', supportedOperatingSystemMessage, 0)
utils.writeConsoleMsg('error', 'checkSupportedOperatingSystem ::: ' + supportedOperatingSystemMessage)
}
}
/**
* @function openReleasesOverview
* @summary Opens the ttth release page
* @description Opens the url https://github.com/yafp/ttth/releases in the default browser. Used in searchUpdate().
* @memberof renderer
*/
function openReleasesOverview () {
const { urlGitHubReleases } = require('./js/ttth/modules/urlsGithub.js')
utils.writeConsoleMsg('info', 'openReleasesOverview ::: Opening _' + urlGitHubReleases + '_ to show available releases')
utils.openURL(urlGitHubReleases)
}
/**
* @function searchUpdate
* @summary Checks if there is a new release available
* @description Compares the local app version number with the tag of the latest github release. Displays a notification in the settings window if an update is available.
* @param {boolean} [silent] - Boolean with default value. Shows a feedback in case of no available updates If "silent" = false. Special handling for manually triggered update search
* @memberof renderer
*/
function searchUpdate (silent = true) {
// when executed manually via menu -> user should see that update-check is running
/*
if (silent === false) {
utils.showNoty('info', 'Searching for updates')
}
*/
// const { urlGitHubRepoTags } = require('./js/ttth/modules/urlsGithub.js') // old
const { urlGithubApiReleases } = require('./js/ttth/modules/urlsGithub.js')
// get setting
const curSettingEnablePrereleases = utils.globalObjectGet('settingEnablePrereleases')
utils.writeConsoleMsg('info', 'searchUpdate ::: Setting enablePrereleases is set to _' + curSettingEnablePrereleases + '_.')
let remoteAppVersionLatest = '0.0.0'
let remoteAppVersionLatestPrerelease = false
let localAppVersion = '0.0.0'
let versions
// get local version
//
// localAppVersion = require('electron').remote.app.getVersion()
localAppVersion = utils.getAppVersion()
// localAppVersion = '0.0.1'; // overwrite variable to simulate
// var updateStatus = $.get(urlGithubApiReleases, function (data) {
$.get(urlGithubApiReleases, function (data) {
// 3000 // in milliseconds
// success
versions = data.sort(function (v1, v2) {
// return semver.compare(v2.tag_name, v1.tag_name);
// console.error(v1.tag_name)
// console.error(v2.tag_name)
})
if (curSettingEnablePrereleases === true) {
// user wants the latest release - ignoring if it is a prerelease or an official one
utils.writeConsoleMsg('info', 'searchUpdate ::: Including pre-releases in update search')
remoteAppVersionLatest = versions[0].tag_name // Example: 0.4.2
remoteAppVersionLatestPrerelease = versions[0].prerelease // boolean
} else {
// user wants official releases only
utils.writeConsoleMsg('info', 'searchUpdate ::: Ignoring pre-releases in update search')
// find the latest non pre-release build
// loop over the versions array to find the latest non-pre-release
// var latestOfficialRelease
for (var i = 0; i < versions.length; i++) {
if (versions[i].prerelease === false) {
// latestOfficialRelease = i
break
}
}
remoteAppVersionLatest = versions[i].tag_name // Example: 0.4.2
// remoteAppVersionLatest = '66.6.6' // overwrite variable to simulate available updates
remoteAppVersionLatestPrerelease = versions[i].prerelease // boolean
}
utils.writeConsoleMsg('info', 'searchUpdate ::: Local ttth version: _' + localAppVersion + '_.')
utils.writeConsoleMsg('info', 'searchUpdate ::: Latest ttth version: _' + remoteAppVersionLatest + '_ - Is pre-release: _' + remoteAppVersionLatestPrerelease + '_.')
// If a stable (not a prelease) update is available - see #73
if (localAppVersion < remoteAppVersionLatest) {
utils.writeConsoleMsg('info', 'searchUpdate ::: Found update, notify user')
// ask user using a noty confirm dialog
const Noty = require('noty')
const n = new Noty(
{
theme: 'bootstrap-v4',
layout: 'bottom',
type: 'info',
closeWith: [''], // to prevent closing the confirm-dialog by clicking something other then a confirm-dialog-button
text: 'A <b>ttth</b> update from <b>' + localAppVersion + '</b> to version <b>' + remoteAppVersionLatest + '</b> is available. Do you want to visit the release page?',
buttons: [
Noty.button('Yes', 'btn btn-success', function () {
n.close()
openReleasesOverview()
},
{
id: 'button1', 'data-status': 'ok'
}),
Noty.button('No', 'btn btn-secondary float-right', function () {
n.close()
})
]
})
// show the noty dialog
n.show()
} else {
utils.writeConsoleMsg('info', 'searchUpdate ::: No newer version of ttth found.')
// when executed manually via menu -> user should see result of this search
if (silent === false) {
utils.showNoty('success', 'No <b>ttth</b> updates available')
}
}
utils.writeConsoleMsg('info', 'searchUpdate ::: Successfully checked ' + urlGithubApiReleases + ' for available releases')
})
.done(function () {
// utils.writeConsoleMsg('info', 'searchUpdate ::: Successfully checked ' + urlGithubApiReleases + ' for available releases');
})
.fail(function () {
utils.writeConsoleMsg('info', 'searchUpdate ::: Checking ' + urlGithubApiReleases + ' for available releases failed.')
utils.showNoty('error', 'Checking <b>' + urlGithubApiReleases + '</b> for available ttth releases failed. Please troubleshoot your network connection.', 0)
})
.always(function () {
utils.writeConsoleMsg('info', 'searchUpdate ::: Finished checking ' + urlGithubApiReleases + ' for available releases')
})
}
/**
* @function validateConfiguredDefaultView
* @summary Checks on startup if the service configured as default view is a valid / enabled service
* @description Checks if the default view is valid, otherwise fallbacks to settings view
* @memberof renderer
*/
function validateConfiguredDefaultView () {
readLocalUserSetting('settingDefaultView')
}
/**
* @function loadServiceSpecificCode
* @summary Executes service specific javascript code on service-activation
* @description Executes service specific javascript code on service-activation
* @memberof renderer
* @param {string} serviceId - The ID of the service
* @param {string} serviceName - Name of the service
*/
function loadServiceSpecificCode (serviceId, serviceName) {
utils.writeConsoleMsg('info', 'loadServiceSpecificCode ::: Checking for service-specific code for the service: ' + serviceName + ' with the id: _' + serviceId + '_.')
switch (serviceName) {
// V1: unread message handler: NO - && Link handler: NO
//
case 'dropbox':
case 'github':
case 'googleCalendar':
case 'googleContacts':
case 'googleDrive':
case 'googlePhotos':
case 'nextcloud':
utils.writeConsoleMsg('info', 'loadServiceSpecificCode ::: Executing ' + serviceName + ' specific things')
eventListenerForSingleService(serviceId, false, false)
break
// V2: unread-message-handler: NO - && - Link-handler: YES
case 'freenode':
case 'googleDuo':
case 'googleKeep':
case 'linkedIn':
case 'reddit':
case 'wechat':
case 'wire':
utils.writeConsoleMsg('info', 'loadServiceSpecificCode ::: Executing ' + serviceName + ' specific things')
eventListenerForSingleService(serviceId, false, true)
break
// V3: Unread-message-handler: YES - && - link handler: NO
case 'gitter':
case 'twitter':
case 'xing':
utils.writeConsoleMsg('info', 'loadServiceSpecificCode ::: Executing ' + serviceName + ' specific things')
eventListenerForSingleService(serviceId, true, false)
break
// V4: Unread-message-handler: YES && link-handler: YES
case 'discord':
case 'googleMail':
case 'googleMessages':
case 'icq':
case 'mattermost':
case 'messenger':
case 'microsoftOutlook':
case 'microsoftOffice365':
case 'microsoftTeams':
case 'riot':
case 'skype':
case 'slack':
case 'steam':
case 'telegram':
case 'threema':
utils.writeConsoleMsg('info', 'loadServiceSpecificCode ::: Executing ' + serviceName + ' specific things')
eventListenerForSingleService(serviceId, true, true)
break
// Specialcase: WhatsApp
case 'whatsapp':
utils.writeConsoleMsg('info', 'loadServiceSpecificCode ::: Executing ' + serviceName + ' specific things')
/* global serviceWhatsAppRegister */
serviceWhatsAppRegister()
eventListenerForSingleService(serviceId, true, true)
break
default:
// utils.writeConsoleMsg("info", "loadServiceSpecificCode ::: Nothing to do here");
}
}
/**
* @function initAvailableServicesSelection
* @summary fills the select item in settings-page (which features all supported services)
* @description fills the select item in settings-page (which features all supported services). Source is services.json
* @memberof renderer
*/
function initAvailableServicesSelection () {
utils.writeConsoleMsg('info', 'initAvailableServicesSelection ::: Reload settings select with all supported service definitions')
let counterSupportedServices = 0
const dropdown = $('#select_availableServices') // get reference to select which contains all supported service type definitions
dropdown.prop('selectedIndex', 0) // select the first entry
// url to service definitions
const path = require('path')
const url = path.join(__dirname, '/js/ttth/services.json')
// Populate select with list of provinces
$.getJSON(url, function (data) {
$.each(data, function (key, entry) {
dropdown.append($('<option></option>').attr('value', entry.id).text(entry.nameLong)) // add option to select
counterSupportedServices = counterSupportedServices + 1 // count services
})
utils.writeConsoleMsg('info', 'initAvailableServicesSelection ::: Finished reloading settings select with all supported service definitions. Found _' + counterSupportedServices + '_ service types.')
})
}
/**
* @function loadConfiguredUserServices
* @summary loads all the configured-user-services to the configured-services-section of the settings tab.
* @description removes all configured user services from settings view, reads all configured user services and re-adds them to the settings ui under 'Configured services'
* @memberof renderer
*/
function loadConfiguredUserServices () {
const storage = require('electron-json-storage')
utils.jsonStoragePathSet() // set default path
$('#settingsServicesConfigured').empty() // empty the div
// read all user service configuration files
storage.getAll(function (error, data) {
if (error) {
utils.writeConsoleMsg('error', 'loadConfiguredUserServices ::: Error while trying to get all user service configurations. Error: ' + error)
throw error
}
// show object which contains all config files
// utils.writeConsoleMsg("error", (data);
// utils.writeConsoleMsg("error", (typeof data);
let serviceCount = 0
utils.writeConsoleMsg('info', 'loadConfiguredUserServices ::: Found the following user configs: _' + data + '_.')
// loop over upper object
for (const key in data) {
// if (data.hasOwnProperty(key)) {
utils.writeConsoleMsg('info', 'loadConfiguredUserServices ::: ' + key + ' -> ' + data[key])
// show 2 services per row
if (serviceCount % 2 === 0) {
// odd
// create a new row
$('#settingsServicesConfigured').append("<div class='row ttthServiceRow' id='conf_" + serviceCount + "'></div>")
if (data[key].serviceEnableStatus === true) {
// show enabled configured service
$('#conf_' + serviceCount).append('<div class="col-sm-6"><div class="input-group input-group-sm mb-1"><div class="input-group-prepend"><div class="input-group-text"><i title="Service: ' + data[key].type + '" class="ttthServiceIcon ' + data[key].icon + '"></i></div></div><input type="text" class="form-control" id="label_' + data[key].url + '" aria-label="Text input with checkbox" value=' + data[key].name + ' title=' + data[key].url + ' disabled><div class="input-group-prepend"><button type="button" id="bt_configSingleService_' + key + '" title="configure" class="btn btn-dark" onClick="configureSingleUserService(\'' + key + '\')"><i class="fas fa-cog"></i></button><button type="button" class="btn btn-success btn-sm" id="bt_' + key + '" title="enabled" onClick="settingsToggleEnableStatusOfSingleUserService(\'' + key + '\');"><i id=statusIconService_' + key + ' class="fas fa-toggle-on"></i></button><button type="button" class="btn btn-danger btn-sm" id="bt_delete' + key + '" title="delete" onClick="deleteConfiguredService(\'' + key + '\');"><i class="fas fa-trash-alt"></i></button></div></div></div>')
} else {
// show disabled configured service
$('#conf_' + serviceCount).append('<div class="col-sm-6"><div class="input-group input-group-sm mb-1"><div class="input-group-prepend"><div class="input-group-text"><i title="Service: ' + data[key].type + '" class="ttthServiceIcon ' + data[key].icon + '"></i></div></div><input type="text" class="form-control" id="label_' + data[key].url + '" aria-label="Text input with checkbox" value=' + data[key].name + ' title=' + data[key].url + ' disabled><div class="input-group-prepend"><button type="button" id="bt_configSingleService_' + key + '" title="configure" class="btn btn-dark" onClick="configureSingleUserService(\'' + key + '\')"><i class="fas fa-cog"></i></button><button type="button" class="btn btn-secondary btn-sm" id="bt_' + key + '" title="disabled" onClick="settingsToggleEnableStatusOfSingleUserService(\'' + key + '\');"><i id=statusIconService_' + key + ' class="fas fa-toggle-off"></i></button><button type="button" class="btn btn-danger btn-sm" id="bt_delete' + key + '" title="delete" onClick="deleteConfiguredService(\'' + key + '\');"><i class="fas fa-trash-alt"></i></button></div></div></div>')
}
} else {
// ...even - add to existing row - in col 2
// add something to the existing row
const rowReference = serviceCount - 1
if (data[key].serviceEnableStatus === true) {
// show enabled configured service
$('#conf_' + rowReference).append('<div class="col-sm-6"><div class="input-group input-group-sm mb-1"><div class="input-group-prepend"><div class="input-group-text"><i title="Service: ' + data[key].type + '" class="ttthServiceIcon ' + data[key].icon + '"></i></div></div><input type="text" class="form-control" id="label_' + data[key].url + '" aria-label="Text input with checkbox" value=' + data[key].name + ' title=' + data[key].url + ' disabled><div class="input-group-prepend"><button type="button" id="bt_configSingleService_' + key + '" title="configure" class="btn btn-dark" onClick="configureSingleUserService(\'' + key + '\')"><i class="fas fa-cog"></i></button><button type="button" class="btn btn-success btn-sm" id="bt_' + key + '" title="enabled" onClick="settingsToggleEnableStatusOfSingleUserService(\'' + key + '\');"><i id=statusIconService_' + key + ' class="fas fa-toggle-on"></i></button><button type="button" class="btn btn-danger btn-sm" id="bt_delete' + key + '" title="delete" onClick="deleteConfiguredService(\'' + key + '\');"><i class="fas fa-trash-alt"></i></button></div></div></div>')
} else {
// show disabled configured service
$('#conf_' + rowReference).append('<div class="col-sm-6"><div class="input-group input-group-sm mb-1"><div class="input-group-prepend"><div class="input-group-text"><i title="Service: ' + data[key].type + '" class="ttthServiceIcon ' + data[key].icon + '"></i></div></div><input type="text" class="form-control" id="label_' + data[key].url + '" aria-label="Text input with checkbox" value=' + data[key].name + ' title=' + data[key].url + ' disabled><div class="input-group-prepend"><button type="button" id="bt_configSingleService_' + key + '" title="configure" class="btn btn-dark" onClick="configureSingleUserService(\'' + key + '\')"><i class="fas fa-cog"></i></button><button type="button" class="btn btn-secondary btn-sm" id="bt_' + key + '" title="disabled" onClick="settingsToggleEnableStatusOfSingleUserService(\'' + key + '\');"><i id=statusIconService_' + key + ' class="fas fa-toggle-off"></i></button><button type="button" class="btn btn-danger btn-sm" id="bt_delete' + key + '" title="delete" onClick="deleteConfiguredService(\'' + key + '\');"><i class="fas fa-trash-alt"></i></button></div></div></div>')
}
}
serviceCount = serviceCount + 1
// }
}
})
utils.writeConsoleMsg('info', 'loadConfiguredUserServices ::: Finished loading all configured user services to settings page')
}
/**
* @function initSettingsPage
* @summary Initializes the settings page
* @description Shows links to github informations. update informations. Initializes the service-checkboxes on loading the view.
* @memberof renderer
*/
function initSettingsPage () {
// Start checking each single option
readLocalUserSetting('settingAutostart') // Option: Autostart
readLocalUserSetting('settingTheme') // Option: Theme
readLocalUserSetting('settingDisableTray') // Option: DisableTray (Linux only)
readLocalUserSetting('settingUrgentWindow') // Option: Urgent Window
readLocalUserSetting('settingEnableErrorReporting') // Option: Urgent Window
readLocalUserSetting('settingEnablePrereleases') // Option: Urgent Window
// load all supported services to drop-down-list (used for adding new services)
initAvailableServicesSelection()
// show all user-configured services under "configured services"
loadConfiguredUserServices()
}
/**
* @function removeServiceTab
* @summary Remove a single service tab from the UI
* @description Removes the li item from tab menu, removes the tab itself
* @memberof renderer
* @param {string} tabId
*/
function removeServiceTab (tabId) {
utils.writeConsoleMsg('info', 'removeServiceTab ::: Starting to remove the tab: _' + tabId + '_.')
// remove service nav-item from menu
$('#menu_' + tabId).remove()
utils.writeConsoleMsg('info', 'removeServiceTab ::: Removed service nav item from navigation (_' + tabId + '_)')
// get webview
// var webview = document.getElementById("webview_" + tabId);
// remove webview listeners
// webview.removeEventListener("ipc-message");
// remove webview itself
// webview.remove();
// utils.writeConsoleMsg("info", "removeServiceTab ::: Removing the webview itself: _" + webview + "_.");
// remove tabcontent from tab pane
$('#' + tabId).remove()
// remove service from select for DefaultView
$('#selectDefaultView option[value=' + tabId + ']').remove()
// reload the main window (see #117 - to avoid sending request to non-existing webviews)
// const { ipcRenderer } = require('electron')
// ipcRenderer.send('reloadMainWindow')
// baustelle
setTimeout(function () {
const { ipcRenderer } = require('electron')
ipcRenderer.send('reloadMainWindow')
}, 150)
utils.writeConsoleMsg('info', 'removeServiceTab ::: Finished removing the tab: _' + tabId + '_.')
}
/**
* @function addServiceTab
* @summary Add a single tab to UI
* @description Add the li item to tab menu, adds the tab itself
* @memberof renderer
* @param {string} serviceId
* @param {string} serviceType
* @param {string} serviceName
* @param {string} serviceIcon
* @param {string} serviceUrl
* @param {string} serviceInjectCode
* @param {string} serviceUserAgentDefault
* @param {string} serviceUserAgentCustom
*/
function addServiceTab (serviceId, serviceType, serviceName, serviceIcon, serviceUrl, serviceInjectCode, serviceUserAgentDefault, serviceUserAgentCustom) {
utils.writeConsoleMsg('info', 'addServiceTab ::: Starting to add the tab: _' + serviceId + '_.')
// tab-position
const existingTabs = $('#myTabs li').length // get amount of tabs
const newTabPosition = existingTabs - 1 // calculate new tab position
// choose the right userAgent
let userAgent = appWideUserAgentDefault // setting a project wide default
if (serviceUserAgentDefault !== '') {
userAgent = serviceUserAgentDefault // overwrite with service-specific default, if set
}
if (serviceUserAgentCustom !== '') {
userAgent = serviceUserAgentCustom // overwrite with service-specific custom, if set
}
// Baustelle: FIXME - see #185
//
// check if injectCode path is valid / exists - see #185
if (serviceInjectCode === '') {
utils.writeConsoleMsg('info', 'addServiceTab ::: No inject code given, therefor nothing to validate.')
} else {
const path = require('path')
const fs = require('fs')
const relInjectPath = serviceInjectCode.replace('./', '')
const currentPath = path.join(__dirname, relInjectPath)
utils.writeConsoleMsg('info', 'addServiceTab ::: Full inject path: _' + currentPath + '_. Now checkiing if it is valid')
if (fs.existsSync(currentPath)) {
utils.writeConsoleMsg('info', 'addServiceTab ::: Path to given inject code file is valid. Valid path is: _' + serviceInjectCode + '_.')
} else {
utils.writeConsoleMsg('error', 'addServiceTab ::: Trying to inject a non existing inject code file. Invalid path is: _' + serviceInjectCode + '_.')
serviceInjectCode = '' // reset the path
utils.showNoty('error', 'The service <b>' + serviceName + '</b> (id: ' + serviceId + ') tried to load a non-valid inject file. Inject code is now ignored. Please check the service configuration (.json file).', 0)
}
}
// Parsing url and extract domain for persist-handling of webview
const serviceDomain = utils.getDomain(serviceUrl)
// add new list item to unordner list (tabs/menu)
//
// $('#myTabs li:eq(' + newTabPosition + ')').after('<li class="nav-item small" id=menu_'+ serviceId +'><a class="nav-link ttth_nonSelectableText" id=target_' + serviceId +' href=#' + serviceId + ' role="tab" data-toggle="tab"><i class="' + serviceIcon +'"></i> ' + serviceName + ' <span id=badge_' + serviceId + ' class="badge badge-success"></span></a></li>');
$('#myTabs li:eq(' + newTabPosition + ')').after("<li class='nav-item small' id=menu_" + serviceId + "><a class='nav-link ttth_nonSelectableText' id=target_" + serviceId + ' href=#' + serviceId + " role='tab' data-toggle='tab'><span id=shortcut_" + serviceId + " class='badge badge-pill badge-warning'></span> <i id=icon_" + serviceId + " class='" + serviceIcon + "'></i> " + serviceName + ' <span id=badge_' + serviceId + " class='badge badge-success'></span></a></li>")
utils.writeConsoleMsg('info', 'addServiceTab ::: Added the navigation tab for service: _' + serviceId + '_.')
// add the tab itself to #tabPanes
//
$('#tabPanes').append("<div role='tabpanel' class='tab-pane fade flex-fill ttth_resizer container-fluid' id=" + serviceId + '></div>')
utils.writeConsoleMsg('info', 'addServiceTab ::: Added the tab pane for service: _' + serviceId + '_.')
// add webview to new tab
//
if (serviceType === 'whatsapp') {
// Whatsapp needs: - no partition
$('#' + serviceId).append('<webview id=webview_' + serviceId + " class='ttth_resizer' src=" + serviceUrl + ' preload=' + serviceInjectCode + " userAgent='" + userAgent + "'></webview>")
} else {
if (serviceInjectCode === '') {
// no inject code
$('#' + serviceId).append('<webview id=webview_' + serviceId + ' partition=persist:' + serviceDomain + " class='ttth_resizer' src=" + serviceUrl + ' userAgent="' + userAgent + '"></webview>')
} else {
// got injectCode, preload it
$('#' + serviceId).append('<webview id=webview_' + serviceId + ' partition=persist:' + serviceDomain + " class='ttth_resizer' src=" + serviceUrl + ' preload=' + serviceInjectCode + ' userAgent="' + userAgent + '"></webview>')
}
}
utils.writeConsoleMsg('info', 'addServiceTab ::: Finished adding the tab: _' + serviceId + '_.')
$('#selectDefaultView').append(new Option(serviceName, serviceId)) // add service to select for DefaultView
loadServiceSpecificCode(serviceId, serviceType)
}
/**
* @function updateGlobalServicesShortcuts
* @summary Assigns global shortcuts for all service tabs
* @description Assigns global shortcuts for all service tabs
* @memberof renderer
*/
function updateGlobalServicesShortcuts () {
const { ipcRenderer } = require('electron')
let tabCounter = 0
let currentTabId
let numberOfEnabledServices // counts the amount of enabled user services
utils.writeConsoleMsg('info', 'updateGlobalServicesShortcuts ::: Starting to update global service shortcuts')
// Ensure to remove all possible shortcuts before re-creating them. See #74
//
// count enabled services:
numberOfEnabledServices = $('#myTabs li').length
numberOfEnabledServices = numberOfEnabledServices - 1 // as the settings tab doesnt count
// if there are configured services so far - delete all existing shortcuts
if (numberOfEnabledServices > 0) {
// ipcRenderer.send("deleteAllGlobalServicesShortcut", numberOfEnabledServices);
ipcRenderer.send('deleteAllGlobalServicesShortcut', 9)
}
// Create new global shortcuts
$('#myTabs li a').each(function () {
currentTabId = $(this).attr('id')
if (currentTabId === 'target_Settings') {
utils.writeConsoleMsg('info', 'updateGlobalServicesShortcuts ::: Ignoring settings tab.') // Shortcut for settings tab is already hard-coded.
} else {
// dynamic shortcuts for all services (well max. 9 - not all)
tabCounter = tabCounter + 1
if (tabCounter < 10) {
// can't assign shortcuts > 9
ipcRenderer.send('createNewGlobalShortcut', 'CmdOrCtrl+' + tabCounter, currentTabId) // create dynamic globalShortcut
}
}
})
utils.writeConsoleMsg('info', 'updateGlobalServicesShortcuts ::: Finished updating global shortcuts for services')
}
/**
* @function settingsToggleEnableStatusOfSingleUserService
* @summary Enables or disabled the status of a single user configured service
* @description User can enable or disable his configured services in settings page.
* @memberof renderer
* @param {string} configuredUserServiceConfigName - Name of the config file of the selected service
*/
function settingsToggleEnableStatusOfSingleUserService (configuredUserServiceConfigName) { // eslint-disable-line no-unused-vars
utils.writeConsoleMsg('info', 'settingsToggleEnableStatusOfSingleUserService ::: Toggling the configured service defined in config file: _' + configuredUserServiceConfigName + '_.')
const storage = require('electron-json-storage')
utils.jsonStoragePathSet() // set default path
let serviceEnableStatus
// get content from service configuration file
storage.get(configuredUserServiceConfigName, function (error, data) {
if (error) {
utils.writeConsoleMsg('info', 'settingsToggleEnableStatusOfSingleUserService ::: Error while trying to get service informations from service _' + configuredUserServiceConfigName + '_ . Error: ' + error)
throw error
}
const type = data.type
const name = data.name
const icon = data.icon
const url = data.url
const injectCode = data.injectCode
const userAgentDefault = data.userAgentDefault
const userAgentCustom = data.userAgentCustom
// get status of enable/disable button:
if ($('#bt_' + configuredUserServiceConfigName).attr('title') === 'enabled') {
// is enabled - so disable it
// Status Button
$('#bt_' + configuredUserServiceConfigName).removeClass() // update button type by removing class and ...
$('#bt_' + configuredUserServiceConfigName).addClass('btn btn-secondary btn-sm') // update button type by adding a new class
$('#bt_' + configuredUserServiceConfigName).prop('title', 'disabled') // update button title
// update button icon
$('#statusIconService_' + configuredUserServiceConfigName).removeClass()
$('#statusIconService_' + configuredUserServiceConfigName).addClass('fas fa-toggle-off')
// set serviceEnableStatus variable
serviceEnableStatus = false
// remove service tab
removeServiceTab(configuredUserServiceConfigName)
utils.writeConsoleMsg('info', 'settingsToggleEnableStatusOfSingleUserService ::: Service _' + configuredUserServiceConfigName + '_ is now disabled.')
utils.showNoty('success', 'Disabled the service <b>' + configuredUserServiceConfigName + '</b>.')
} else {
// is disabled - so enable it
// Status Button
$('#bt_' + configuredUserServiceConfigName).removeClass() // update button type by removing class and ...
$('#bt_' + configuredUserServiceConfigName).addClass('btn btn-success btn-sm') // update button type by adding a new class
$('#bt_' + configuredUserServiceConfigName).prop('title', 'enabled') // update button title
// update button icon
$('#statusIconService_' + configuredUserServiceConfigName).removeClass()
$('#statusIconService_' + configuredUserServiceConfigName).addClass('fas fa-toggle-on')
// set serviceEnableStatus variable
serviceEnableStatus = true
// add tab for this enabled service
addServiceTab(configuredUserServiceConfigName, type, name, icon, url, injectCode, userAgentDefault, userAgentCustom)
// add service to selectDefaultView
$('#selectDefaultView').append(new Option(name, configuredUserServiceConfigName))
utils.writeConsoleMsg('info', 'settingsToggleEnableStatusOfSingleUserService ::: Service _' + configuredUserServiceConfigName + '_ is now enabled.')
utils.showNoty('success', 'Enabled the service <b>' + configuredUserServiceConfigName + '</b>.')
}
// update the config of the configured service (status)
storage.set(configuredUserServiceConfigName, {
type: type,
name: name,
icon: icon,
url: url,
injectCode: injectCode,
serviceEnableStatus: serviceEnableStatus,
userAgentDefault: userAgentDefault,
userAgentCustom: userAgentCustom
}, function (error) {
if (error) {
utils.writeConsoleMsg('error', 'settingsToggleEnableStatusOfSingleUserService ::: Error while trying to update the user service _' + configuredUserServiceConfigName + '_. Error: ' + error)
throw error
}
updateGlobalServicesShortcuts() // must re-set the globalShortcuts for all existing services / tabs - see #74
})
})
utils.writeConsoleMsg('info', 'settingsToggleEnableStatusOfSingleUserService ::: Service _' + configuredUserServiceConfigName + '_ config file is now updated (status)')
}
/**
* @function settingsToggleErrorReporting
* @summary Enables or disabled the error reporting function
* @description Enables or disabled the error reporting function
* @memberof renderer
* @todo This functions gets ignored for eslint/standardx as it is only called from mainWindow.html
*/
function settingsToggleErrorReporting () { // eslint-disable-line no-unused-vars
if ($('#checkboxSettingErrorReporting').is(':checked')) {
utils.writeConsoleMsg('info', 'settingsToggleErrorReporting ::: Error reporting is now enabled')
writeLocalUserSetting('settingEnableErrorReporting', true)
sentry.enableSentry()
utils.showNoty('success', "<i class='fas fa-toggle-on'></i> <b>Option:</b> <u>Error Reporting</u> is now enabled.")
} else {
// ask if user really wants to disable error-reporting (using a confirm dialog)
const Noty = require('noty')
const n = new Noty(
{
theme: 'bootstrap-v4',
layout: 'bottom',
type: 'info',
closeWith: [''], // to prevent closing the confirm-dialog by clicking something other then a confirm-dialog-button
text: 'Do you really want to disable error-reporting?<br><br>* We don\'t track users<br>* We do collect error reports<br><br>This helps us finding and fixing bugs in ttth',
buttons: [
Noty.button('Yes', 'btn btn-success', function () {
n.close()
utils.writeConsoleMsg('warn', 'settingsToggleErrorReporting ::: Error reporting is now disabled')
writeLocalUserSetting('settingEnableErrorReporting', false)
sentry.disableSentry()
utils.showNoty('success', "<i class='fas fa-toggle-off'></i> <b>Option:</b> <u>Error Reporting</u> is now disabled.")
},
{
id: 'button1', 'data-status': 'ok'
}),
Noty.button('No', 'btn btn-secondary ttth_btnDownloadActionWidth float-right', function () {
n.close()
$('#checkboxSettingErrorReporting').prop('checked', true) // revert state of checkbox
utils.showNoty('success', '<b>Thanks</b> for supporting ttth development with your error reports.')
utils.writeConsoleMsg('warn', 'settingsToggleErrorReporting ::: User cancelled disabling of error-reporting')
utils.showNoty('success', "<i class='fas fa-toggle-on'></i> <b>Option:</b> <u>Error Reporting</u> is now enabled.")
})
]
})
n.show() // show the noty dialog
}
}
/**
* @function settingsToggleEnablePrereleases
* @summary Handles toggling the checkbox for the setting/option enable-preleases
* @description Handles toggling the checkbox for the setting/option enable-preleases
* @memberof renderer
* @todo This functions gets ignored for eslint/standardx as it is only called from mainWindow.html
*/
function settingsToggleEnablePrereleases () { // eslint-disable-line no-unused-vars
let newSettingEnablePrereleases
if ($('#checkboxSettingEnablePrereleases').is(':checked')) {
newSettingEnablePrereleases = true
utils.writeConsoleMsg('info', 'settingsToggleEnablePrereleases ::: Pre-Releases is now enabled')
utils.showNoty('success', "<i class='fas fa-toggle-on'></i> <b>Option:</b> <u>Enable Prereleases</u> is now enabled.")
writeLocalUserSetting('settingEnablePrereleases', newSettingEnablePrereleases)
} else {
newSettingEnablePrereleases = false
utils.writeConsoleMsg('info', 'settingsToggleEnablePrereleases ::: Pre-Releases is now disabled')
utils.showNoty('success', "<i class='fas fa-toggle-off'></i> <b>Option:</b> <u>Enable Prereleases</u> is now disabled.")
writeLocalUserSetting('settingEnablePrereleases', newSettingEnablePrereleases)
}
}
/**
* @function fontAwesomeShowIconGallery
* @summary Reads all user configured service files and adds the enabled services as tabs
* @description Reads all user configured service files and adds the enabled services as tabs
* @memberof renderer
* @todo This functions gets ignored for eslint/standardx as it is only called from configWindow.html
*/
function fontAwesomeShowIconGallery () { // eslint-disable-line no-unused-vars
utils.openURL('https://fontawesome.com/icons?d=gallery&m=free')
}
/**
* @function loadEnabledUserServices
* @summary Reads all user configured service files and adds the enabled services as tabs
* @description Reads all user configured service files and adds the enabled services as tabs
* @memberof renderer
*/
function loadEnabledUserServices () {
const storage = require('electron-json-storage')
utils.jsonStoragePathSet() // set default path
utils.writeConsoleMsg('info', 'loadEnabledUserServices ::: Starting to fetch all user configured service files')
// loop over all json files - add tab for the enabled ones
storage.getAll(function (error, data) {
if (error) {
utils.writeConsoleMsg('error', 'loadEnabledUserServices ::: Error while trying to get all enabled user services. Error: ' + error)
utils.writeConsoleMsg('error', 'loadEnabledUserServices ::: Error:', error)
throw error
}
// show object which contains all config files
// utils.writeConsoleMsg("info", "loadEnabledUserServices ::: Object: " + data);
// console.error(data);
// loop over upper object
for (const key in data) {
// if (data.hasOwnProperty(key)) {
utils.writeConsoleMsg('info', 'loadEnabledUserServices ::: ' + key)
utils.writeConsoleMsg('info', 'loadEnabledUserServices ::: ' + key + ' -> ' + data[key])
// show enabled configured service
if (data[key].serviceEnableStatus === true) {
utils.writeConsoleMsg('info', 'loadEnabledUserServices ::: Trying to add the enabled service: _' + key + '_.')
addServiceTab(key, data[key].type, data[key].name, data[key].icon, data[key].url, data[key].injectCode, data[key].userAgentDefault, data[key].userAgentCustom)
} else {
utils.writeConsoleMsg('info', 'loadEnabledUserServices ::: Skipped service: _' + key + '_, as it not enabled.')
}
// }
}
utils.writeConsoleMsg('info', 'loadEnabledUserServices ::: Finished current service: ' + data)
})
}
/**
* @function deleteConfiguredService
* @summary Deletes a single configured user service
* @description Removes the tab, deletes the service user config, reloads the settings view which shows all user configured services.
* @memberof renderer
* @param {string} serviceId - the service id
*/
function deleteConfiguredService (serviceId) { // eslint-disable-line no-unused-vars
utils.writeConsoleMsg('info', 'deleteConfiguredService ::: Deleting the user service: _' + serviceId + '_.')
// cleanup after deleting the entire service
// var webview = document.getElementById("webview_" + serviceId);
// delete all Event handlers
$('#webview_' + serviceId).unbind('did-start-loading')
$('#webview_' + serviceId).unbind('dom-ready')
$('#webview_' + serviceId).unbind('did-stop-loading')
$('#webview_' + serviceId).unbind('ipc-message')
$('#webview_' + serviceId).unbind('new-window')
utils.writeConsoleMsg('warn', 'deleteConfiguredService ::: Deleted all event handlers from webview')
// Delete the webview of this service
$('#webview_' + serviceId).remove()
utils.writeConsoleMsg('warn', 'deleteConfiguredService ::: Removed the webview itself')
removeServiceTab(serviceId) // remove service tab in UI
// delete json config of this service
const storage = require('electron-json-storage')
utils.jsonStoragePathSet() // set default oath
storage.remove(serviceId, function (error) {
if (error) {
utils.writeConsoleMsg('error', 'deleteConfiguredService ::: Error while trying to delete the user service: _' + serviceId + '_. Error: ' + error)
throw error
}
})
utils.writeConsoleMsg('info', 'deleteConfiguredService ::: Finished deleting the user service: _' + serviceId + '_.')
utils.showNoty('success', 'Successfully deleted the service <b>' + serviceId + '</b>.')
// reload the main window
const { ipcRenderer } = require('electron')
ipcRenderer.send('reloadMainWindow')
}
/**
* @function settingsUserAddNewService
* @summary user wants to configure a new service
* @description user wants to configure a new service. Gets called from mainWindow.html
* @memberof renderer
* @todo This functions gets ignored for eslint/standardx as it is only called from mainWindow.html
*/
function settingsUserAddNewService () { // eslint-disable-line no-unused-vars
utils.writeConsoleMsg('info', 'settingsUserAddNewService ::: Starting to add a new user configured service.')
const storage = require('electron-json-storage')
utils.jsonStoragePathSet() // set default path
// get selected option from #select_availableServices
const userSelectedService = $('#select_availableServices').val()
utils.writeConsoleMsg('info', 'settingsUserAddNewService ::: Selected service type is: _' + userSelectedService + '_.')
if (userSelectedService !== null) {
utils.writeConsoleMsg('info', 'settingsUserAddNewService ::: Should add a new service of type: _' + userSelectedService + '_.')
// check if this service allows multiple instances
utils.writeConsoleMsg('info', 'settingsUserAddNewService ::: Checking if the service: _' + userSelectedService + '_ allows multiple instances')
// Parse service template
// const url = __dirname + '/js/ttth/services.json'
const path = require('path')
const url = path.join(__dirname, '/js/ttth/services.json')
$.getJSON(url, function (data) {
$.each(data, function (key, entry) {
if (entry.id === userSelectedService) {
// check if it allows multiple instances
if (entry.multiple === true) {
utils.writeConsoleMsg('info', 'settingsUserAddNewService ::: Service: _' + userSelectedService + '_ allows multiple instances')
// serviceAllowsMultipleInstances = true;
// send ipc to show second window
const { ipcRenderer } = require('electron')
ipcRenderer.send('showConfigureSingleServiceWindowNew', userSelectedService)
} else {
// single instance service
utils.writeConsoleMsg('warn', 'settingsUserAddNewService ::: Service: _' + userSelectedService + '_ does NOT allows multiple instances')
utils.writeConsoleMsg('info', 'settingsUserAddNewService ::: Check if there already exists an instance of the service type: _' + userSelectedService + '_.')
// check if there is already a configured service of that type.
// check which configs already exist
storage.getAll(function (error, data) {
if (error) {
utils.writeConsoleMsg('error', 'settingsUserAddNewService ::: Error while trying to get all user service configurations. Error: ' + error)
throw error
}
utils.writeConsoleMsg('info', data) // show object which contains all config files
for (const key in data) {
// if (data.hasOwnProperty(key)) {
// utils.writeConsoleMsg("info", key + " -> " + data[key]);
utils.writeConsoleMsg('info', data[key].type)
if (data[key].type === userSelectedService) {
utils.showNoty('error', 'There is already a configured service of the type <b>' + userSelectedService + '</b>.', 0)
return
}
// }
}
const { ipcRenderer } = require('electron')
ipcRenderer.send('showConfigureSingleServiceWindowNew', userSelectedService)
})
}
}
})
})
} else {
utils.writeConsoleMsg('warn', 'settingsUserAddNewService ::: No service type selected. Unable to add a new service.')
utils.showNoty('error', 'No service type selected. Unable to add a new service.')
}
}
/**
* @function localizeUserInterface
* @summary Localizes the user interface
* @description Is using i18next to localize the user interface. Translations are located in app/locales/.
* @memberof renderer
* @param {string} windowName - ...
*/
function localizeUserInterface (windowName) {
const isDev = require('electron-is-dev')
const path = require('path')
utils.writeConsoleMsg('info', 'localizeUserInterface ::: Localizing: _' + windowName + '_')
// detect user language
let userLang = navigator.language || navigator.userLanguage
utils.writeConsoleMsg('info', 'localizeUserInterface ::: Detected user language: ' + userLang)
// if the project is not packaged - overwrite the language ...
if (isDev) {
userLang = 'en' // to EN. This is used to ensure the screenshots are in the expected language
// userLang = "pl"; // to PL. This is used to test unsupported languages
utils.writeConsoleMsg('warn', 'localizeUserInterface ::: Overwritten user language in dev environment to: ' + userLang)
}
const i18next = require('i18next')
const Backend = require('i18next-sync-fs-backend')
i18next
.use(Backend)
.init({
debug: true, // logs info-level to console output. Helps finding issues with loading not working.
lng: userLang, // configured user language
whitelist: ['en', 'de', 'fr'], // supported languages
fallbackLng: 'en', // language to use if translations in user language are not available.
ns: 'translation', // string or array of namespaces to load
defaultNS: 'translation', // default namespace used if not passed to translation function
updateMissing: false,
initImmediate: true,
backend:
{
// path where resources get loaded from
// loadPath: __dirname + '/locales/{{lng}}/{{ns}}.json',
loadPath: path.join(__dirname, '/locales/{{lng}}/{{ns}}.json'),
// path to post missing resources
// addPath: __dirname + '/locales/{{lng}}/{{ns}}.missing.json',
addPath: path.join(__dirname, '/locales/{{lng}}/{{ns}}.missing.json'),
// jsonIndent to use when storing json files
jsonIndent: 2
}
})
$(function () {
// attribute: text
$('[i18n-text]').each(function () {
const node = $(this); const key = node.attr('i18n-text')
node.text(i18next.t(key))
})
// attribute: title
$('[i18n-title]').each(function () {
const node = $(this); const key = node.attr('i18n-title')
node.attr('title', i18next.t(key))
})
// attribute: placeholder
$('[i18n-placeholder]').each(function () {
const node = $(this); const key = node.attr('i18n-placeholder')
node.attr('placeholder', i18next.t(key))
})
// attribute: value
$('[i18n-value]').each(function () {
const node = $(this); const key = node.attr('i18n-value')
node.attr('value', i18next.t(key))
})
})
}
/**
* @function checkNetworkConnectivityPeriodic
* @summary Periodically checks if network access exists or not
* @description Testmethod to inform the user when there is no access to the internet.
* @memberof renderer
* @param {number} timeInterval - The time interval which is used to start re-testing
*/
function checkNetworkConnectivityPeriodic (timeInterval) {
const isOnline = require('is-online') // for online connectivity checks
let continuousErrors = 0
// var intervalID = setInterval(function () { // CLEANME
setInterval(function () {
(async () => {
if (await isOnline() === true) {
// utils.writeConsoleMsg('info', 'checkNetworkConnectivityPeriodic ::: Connectivity is OK')
continuousErrors = 0 // reset counter
} else {
continuousErrors = continuousErrors + 1
// to avoid annoying notifications we report back only if the error happens X times in a row
if (continuousErrors === 3) {
utils.showNoty('error', 'Realizing connectivity issues, please troubleshoot your internet connection if this message appears.')
continuousErrors = 0 // reset counter
}
utils.writeConsoleMsg('warn', 'checkNetworkConnectivityPeriodic ::: Connectivity to the web looks broken. (Errors in a row: ' + continuousErrors + ').')
}
})()
}, timeInterval)
}
/**
* @function onMainWindowBeforeReady
* @summary Executed before onReady
* @description launcher for several init methods before jquerys ready signal. Gets called from mainWindow.html
* @memberof renderer
* @todo This functions gets ignored for eslint/standardx as it is only called from mainWindow.html
*/
function onMainWindowBeforeReady () { // eslint-disable-line no-unused-vars
checkSupportedOperatingSystem() // check operating system
titlebarInit() // init the custom titlebar - see #115
uscu.updateAllUserServiceConfigurations() // update the configured UserServices (introduced with switch from 1.7.0 to 1.8.0)
checkNetworkConnectivityPeriodic(10000) // start periodic network checker - 10.000 milliseconds = 10 seconds
utils.writeConsoleMsg('info', 'onMainWindowBeforeReady( ::: Finished.')
}
/**
* @function onMainWindowAfterReady
* @summary Executed 1 sec after onReady code is executed
* @description This method is responsible for the second stage of loading & initializing.
* @memberof renderer
*/
function onMainWindowAfterReady () {
updateGlobalServicesShortcuts() // update global shortcuts for all loaded / enabled services
validateConfiguredDefaultView() // validate default view
// Configure click-handler for navigation/tabs
$('#myTabs a').click(function (link) {
let target = link.currentTarget.innerText
// remove leading space
if (target.substr(0, 1) === ' ') {
target = target.substr(1)
}
console.log('ready ::: Switched to tab: _' + target + '_.')
})
utils.writeConsoleMsg('info', 'onMainWindowAfterReady ::: Finished.')
}
/**
* @function onMainWindowReady
* @summary Initialized the application after jquerys ready signal
* @description launcher for several init methods after jquerys ready signal. Gets called from mainWindow.html
* @memberof renderer
* @todo This functions gets ignored for eslint/standardx as it is only called from mainWindow.html
*/
function onMainWindowReady () { // eslint-disable-line no-unused-vars
loadEnabledUserServices() // load the configured user services
initSettingsPage() // init the settings tab
localizeUserInterface('mainWindow.html') // Translate using i18next
setTimeout(function () {
onMainWindowAfterReady() // executing some things later ...
}, 1000)
utils.writeConsoleMsg('info', 'onMainWindowReady ::: Finished.')
}
// ----------------------------------------------------------------------------
// ipcRenderer things
// ----------------------------------------------------------------------------
/**
* @name reloadCurrentService
* @summary Reloads the current service tab
* @description Called via ipc from main.js when user wants to reload the current service tab
* @memberof renderer
*/
require('electron').ipcRenderer.on('reloadCurrentService', function () {
let tabValue = $('.nav-tabs .active').attr('href') // get href of current active tab
tabValue = tabValue.substring(1) // cut the first char ( = #)
if (tabValue !== 'Settings') {
utils.writeConsoleMsg('info', 'reloadCurrentService ::: Current active tab is: ' + tabValue)
utils.showNoty('info', 'Trying to reload the current service: <b>' + tabValue + '</b>.')
doAnimateServiceIcon(true, tabValue) // Start animating
// get configured target url & inject code from config
const storage = require('electron-json-storage')
utils.jsonStoragePathSet() // set default path
storage.get(tabValue, function (error, data) {
if (error) {
utils.writeConsoleMsg('error', 'reloadCurrentService ::: Error while trying to get a single user service configuration. Service: ' + tabValue + '. Error: ' + error)
throw error
}
const url = data.url
// Sentry: TTTH-3S
if (typeof url === 'undefined') {
// url is undefined
utils.showNoty('error', 'Trying to reload service: <b>' + tabValue + '</b> failed, as URL is undefined.', 0)
utils.writeConsoleMsg('error', 'reloadCurrentService ::: Reloading current active service: ' + tabValue + ' failed, as its URL is undefined.')
} else {
// document.getElementById('webview_' + tabValue).loadURL(url) // see: #186
// BAUSTELLE
// #186 - most likely not helping - as the webview in fact still exists.
if ($('#webview_' + tabValue).length) {
utils.writeConsoleMsg('info', 'reloadCurrentService ::: Set new URL of service _' + tabValue + '_ to: _' + url + '_.')
// document.getElementById('webview_' + tabValue).loadURL(url)
document.getElementById('webview_' + tabValue).reload()
} else {
utils.showNoty('error', 'Trying to reload service: <b>' + tabValue + '</b> failed, as the entire webview itself no longer exists.', 0)
utils.writeConsoleMsg('error', 'reloadCurrentService ::: Reloading current active service: ' + tabValue + ' failed, as the entire webview itself no longer exists.')
}
// end of #186
}
// TODO
// inject code
// var injectCode = data.injectCode;
})
}
})
/**
* @name showSettings
* @summary Activated the settings tab
* @description Called via ipc from main.js when user wants to see the application settings
* @memberof renderer
*/
require('electron').ipcRenderer.on('showSettings', function () {
utils.writeConsoleMsg('info', 'showSettings ::: Switching to Settings tab')
switchToService('Settings')
})
/**
* @name startSearchUpdates
* @summary Starts the search for application updates (non-silent)
* @description Called via ipc from main.js when user wants to know if application updates are available
* @memberof renderer
*/
require('electron').ipcRenderer.on('startSearchUpdates', function () {
utils.writeConsoleMsg('info', 'startSearchUpdates ::: Show update information div')
searchUpdate(false) // silent = false. Forces result feedback, even if no update is available
})
/**
* @name openDevToolForCurrentService
* @summary Opens the developer tools for the current service
* @description Called via ipc from main.js when user wants to see the developer tools for a single service
* @memberof renderer
*/
require('electron').ipcRenderer.on('openDevToolForCurrentService', function () {
// get href of current active tab
let tabValue = $('.nav-tabs .active').attr('href')
tabValue = tabValue.substring(1) // cut the first char ( = #)
// This makes no sense on the settings tab
if (tabValue === 'Settings') {
utils.showNoty('info', 'This function is supposed to be used on service tabs, not the settings tab.')
} else {
// default case
utils.writeConsoleMsg('info', 'openDevToolForCurrentService ::: Trying to open DevTools for current service: _' + tabValue + '_.')
const webview = document.getElementById('webview_' + tabValue) // get webview
webview.openDevTools() // Open devTools
}
})
/**
* @name nextTab
* @summary Jumps to the next tab
* @description Called via ipc from main.js when user wants to see jump to the next tab
* @memberof renderer
*/
require('electron').ipcRenderer.on('nextTab', function () {
let currentTabId
const enabledTabsArray = [] // should store all visible names
let currentActiveTabId // Id of active tab
let serviceName // used to call the function switchToService()
// get current selected / active tab
currentActiveTabId = $('.nav-item .active').attr('id')
currentActiveTabId = currentActiveTabId.replace('target_', '')
utils.writeConsoleMsg('info', 'nextTab ::: Active tab is: ' + currentActiveTabId)
// get list of all visible service-tabs
$('#myTabs li a').each(function () {
currentTabId = $(this).attr('id')
// check if entry is visible or not
if ($('#' + currentTabId).is(':visible')) {
currentTabId = currentTabId.replace('target_', '')
if (currentTabId !== 'Settings') {
enabledTabsArray.push(currentTabId)
}
}
})
const currentPositionInArray = enabledTabsArray.indexOf(currentActiveTabId) // find position of current tab in the array of enabled services
// get next array position
if (currentPositionInArray < enabledTabsArray.length - 1) {
serviceName = enabledTabsArray[currentPositionInArray + 1]
} else {
serviceName = enabledTabsArray[0]
}
utils.writeConsoleMsg('info', 'nextTab ::: Should switch to: ' + serviceName + ' now.')
switchToService(serviceName) // jump to next tab
})
/**
* @name previousTab
* @summary Jumps to the previous Tab
* @description Called via ipc from main.js when user wants to see jump to the previous tab
* @memberof renderer
*/
require('electron').ipcRenderer.on('previousTab', function () {
// variables
let currentTabId
const enabledTabsArray = [] // should store all visible names
let currentActiveTabId // Id of active tab
let serviceName // used to call the function switchToService()
// get current selected / active tab
currentActiveTabId = $('.nav-item .active').attr('id')
currentActiveTabId = currentActiveTabId.replace('target_', '')
utils.writeConsoleMsg('info', 'previous ::: Active tab is: ' + currentActiveTabId)
// get list of all visible service-tabs
$('#myTabs li a').each(function () {
currentTabId = $(this).attr('id')
// check if entry is visible or not
if ($('#' + currentTabId).is(':visible')) {
currentTabId = currentTabId.replace('target_', '')
if (currentTabId !== 'Settings') {
enabledTabsArray.push(currentTabId)
}
}
})
// find position of current tab in the array of enabled services
const currentPositionInArray = enabledTabsArray.indexOf(currentActiveTabId)
// get previous array position
if (currentPositionInArray > 0) {
serviceName = enabledTabsArray[currentPositionInArray - 1]
} else {
serviceName = enabledTabsArray[enabledTabsArray.length - 1]
}
utils.writeConsoleMsg('info', 'previousTab ::: Should switch to: ' + serviceName + ' now.')
switchToService(serviceName) // jump to previous tab
})
// Call from main.js ::: serviceToCreate (in configServiceWindow)
//
require('electron').ipcRenderer.on('serviceToCreate', function (event, serviceId) {
utils.writeConsoleMsg('info', 'serviceToCreate ::: Should create a new service of type: _' + serviceId + '_.')
utils.writeConsoleMsg('info', 'serviceToCreate ::: Loading default values from service definition')
// var newServiceId = generateNewRandomServiceID(serviceId) // generate id for new service
const newServiceId = utils.generateNewRandomServiceID(serviceId) // generate id for new service
// read json file
const path = require('path')
const url = path.join(__dirname, '/js/ttth/services.json')
$.getJSON(url, function (data) {
$.each(data, function (key, entry) {
if (entry.id === serviceId) {
// update UI with default values
$('#input_serviceId').val(newServiceId)
$('#input_serviceType').val(entry.id)
$('#input_serviceName').val(entry.name)
$('#input_serviceIcon').val(entry.icon)
$('#input_serviceUrl').val(entry.url)
$('#input_serviceInjectCode').val(entry.injectCode)
$('#input_serviceEnableStatus').val(true)
$('#input_serviceUserAgentDefault').val(entry.userAgentDefault)
$('#input_serviceUserAgentCustom').val('')
// button visibility
$('#bt_saveExistingService').hide() // hide save buttons (only used for editing existing services)
$('#bt_addNewService').show() // show the add-new-service button
previewIcon() // preview the icon
utils.writeConsoleMsg('info', 'serviceToCreate ::: Loaded default values for this service-type to UI')
}
})
})
})
// Call from main.js ::: serviceToConfigure (in configServiceWindow)
//
require('electron').ipcRenderer.on('serviceToConfigure', function (event, serviceId) {
const storage = require('electron-json-storage')
utils.jsonStoragePathSet() // set default path
utils.writeConsoleMsg('info', 'serviceToConfigure ::: Should configure the service: ' + serviceId)
utils.writeConsoleMsg('info', 'serviceToConfigure ::: Loading current values from service config')
storage.get(serviceId, function (error, data) {
if (error) {
utils.writeConsoleMsg('error', 'serviceToConfigure ::: Error while trying to load service data for the service: ' + serviceId + '. Error: ' + error)
throw error
}
// update UI of second window
$('#input_serviceId').val(serviceId)
$('#input_serviceType').val(data.type)
$('#input_serviceName').val(data.name)
$('#input_serviceIcon').val(data.icon)
$('#input_serviceUrl').val(data.url)
$('#input_serviceInjectCode').val(data.injectCode)
$('#input_serviceEnableStatus').val(data.serviceEnableStatus)
$('#input_serviceUserAgentDefault').val(data.userAgentDefault)
$('#input_serviceUserAgentCustom').val(data.userAgentCustom)
// button visibility
$('#bt_addNewService').hide() // hide Add-new-service button
$('#bt_saveExistingService').show() // show the edit service button
previewIcon() // preview the icon
utils.writeConsoleMsg('info', 'serviceToConfigure ::: Loaded current values for this service to UI')
})
})
// Call from main.js ::: switchToTab
//
require('electron').ipcRenderer.on('switchToTab', function (event, targetTab) {
utils.writeConsoleMsg('info', 'switchToTab ::: Switching to tab: ' + targetTab)
$('#' + targetTab).trigger('click')
})
// Call from main.js :::
//
require('electron').ipcRenderer.on('showNoConnectivityError', function () {
utils.writeConsoleMsg('error', 'showNoConnectivityError ::: There is no internet connection.')
utils.showNoty('error', 'No access to the internet (critical) ', 0)
})
// Executed from main.js - on-ready-to-show
//
//
// Call from main.js ::: on-ready - startSearchUpdates
require('electron').ipcRenderer.on('startSearchUpdatesSilent', function () {
searchUpdate(true) // If silent = false -> Forces result feedback, even if no update is available
})