mirror of
https://github.com/keepassxreboot/keepassxc-browser.git
synced 2026-03-11 08:54:43 +00:00
Keyboard shortcut configuration page for Firefox
This commit is contained in:
parent
2deb597137
commit
c73b85e751
6 changed files with 244 additions and 7 deletions
|
|
@ -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."
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
53
keepassxc-browser/options/shortcuts.css
Normal file
53
keepassxc-browser/options/shortcuts.css
Normal 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;
|
||||
}
|
||||
47
keepassxc-browser/options/shortcuts.html
Normal file
47
keepassxc-browser/options/shortcuts.html
Normal 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>
|
||||
117
keepassxc-browser/options/shortcuts.js
Normal file
117
keepassxc-browser/options/shortcuts.js
Normal 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);
|
||||
Loading…
Reference in a new issue