-const { app, ipcMain, protocol, session, BrowserWindow, BrowserView, Menu, nativeImage, clipboard, dialog, Notification } = require('electron');
+const { app, shell, ipcMain, protocol, session, BrowserWindow, BrowserView, Menu, nativeImage, clipboard, dialog, Notification } = require('electron');
const path = require('path');
-const fs = require('fs');
-const url = require('url');
+const { parse, format } = require('url');
const os = require('os');
+const https = require('https');
+const http = require('http');
-const localShortcut = require("electron-localshortcut");
+const pkg = require(`${app.getAppPath()}/package.json`);
+const protocolStr = 'flast';
+const fileProtocolStr = `${protocolStr}-file`;
+
+const { download } = require('electron-dl');
+const platform = require('electron-platform');
+const localShortcut = require('electron-localshortcut');
const Config = require('electron-store');
const config = new Config({
defaults: {
design: {
- homeButton: false,
- darkTheme: false,
+ isHomeButton: false,
+ isBookmarkBar: false,
+ isDarkTheme: false,
+ isCustomTitlebar: true,
theme: 'default'
},
homePage: {
- defaultPage: 'my://newtab',
+ isDefaultHomePage: true,
+ defaultPage: `${protocolStr}://home`,
+ },
+ searchEngine: {
defaultEngine: 'Google',
searchEngines: [
{
url: 'https://search.goo.ne.jp/web.jsp?MT=%s'
},
{
+ name: 'OCN',
+ url: 'https://search.goo.ne.jp/web.jsp?MT=%s'
+ },
+ {
+ name: 'Baidu',
+ url: 'https://www.baidu.com/s?wd=%s'
+ },
+ {
name: 'Google Translate',
url: 'https://translate.google.com/?text=%s'
},
{
name: 'GitHub',
url: 'https://github.com/search?q=%s'
+ },
+ {
+ name: 'DuckDuckGo',
+ url: 'https://duckduckgo.com/?q=%s'
+ },
+ {
+ name: 'Yahoo',
+ url: 'https://search.yahoo.com/search?p=%s'
+ },
+ {
+ name: 'Amazon',
+ url: 'https://www.amazon.co.jp/s?k=%s'
}
]
},
- adBlocker: true,
+ pageSettings: {
+ media: -1,
+ geolocation: -1,
+ notifications: -1,
+ midiSysex: -1,
+ pointerLock: -1,
+ fullscreen: 1,
+ openExternal: -1,
+ },
+ isAdBlock: true,
+ language: 'ja',
window: {
- isCustomTitlebar: true,
+ isCloseConfirm: true,
isMaximized: false,
bounds: {
width: 1100,
},
});
+const lang = require(`${app.getAppPath()}/langs/${config.get('language')}.js`);
+
const Datastore = require('nedb');
let db = {};
+db.pageSettings = new Datastore({
+ filename: path.join(app.getPath('userData'), 'Files', 'PageSettings.db'),
+ autoload: true,
+ timestampData: true
+});
-db.history = new Datastore({
+db.historys = new Datastore({
filename: path.join(app.getPath('userData'), 'Files', 'History.db'),
autoload: true,
timestampData: true
});
-db.bookmark = new Datastore({
- filename: path.join(app.getPath('userData'), 'Files', 'Bookmark.db'),
+db.downloads = new Datastore({
+ filename: path.join(app.getPath('userData'), 'Files', 'Download.db'),
+ autoload: true,
+ timestampData: true
+});
+db.bookmarks = new Datastore({
+ filename: path.join(app.getPath('userData'), 'Files', 'Bookmarks.db'),
+ autoload: true,
+ timestampData: true
+});
+
+db.apps = new Datastore({
+ filename: path.join(app.getPath('userData'), 'Files', 'Apps.db'),
autoload: true,
timestampData: true
});
-const { loadFilters, updateFilters, removeAds } = require('./AdBlocker');
+const { loadFilters, updateFilters, runAdblockService, removeAds } = require('./AdBlocker');
let floatingWindows = [];
let views = [];
-let tabCount = 0;
-getBaseWindow = (width = 1100, height = 680, minWidth = 320, minHeight = 200, x, y, frame = false) => {
+getBaseWindow = (width = 1100, height = 680, minWidth = 500, minHeight = 360, x, y, frame = false) => {
return new BrowserWindow({
- width, height, minWidth, minHeight, x, y, 'titleBarStyle': 'hidden', frame, fullscreenable: true,
+ width, height, minWidth, minHeight, x, y, titleBarStyle: 'hidden', frame, fullscreenable: true,
+ icon: `${__dirname}/static/app/icon.png`,
+ show: false,
webPreferences: {
nodeIntegration: true,
webviewTag: true,
});
}
-registerProtocols = () => {
- protocol.isProtocolHandled('my', (handled) => {
- console.log(handled);
+loadSessionAndProtocol = () => {
+ const ses = session.defaultSession;
+
+ setPermissionRequestHandler(ses, false);
+
+ protocol.isProtocolHandled(protocolStr, (handled) => {
if (!handled) {
- protocol.registerFileProtocol('my', (request, callback) => {
- const parsed = url.parse(request.url);
+ protocol.registerFileProtocol(protocolStr, (request, callback) => {
+ const parsed = parse(request.url);
- if (parsed.hostname.endsWith('.css') || parsed.hostname.endsWith('.js')) {
- return callback({
- path: path.join(app.getAppPath(), 'pages', parsed.hostname),
- });
- } else {
- return callback({
- path: path.join(app.getAppPath(), 'pages', `${parsed.hostname}.html`),
- });
- }
+ return callback({
+ path: path.join(app.getAppPath(), 'pages', `${parsed.hostname}.html`),
+ });
}, (error) => {
if (error) console.error('Failed to register protocol: ' + error);
});
}
});
-}
-registerProtocolWithPrivateMode = (windowId) => {
- session.fromPartition(windowId).protocol.registerFileProtocol('my', (request, callback) => {
- const parsed = url.parse(request.url);
+ protocol.isProtocolHandled(fileProtocolStr, (handled) => {
+ if (!handled) {
+ protocol.registerFileProtocol(fileProtocolStr, (request, callback) => {
+ const parsed = parse(request.url);
- if (parsed.hostname.endsWith('.css') || parsed.hostname.endsWith('.js')) {
- return callback({
- path: path.join(app.getAppPath(), 'pages', parsed.hostname),
- });
- } else {
- return callback({
- path: path.join(app.getAppPath(), 'pages', `${parsed.hostname}.html`),
+ return callback({
+ path: path.join(app.getAppPath(), 'pages', 'static', parsed.pathname),
+ });
+ }, (error) => {
+ if (error) console.error('Failed to register protocol: ' + error);
});
}
+ });
+}
+
+loadSessionAndProtocolWithPrivateMode = (windowId) => {
+ const ses = session.fromPartition(windowId);
+ ses.setUserAgent(ses.getUserAgent().replace(/ Electron\/[0-9\.]*/g, '') + ' PrivMode');
+
+ setPermissionRequestHandler(ses, true);
+
+ ses.protocol.registerFileProtocol(protocolStr, (request, callback) => {
+ const parsed = parse(request.url);
+
+ return callback({
+ path: path.join(app.getAppPath(), 'pages', `${parsed.hostname}.html`),
+ });
+ }, (error) => {
+ if (error) console.error('Failed to register protocol: ' + error);
+ });
+
+ ses.protocol.registerFileProtocol(fileProtocolStr, (request, callback) => {
+ const parsed = parse(request.url);
+
+ return callback({
+ path: path.join(app.getAppPath(), 'pages', 'static', parsed.pathname),
+ });
}, (error) => {
if (error) console.error('Failed to register protocol: ' + error);
});
}
+setPermissionRequestHandler = (ses, isPrivate = false) => {
+ if (!isPrivate) {
+ ses.setPermissionRequestHandler((webContents, permission, callback) => {
+ const url = parse(webContents.getURL());
+
+ db.pageSettings.findOne({ origin: `${url.protocol}//${url.hostname}` }, (err, doc) => {
+ if (doc != undefined) {
+ if (permission == 'media' && doc.media != undefined && doc.media > -1)
+ return callback(doc.media === 0);
+ if (permission == 'geolocation' && doc.geolocation != undefined && doc.geolocation > -1)
+ return callback(doc.geolocation === 0);
+ if (permission == 'notifications' && doc.notifications != undefined && doc.notifications > -1)
+ return callback(doc.notifications === 0);
+ if (permission == 'midiSysex' && doc.midiSysex != undefined && doc.midiSysex > -1)
+ return callback(doc.midiSysex === 0);
+ if (permission == 'pointerLock' && doc.pointerLock != undefined && doc.pointerLock > -1)
+ return callback(doc.pointerLock === 0);
+ if (permission == 'fullscreen' && doc.fullscreen != undefined && doc.fullscreen > -1)
+ return callback(doc.fullscreen === 0);
+ if (permission == 'openExternal' && doc.openExternal != undefined && doc.openExternal > -1)
+ return callback(doc.openExternal === 0);
+ } else {
+ if (config.get(`pageSettings.${permission}`) === null || config.get(`pageSettings.${permission}`) === -1) {
+ if (Notification.isSupported()) {
+ const notify = new Notification({
+ icon: path.join(app.getAppPath(), 'static', 'app', 'icon.png'),
+ title: `${url.protocol}//${url.hostname} が権限を要求しています。`,
+ body: '詳細はここをクリックしてください。',
+ silent: true
+ });
+
+ notify.show();
+
+ notify.on('click', (e) => {
+ dialog.showMessageBox({
+ type: 'info',
+ title: '権限の要求',
+ message: `${url.protocol}//${url.hostname} が権限を要求しています。`,
+ detail: `要求内容: ${permission}`,
+ checkboxLabel: 'このサイトでは今後も同じ処理をする',
+ checkboxChecked: false,
+ noLink: true,
+ buttons: ['はい / Yes', 'いいえ / No'],
+ defaultId: 0,
+ cancelId: 1
+ }, (res, checked) => {
+ if (checked) {
+ if (permission == 'media')
+ db.pageSettings.update({ origin: `${url.protocol}//${url.hostname}` }, { origin: `${url.protocol}//${url.hostname}`, media: res }, { upsert: true });
+ if (permission == 'geolocation')
+ db.pageSettings.update({ origin: `${url.protocol}//${url.hostname}` }, { origin: `${url.protocol}//${url.hostname}`, geolocation: res }, { upsert: true });
+ if (permission == 'notifications')
+ db.pageSettings.update({ origin: `${url.protocol}//${url.hostname}` }, { origin: `${url.protocol}//${url.hostname}`, notifications: res }, { upsert: true });
+ if (permission == 'midiSysex')
+ db.pageSettings.update({ origin: `${url.protocol}//${url.hostname}` }, { origin: `${url.protocol}//${url.hostname}`, midiSysex: res }, { upsert: true });
+ if (permission == 'pointerLock')
+ db.pageSettings.update({ origin: `${url.protocol}//${url.hostname}` }, { origin: `${url.protocol}//${url.hostname}`, pointerLock: res }, { upsert: true });
+ if (permission == 'fullscreen')
+ db.pageSettings.update({ origin: `${url.protocol}//${url.hostname}` }, { origin: `${url.protocol}//${url.hostname}`, fullscreen: res }, { upsert: true });
+ if (permission == 'openExternal')
+ db.pageSettings.update({ origin: `${url.protocol}//${url.hostname}` }, { origin: `${url.protocol}//${url.hostname}`, openExternal: res }, { upsert: true });
+ }
+ return callback(res === 0);
+ });
+ });
+ notify.on('close', (e) => {
+ return callback(false);
+ });
+ } else {
+ dialog.showMessageBox({
+ type: 'info',
+ title: '権限の要求',
+ message: `${url.protocol}//${url.hostname} が権限を要求しています。`,
+ detail: `要求内容: ${permission}`,
+ checkboxLabel: 'このサイトでは今後も同じ処理をする',
+ checkboxChecked: false,
+ noLink: true,
+ buttons: ['はい / Yes', 'いいえ / No'],
+ defaultId: 0,
+ cancelId: 1
+ }, (res, checked) => {
+ if (checked) {
+ if (permission == 'media')
+ db.pageSettings.update({ origin: `${url.protocol}//${url.hostname}` }, { origin: `${url.protocol}//${url.hostname}`, media: res }, { upsert: true });
+ if (permission == 'geolocation')
+ db.pageSettings.update({ origin: `${url.protocol}//${url.hostname}` }, { origin: `${url.protocol}//${url.hostname}`, geolocation: res }, { upsert: true });
+ if (permission == 'notifications')
+ db.pageSettings.update({ origin: `${url.protocol}//${url.hostname}` }, { origin: `${url.protocol}//${url.hostname}`, notifications: res }, { upsert: true });
+ if (permission == 'midiSysex')
+ db.pageSettings.update({ origin: `${url.protocol}//${url.hostname}` }, { origin: `${url.protocol}//${url.hostname}`, midiSysex: res }, { upsert: true });
+ if (permission == 'pointerLock')
+ db.pageSettings.update({ origin: `${url.protocol}//${url.hostname}` }, { origin: `${url.protocol}//${url.hostname}`, pointerLock: res }, { upsert: true });
+ if (permission == 'fullscreen')
+ db.pageSettings.update({ origin: `${url.protocol}//${url.hostname}` }, { origin: `${url.protocol}//${url.hostname}`, fullscreen: res }, { upsert: true });
+ if (permission == 'openExternal')
+ db.pageSettings.update({ origin: `${url.protocol}//${url.hostname}` }, { origin: `${url.protocol}//${url.hostname}`, openExternal: res }, { upsert: true });
+ }
+ return callback(res === 0);
+ });
+ }
+ } else if (config.get(`pageSettings.${permission}`) === 0) {
+ return callback(false);
+ } else if (config.get(`pageSettings.${permission}`) === 1) {
+ return callback(true);
+ }
+ }
+ });
+ });
+ } else {
+ ses.setPermissionRequestHandler((webContents, permission, callback) => {
+ const url = parse(webContents.getURL());
+
+ if (config.get(`pageSettings.${permission}`) === null || config.get(`pageSettings.${permission}`) === -1) {
+ if (Notification.isSupported()) {
+ const notify = new Notification({
+ icon: path.join(app.getAppPath(), 'static', 'app', 'icon.png'),
+ title: `${url.protocol}//${url.hostname} が権限を要求しています。`,
+ body: '詳細はここをクリックしてください。\nプライベート ウィンドウ',
+ silent: true
+ });
+
+ notify.show();
+
+ notify.on('click', (e) => {
+ dialog.showMessageBox({
+ type: 'info',
+ title: '権限の要求',
+ message: `${url.protocol}//${url.hostname} が権限を要求しています。`,
+ detail: `要求内容: ${permission}`,
+ noLink: true,
+ buttons: ['はい / Yes', 'いいえ / No'],
+ defaultId: 0,
+ cancelId: 1
+ }, (res) => {
+ return callback(res === 0);
+ });
+ });
+ notify.on('close', (e) => {
+ return callback(false);
+ });
+ } else {
+ dialog.showMessageBox({
+ type: 'info',
+ title: '権限の要求',
+ message: `${url.protocol}//${url.hostname} が権限を要求しています。`,
+ detail: `要求内容: ${permission}`,
+ noLink: true,
+ buttons: ['はい / Yes', 'いいえ / No'],
+ defaultId: 0,
+ cancelId: 1
+ }, (res) => {
+ return callback(res === 0);
+ });
+ }
+ } else if (config.get(`pageSettings.${permission}`) === 0) {
+ return callback(false);
+ } else if (config.get(`pageSettings.${permission}`) === 1) {
+ return callback(true);
+ }
+ });
+ }
+}
+
module.exports = class WindowManager {
constructor() {
this.windows = new Map();
ipcMain.on('window-add', (e, args) => {
this.addWindow(args.isPrivate);
});
+
+ ipcMain.on('window-fullScreen', (e, args) => {
+ this.addWindow(args.isPrivate);
+ });
+
+ ipcMain.on('window-fixBounds', (e, args) => {
+ this.windows.forEach((value, key) => {
+ this.fixBounds(key, (floatingWindows.indexOf(key) != -1));
+ })
+ });
+
+ ipcMain.on('window-change-settings', (e, args) => {
+ this.windows.forEach((value, key) => {
+ value.webContents.send('window-change-settings', {});
+ })
+ });
ipcMain.on('update-filters', (e, args) => {
updateFilters();
});
ipcMain.on('data-history-get', (e, args) => {
- db.history.find({}).sort({ createdAt: -1 }).exec((err, docs) => {
+ db.historys.find({}).sort({ createdAt: -1 }).exec((err, docs) => {
e.sender.send('data-history-get', { historys: docs });
});
});
ipcMain.on('data-history-clear', (e, args) => {
- db.history.remove({}, { multi: true });
+ db.historys.remove({}, { multi: true });
+ });
+
+ ipcMain.on('data-downloads-get', (e, args) => {
+ db.downloads.find({}).sort({ createdAt: -1 }).exec((err, docs) => {
+ e.sender.send('data-downloads-get', { downloads: docs });
+ });
+ });
+
+ ipcMain.on('data-downloads-clear', (e, args) => {
+ db.downloads.remove({}, { multi: true });
});
- ipcMain.on('data-bookmark-get', (e, args) => {
- db.bookmark.find({ isPrivate: args.isPrivate }).sort({ createdAt: -1 }).exec((err, docs) => {
- e.sender.send('data-bookmark-get', { bookmarks: docs });
+ ipcMain.on('data-bookmarks-get', (e, args) => {
+ db.bookmarks.find({ isPrivate: args.isPrivate }).sort({ createdAt: -1 }).exec((err, docs) => {
+ e.sender.send('data-bookmarks-get', { bookmarks: docs });
});
});
- ipcMain.on('data-bookmark-clear', (e, args) => {
- db.bookmark.remove({}, { multi: true });
+ ipcMain.on('data-bookmarks-clear', (e, args) => {
+ db.bookmarks.remove({}, { multi: true });
+ });
+
+ ipcMain.on('data-apps-add', (e, args) => {
+ db.apps.update({ id: args.id }, { id: args.id, name: args.name, description: args.description, url: args.url }, { upsert: true });
+
+ db.apps.find({}).sort({ createdAt: -1 }).exec();
+ });
+
+ ipcMain.on('data-apps-remove', (e, args) => {
+ db.apps.remove({ id: args.id }, {});
+ });
+
+ ipcMain.on('data-apps-get', (e, args) => {
+ db.apps.find({}).sort({ createdAt: -1 }).exec((err, docs) => {
+ e.sender.send('data-apps-get', { apps: docs });
+ });
+ });
+
+ ipcMain.on('data-apps-is', (e, args) => {
+ db.apps.find({ id: args.id }).exec((err, docs) => {
+ e.sender.send('data-apps-is', { id: args.id, isInstalled: (docs.length > 0 ? true : false) });
+ });
+ });
+
+ ipcMain.on('data-apps-clear', (e, args) => {
+ db.apps.remove({}, { multi: true });
});
ipcMain.on('clear-browsing-data', () => {
});
config.clear();
- db.history.remove({}, { multi: true });
- db.bookmark.remove({}, { multi: true });
+ db.pageSettings.remove({}, { multi: true });
+
+ db.historys.remove({}, { multi: true });
+ db.downloads.remove({}, { multi: true });
+ db.bookmarks.remove({}, { multi: true });
+ db.apps.remove({}, { multi: true });
});
}
addWindow = (isPrivate = false) => {
- registerProtocols();
+ loadSessionAndProtocol();
loadFilters();
const { width, height, x, y } = config.get('window.bounds');
- const window = getBaseWindow(config.get('window.isMaximized') ? 1110 : width, config.get('window.isMaximized') ? 680 : height, 320, 200, x, y, !config.get('window.isCustomTitlebar'));
+ const window = getBaseWindow(config.get('window.isMaximized') ? 1110 : width, config.get('window.isMaximized') ? 680 : height, 500, 360, x, y, !config.get('design.isCustomTitlebar'));
- const id = (!isPrivate ? window.id : `private-${window.id}`);
+ const id = (!isPrivate ? `window-${window.id}` : `private-${window.id}`);
config.get('window.isMaximized') && window.maximize();
- const startUrl = process.env.ELECTRON_START_URL || url.format({
+ const startUrl = process.env.ELECTRON_START_URL || format({
pathname: path.join(__dirname, '/../build/index.html'), // 警告:このファイルを移動する場合ここの相対パスの指定に注意してください
protocol: 'file:',
slashes: true,
window.loadURL(startUrl);
+ window.once('ready-to-show', () => {
+ window.show();
+ });
+
+ window.on('closed', () => {
+ this.windows.delete(id);
+ });
+
+ window.on('close', (e) => {
+ delete views[id];
+
+ config.set('window.isMaximized', window.isMaximized());
+ config.set('window.bounds', window.getBounds());
+ });
+
+ window.on('focus', () => {
+ window.webContents.send(`window-focus-${id}`, {});
+ });
+ window.on('blur', () => {
+ window.webContents.send(`window-blur-${id}`, {});
+ });
+
+ window.on('maximize', this.fixBounds.bind(this, id, (floatingWindows.indexOf(id) != -1)));
+ window.on('unmaximize', this.fixBounds.bind(this, id, (floatingWindows.indexOf(id) != -1)));
+ window.on('enter-full-screen', this.fixBounds.bind(this, id, (floatingWindows.indexOf(id) != -1)));
+ window.on('leave-full-screen', this.fixBounds.bind(this, id, (floatingWindows.indexOf(id) != -1)));
+ window.on('enter-html-full-screen', this.fixBounds.bind(this, id, (floatingWindows.indexOf(id) != -1)));
+ window.on('leave-html-full-screen', this.fixBounds.bind(this, id, (floatingWindows.indexOf(id) != -1)));
+
+ this.registerListeners(id);
+
localShortcut.register(window, 'CmdOrCtrl+Shift+I', () => {
if (window.getBrowserView() == undefined) return;
const view = window.getBrowserView();
view.webContents.reloadIgnoringCache();
});
- window.on('closed', () => {
- this.windows.delete(id);
- });
-
- ['resize', 'move'].forEach(ev => {
- window.on(ev, () => {
- config.set('window.isMaximized', window.isMaximized());
- config.set('window.bounds', window.getBounds());
- })
- });
-
- window.on('close', (e) => {
- for (var i = 0; i < views.length; i++) {
- if (views[i].windowId == id) {
- views.splice(i, 1);
- }
- }
- });
-
- window.on('maximize', this.fixBounds.bind(this, id, (floatingWindows.indexOf(id) != -1)));
- window.on('unmaximize', this.fixBounds.bind(this, id, (floatingWindows.indexOf(id) != -1)));
- window.on('enter-full-screen', this.fixBounds.bind(this, id, (floatingWindows.indexOf(id) != -1)));
- window.on('leave-full-screen', this.fixBounds.bind(this, id, (floatingWindows.indexOf(id) != -1)));
- window.on('enter-html-full-screen', this.fixBounds.bind(this, id, (floatingWindows.indexOf(id) != -1)));
- window.on('leave-html-full-screen', this.fixBounds.bind(this, id, (floatingWindows.indexOf(id) != -1)));
-
- // registerProtocols();
- this.registerListeners(id);
+ localShortcut.register(window, 'F11', () => {
+ const window = this.windows.get(id);
+
+ window.setFullScreen(!window.isFullScreen());
+ this.fixBounds(id, (floatingWindows.indexOf(id) != -1));
+ })
this.windows.set(id, window);
+
+ if (process.argv != undefined) {
+ window.webContents.send(`tab-add-${id}`, { url: process.argv[process.argv.length - 1] });
+ }
}
registerListeners = (id) => {
- ipcMain.on(`browserview-add-${id}`, (e, args) => {
+ ipcMain.on(`window-fullScreen-${id}`, (e, args) => {
+ const window = this.windows.get(id);
+
+ window.setFullScreen(!window.isFullScreen());
+ this.fixBounds(id, (floatingWindows.indexOf(id) != -1));
+ });
+
+ ipcMain.on(`browserView-add-${id}`, (e, args) => {
this.addView(id, args.url, args.isActive);
});
- ipcMain.on(`browserview-remove-${id}`, (e, args) => {
+ ipcMain.on(`browserView-remove-${id}`, (e, args) => {
this.removeView(id, args.id);
});
- ipcMain.on(`browserview-select-${id}`, (e, args) => {
+ ipcMain.on(`browserView-select-${id}`, (e, args) => {
this.selectView(id, args.id);
});
- ipcMain.on(`browserview-get-${id}`, (e, args) => {
+ ipcMain.on(`browserView-get-${id}`, (e, args) => {
let datas = [];
- for (var i = 0; i < views.length; i++) {
- if (views[i].windowId == id) {
- const url = views[i].view.webContents.getURL();
- datas.push({ id: views[i].id, title: views[i].view.webContents.getTitle(), url: url, icon: url.startsWith('my://') ? undefined : `http://www.google.com/s2/favicons?domain=${url}` });
- }
- }
- e.sender.send(`browserview-get-${id}`, { views: datas });
+
+ views[id].map((item) => {
+ const url = item.view.webContents.getURL();
+
+ datas.push({ id: item.view.webContents.id, title: item.view.webContents.getTitle(), url, icon: this.getFavicon(url), color: '#0a84ff', isBookmarked: false });
+ });
+ e.sender.send(`browserView-get-${id}`, { views: datas });
});
- ipcMain.on(`browserview-goBack-${id}`, (e, args) => {
- views.filter(function (view, i) {
- if (view.id == args.id) {
- let webContents = views[i].view.webContents;
+ ipcMain.on(`browserView-goBack-${id}`, (e, args) => {
+ views[id].filter(function (view, i) {
+ if (view.view.webContents.id == args.id) {
+ let webContents = views[id][i].view.webContents;
if (webContents.canGoBack())
webContents.goBack();
}
});
});
- ipcMain.on(`browserview-goForward-${id}`, (e, args) => {
- views.filter(function (view, i) {
- if (view.id == args.id) {
- let webContents = views[i].view.webContents;
+ ipcMain.on(`browserView-goForward-${id}`, (e, args) => {
+ views[id].filter(function (view, i) {
+ if (view.view.webContents.id == args.id) {
+ let webContents = views[id][i].view.webContents;
if (webContents.canGoForward())
webContents.goForward();
}
});
});
- ipcMain.on(`browserview-reload-${id}`, (e, args) => {
- views.filter(function (view, i) {
- if (view.id == args.id) {
- let webContents = views[i].view.webContents;
+ ipcMain.on(`browserView-reload-${id}`, (e, args) => {
+ views[id].filter(function (view, i) {
+ if (view.view.webContents.id == args.id) {
+ let webContents = views[id][i].view.webContents;
webContents.reload();
}
});
});
- ipcMain.on(`browserview-stop-${id}`, (e, args) => {
- views.filter(function (view, i) {
- if (view.id == args.id) {
- let webContents = views[i].view.webContents;
+ ipcMain.on(`browserView-stop-${id}`, (e, args) => {
+ views[id].filter(function (view, i) {
+ if (view.view.webContents.id == args.id) {
+ let webContents = views[id][i].view.webContents;
webContents.stop();
}
});
});
- ipcMain.on(`browserview-goHome-${id}`, (e, args) => {
- views.filter(function (view, i) {
- if (view.id == args.id) {
- let webContents = views[i].view.webContents;
- webContents.loadURL(config.get('homePage.defaultPage'));
+ ipcMain.on(`browserView-goHome-${id}`, (e, args) => {
+ views[id].filter(function (view, i) {
+ if (view.view.webContents.id == args.id) {
+ let webContents = views[id][i].view.webContents;
+ webContents.loadURL(config.get('homePage.isDefaultHomePage') ? `${protocolStr}://home/` : config.get('homePage.defaultPage'));
}
});
});
- ipcMain.on(`browserview-loadURL-${id}`, (e, args) => {
- views.filter(function (view, i) {
- if (view.id == args.id) {
- let webContents = views[i].view.webContents;
+ ipcMain.on(`browserView-loadURL-${id}`, (e, args) => {
+ views[id].filter(function (view, i) {
+ if (view.view.webContents.id == args.id) {
+ let webContents = views[id][i].view.webContents;
webContents.loadURL(args.url);
}
});
});
- ipcMain.on(`browserview-loadFile-${id}`, (e, args) => {
- views.filter(function (view, i) {
- if (view.id == args.id) {
- let webContents = views[i].view.webContents;
+ ipcMain.on(`browserView-loadFile-${id}`, (e, args) => {
+ views[id].filter(function (view, i) {
+ if (view.view.webContents.id == args.id) {
+ let webContents = views[id][i].view.webContents;
webContents.loadFile(args.url);
}
});
});
+ ipcMain.on(`browserView-zoomIn-${id}`, (e, args) => {
+ views[id].filter(function (view, i) {
+ if (view.view.webContents.id == args.id) {
+ let webContents = views[id][i].view.webContents;
+ console.log(webContents.getZoomFactor());
+ webContents.setZoomFactor(webContents.getZoomFactor() + 0.1);
+ }
+ });
+ });
+
+ ipcMain.on(`browserView-zoomOut-${id}`, (e, args) => {
+ views[id].filter(function (view, i) {
+ if (view.view.webContents.id == args.id) {
+ let webContents = views[id][i].view.webContents;
+ console.log(webContents.getZoomFactor());
+ webContents.setZoomFactor(webContents.getZoomFactor() - 0.1);
+ }
+ });
+ });
+
ipcMain.on(`data-bookmark-add-${id}`, (e, args) => {
- views.filter((view, i) => {
- if (view.id == args.id) {
- let v = views[i].view;
- db.bookmark.insert({ title: v.webContents.getTitle(), url: v.webContents.getURL(), isPrivate: args.isPrivate });
- this.updateBookmarkState(id, args.id, v);
+ views[id].filter((view, i) => {
+ if (view.view.webContents.id == args.id) {
+ let v = views[id][i].view;
+ db.bookmarks.insert({ title: v.webContents.getTitle(), url: v.webContents.getURL(), isPrivate: args.isPrivate });
+ this.updateViewState(id, v);
}
});
});
ipcMain.on(`data-bookmark-remove-${id}`, (e, args) => {
- views.filter((view, i) => {
- if (view.id == args.id) {
- let v = views[i].view;
- db.bookmark.remove({ url: v.webContents.getURL(), isPrivate: args.isPrivate }, {});
- this.updateBookmarkState(id, args.id, v);
+ views[id].filter((view, i) => {
+ if (view.view.webContents.id == args.id) {
+ let v = views[id][i].view;
+ db.bookmarks.remove({ url: v.webContents.getURL(), isPrivate: args.isPrivate }, {});
+ this.updateViewState(id, v);
}
});
});
ipcMain.on(`data-bookmark-has-${id}`, (e, args) => {
- views.filter((view, i) => {
- if (view.id == args.id) {
- let v = views[i].view;
- db.bookmark.find({ url: v.webContents.getURL(), isPrivate: args.isPrivate }, (err, docs) => {
+ views[id].filter((view, i) => {
+ if (view.view.webContents.id == args.id) {
+ let v = views[id][i].view;
+ db.bookmarks.find({ url: v.webContents.getURL(), isPrivate: args.isPrivate }, (err, docs) => {
e.sender.send(`data-bookmark-has-${id}`, { isBookmarked: (docs.length > 0 ? true : false) });
});
}
});
}
- updateNavigationState = (windowId, id, view) => {
- const window = this.windows.get(windowId);
- window.webContents.send(`update-navigation-state-${windowId}`, {
- id: id,
+ getFavicon = (url) => {
+ const parsed = parse(url);
+ return url.startsWith(`${protocolStr}://`) || url.startsWith(`${fileProtocolStr}://`) ? undefined : `https://www.google.com/s2/favicons?domain=${parsed.protocol}//${parsed.hostname}`;
+ }
+
+ updateNavigationState = (id, view) => {
+ const window = this.windows.get(id);
+ window.webContents.send(`update-navigation-state-${id}`, {
+ id: view.webContents.id,
canGoBack: view.webContents.canGoBack(),
canGoForward: view.webContents.canGoForward(),
});
}
- updateBookmarkState = (windowId, id, view) => {
- const window = this.windows.get(windowId);
- db.bookmark.find({ url: view.webContents.getURL(), isPrivate: (String(windowId).startsWith('private')) }, (err, docs) => {
- window.webContents.send(`browserview-load-${windowId}`, { id: id, title: view.webContents.getTitle(), url: view.webContents.getURL(), isBookmarked: (docs.length > 0 ? true : false) });
+ updateViewState = (id, view) => {
+ const window = this.windows.get(id);
+ db.bookmarks.find({ url: view.webContents.getURL(), isPrivate: (String(id).startsWith('private')) }, (err, docs) => {
+ const url = view.webContents.getURL();
+
+ window.webContents.send(`browserView-load-${id}`, { id: view.webContents.id, title: view.webContents.getTitle(), url: url, icon: this.getFavicon(url), color: '#0a84ff', isAudioPlaying: !view.webContents.isCurrentlyAudible(), isBookmarked: (docs.length > 0 ? true : false) });
});
}
+ getColor = (view) => {
+ return new Promise((resolve, reject) => {
+ if (view !== null && !view.isDestroyed() && view.webContents !== null) {
+ view.webContents.executeJavaScript(
+ `(function () {
+ const heads = document.head.children;
+ for (var i = 0; i < heads.length; i++) {
+ if (heads[i].getAttribute('name') === 'theme-color') {
+ return heads[i].getAttribute('content');
+ }
+ }
+ })()`, false, async (result) => {
+ resolve(result !== null ? result : '#0a84ff');
+ });
+ } else {
+ reject(new Error('WebContents are not available'));
+ }
+ });
+ };
+
fixBounds = (windowId, isFloating = false) => {
const window = this.windows.get(windowId);
const { width, height } = window.getContentBounds();
+ const baseBarHeight = 73;
+ const bookMarkBarHeight = 28;
+
view.setAutoResize({ width: true, height: true });
if (isFloating) {
window.setMinimizable(false);
});
} else {
view.setBounds({
- x: 1,
- y: 73 + 1,
- width: width - 2,
- height: window.isMaximized() ? height - 73 : (height - 73) - 2,
+ x: config.get('design.isCustomTitlebar') ? 1 : 0,
+ y: config.get('design.isCustomTitlebar') ? this.getHeight(true, height, baseBarHeight, bookMarkBarHeight) + 1 : this.getHeight(true, height, baseBarHeight, bookMarkBarHeight),
+ width: config.get('design.isCustomTitlebar') ? width - 2 : width,
+ height: window.isMaximized() ? this.getHeight(false, height, baseBarHeight, bookMarkBarHeight) : (config.get('design.isCustomTitlebar') ? (this.getHeight(false, height, baseBarHeight, bookMarkBarHeight)) - 2 : (this.getHeight(false, height, baseBarHeight, bookMarkBarHeight)) - 1),
});
}
}
view.setAutoResize({ width: true, height: true });
}
- addView = (windowId, url, isActive) => {
- const id = tabCount++;
- this.addTab(windowId, id, url, isActive);
+ getDomain = (url) => {
+ let hostname = url;
+
+ if (hostname.indexOf('http://') !== -1 || hostname.indexOf('https://') !== -1) {
+ hostname = hostname.split('://')[1];
+ }
+
+ if (hostname.indexOf('?') !== -1) {
+ hostname = hostname.split('?')[0];
+ }
+
+ if (hostname.indexOf('://') !== -1) {
+ hostname = `${hostname.split('://')[0]}://${hostname.split('/')[2]}`;
+ } else {
+ hostname = hostname.split('/')[0];
+ }
+
+ return hostname;
+ }
+
+ getCertificate = (url) => {
+ return new Promise((resolve, reject) => {
+ if (url.startsWith('http://')) return resolve({ type: 'InSecure' });
+ else if (url.startsWith(`${protocolStr}://`) || url.startsWith(`${fileProtocolStr}://`)) return resolve({ type: 'Internal' });
+
+ const domain = this.getDomain(url);
+
+ let options = {
+ host: domain,
+ port: 443,
+ method: 'GET'
+ };
+
+ let req = https.request(options, (res) => {
+ let certificate = res.connection.getPeerCertificate();
+ if (certificate.subject == null) return;
+
+ const data = {
+ type: 'Secure',
+ title: certificate.subject.O,
+ country: certificate.subject.C
+ };
+ resolve(data);
+ });
+
+ req.end();
+ });
+ }
+
+ getHeight = (b, height, baseBarHeight, bookMarkBarHeight) => {
+ if (b) {
+ return config.get('design.isBookmarkBar') ? (baseBarHeight + bookMarkBarHeight) : baseBarHeight;
+ } else {
+ return height - (config.get('design.isBookmarkBar') ? (baseBarHeight + bookMarkBarHeight) : baseBarHeight);
+ }
+ };
+
+ addView = (id, url, isActive) => {
+ if (String(id).startsWith('private')) {
+ loadSessionAndProtocolWithPrivateMode(id);
+ }
+
+ this.addTab(id, url, isActive);
}
removeView = (windowId, id) => {
- views.filter((view, i) => {
- if (windowId == view.windowId && id == view.id) {
- views.splice(i, 1);
+ views[windowId].filter((view, i) => {
+ if (view.view.webContents.id == id) {
+ const index = i;
+
+ if (index + 1 < views[windowId].length) {
+ this.selectView2(windowId, index + 1);
+ } else if (index - 1 >= 0) {
+ this.selectView2(windowId, index - 1);
+ }
+
+ views[windowId][index].view.destroy();
+ views[windowId].splice(index, 1);
}
});
}
selectView = (windowId, id) => {
const window = this.windows.get(windowId);
- views.filter((view, i) => {
- if (windowId == view.windowId && id == view.id) {
- window.setBrowserView(views[i].view);
- window.setTitle(views[i].view.webContents.getTitle());
- window.webContents.send(`browserview-set-${windowId}`, { id: id });
+ views[windowId].filter((item, i) => {
+ if (id == item.view.webContents.id) {
+ window.setBrowserView(item.view);
+ window.setTitle(`${item.view.webContents.getTitle()} - ${pkg.name}`);
+
+ this.updateNavigationState(windowId, item.view);
+ this.updateViewState(windowId, item.view);
+
+ window.webContents.send(`browserView-set-${windowId}`, { id: id });
this.fixBounds(windowId, (floatingWindows.indexOf(windowId) != -1));
}
});
}
+ selectView2 = (windowId, i) => {
+ const window = this.windows.get(windowId);
+ const item = views[windowId][i];
+
+ window.setBrowserView(item.view);
+ window.setTitle(`${item.view.webContents.getTitle()} - ${pkg.name}`);
+ window.webContents.send(`browserView-set-${windowId}`, { id: item.id });
+ this.fixBounds(windowId, (floatingWindows.indexOf(windowId) != -1));
+ }
+
getViews = (windowId) => {
let datas = [];
- for (var i = 0; i < views.length; i++) {
- if (views[i].windowId == windowId) {
- const url = views[i].view.webContents.getURL();
- datas.push({ id: views[i].id, title: views[i].view.webContents.getTitle(), url: url, icon: url.startsWith('my://') ? undefined : `http://www.google.com/s2/favicons?domain=${url}` });
- }
+ for (var i = 0; i < views[windowId].length; i++) {
+ const url = views[windowId][i].view.webContents.getURL();
+
+ datas.push({ id: views[windowId][i].view.webContents.id, title: views[windowId][i].view.webContents.getTitle(), url: url, icon: this.getFavicon(url) });
}
const window = this.windows.get(windowId);
- window.webContents.send(`browserview-get-${windowId}`, { views: datas });
+ window.webContents.send(`browserView-get-${windowId}`, { views: datas });
}
- addTab = (windowId, id, url = config.get('homePage.defaultPage'), isActive = true) => {
- const window = this.windows.get(windowId);
-
+ addTab = (windowId, url = config.get('homePage.defaultPage'), isActive = true) => {
const view = new BrowserView({
webPreferences: {
nodeIntegration: false,
}
});
- const defaultUserAgent = view.webContents.getUserAgent();
+ view.webContents.setVisualZoomLevelLimits(1, 3);
- if (String(windowId).startsWith('private')) {
- registerProtocolWithPrivateMode(windowId);
- }
+ const window = this.windows.get(windowId);
+ const id = view.webContents.id;
+
+ const executeJs = this.getRandString(12);
+ let viewId = '';
+
+ runAdblockService(window, windowId, id, view.webContents.session);
view.webContents.on('did-start-loading', () => {
if (view.isDestroyed()) return;
- window.webContents.send(`browserview-start-loading-${windowId}`, { id: id });
+ window.webContents.send(`browserView-start-loading-${windowId}`, { id: id });
});
view.webContents.on('did-stop-loading', () => {
if (view.isDestroyed()) return;
- window.webContents.send(`browserview-stop-loading-${windowId}`, { id: id });
+ window.webContents.send(`browserView-stop-loading-${windowId}`, { id: id });
});
- view.webContents.on('did-finish-load', (e) => {
+ view.webContents.on('did-start-navigation', (e) => {
if (view.isDestroyed()) return;
- if (String(windowId).startsWith('private'))
- view.webContents.setUserAgent(defaultUserAgent + ' PrivMode');
+ const url = view.webContents.getURL();
- window.setTitle(view.webContents.getTitle());
- this.updateBookmarkState(windowId, id, view);
+ /*
+ view.webContents.executeJavaScript(
+ `(function () {
+ if (document.getElementById('tip-${executeJs}') === null) {
+ let ${executeJs} = document.createElement('span');
+ document.body.insertBefore(${executeJs}, document.body.firstChild);
+
+ ${executeJs}.id = 'tip-${executeJs}';
+ ${executeJs}.style.display = 'none';
+ ${executeJs}.style.position = 'fixed';
+ ${executeJs}.style.bottom = 0;
+ ${executeJs}.style.left = 0;
+ ${executeJs}.style.zIndex = 999999;
+ ${executeJs}.style.padding = '2px';
+ ${executeJs}.style.userSelect = 'none';
+ ${executeJs}.style.backgroundColor = '#f9f9fa';
+ ${executeJs}.style.color = '#c7c7c7';
+ ${executeJs}.style.borderTop = 'solid 1px #c7c7c7';
+ ${executeJs}.style.borderRight = 'solid 1px #c7c7c7';
+ ${executeJs}.style.fontSize = '12px';
+ document.getElementById('tip-${executeJs}').style.fontFamily = '"Lato","Helvetica Neue",Helvetica,Arial,sans-serif';
+ }
+ })()`
+ );
+ */
- this.updateNavigationState(windowId, id, view);
- });
+ if (config.get('isAdBlock') && !(view.webContents.getURL().startsWith(`${protocolStr}://`) || view.webContents.getURL().startsWith(`${fileProtocolStr}://`)))
+ removeAds(url, view.webContents);
- view.webContents.on('did-start-navigation', (e) => {
+ this.updateNavigationState(windowId, view);
+ });
+ view.webContents.on('did-finish-load', (e) => {
if (view.isDestroyed()) return;
- const url = view.webContents.getURL();
+ viewId = this.getRandString(12);
- if (config.get('adBlocker'))
- removeAds(url, view.webContents);
+ this.getCertificate(view.webContents.getURL()).then((certificate) => {
+ window.webContents.send(`browserView-certificate-${windowId}`, { id, certificate });
+ });
- this.updateNavigationState(windowId, id, view);
+ window.setTitle(`${view.webContents.getTitle()} - ${pkg.name}`);
+
+ this.updateViewState(windowId, view);
+ this.updateNavigationState(windowId, view);
+ });
+ view.webContents.on('did-fail-load', (e, code, description, url, isMainFrame, processId, routingId) => {
+ if (view.isDestroyed() || !isMainFrame || code === -3) return;
+
+ dialog.showMessageBox({ message: `${code}: ${description}` });
});
view.webContents.on('page-title-updated', (e) => {
if (view.isDestroyed()) return;
- window.setTitle(view.webContents.getTitle());
- this.updateBookmarkState(windowId, id, view);
+ if (!String(windowId).startsWith('private') && !(view.webContents.getURL().startsWith(`${protocolStr}://`) || view.webContents.getURL().startsWith(`${fileProtocolStr}://`)))
+ db.historys.update({ id: viewId }, { id: viewId, title: view.webContents.getTitle(), url: view.webContents.getURL() }, { upsert: true });
- if (!String(windowId).startsWith('private') && !view.webContents.getURL().startsWith('my://'))
- db.history.insert({ title: view.webContents.getTitle(), url: view.webContents.getURL() });
+ window.setTitle(`${view.webContents.getTitle()} - ${pkg.name}`);
- this.updateNavigationState(windowId, id, view);
+ this.updateViewState(windowId, view);
+ this.updateNavigationState(windowId, view);
});
-
view.webContents.on('page-favicon-updated', (e, favicons) => {
if (view.isDestroyed()) return;
- window.setTitle(view.webContents.getTitle());
- db.bookmark.find({ url: view.webContents.getURL(), isPrivate: (String(windowId).startsWith('private')) }, (err, docs) => {
- window.webContents.send(`browserview-load-${windowId}`, { id: id, title: view.webContents.getTitle(), url: view.webContents.getURL(), favicon: favicons[0], isBookmarked: (docs.length > 0 ? true : false) });
- });
+ if (!String(windowId).startsWith('private') && !(view.webContents.getURL().startsWith(`${protocolStr}://`) || view.webContents.getURL().startsWith(`${fileProtocolStr}://`)))
+ db.historys.update({ id: viewId }, { id: viewId, title: view.webContents.getTitle(), url: view.webContents.getURL() }, { upsert: true });
- this.updateNavigationState(windowId, id, view);
- });
+ window.setTitle(`${view.webContents.getTitle()} - ${pkg.name}`);
+ this.updateViewState(windowId, view);
+ this.updateNavigationState(windowId, view);
+ });
view.webContents.on('did-change-theme-color', (e, color) => {
if (view.isDestroyed()) return;
- window.setTitle(view.webContents.getTitle());
- db.bookmark.find({ url: view.webContents.getURL(), isPrivate: (String(windowId).startsWith('private')) }, (err, docs) => {
- window.webContents.send(`browserview-load-${windowId}`, { id: id, title: view.webContents.getTitle(), url: view.webContents.getURL(), color: color, isBookmarked: (docs.length > 0 ? true : false) });
- });
+ if (!String(windowId).startsWith('private') && !(view.webContents.getURL().startsWith(`${protocolStr}://`) || view.webContents.getURL().startsWith(`${fileProtocolStr}://`)))
+ db.historys.update({ id: viewId }, { id: viewId, title: view.webContents.getTitle(), url: view.webContents.getURL() }, { upsert: true });
+
+ window.setTitle(`${view.webContents.getTitle()} - ${pkg.name}`);
+
+ this.updateViewState(windowId, view);
+ this.updateNavigationState(windowId, view);
+
+ window.webContents.send(`browserView-theme-color-${windowId}`, { id: view.webContents.id, color });
});
+ view.webContents.on('update-target-url', (e, url) => {
+ /*
+ if (url.length > 0) {
+ view.webContents.executeJavaScript(
+ `(function () {
+ let dom = document.getElementById('tip-${executeJs}');
+
+ document.getElementById('tip-${executeJs}').style.display = 'block';
+ dom.textContent = '${url}';
+ })()`
+ );
+ } else {
+ view.webContents.executeJavaScript(
+ `(function () {
+ document.getElementById('tip-${executeJs}').style.display = 'none';
+ })()`
+ );
+ }
+ */
+ })
+
view.webContents.on('new-window', (e, url) => {
if (view.isDestroyed()) return;
this.addView(windowId, url, true);
});
+ view.webContents.on('certificate-error', (e, url, error, certificate, callback) => {
+ e.preventDefault();
+ if (Notification.isSupported()) {
+ const notify = new Notification({
+ icon: path.join(app.getAppPath(), 'static', 'app', 'icon.png'),
+ title: `プライバシー エラー`,
+ body: '詳細はここをクリックしてください。',
+ silent: true
+ });
+
+ notify.show();
+
+ notify.on('click', (e) => {
+ dialog.showMessageBox({
+ type: 'warning',
+ title: 'プライバシー エラー',
+ message: 'この接続ではプライバシーが保護されません',
+ detail: `${parse(url).hostname} の証明書を信頼することができませんでした。\n信頼できるページに戻ることをおすすめします。\nこのまま閲覧することも可能ですが安全ではありません。`,
+ noLink: true,
+ buttons: ['続行', 'キャンセル'],
+ defaultId: 1,
+ cancelId: 1
+ }, (res) => {
+ callback(res === 0);
+ });
+ });
+ notify.on('close', (e) => {
+ callback(false);
+ });
+ } else {
+ dialog.showMessageBox({
+ type: 'warning',
+ title: 'プライバシー エラー',
+ message: 'この接続ではプライバシーが保護されません',
+ detail: `${parse(url).hostname} の証明書を信頼することができませんでした。\n信頼できるページに戻ることをおすすめします。\nこのまま閲覧することも可能ですが安全ではありません。`,
+ noLink: true,
+ buttons: ['続行', 'キャンセル'],
+ defaultId: 1,
+ cancelId: 1
+ }, (res) => {
+ callback(res === 0);
+ });
+ }
+ });
+
view.webContents.on('context-menu', (e, params) => {
if (view.isDestroyed()) return;
- const menu = Menu.buildFromTemplate(
- [
- ...(params.linkURL !== '' ?
- [
- {
- label: '新しいタブで開く',
- click: () => {
- this.addView(windowId, params.linkURL, true);
- }
- },
- {
- label: '新しいウィンドウで開く',
- enabled: false,
- click: () => { view.webContents.openDevTools(); }
- },
- {
- label: 'プライベート ウィンドウで開く',
- enabled: false,
- click: () => { view.webContents.openDevTools(); }
- },
- { type: 'separator' },
- {
- label: 'リンクをコピー',
- accelerator: 'CmdOrCtrl+C',
- click: () => {
- clipboard.clear();
- clipboard.writeText(params.linkURL);
- }
- },
- { type: 'separator' }
- ] : []),
- ...(params.hasImageContents ?
- [
- {
- label: '新しいタブで画像を開く',
- click: () => {
- this.addView(windowId, params.srcURL, true);
- }
- },
- {
- label: '画像をコピー',
- click: () => {
- const img = nativeImage.createFromDataURL(params.srcURL);
-
- clipboard.clear();
- clipboard.writeImage(img);
- }
- },
- {
- label: '画像アドレスをコピー',
- click: () => {
- clipboard.clear();
- clipboard.writeText(params.srcURL);
- }
- },
- { type: 'separator' }
- ] : []),
- ...(params.isEditable ?
- [
- {
- label: '元に戻す',
- accelerator: 'CmdOrCtrl+Z',
- enabled: params.editFlags.canUndo,
- click: () => { view.webContents.undo(); }
- },
- {
- label: 'やり直す',
- accelerator: 'CmdOrCtrl+Y',
- enabled: params.editFlags.canRedo,
- click: () => { view.webContents.redo(); }
- },
- { type: 'separator' },
- {
- label: '切り取り',
- accelerator: 'CmdOrCtrl+X',
- enabled: params.editFlags.canCut,
- click: () => { view.webContents.cut(); }
- },
- {
- label: 'コピー',
- accelerator: 'CmdOrCtrl+C',
- enabled: params.editFlags.canCopy,
- click: () => { view.webContents.copy(); }
- },
- {
- label: '貼り付け',
- accelerator: 'CmdOrCtrl+V',
- enabled: params.editFlags.canPaste,
- click: () => { view.webContents.paste(); }
- },
- { type: 'separator' },
- {
- label: 'すべて選択',
- accelerator: 'CmdOrCtrl+A',
- enabled: params.editFlags.canSelectAll,
- click: () => { view.webContents.selectAll(); }
- },
- { type: 'separator' }
- ] : []),
- ...(params.selectionText !== '' && !params.isEditable ?
- [
- {
- label: 'コピー',
- accelerator: 'CmdOrCtrl+C',
- click: () => { view.webContents.copy(); }
- },
- {
- label: `Googleで「${params.selectionText}」を検索`,
- click: () => {
- this.addView(windowId, `https://www.google.co.jp/search?q=${params.selectionText}`, true);
+ let menu;
+ if (params.linkURL !== '' && !params.hasImageContents) {
+ menu = Menu.buildFromTemplate(
+ [
+ {
+ label: lang.window.view.contextMenu.link.newTab,
+ click: () => {
+ this.addView(windowId, params.linkURL, true);
+ }
+ },
+ {
+ label: lang.window.view.contextMenu.link.newWindow,
+ enabled: false,
+ click: () => { view.webContents.openDevTools(); }
+ },
+ {
+ label: lang.window.view.contextMenu.link.openPrivateWindow,
+ enabled: false,
+ click: () => { view.webContents.openDevTools(); }
+ },
+ { type: 'separator' },
+ {
+ label: lang.window.view.contextMenu.link.copy,
+ accelerator: 'CmdOrCtrl+C',
+ click: () => {
+ clipboard.clear();
+ clipboard.writeText(params.linkURL);
+ }
+ },
+ { type: 'separator' },
+ {
+ label: lang.window.view.contextMenu.devTool,
+ accelerator: 'CmdOrCtrl+Shift+I',
+ enabled: !view.webContents.getURL().startsWith(`${protocolStr}://`),
+ click: () => {
+ if (view.webContents.isDevToolsOpened())
+ view.webContents.devToolsWebContents.focus();
+ else
+ view.webContents.openDevTools();
+ }
+ }
+ ]
+ );
+ } else if (params.linkURL === '' && params.hasImageContents) {
+ menu = Menu.buildFromTemplate(
+ [
+ {
+ label: lang.window.view.contextMenu.image.newTab,
+ click: () => {
+ this.addView(windowId, params.srcURL, true);
+ }
+ },
+ {
+ label: lang.window.view.contextMenu.image.saveImage,
+ enabled: !view.webContents.getURL().startsWith(`${protocolStr}://`),
+ click: () => {
+ download(window, params.srcURL, {
+ directory: app.getPath('downloads'),
+ saveAs: true
+ });
+ }
+ },
+ {
+ label: lang.window.view.contextMenu.image.copyImage,
+ click: () => {
+ const img = nativeImage.createFromDataURL(params.srcURL);
+
+ clipboard.clear();
+ clipboard.writeImage(img);
+ }
+ },
+ {
+ label: lang.window.view.contextMenu.image.copyLink,
+ click: () => {
+ clipboard.clear();
+ clipboard.writeText(params.srcURL);
+ }
+ },
+ { type: 'separator' },
+ {
+ label: lang.window.view.contextMenu.devTool,
+ accelerator: 'CmdOrCtrl+Shift+I',
+ enabled: !view.webContents.getURL().startsWith(`${protocolStr}://`),
+ click: () => {
+ if (view.webContents.isDevToolsOpened())
+ view.webContents.devToolsWebContents.focus();
+ else
+ view.webContents.openDevTools();
+ }
+ }
+ ]
+ );
+ } else if (params.linkURL !== '' && params.hasImageContents) {
+ menu = Menu.buildFromTemplate(
+ [
+ {
+ label: lang.window.view.contextMenu.link.newTab,
+ click: () => {
+ this.addView(windowId, params.linkURL, true);
+ }
+ },
+ {
+ label: lang.window.view.contextMenu.link.newWindow,
+ enabled: false,
+ click: () => { view.webContents.openDevTools(); }
+ },
+ {
+ label: lang.window.view.contextMenu.link.openPrivateWindow,
+ enabled: false,
+ click: () => { view.webContents.openDevTools(); }
+ },
+ { type: 'separator' },
+ {
+ label: lang.window.view.contextMenu.link.copy,
+ accelerator: 'CmdOrCtrl+C',
+ click: () => {
+ clipboard.clear();
+ clipboard.writeText(params.linkURL);
+ }
+ },
+ { type: 'separator' },
+ {
+ label: lang.window.view.contextMenu.image.newTab,
+ click: () => {
+ this.addView(windowId, params.srcURL, true);
+ }
+ },
+ {
+ label: lang.window.view.contextMenu.image.saveImage,
+ enabled: !view.webContents.getURL().startsWith(`${protocolStr}://`),
+ click: () => {
+ download(window, params.srcURL, {
+ directory: app.getPath('downloads'),
+ saveAs: true
+ });
+ }
+ },
+ {
+ label: lang.window.view.contextMenu.image.copyImage,
+ click: () => {
+ const img = nativeImage.createFromDataURL(params.srcURL);
+
+ clipboard.clear();
+ clipboard.writeImage(img);
+ }
+ },
+ {
+ label: lang.window.view.contextMenu.image.copyLink,
+ click: () => {
+ clipboard.clear();
+ clipboard.writeText(params.srcURL);
+ }
+ },
+ { type: 'separator' },
+ {
+ label: lang.window.view.contextMenu.devTool,
+ accelerator: 'CmdOrCtrl+Shift+I',
+ enabled: !view.webContents.getURL().startsWith(`${protocolStr}://`),
+ click: () => {
+ if (view.webContents.isDevToolsOpened())
+ view.webContents.devToolsWebContents.focus();
+ else
+ view.webContents.openDevTools();
+ }
+ }
+ ]
+ );
+ } else if (params.isEditable) {
+ menu = Menu.buildFromTemplate(
+ [
+ {
+ label: lang.window.view.contextMenu.editable.undo,
+ accelerator: 'CmdOrCtrl+Z',
+ enabled: params.editFlags.canUndo,
+ click: () => { view.webContents.undo(); }
+ },
+ {
+ label: lang.window.view.contextMenu.editable.redo,
+ accelerator: 'CmdOrCtrl+Y',
+ enabled: params.editFlags.canRedo,
+ click: () => { view.webContents.redo(); }
+ },
+ { type: 'separator' },
+ {
+ label: lang.window.view.contextMenu.editable.cut,
+ accelerator: 'CmdOrCtrl+X',
+ enabled: params.editFlags.canCut,
+ click: () => { view.webContents.cut(); }
+ },
+ {
+ label: lang.window.view.contextMenu.editable.copy,
+ accelerator: 'CmdOrCtrl+C',
+ enabled: params.editFlags.canCopy,
+ click: () => { view.webContents.copy(); }
+ },
+ {
+ label: lang.window.view.contextMenu.editable.paste,
+ accelerator: 'CmdOrCtrl+V',
+ enabled: params.editFlags.canPaste,
+ click: () => { view.webContents.paste(); }
+ },
+ { type: 'separator' },
+ {
+ label: lang.window.view.contextMenu.editable.selectAll,
+ accelerator: 'CmdOrCtrl+A',
+ enabled: params.editFlags.canSelectAll,
+ click: () => { view.webContents.selectAll(); }
+ },
+ { type: 'separator' },
+ {
+ label: lang.window.view.contextMenu.devTool,
+ accelerator: 'CmdOrCtrl+Shift+I',
+ enabled: !view.webContents.getURL().startsWith(`${protocolStr}://`),
+ click: () => {
+ if (view.webContents.isDevToolsOpened())
+ view.webContents.devToolsWebContents.focus();
+ else
+ view.webContents.openDevTools();
+ }
+ }
+ ]
+ );
+ } else if (params.selectionText !== '' && !params.isEditable) {
+ menu = Menu.buildFromTemplate(
+ [
+ {
+ label: lang.window.view.contextMenu.selection.copy,
+ accelerator: 'CmdOrCtrl+C',
+ click: () => { view.webContents.copy(); }
+ },
+ {
+ label: String(lang.window.view.contextMenu.selection.textSearch).replace(/{name}/, 'Google').replace(/{text}/, params.selectionText),
+ click: () => {
+ this.addView(windowId, `https://www.google.co.jp/search?q=${params.selectionText}`, true);
+ }
+ },
+ { type: 'separator' },
+ {
+ label: lang.window.view.contextMenu.devTool,
+ accelerator: 'CmdOrCtrl+Shift+I',
+ enabled: !view.webContents.getURL().startsWith(`${protocolStr}://`),
+ click: () => {
+ if (view.webContents.isDevToolsOpened())
+ view.webContents.devToolsWebContents.focus();
+ else
+ view.webContents.openDevTools();
+ }
+ }
+ ]
+ );
+ } else {
+ menu = Menu.buildFromTemplate(
+ [
+ {
+ label: lang.window.view.contextMenu.back,
+ accelerator: 'Alt+Left',
+ icon: view.webContents.canGoBack() ? `${app.getAppPath()}/static/arrow_back.png` : `${app.getAppPath()}/static/arrow_back_inactive.png`,
+ enabled: view.webContents.canGoBack(),
+ click: () => { view.webContents.goBack(); }
+ },
+ {
+ label: lang.window.view.contextMenu.forward,
+ accelerator: 'Alt+Right',
+ icon: view.webContents.canGoForward() ? `${app.getAppPath()}/static/arrow_forward.png` : `${app.getAppPath()}/static/arrow_forward_inactive.png`,
+ enabled: view.webContents.canGoForward(),
+ click: () => { view.webContents.goForward(); }
+ },
+ {
+ label: !view.webContents.isLoadingMainFrame() ? lang.window.view.contextMenu.reload.reload : lang.window.view.contextMenu.reload.stop,
+ accelerator: 'CmdOrCtrl+R',
+ icon: !view.webContents.isLoadingMainFrame() ? `${app.getAppPath()}/static/refresh.png` : `${app.getAppPath()}/static/close.png`,
+ click: () => { !view.webContents.isLoadingMainFrame() ? view.webContents.reload() : view.webContents.stop(); }
+ },
+ { type: 'separator' },
+ {
+ label: lang.window.view.contextMenu.floatingWindow,
+ type: 'checkbox',
+ checked: (floatingWindows.indexOf(windowId) != -1),
+ enabled: (!window.isFullScreen() && !window.isMaximized() && config.get('design.isCustomTitlebar')),
+ click: () => {
+ if (floatingWindows.indexOf(windowId) != -1) {
+ floatingWindows.filter((win, i) => {
+ if (windowId == win) {
+ floatingWindows.splice(i, 1);
+ }
+ });
+ } else {
+ floatingWindows.push(windowId);
}
- },
- { type: 'separator' }
- ] : []),
- {
- label: '戻る',
- accelerator: 'Alt+Left',
- enabled: view.webContents.canGoBack(),
- click: () => { view.webContents.goBack(); }
- },
- {
- label: '進む',
- accelerator: 'Alt+Right',
- enabled: view.webContents.canGoForward(),
- click: () => { view.webContents.goForward(); }
- },
- {
- label: '再読み込み',
- accelerator: 'CmdOrCtrl+R',
- click: () => { view.webContents.reload(); }
- },
- { type: 'separator' },
- {
- label: 'Floating Window (Beta)',
- type: 'checkbox',
- checked: (floatingWindows.indexOf(windowId) != -1),
- enabled: (!window.isFullScreen() && !window.isMaximized()),
- click: () => {
- if (floatingWindows.indexOf(windowId) != -1) {
- floatingWindows.filter((win, i) => {
- if (windowId == win) {
- floatingWindows.splice(i, 1);
+ this.fixBounds(windowId, (floatingWindows.indexOf(windowId) != -1));
+ }
+ },
+ { type: 'separator' },
+ {
+ label: lang.window.view.contextMenu.savePage,
+ accelerator: 'CmdOrCtrl+S',
+ icon: `${app.getAppPath()}/static/save.png`,
+ enabled: !view.webContents.getURL().startsWith(`${protocolStr}://`),
+ click: () => {
+ dialog.showSaveDialog(window, {
+ defaultPath: `${app.getPath('downloads')}/${view.webContents.getTitle()}.html`,
+ filters: [
+ { name: 'HTML', extensions: ['htm', 'html'] },
+ { name: 'All Files', extensions: ['*'] }
+ ]
+ }, (fileName) => {
+ if (fileName != undefined) {
+ view.webContents.savePage(fileName, 'HTMLComplete', (err) => {
+ if (!err) console.log('Page Save successfully');
+ });
}
});
- } else {
- floatingWindows.push(windowId);
}
- this.fixBounds(windowId, (floatingWindows.indexOf(windowId) != -1));
- }
- },
- { type: 'separator' },
- {
- label: 'ページの保存',
- accelerator: 'CmdOrCtrl+S',
- enabled: !view.webContents.getURL().startsWith('my://'),
- click: () => {
- view.webContents.savePage(`${app.getPath('downloads')}/${view.webContents.getTitle()}.html`, 'HTMLComplete', (err) => {
- if (!err) console.log('Page Save successfully');
- });
+ },
+ {
+ label: lang.window.view.contextMenu.print,
+ accelerator: 'CmdOrCtrl+P',
+ icon: `${app.getAppPath()}/static/print.png`,
+ enabled: !view.webContents.getURL().startsWith(`${protocolStr}://`),
+ click: () => { view.webContents.print(); }
+ },
+ { type: 'separator' },
+ {
+ label: lang.window.view.contextMenu.viewSource,
+ enabled: !view.webContents.getURL().startsWith(`${protocolStr}://`),
+ click: () => { this.addView(windowId, `view-source:${view.webContents.getURL()}`, true); }
+ },
+ {
+ label: lang.window.view.contextMenu.devTool,
+ accelerator: 'CmdOrCtrl+Shift+I',
+ enabled: !view.webContents.getURL().startsWith(`${protocolStr}://`),
+ click: () => {
+ if (view.webContents.isDevToolsOpened())
+ view.webContents.devToolsWebContents.focus();
+ else
+ view.webContents.openDevTools();
+ }
}
- },
- {
- label: '印刷',
- accelerator: 'CmdOrCtrl+P',
- enabled: !view.webContents.getURL().startsWith('my://'),
- click: () => { view.webContents.print(); }
- },
- { type: 'separator' },
- {
- label: 'デベロッパーツール',
- accelerator: 'CmdOrCtrl+Shift+I',
- enabled: !view.webContents.getURL().startsWith('my://'),
- click: () => { if (view.webContents.isDevToolsOpened()) { view.webContents.devToolsWebContents.focus(); } else { view.webContents.openDevTools(); } }
- }
- ]
- );
+ ]
+ );
+ }
menu.popup();
});
view.webContents.on('before-input-event', (e, input) => {
if (view.isDestroyed()) return;
+ window.webContents.setIgnoreMenuShortcuts(true);
- if ((input.control || input.meta) && input.shift && input.key == 'I') {
- e.preventDefault();
- if (view.webContents.isDevToolsOpened()) {
- view.webContents.devToolsWebContents.focus();
- } else {
- view.webContents.openDevTools();
+ if (input.control) {
+ if (input.shift && input.key == 'I') {
+ e.preventDefault();
+ window.webContents.setIgnoreMenuShortcuts(true);
+ view.webContents.setIgnoreMenuShortcuts(true);
+
+ if (view.webContents.isDevToolsOpened()) {
+ view.webContents.devToolsWebContents.focus();
+ } else {
+ view.webContents.openDevTools();
+ }
+ } else if (input.shift && input.key == 'R') {
+ e.preventDefault();
+ window.webContents.setIgnoreMenuShortcuts(true);
+ view.webContents.setIgnoreMenuShortcuts(true);
+
+ view.webContents.reloadIgnoringCache();
+ } else if (input.key == 'T') {
+ e.preventDefault();
+ window.webContents.setIgnoreMenuShortcuts(true);
+ // view.webContents.setIgnoreMenuShortcuts(true);
+
+ this.addView(windowId, config.get('homePage.defaultPage'), true);
+ }
+ } else if (input.alt) {
+ if (input.key == 'ArrowLeft') {
+ e.preventDefault();
+ // window.webContents.setIgnoreMenuShortcuts(true);
+ view.webContents.setIgnoreMenuShortcuts(true);
+
+ if (view.webContents.canGoBack())
+ view.webContents.goBack();
+ } else if (input.key == 'ArrowRight') {
+ e.preventDefault();
+ // window.webContents.setIgnoreMenuShortcuts(true);
+ view.webContents.setIgnoreMenuShortcuts(true);
+
+ if (view.webContents.canGoForward())
+ view.webContents.goForward();
+ }
+ } else {
+ if (input.key == 'F11') {
+ e.preventDefault();
+ window.webContents.setIgnoreMenuShortcuts(true);
+ view.webContents.setIgnoreMenuShortcuts(true);
+
+ window.setFullScreen(!window.isFullScreen());
+ this.fixBounds(windowId, (floatingWindows.indexOf(windowId) != -1));
}
- } else if ((input.control || input.meta) && input.key == 'R') {
- e.preventDefault();
- view.webContents.reload();
- } else if ((input.control || input.meta) && input.shift && input.key == 'R') {
- e.preventDefault();
- view.webContents.reloadIgnoringCache();
}
});
view.webContents.session.on('will-download', (event, item, webContents) => {
+ if (id !== webContents.id) return;
+
+ const str = this.getRandString(12);
+ db.downloads.update({ id: str }, { id: str, name: item.getFilename(), url: item.getURL(), type: item.getMimeType(), size: item.getTotalBytes(), path: item.getSavePath(), status: item.getState() }, { upsert: true });
+
item.on('updated', (e, state) => {
- if (state === 'interrupted') {
- console.log('Download is interrupted but can be resumed')
- } else if (state === 'progressing') {
- if (item.isPaused()) {
- console.log('Download is paused')
- } else {
- console.log(`Received bytes: ${item.getReceivedBytes()}`)
- }
- }
+ db.downloads.update({ id: str }, { id: str, name: item.getFilename(), url: item.getURL(), type: item.getMimeType(), size: item.getTotalBytes(), path: item.getSavePath(), status: item.getState() }, { upsert: true });
});
item.once('done', (e, state) => {
+ const filePath = item.getSavePath();
+ db.downloads.update({ id: str }, { id: str, name: item.getFilename(), url: item.getURL(), type: item.getMimeType(), size: item.getTotalBytes(), path: item.getSavePath(), status: item.getState() }, { upsert: true });
if (state === 'completed') {
- console.log('Download successfully')
+ window.webContents.send(`notification-${windowId}`, { id: id, content: `${item.getFilename()} のダウンロードが完了しました。` });
+
+ if (!Notification.isSupported()) return;
+ const notify = new Notification({
+ icon: path.join(app.getAppPath(), 'static', 'app', 'icon.png'),
+ title: 'ダウンロード完了',
+ body: `${item.getFilename()} のダウンロードが完了しました。\n詳細はここをクリックしてください。`
+ });
+
+ notify.show();
+
+
+ notify.on('click', (e) => {
+ if (filePath !== undefined)
+ shell.openItem(filePath);
+ });
} else {
- console.log(`Download failed: ${state}`)
+ console.log(`Download failed: ${state}`);
}
});
});
view.webContents.loadURL(url);
- views.push({ windowId, id, view });
- console.log(views);
+ if (views[windowId] == undefined)
+ views[windowId] = [];
+ views[windowId].push({ id, view, isNotificationBar: false });
if (isActive) {
- window.webContents.send(`browserview-set-${windowId}`, { id: id });
+ window.webContents.send(`browserView-set-${windowId}`, { id: id });
window.setBrowserView(view);
}
this.fixBounds(windowId, (floatingWindows.indexOf(windowId) != -1));
this.getViews(windowId);
}
+
+ getRandString = (length) => {
+ const char = 'abcdefghijklmnopqrstuvwxyz0123456789';
+ const charLength = char.length;
+
+ let str = '';
+ for (var i = 0; i < length; i++) {
+ str += char[Math.floor(Math.random() * charLength)];
+ }
+
+ return str;
+ }
}
\ No newline at end of file