πŸ“œ ⬆️ ⬇️

Own VPN client on JavaScript. Part 8 - Electron Setting Component

PS Each part is a part, by itself it does not make sense to get the necessary context and not to experience cognitive dissonance from the lack of so necessary blocks of text, start reading from part 1

Setting - Electron component , application settings element.

Folder structure

context β”‚ β”‚ index.js β”‚ └───client //      β”‚ creater-option.js β”‚ index.html β”‚ style.css β”‚ └───fonts font1.woff2 font2.woff2 font3.woff2 font4.woff2 font5.woff2 font6.woff2 font7.woff2 


')
index.js - The file in which the Electron component is created.

Contents of the index.js file.
Code
 const { BrowserWindow, ipcMain } = require('electron') module.exports = class Notification { constructor(parent) { this.root = new BrowserWindow({ frame: false, //   transparent: true, //   resizable: false, //   show: false, //      height: 520, width: 350, center: true, parent }) //   this.root.loadURL(`${__dirname}/client/index.html`) //   SETTING_CLOSE ( ) ipcMain.on('SETTING_CLOSE', e => { this.root.hide() e.returnValue = 'ok' }) } onSave(cb) { //   SETTING_SAVE     ipcMain.on('SETTING_SAVE', e => { cb() this.root.hide() e.returnValue = 'ok' }) } ready() { //      return new Promise(res => { this.root.once('ready-to-show', res) }) } show() { //   this.root.show() } hide() { //   this.root.hide() } get() { //   return new Promise(resolve => { this.root.webContents.send('SETTING_GET') ipcMain.once('SETTING_DATA', (e, data) => { resolve(JSON.parse(data)) }) }) } } 



index.html - HTML page window.

Contents of the index.html file.
Code
 <!DOCTYPE html> <html lang='en'> <head> <meta charset='UTF-8'> <link rel='stylesheet' type='text/css' href='style.css'> </head> <body> <div class='body'> <div class='settings'> <div class='wrapper'> <div>  ()</div> <select name='NumVpnSessions'> <option value='-'>---</option> </select> </div> <div class='wrapper'> <div>Ping ()</div> <select name='Ping'> <option value='-'>---</option> </select> </div> <div class='wrapper'> <div>  ()</div> <select name='TotalUsers'> <option value='-'>---</option> </select> </div> <div class='wrapper'> <div></div> <select name='CountryLong'> <option value='-'>---</option> </select> </div> <div class='wrapper'> <div>  ()</div> <select name='Uptime'> <option value='-'>---</option> </select> </div> <div class='wrapper'> <div> ()</div> <select name='Speed'> <option value='-'>---</option> </select> </div> <div class='wrapper'> <div>  ()</div> <select name='TotalTraffic'> <option value='-'>---</option> </select> </div> <div class='wrapper'> <div>  ()</div> <select name='Score'> <option value='-'>---</option> </select> </div> <div class='wrapper'> <div>. .</div> <select name='PositionNotify'> <option value='BR'> </option> <option value='TR'> </option> <option value='BL'> </option> <option value='TL'> </option> </select> </div> <label for='auto-reconnect'> <div class='wrapper'> <div>-  VPN</div> <input type="checkbox" name='AutoReconnect' id='auto-reconnect' hidden> <div class='new_check'></div> </div> </label> <label for='auto-update'> <div class='wrapper'> <div>- </div> <input type="checkbox" name='AutoUpdate' id='auto-update' hidden> <div class='new_check'></div> </div> </label> <label for='permutation'> <div class='wrapper'> <div>   ( )</div> <input type="checkbox" name='Permutation' id='permutation' hidden> <div class='new_check'></div> </div> </label> <label for='start-hidden'> <div class='wrapper'> <div> </div> <input type="checkbox" name='StartHidden' id='start-hidden' hidden> <div class='new_check'></div> </div> </label> </div> <div class='btn-nav'> <div class='btn save'></div> <div class='btn close'></div> </div> </div> <script> const save = document.getElementsByClassName('save')[0] , close = document.getElementsByClassName('close')[0] , NumVpnSessions = document.getElementsByName('NumVpnSessions')[0] , Ping = document.getElementsByName('Ping')[0] , TotalUsers = document.getElementsByName('TotalUsers')[0] , CountryLong = document.getElementsByName('CountryLong')[0] , Uptime = document.getElementsByName('Uptime')[0] , Speed = document.getElementsByName('Speed')[0] , TotalTraffic = document.getElementsByName('TotalTraffic')[0] , Score = document.getElementsByName('Score')[0] , AutoReconnect = document.getElementsByName('AutoReconnect')[0] , Permutation = document.getElementsByName('Permutation')[0] , AutoUpdate = document.getElementsByName('AutoUpdate')[0] , StartHidden = document.getElementsByName('StartHidden')[0] , PositionNotify = document.getElementsByName('PositionNotify')[0] , { ipcRenderer, shell } = require('electron') //     JSON const getSetting = () => JSON.stringify({ Ping: Ping.value || '-', NumVpnSessions: NumVpnSessions.value || '-', TotalUsers: TotalUsers.value || '-', CountryLong: CountryLong.value || '-', Uptime: Uptime.value || '-', Speed: Speed.value || '-', TotalTraffic: TotalTraffic.value || '-', Score: Score.value || '-', AutoReconnect: AutoReconnect.checked || false, AutoUpdate: AutoUpdate.checked || false, Permutation: Permutation.checked || false, StartHidden: StartHidden.checked || false, PositionNotify: PositionNotify.value || 'BR' }) //   save.addEventListener('click', () => { //     localStorage localStorage.setItem('vpn_setting', getSetting()) //   SETTING_SAVE   ipcRenderer.sendSync('SETTING_SAVE') }) //   close.addEventListener('click', () => { //   SETTING_CLOSE   ipcRenderer.sendSync('SETTING_CLOSE') }) </script> <script src='creater-option.js'></script> <script> //       const vpn_setting = JSON.parse(localStorage.vpn_setting || "{}") Ping.value = vpn_setting.Ping || '-' NumVpnSessions.value = vpn_setting.NumVpnSessions || '-' TotalUsers.value = vpn_setting.TotalUsers || '-' CountryLong.value = vpn_setting.CountryLong || '-' Uptime.value = vpn_setting.Uptime || '-' Speed.value = vpn_setting.Speed || '-' TotalTraffic.value = vpn_setting.TotalTraffic || '-' Score.value = vpn_setting.Score || '-' AutoReconnect.checked = vpn_setting.AutoReconnect || false AutoUpdate.checked = vpn_setting.AutoUpdate || false Permutation.checked = vpn_setting.Permutation || false StartHidden.checked = vpn_setting.StartHidden || false PositionNotify.value = vpn_setting.PositionNotify || 'BR' //     ipcRenderer.on('SETTING_GET', (e, data) => { //   SETTING_DATA       ipcRenderer.send('SETTING_DATA', getSetting()) }) </script> </body> </html> 



creater-option.js - Creates an option for all select on the page.

The contents of the creater-option.js file .
Code
 //   NumVpnSessions.innerHTML += Array(100).fill(1).map((e, i) => { if (i < 10) { return `<option value='${i+1}'>${i+1}</option>` } return `<option value='${parseInt(i*1.5)}'>${parseInt(i*1.5)}</option>` }).join('') //  Ping.innerHTML += Array(150).fill(1).map((e, i) => { if (i < 10) { return `<option value='${i+1}'>${i+1}ms</option>` } return `<option value='${parseInt(i*1.5)}'>${parseInt(i*1.5)}ms</option>` }).join('') //    TotalUsers.innerHTML += Array(150).fill(1).map((e, i) => `<option value='${parseInt((i+1)*(i+1))}'>${parseInt((i+1)*(i+1))}</option>`).join('') //  const Contrys = ['Japan', 'Korea Republic of', 'United States', 'Thailand', 'Germany', 'New Zealand', 'Argentina', 'Poland', 'United Kingdom', 'Hong Kong', 'Viet Nam', 'Russian Federation', 'France', 'China', 'Singapore', 'Trinidad and Tobago', 'Moldova Republic of', 'Canada', 'Romania', 'Algeria', 'Venezuela', 'Indonesia', 'Brazil', 'Mexico', 'Cyprus', 'Iceland', 'Bangladesh', 'Morocco', 'Iraq', 'Ukraine', 'Iran', 'Turkey', 'Angola', 'El Salvador', 'Chile', 'Egypt', 'Spain', 'Netherlands', 'Colombia' ] CountryLong.innerHTML += Contrys.map(e => `<option value='${e}'>${e}</option>`).join('') //   Uptime.innerHTML += Array(79).fill(1).map((e, i) => { if (i < 15) { return `<option value='${(i+1)*60*1000}'>${i+1} .</option>` } if (i < 18) { return `<option value='${(i-13)*15*60*1000}'>${(i-13)*15} .</option>` } if (i < 40) { return `<option value='${(i-16)*60*60*1000}'>${(i-16)} .</option>` } if (i < 69) { return `<option value='${(i-38)*24*60*60*1000}'>${(i-38)} .</option>` } if (i < 79) { return `<option value='${(i-67)*30*24*60*60*1000}'>${(i-67)} .</option>` } }).join('') //  Speed.innerHTML += Array(100).fill(1).map((e, i) => { if (i < 5) { return `<option value='${parseInt(1048576*((i+1)/100))}'>${(i+1)/100} Mbit</option>` } if (i < 9) { return `<option value='${parseInt(1048576*((i+1)/10))}'>${(i+1)/10} Mbit</option>` } if (i < 19) { return `<option value='${parseInt(1048576*(i-8))}'>${(i-8)} Mbit</option>` } return `<option value='${parseInt(1048576*((i-18)*i))}'>${(i-18)*i} Mbit</option>` }).join('') //   TotalTraffic.innerHTML += Array(150).fill(1).map((e, i) => { if (i < 10) { return `<option value='${parseInt(1048576*(i+1))}'>${i+1} Mbit</option>` } if (i < 20) { return `<option value='${parseInt(1048576*((i+1)*10))}'>${(i+1)*10} Mbit</option>` } if (i < 50) { return `<option value='${parseInt(1048576*((i+1)*100))}'>${(i+1)*100} Mbit</option>` } if (i < 60) { return `<option value='${parseInt(1073741824*((i-45)*1))}'>${(i-45)*1} Gbit</option>` } if (i < 70) { return `<option value='${parseInt(1073741824*((i-45)*10))}'>${(i-45)*10} Gbit</option>` } if (i < 150) { return `<option value='${parseInt(1073741824*((i-45)*100))}'>${(i-45)*100} Gbit</option>` } }).join('') //   Score.innerHTML += Array(100).fill(1).map((e, i) => `<option value='${(i+25)*(i+25)*(i+25)}'>${i+1}%</option>`).reverse().join('') 



style.css - page styles.

Contents of the style.css file.
Code
 @font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font1.woff2) format('woff2'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font2.woff2) format('woff2'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font3.woff2) format('woff2'); unicode-range: U+1F00-1FFF; } /* greek */ @font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font4.woff2) format('woff2'); unicode-range: U+0370-03FF; } /* vietnamese */ @font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font5.woff2) format('woff2'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font6.woff2) format('woff2'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(fonts/font7.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } * { font-family: 'Source Sans Pro', sans-serif; padding: 0; margin: 0; overflow: hidden; background: rgba(0, 0, 0, 0); color: #eee; } .body { font-size: 14px; width: 345px; border-radius: 10px; background: rgba(36, 39, 39, 0.9); padding: 20px 0px 20px 0px; display: flex; justify-content: center; align-items: center; flex-direction: column; height: 480px; } .settings { height: 100%; display: flex; justify-content: space-between; align-items: center; flex-direction: column; } .wrapper { display: flex; align-items: center; justify-content: space-between; width: 300px } select { outline: none; border: none; background: rgba(51, 55, 55, 0.9); border-radius: 6px; padding: 4px 10px 4px 10px; cursor: pointer; } select:hover { background: rgba(53, 57, 57, 0.9); } option { background: rgba(56, 60, 60, 0.9); } .btn-nav { display: flex; justify-content: space-around; align-items: center; margin-top: 30px; } .btn { cursor: pointer; margin-top: 10px; padding: 4px 10px 4px 10px; border-radius: 6px; user-select: none; margin: 0px 10px 0px 10px; } .btn:hover { color: #ccc } .button { margin-top: 10px; } .new_check { cursor: pointer; width: 20px; height: 20px; border-radius: 100%; margin-right: 30px; background: rgba(51, 55, 55, 0.9); } #auto-reconnect:checked + .new_check { background: radial-gradient(rgba(244, 244, 244, 0.9) 30%, rgba(51, 55, 55, 0.9) 29%); } #auto-update:checked + .new_check { background: radial-gradient(rgba(244, 244, 244, 0.9) 30%, rgba(51, 55, 55, 0.9) 29%); } #permutation:checked + .new_check { background: radial-gradient(rgba(244, 244, 244, 0.9) 30%, rgba(51, 55, 55, 0.9) 29%); } #start-hidden:checked + .new_check { background: radial-gradient(rgba(244, 244, 244, 0.9) 30%, rgba(51, 55, 55, 0.9) 29%); } 



Application
Application use: / app / Setting .

API
Interface component Setting.

 const { app } = require('electron') , SETTING = require('./../../app/components/setting') app.on('ready', async() => { const Setting = new SETTING() //          await Setting.ready() //   Setting.show() //   Setting.onSave(async () => { //   const vpn_setting = await Setting.get() console.log(vpn_setting) }) }) 

Test
Test version: / app_test / Setting .

image

Part 9 - Callback Component


VPN   JavaScript by JSus

Source: https://habr.com/ru/post/429440/


All Articles