Keyboard shortcut configuration page for Firefox

This commit is contained in:
varjolintu 2018-10-29 14:09:34 +02:00 committed by Janek Bevendorff
parent 2deb597137
commit c73b85e751
6 changed files with 244 additions and 7 deletions

View file

@ -395,9 +395,9 @@
"message": "About",
"description": "About page header."
},
"optionsButtonConfigureShortcuts": {
"message": "Configure shortcuts",
"description": "Keyboard shortcut button text."
"optionsConfigureShortcuts": {
"message": " Configure shortcuts",
"description": "Keyboard shortcut button and title text."
},
"optionsButtonSave": {
"message": "Save",
@ -426,6 +426,10 @@
"optionsButtonCancel": {
"message": "Cancel",
"description": "Cancel button text when removing database key or custom login fields."
},
"optionsButtonReset": {
"message": "Reset",
"description": "Reset button text for keyboard shortcuts."
},
"optionsLabelBlinkTime": {
"message": "Blink Time:",
@ -579,6 +583,18 @@
"message": "Recommended: $1",
"description": "Recommended setting text."
},
"optionsShortcutsSuccess": {
"message": "Shortcut for $1 has been successfully changed.",
"description": "Message for successful keyboard shortcut change."
},
"optionsShortcutsInfo": {
"message": "Shortcut for $1 has been reset.",
"description": "Info message for changing keyboard shortcuts."
},
"optionsShortcutsDanger": {
"message": "Error: Shortcut for $1 has not been changed!",
"description": "Error message for changing keyboard shortcuts."
},
"optionsConnectedDatabasesText": {
"message": "The following KeePassXC databases are connected to KeePassXC-Browser.",
"description": "Info text about connected databases."

View file

@ -35,7 +35,7 @@
<span data-i18n="contextMenuFillPassword"></span>: <span id="fill-password-shortcut">error</span><br />
<span data-i18n="contextMenuFillTOTP"></span>: <span id="fill-totp-shortcut">error</span>
</p>
<p id="chrome-only"><button class="btn btn-sm btn-primary" id="configureCommands" type="button"><span class="glyphicon glyphicon-cog"></span> <span data-i18n="optionsButtonConfigureShortcuts"/></button></p>
<p id="chrome-only"><button class="btn btn-sm btn-primary" id="configureCommands" type="button"><span class="glyphicon glyphicon-cog"></span><span data-i18n="optionsConfigureShortcuts"/></button></p>
<p>
<div class="form-group">
<label for="blinkTimeout" data-i18n="optionsLabelBlinkTime"></label>

View file

@ -126,8 +126,10 @@ options.initGeneralSettings = function() {
});
});
$('#configureCommands').click(function(){
browser.tabs.create({ url: 'chrome://extensions/configureCommands' });
$('#configureCommands').click(function() {
browser.tabs.create({
url: isFirefox() ? browser.runtime.getURL("options/shortcuts.html") : 'chrome://extensions/configureCommands'
});
});
$('#blinkTimeoutButton').click(function(){
@ -392,7 +394,9 @@ options.initSitePreferences = function() {
options.initAbout = function() {
$('#tab-about em.versionCIP').text(browser.runtime.getManifest().version);
if (isFirefox()) {
// Hides keyboard shortcut configure button if Firefox version is < 60 (API is not compatible)
if (isFirefox() && Number(navigator.userAgent.substr(navigator.userAgent.lastIndexOf('/')+1, 2)) < 60) {
$('#chrome-only').remove();
}
};

View file

@ -0,0 +1,53 @@
body {
padding-top: 20px;
}
.conf-container {
margin: 0 auto;
width: 680px;
max-height: 315px;
background-color: white;
border: 1px solid #ccc;
border-radius: 4px;
box-shadow: 0 4px 6px 0 hsla(0, 0%, 0%, 0.2);
}
.conf-container .conf-title {
margin: 10px 0 0 20px;
display: flex;
flex-direction: row;
align-items: center;
}
.conf-title #icon {
width: 3em;
}
.conf-container > hr {
margin: 10px 0;
}
.conf-content {
margin: 10px 0 20px 40px;
}
#conf-row {
display: flex;
align-items: center;
justify-content: flex-start;
}
#conf-row div:first-child {
width: 200px;
margin: 10px;
}
#conf-row button {
margin-left: 10px;
}
.alert {
box-shadow: 0 4px 6px 0 hsla(0, 0%, 0%, 0.2);
margin: 20px auto;
width: 680px;
}

View file

@ -0,0 +1,47 @@
<html>
<head>
<title data-i18n="popupTitle"></title>
<meta charset="UTF-8">
<link rel="stylesheet" href="shortcuts.css" />
<link rel="stylesheet" href="../options/bootstrap.min.css" />
<script src="../browser-polyfill.min.js"></script>
<script src="../jquery-3.3.1.min.js"></script>
<script src="../options/bootstrap.min.js" /></script>
<script defer src="shortcuts.js"></script>
<script defer src="../global.js"></script>
<script defer src="../translate.js"></script>
</head>
<body>
<div class="conf-container">
<div class="conf-title">
<div id="icon">
<img src="/icons/keepassxc_19x19.png" alt="logo" />
</div>
<div id="title">
<h5 class="muted"><span data-i18n="optionsConfigureShortcuts"/></h3>
</div>
</div>
<hr />
<div class="conf-content">
<div id="conf-row">
<div><span data-i18n="contextMenuFillUsernameAndPassword"></span></div>
<input type="text" id="fill-username-password"/>
<button class="btn btn-sm btn-primary" id="buttonSaveUserandPass" type="button"><span class="glyphicon glyphicon-floppy-disk"></span> <span data-i18n="optionsButtonSave"/></button>
<button class="btn btn-sm btn-danger"><span class="glyphicon glyphicon-remove-sign"></span> <span data-i18n="optionsButtonReset"></span></button>
</div>
<div id="conf-row">
<div><span data-i18n="contextMenuFillPassword"></span></div>
<input type="text" id="fill-password"/>
<button class="btn btn-sm btn-primary" id="buttonSavePass" type="button"><span class="glyphicon glyphicon-floppy-disk"></span> <span data-i18n="optionsButtonSave"/></button>
<button class="btn btn-sm btn-danger"><span class="glyphicon glyphicon-remove-sign"></span> <span data-i18n="optionsButtonReset"></span></button>
</div>
<div id="conf-row">
<div><span data-i18n="contextMenuFillTOTP"></span></div>
<input type="text" id="fill-totp"/>
<button class="btn btn-sm btn-primary" id="buttonSaveTotp" type="button"><span class="glyphicon glyphicon-floppy-disk"></span> <span data-i18n="optionsButtonSave"/></button>
<button class="btn btn-sm btn-danger"><span class="glyphicon glyphicon-remove-sign"></span> <span data-i18n="optionsButtonReset"></span></button>
</div>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,117 @@
'use strict';
let tempArray = [];
let keyArray = [];
document.querySelectorAll('input').forEach((b) => {
b.addEventListener('keydown', e => handleKeyDown(e));
b.addEventListener('keyup', e => handleKeyUp(e));
});
const saveButtons = document.querySelectorAll('.btn-primary');
for (const b of saveButtons) {
b.addEventListener('click', e => {
updateShortcut(b.parentElement.children[1].getAttribute('id'))
});
}
const resetButtons = document.querySelectorAll('.btn-danger');
for (const b of resetButtons) {
b.addEventListener('click', e => {
resetShortcut(b.parentElement.children[1].getAttribute('id'))
});
}
async function handleKeyDown(e) {
if (!e.repeat) {
e.currentTarget.value = '';
// Transform single keys to upper case for comparison
const key = e.key.length === 1 ? e.key.toUpperCase() : e.key;
tempArray.push(key);
keyArray.push(key);
}
};
async function handleKeyUp(e) {
if (!e.repeat) {
e.currentTarget.value = '';
const index = tempArray.indexOf(e.key.length === 1 ? e.key.toUpperCase() : e.key);
if (index !== -1) {
tempArray.splice(index, 1);
}
if (tempArray.length === 0) {
let text = '';
for (let i = 0; i < keyArray.length; ++i) {
const currentText = keyArray[i] === 'Control' ? handleControl() : keyArray[i];
text += currentText;
if (i !== keyArray.length - 1) {
text += '+';
}
}
keyArray = [];
e.currentTarget.value = text;
}
}
};
async function updateKeys() {
const commands = await browser.commands.getAll();
for (const c of commands) {
const elem = document.getElementById(c.name);
if (elem) {
elem.value = c.shortcut;
}
}
};
async function updateShortcut(shortcut) {
try {
await browser.commands.update({
name: shortcut,
shortcut: document.querySelector('#' + shortcut).value
});
createBanner('success', shortcut);
} catch(e) {
console.log('Cannot change shortcut: ' + e);
createBanner('danger', shortcut);
}
};
async function resetShortcut(shortcut) {
await browser.commands.reset(shortcut);
createBanner('info', shortcut);
updateKeys();
};
// Ctrl behaves differently on different OS's. macOS needs to return MacCtrl instead of Ctrl (which will be handled as Command)
function handleControl() {
return (navigator.platform === 'MacIntel') ? 'MacCtrl' : 'Ctrl';
}
// Possible types: success, info, danger
function createBanner(type, shortcut) {
const banner = document.createElement('div');
banner.classList.add('alert', 'alert-dismissible', 'alert-' + type, 'fade', 'in');
if (type === 'success') {
banner.textContent = tr('optionsShortcutsSuccess', shortcut);
} else if (type === 'info') {
banner.textContent = tr('optionsShortcutsInfo', shortcut);
} else if (type === 'danger') {
banner.textContent = tr('optionsShortcutsDanger', shortcut);
} else {
return;
}
document.body.appendChild(banner);
// Destroy the banner after five seconds
setTimeout(() => {
document.body.removeChild(banner);
}, 5000);
};
document.addEventListener('DOMContentLoaded', updateKeys);