Skip to content

Commit

Permalink
✨ Add keyboard shortcuts to navigate tabs
Browse files Browse the repository at this point in the history
Also adds support for multiple windows (Cmd+N to open, Cmd+Shift+W to close)

Closes #19
  • Loading branch information
saul committed Feb 24, 2016
1 parent 0c0fe90 commit b72f25d
Show file tree
Hide file tree
Showing 4 changed files with 296 additions and 11 deletions.
33 changes: 23 additions & 10 deletions background.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,46 @@
'use strict';

const assert = require('assert');
const electron = require('electron');
const template = require('./js/menu');

const app = electron.app;
const Menu = electron.Menu;
const BrowserWindow = electron.BrowserWindow;

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
var mainWindow = null;
var windows = {};

app.on('window-all-closed', function () {
app.on('window-all-closed', () => {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform != 'darwin') {
app.quit();
}
});

app.on('ready', function () {
var electronScreen = electron.screen;
var size = electronScreen.getPrimaryDisplay().workAreaSize;
app.on('ready', () => {
var menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);

app.emit('new-window');
});

app.on('new-window', () => {
let size = electron.screen.getPrimaryDisplay().workAreaSize;

let window = new BrowserWindow({width: size.width, height: size.height, icon: 'logo.png'});
window.loadURL('file://' + __dirname + '/index.html');
window.webContents.openDevTools();

mainWindow = new BrowserWindow({width: size.width, height: size.height, icon: 'logo.png'});
mainWindow.loadURL('file://' + __dirname + '/index.html');
mainWindow.webContents.openDevTools();
const id = window.id;
windows[id] = window;

mainWindow.on('closed', function () {
window.on('closed', () => {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null;
delete windows[id];
});
});
49 changes: 49 additions & 0 deletions components/App.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<template>
<title v-if="selectedTab">Gamevis - {{ selectedTab.title }}</title>

<div class="container-fluid">
<gv-alerts v-ref:alerts></gv-alerts>

Expand Down Expand Up @@ -29,13 +31,20 @@
</template>

<script type="text/babel">
const ipc = window.require('electron').ipcRenderer;
export default {
el: 'body',
replace: false,
data: {
atomicTabs: 0,
tabs: [],
},
computed: {
selectedTab() {
return this.tabs.find(q => q.selected);
}
},
methods: {
addTab() {
let i = this.tabs.push({
Expand Down Expand Up @@ -72,10 +81,47 @@
}
},
switchTab(index) {
if (index < 0 || index >= this.tabs.length) {
console.warn('cannot switch to non-existent tab');
return;
}
this.tabs.forEach((q, i) => {
q.selected = i == index;
});
},
command(_, cmd) {
let selectedIndex = this.tabs.findIndex(q => q.selected);
switch (cmd) {
case 'new-tab':
this.addTab();
break;
case 'close-tab':
if (this.tabs.length === 1) {
window.close();
} else {
this.closeTab(selectedIndex);
}
break;
case 'next-tab':
this.switchTab(selectedIndex + 1);
break;
case 'previous-tab':
this.switchTab(selectedIndex - 1);
break;
}
},
keyDown(e) {
let cmdOrCtrl = e.metaKey || e.ctrlKey;
let numKey = e.which - 48;
if (cmdOrCtrl && numKey > 0 && numKey < 9) {
this.switchTab(numKey - 1);
} else if (cmdOrCtrl && numKey == 9) {
this.switchTab(this.tabs.length - 1);
}
}
},
events: {
error(err) {
Expand All @@ -84,6 +130,9 @@
},
ready() {
this.addTab();
document.onkeydown = this.keyDown.bind(this);
ipc.on('command', this.command.bind(this));
}
}
</script>
1 change: 0 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<html>
<head>
<meta charset="UTF-8">
<title>Gamevis</title>
<link rel="stylesheet" href="dist/css/style.css">
</head>

Expand Down
224 changes: 224 additions & 0 deletions js/menu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
'use strict';

const app = require('electron').app;

function sendCommand(window, command) {
if (window) {
window.webContents.send('command', command);
}
}

let template = [
{
label: 'File',
submenu: [
{
label: 'New Tab',
accelerator: 'CmdOrCtrl+T',
click(item, focusedWindow) {
sendCommand(focusedWindow, 'new-tab');
}
},
{
label: 'New Window',
accelerator: 'CmdOrCtrl+N',
click() {
app.emit('new-window');
}
},
{
type: 'separator'
},
{
label: 'Close Tab',
accelerator: 'CmdOrCtrl+W',
click(item, focusedWindow) {
sendCommand(focusedWindow, 'close-tab');
}
},
{
label: 'Close Window',
accelerator: 'CmdOrCtrl+Shift+W',
role: 'close'
}
]
},
{
label: 'Edit',
submenu: [
{
label: 'Undo',
accelerator: 'CmdOrCtrl+Z',
role: 'undo'
},
{
label: 'Redo',
accelerator: 'Shift+CmdOrCtrl+Z',
role: 'redo'
},
{
type: 'separator'
},
{
label: 'Cut',
accelerator: 'CmdOrCtrl+X',
role: 'cut'
},
{
label: 'Copy',
accelerator: 'CmdOrCtrl+C',
role: 'copy'
},
{
label: 'Paste',
accelerator: 'CmdOrCtrl+V',
role: 'paste'
},
{
label: 'Select All',
accelerator: 'CmdOrCtrl+A',
role: 'selectall'
}
]
},
{
label: 'View',
submenu: [
{
label: 'Reload',
accelerator: 'CmdOrCtrl+R',
click(item, focusedWindow) {
if (focusedWindow)
focusedWindow.reload();
}
},
{
label: 'Toggle Full Screen',
accelerator: (function () {
if (process.platform == 'darwin')
return 'Ctrl+Command+F';
else
return 'F11';
})(),
click(item, focusedWindow) {
if (focusedWindow)
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
}
},
{
label: 'Toggle Developer Tools',
accelerator: (function () {
if (process.platform == 'darwin')
return 'Alt+Command+I';
else
return 'Ctrl+Shift+I';
})(),
click(item, focusedWindow) {
if (focusedWindow)
focusedWindow.toggleDevTools();
}
}
]
},
{
label: 'Window',
role: 'window',
submenu: [
{
label: 'Minimize',
accelerator: 'CmdOrCtrl+M',
role: 'minimize'
},
{
type: 'separator'
},
{
label: 'Select Next Tab',
accelerator: 'CmdOrCtrl+Shift+]',
click(item, focusedWindow) {
sendCommand(focusedWindow, 'next-tab');
}
},
{
label: 'Select Previous Tab',
accelerator: 'CmdOrCtrl+Shift+[',
click(item, focusedWindow) {
sendCommand(focusedWindow, 'previous-tab');
}
}
]
},
{
label: 'Help',
role: 'help',
submenu: [
{
label: 'Learn More',
click() {
require('electron').shell.openExternal('http://github.com/saul/gamevis')
}
}
]
},
];

if (process.platform == 'darwin') {
let name = app.getName();

template.unshift({
label: name,
submenu: [
{
label: 'About ' + name,
role: 'about'
},
{
type: 'separator'
},
{
label: 'Services',
role: 'services',
submenu: []
},
{
type: 'separator'
},
{
label: 'Hide ' + name,
accelerator: 'Command+H',
role: 'hide'
},
{
label: 'Hide Others',
accelerator: 'Command+Alt+H',
role: 'hideothers'
},
{
label: 'Show All',
role: 'unhide'
},
{
type: 'separator'
},
{
label: 'Quit',
accelerator: 'Command+Q',
click() {
app.quit();
}
},
]
});

template[4].submenu.push(
{
type: 'separator'
},
{
label: 'Bring All to Front',
role: 'front'
}
);
}

module.exports = template;

0 comments on commit b72f25d

Please sign in to comment.