mirror of
https://github.com/keepassxreboot/keepassxc-browser.git
synced 2026-03-11 08:54:43 +00:00
Merge pull request #416 from keepassxreboot/acc_fixes
Accessibility fixes
This commit is contained in:
commit
bf70372eae
11 changed files with 476 additions and 202 deletions
|
|
@ -23,6 +23,10 @@
|
|||
"message": "Save credentials",
|
||||
"description": "Save credentials using the extension popup icon."
|
||||
},
|
||||
"contextMenuShowPasswordGenerator": {
|
||||
"message": "Show password generator",
|
||||
"description": "Show password generator text."
|
||||
},
|
||||
"rememberCredentialsPopup": {
|
||||
"message": "Create or modify the credentials by clicking on the extension icon.",
|
||||
"description": "Notification text when saving credentials from the context menu."
|
||||
|
|
@ -95,6 +99,10 @@
|
|||
"message": "No logins found.",
|
||||
"description": "No logins found."
|
||||
},
|
||||
"passwordGeneratorIcon": {
|
||||
"message": "Password generator icon",
|
||||
"description": "Alt attribute text of the password generator icon."
|
||||
},
|
||||
"passwordGeneratorPlaceholder": {
|
||||
"message": "Generated password",
|
||||
"description": "Input field placeholder for generated password."
|
||||
|
|
@ -183,6 +191,10 @@
|
|||
"message": "Please confirm your selection or choose more fields as <em>String fields</em>.",
|
||||
"description": "Confirm a selection text when choosing custom login fields which contains string fields."
|
||||
},
|
||||
"defineKeyboardText": {
|
||||
"message": "You can also use the numbers to choose the input fields from keyboard.",
|
||||
"description": "Help text when choosing custom login fields."
|
||||
},
|
||||
"username": {
|
||||
"message": "Username",
|
||||
"description": "General text for username."
|
||||
|
|
@ -707,6 +719,10 @@
|
|||
"message": "No saved custom login fields found.",
|
||||
"description": "Shown when no saved custom credentials are saved."
|
||||
},
|
||||
"optionsCustomFieldsTableCaption": {
|
||||
"message": "You can manage saved custom login fields using the table below.",
|
||||
"description": "Table caption of Custom login fields page."
|
||||
},
|
||||
"optionsCustomFieldsTabHelpTextFirst": {
|
||||
"message": "If KeePassXC-Browser detects the wrong login fields, you are able to specify the correct fields yourself.",
|
||||
"description": "Saved custom login fields info text, first part."
|
||||
|
|
@ -715,10 +731,6 @@
|
|||
"message": "Go to the page and click on the KeePassXC-Browser icon, then select ",
|
||||
"description": "Saved custom login fields info text, second part."
|
||||
},
|
||||
"optionsCustomFieldsTabHelpTextThird": {
|
||||
"message": "On this page you can manage saved custom login fields.",
|
||||
"description": "Saved custom login fields info text, third part."
|
||||
},
|
||||
"optionsCustomFieldsRemove": {
|
||||
"message": "Remove saved custom login fields?",
|
||||
"description": "Confirmation text when removing saved custom login fields."
|
||||
|
|
@ -756,7 +768,7 @@
|
|||
"description": "Site preferences info text, fourth part."
|
||||
},
|
||||
"optionsSitePreferencesManualAddText": {
|
||||
"message": "Add URL manually:",
|
||||
"message": "Add URL manually",
|
||||
"description": "Label for adding site manually on Site preferences tab."
|
||||
},
|
||||
"optionsSitePreferencesConfirmation": {
|
||||
|
|
@ -767,6 +779,14 @@
|
|||
"message": "KeePassXC-Browser will enable all features for this site and remove username-only detection.",
|
||||
"description": "Part of confirmation text when removing site preferences."
|
||||
},
|
||||
"optionsSitePreferencesTableCaption": {
|
||||
"message": "You can manage saved site preferences using the table below.",
|
||||
"description": "Table caption of Site Preferences page."
|
||||
},
|
||||
"optionsSitePreferencesSelect": {
|
||||
"message": "Option to ignore extension features for the page.",
|
||||
"description": "Title text of select element in Site Preferences."
|
||||
},
|
||||
"optionsAboutChrome": {
|
||||
"message": "Visit KeePassXC-Browser in the Chrome Web Store.",
|
||||
"description": "About page link to Chrome Web Store."
|
||||
|
|
@ -788,11 +808,43 @@
|
|||
"description": "About page text of KeePassXC version."
|
||||
},
|
||||
"optionsAboutContributors": {
|
||||
"message": "Contributors:",
|
||||
"message": "Contributors",
|
||||
"description": "About page text of contributors."
|
||||
},
|
||||
"optionsAboutLicenses": {
|
||||
"message": "Licenses:",
|
||||
"message": "Licenses",
|
||||
"description": "About page text of licenses."
|
||||
},
|
||||
"optionsAboutReportBugs": {
|
||||
"message": "Report bugs",
|
||||
"description": "About page text of reporting bugs."
|
||||
},
|
||||
"optionsAboutCreateNewIssue": {
|
||||
"message": "Create new issue on GitHub",
|
||||
"description": "Link text for creating a new issue."
|
||||
},
|
||||
"optionsAboutDebugInfo": {
|
||||
"message": "The following debug info can be used",
|
||||
"description": "Debug info text."
|
||||
},
|
||||
"optionsErrorInvalidValue": {
|
||||
"message": "Invalid value. Please check the input.",
|
||||
"description": "Error shown when input field has an incorrect value."
|
||||
},
|
||||
"optionsErrorInvalidURL": {
|
||||
"message": "Invalid URL. Please check the input.",
|
||||
"description": "Error shown when input field has an incorrect URL."
|
||||
},
|
||||
"optionsErrorValueExists": {
|
||||
"message": "The value already exists in the list.",
|
||||
"description": "Error shown when trying to add a duplicate value to the list."
|
||||
},
|
||||
"openNewTab": {
|
||||
"message": "Opens a new tab",
|
||||
"description": "Title attribute text."
|
||||
},
|
||||
"httpAuthDialog": {
|
||||
"message": "HTTP Basic Authentication dialog",
|
||||
"description": "Options page HTTP Basic Auth dialog text"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,11 +81,12 @@ browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
|
|||
browser.runtime.onMessage.addListener(kpxcEvent.onMessage);
|
||||
|
||||
const contextMenuItems = [
|
||||
{title: tr('contextMenuFillUsernameAndPassword'), action: 'fill_username_password'},
|
||||
{title: tr('contextMenuFillPassword'), action: 'fill_password'},
|
||||
{title: tr('contextMenuFillTOTP'), action: 'fill_totp'},
|
||||
{title: tr('contextMenuShowPasswordGeneratorIcons'), action: 'activate_password_generator'},
|
||||
{title: tr('contextMenuSaveCredentials'), action: 'remember_credentials'}
|
||||
{ title: tr('contextMenuFillUsernameAndPassword'), action: 'fill_username_password' },
|
||||
{ title: tr('contextMenuFillPassword'), action: 'fill_password' },
|
||||
{ title: tr('contextMenuFillTOTP'), action: 'fill_totp' },
|
||||
{ title: tr('contextMenuShowPasswordGeneratorIcons'), action: 'activate_password_generator' },
|
||||
{ title: tr('contextMenuSaveCredentials'), action: 'remember_credentials' },
|
||||
{ title: tr('contextMenuShowPasswordGenerator'), action: 'show_password_generator' }
|
||||
];
|
||||
|
||||
const menuContexts = ['editable'];
|
||||
|
|
|
|||
|
|
@ -117,15 +117,15 @@ input.genpw-text {
|
|||
}
|
||||
|
||||
.b2c-modal-backdrop:after {
|
||||
content:'';
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background-color: #000000;
|
||||
opacity: 0.8;
|
||||
filter: alpha(opacity=80);
|
||||
opacity: 0.5;
|
||||
filter: alpha(opacity=50);
|
||||
}
|
||||
|
||||
#b2c-cipDefine-fields {
|
||||
|
|
@ -142,7 +142,7 @@ input.genpw-text {
|
|||
left: 150px;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
background-color:rgba(255,255,255,0.3);
|
||||
background-color: rgba(0,0,0,0.8);
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
|
|
@ -168,12 +168,28 @@ input.genpw-text {
|
|||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
#b2c-keyboardHelp {
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
#b2c-keyboardHelp kbd {
|
||||
background-color: #eee;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #b4b4b4;
|
||||
color: #333;
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
padding: 2px 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.b2c-fixed-field {
|
||||
position: absolute;
|
||||
border: 2px solid #efefef;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
z-index: 2147483646;
|
||||
text-align: left;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
background-color:rgba(239,239,239,0.4);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,21 +37,21 @@ browser.runtime.onMessage.addListener(function(req, sender, callback) {
|
|||
cip.setValueWithChange(cip.u, cip.credentials[req.id].login);
|
||||
combination = cipFields.getCombination('username', cip.u);
|
||||
browser.runtime.sendMessage({
|
||||
action: 'page_set_login_id', args: [req.id]
|
||||
action: 'page_set_login_id', args: [ req.id ]
|
||||
});
|
||||
cip.u.focus();
|
||||
}
|
||||
if (cip.p) {
|
||||
cip.setValueWithChange(cip.p, cip.credentials[req.id].password);
|
||||
browser.runtime.sendMessage({
|
||||
action: 'page_set_login_id', args: [req.id]
|
||||
action: 'page_set_login_id', args: [ req.id ]
|
||||
});
|
||||
combination = cipFields.getCombination('password', cip.p);
|
||||
}
|
||||
|
||||
let list = [];
|
||||
if (cip.fillInStringFields(combination.fields, cip.credentials[req.id].stringFields, list)) {
|
||||
cipForm.destroy(false, {'password': list.list[0], 'username': list.list[1]});
|
||||
cipForm.destroy(false, { 'password': list.list[0], 'username': list.list[1] });
|
||||
}
|
||||
}
|
||||
} else if (req.action === 'fill_username_password') {
|
||||
|
|
@ -89,9 +89,10 @@ browser.runtime.onMessage.addListener(function(req, sender, callback) {
|
|||
});
|
||||
} else if (req.action === 'ignore-site') {
|
||||
cip.ignoreSite(req.args);
|
||||
}
|
||||
else if (req.action === 'check_database_hash' && 'hash' in req) {
|
||||
} else if (req.action === 'check_database_hash' && 'hash' in req) {
|
||||
cip.detectDatabaseChange(req.hash);
|
||||
} else if (req.action === 'show_password_generator') {
|
||||
cipPassword.showDialog();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -108,7 +109,7 @@ cipAutocomplete.init = function(field) {
|
|||
}
|
||||
|
||||
const acMenu = jQuery('#kpxc-ac-menu');
|
||||
if (acMenu.length == 0) {
|
||||
if (acMenu.length === 0) {
|
||||
jQuery('<div id=\"kpxc-ac-menu\" class=\"kpxc\"></div>').appendTo('body');
|
||||
}
|
||||
|
||||
|
|
@ -263,6 +264,7 @@ cipPassword.createDialog = function() {
|
|||
.attr('type', 'text')
|
||||
.attr('aria-describedby', 'cip-genpw-quality')
|
||||
.attr('placeholder', tr('passwordGeneratorPlaceholder'))
|
||||
.attr('tabindex', -1)
|
||||
.addClass('genpw-text ui-widget-content ui-corner-all')
|
||||
.on('change keypress paste textInput input', function() {
|
||||
jQuery('#cip-genpw-btn-clipboard:first').removeClass('btn-success');
|
||||
|
|
@ -392,6 +394,7 @@ cipPassword.createIcon = function(field) {
|
|||
.addClass('cip-genpw-icon')
|
||||
.addClass($className)
|
||||
.attr('title', tr('passwordGeneratorGenerateText'))
|
||||
.attr('alt', tr('passwordGeneratorIcon'))
|
||||
.css('z-index', '9999')
|
||||
.css('width', $size)
|
||||
.css('height', $size)
|
||||
|
|
@ -431,6 +434,10 @@ cipPassword.createIcon = function(field) {
|
|||
jQuery('body').append($icon);
|
||||
};
|
||||
|
||||
cipPassword.showDialog = function() {
|
||||
$('.cip-genpw-icon').click();
|
||||
};
|
||||
|
||||
cipPassword.setIconPosition = function($icon, $field) {
|
||||
$icon.css('top', $field.offset().top + $icon.data('offset') + 1)
|
||||
.css('left', $field.offset().left + $field.outerWidth() - $icon.data('size') - $icon.data('offset'));
|
||||
|
|
@ -579,6 +586,7 @@ cipDefine.selection = {
|
|||
fields: []
|
||||
};
|
||||
cipDefine.eventFieldClick = null;
|
||||
cipDefine.keyDown = null;
|
||||
|
||||
cipDefine.init = function() {
|
||||
const $backdrop = jQuery('<div>').attr('id', 'b2c-backdrop').addClass('b2c-modal-backdrop');
|
||||
|
|
@ -598,6 +606,14 @@ cipDefine.init = function() {
|
|||
cipDefine.resetSelection();
|
||||
cipDefine.prepareStep1();
|
||||
cipDefine.markAllUsernameFields($chooser);
|
||||
|
||||
document.addEventListener('keydown', cipDefine.keyDown);
|
||||
};
|
||||
|
||||
cipDefine.close = function() {
|
||||
$('div#b2c-backdrop').remove();
|
||||
$('div#b2c-cipDefine-fields').remove();
|
||||
document.removeEventListener('keydown', cipDefine.keyDown);
|
||||
};
|
||||
|
||||
cipDefine.initDescription = function() {
|
||||
|
|
@ -606,85 +622,44 @@ cipDefine.initDescription = function() {
|
|||
$description.append($h1);
|
||||
const $help = jQuery('<div>').addClass('b2c-chooser-help').attr('id', 'b2c-help');
|
||||
$description.append($help);
|
||||
const $keyboardHelp = jQuery('<div>').addClass('b2c-chooser-help').attr('id', 'b2c-keyboardHelp');
|
||||
$description.append($keyboardHelp);
|
||||
|
||||
// Show keyboard shortcuts help text
|
||||
jQuery('div#b2c-keyboardHelp').text(`${tr('optionsKeyboardShortcutsHeader')}:`).css('margin-bottom', '5px');
|
||||
jQuery('div#b2c-keyboardHelp').append($('<br><kbd>Escape</kbd>')).append(' ' + tr('defineDismiss'));
|
||||
jQuery('div#b2c-keyboardHelp').append($('<br><kbd>S</kbd>')).append(' ' + tr('defineSkip'));
|
||||
jQuery('div#b2c-keyboardHelp').append($('<br><kbd>A</kbd>')).append(' ' + tr('defineAgain'));
|
||||
jQuery('div#b2c-keyboardHelp').append($('<br><kbd>C</kbd>')).append(' ' + tr('defineConfirm'));
|
||||
jQuery('div#b2c-keyboardHelp').append($('<br><kbd>M</kbd>')).append(' ' + tr('defineMore'));
|
||||
jQuery('div#b2c-keyboardHelp').append($('<br><kbd>D</kbd>')).append(' ' + tr('defineDiscard'));
|
||||
|
||||
const $btnDismiss = jQuery('<button>').text(tr('defineDismiss')).attr('id', 'b2c-btn-dismiss')
|
||||
.addClass('btn')
|
||||
.addClass('btn-danger')
|
||||
.click(function(e) {
|
||||
jQuery('div#b2c-backdrop').remove();
|
||||
jQuery('div#b2c-cipDefine-fields').remove();
|
||||
});
|
||||
.click(cipDefine.close);
|
||||
const $btnSkip = jQuery('<button>').text(tr('defineSkip')).attr('id', 'b2c-btn-skip')
|
||||
.addClass('btn')
|
||||
.addClass('btn-info')
|
||||
.css('margin-right', '5px')
|
||||
.click(function() {
|
||||
if (jQuery(this).data('step') === '1') {
|
||||
cipDefine.selection.username = null;
|
||||
cipDefine.prepareStep2();
|
||||
cipDefine.markAllPasswordFields(jQuery('#b2c-cipDefine-fields'), false);
|
||||
} else if (jQuery(this).data('step') === '2') {
|
||||
cipDefine.selection.password = null;
|
||||
cipDefine.prepareStep3();
|
||||
cipDefine.markAllStringFields(jQuery('#b2c-cipDefine-fields'));
|
||||
}
|
||||
});
|
||||
.click(cipDefine.skip);
|
||||
const $btnMore = jQuery('<button>').text(tr('defineMore')).attr('id', 'b2c-btn-more')
|
||||
.addClass('btn')
|
||||
.addClass('btn-info')
|
||||
.css('margin-right', '5px')
|
||||
.css('margin-left', '5px')
|
||||
.click(function() {
|
||||
cipDefine.prepareStep2();
|
||||
cipDefine.markAllPasswordFields(jQuery('#b2c-cipDefine-fields'), true);
|
||||
});
|
||||
.click(cipDefine.more);
|
||||
const $btnAgain = jQuery('<button>').text(tr('defineAgain')).attr('id', 'b2c-btn-again')
|
||||
.addClass('btn')
|
||||
.addClass('btn-warning')
|
||||
.css('margin-right', '5px')
|
||||
.click(function(e) {
|
||||
cipDefine.resetSelection();
|
||||
cipDefine.prepareStep1();
|
||||
cipDefine.markAllUsernameFields(jQuery('#b2c-cipDefine-fields'));
|
||||
})
|
||||
.click(cipDefine.again)
|
||||
.hide();
|
||||
const $btnConfirm = jQuery('<button>').text(tr('defineConfirm')).attr('id', 'b2c-btn-confirm')
|
||||
.addClass('btn')
|
||||
.addClass('btn-primary')
|
||||
.css('margin-right', '15px')
|
||||
.click(function(e) {
|
||||
if (!cip.settings['defined-custom-fields']) {
|
||||
cip.settings['defined-custom-fields'] = {};
|
||||
}
|
||||
|
||||
if (cipDefine.selection.username) {
|
||||
cipDefine.selection.username = cipFields.prepareId(cipDefine.selection.username);
|
||||
}
|
||||
|
||||
if (cipDefine.selection.password) {
|
||||
cipDefine.selection.password = cipFields.prepareId(cipDefine.selection.password);
|
||||
}
|
||||
|
||||
const fieldIds = [];
|
||||
const fieldKeys = Object.keys(cipDefine.selection.fields);
|
||||
for (const i of fieldKeys) {
|
||||
fieldIds.push(cipFields.prepareId(i));
|
||||
}
|
||||
|
||||
const location = cip.getDocumentLocation();
|
||||
cip.settings['defined-custom-fields'][location] = {
|
||||
username: cipDefine.selection.username,
|
||||
password: cipDefine.selection.password,
|
||||
fields: fieldIds
|
||||
};
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'save_settings',
|
||||
args: [ cip.settings ]
|
||||
});
|
||||
|
||||
jQuery('button#b2c-btn-dismiss').click();
|
||||
})
|
||||
.click(cipDefine.confirm)
|
||||
.hide();
|
||||
|
||||
$description.append($btnConfirm);
|
||||
|
|
@ -695,7 +670,7 @@ cipDefine.initDescription = function() {
|
|||
|
||||
const location = cip.getDocumentLocation();
|
||||
if (cip.settings['defined-custom-fields'] && cip.settings['defined-custom-fields'][location]) {
|
||||
const $p = jQuery('<p>').html(tr('defineAlreadySelected') + '<br />');
|
||||
const $p = jQuery('<p>').addClass('alreadySelected').html(tr('defineAlreadySelected') + '<br />');
|
||||
const $btnDiscard = jQuery('<button>')
|
||||
.attr('id', 'btn-warning')
|
||||
.text(tr('defineDiscard'))
|
||||
|
|
@ -703,20 +678,7 @@ cipDefine.initDescription = function() {
|
|||
.addClass('btn')
|
||||
.addClass('btn-sm')
|
||||
.addClass('btn-danger')
|
||||
.click(function(e) {
|
||||
delete cip.settings['defined-custom-fields'][location];
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'save_settings',
|
||||
args: [ cip.settings ]
|
||||
});
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'load_settings'
|
||||
});
|
||||
|
||||
jQuery(this).parent('p').remove();
|
||||
});
|
||||
.click(cipDefine.discard);
|
||||
$p.append($btnDiscard);
|
||||
$description.append($p);
|
||||
}
|
||||
|
|
@ -741,9 +703,10 @@ cipDefine.isFieldSelected = function($cipId) {
|
|||
};
|
||||
|
||||
cipDefine.markAllUsernameFields = function($chooser) {
|
||||
cipDefine.eventFieldClick = function(e) {
|
||||
cipDefine.selection.username = jQuery(this).data('cip-id');
|
||||
jQuery(this).addClass('b2c-fixed-username-field').text(tr('username')).unbind('click');
|
||||
cipDefine.eventFieldClick = function(e, elem) {
|
||||
const field = elem ? jQuery(elem) : jQuery(this);
|
||||
cipDefine.selection.username = field.data('cip-id');
|
||||
field.addClass('b2c-fixed-username-field').text(tr('username')).unbind('click');
|
||||
cipDefine.prepareStep2();
|
||||
cipDefine.markAllPasswordFields(jQuery('#b2c-cipDefine-fields'));
|
||||
};
|
||||
|
|
@ -751,9 +714,10 @@ cipDefine.markAllUsernameFields = function($chooser) {
|
|||
};
|
||||
|
||||
cipDefine.markAllPasswordFields = function($chooser, more) {
|
||||
cipDefine.eventFieldClick = function(e) {
|
||||
cipDefine.selection.password = jQuery(this).data('cip-id');
|
||||
jQuery(this).addClass('b2c-fixed-password-field').text(tr('password')).unbind('click');
|
||||
cipDefine.eventFieldClick = function(e, elem) {
|
||||
const field = elem ? jQuery(elem) : jQuery(this);
|
||||
cipDefine.selection.password = field.data('cip-id');
|
||||
field.addClass('b2c-fixed-password-field').text(tr('password')).unbind('click');
|
||||
cipDefine.prepareStep3();
|
||||
cipDefine.markAllStringFields(jQuery('#b2c-cipDefine-fields'));
|
||||
};
|
||||
|
|
@ -765,16 +729,18 @@ cipDefine.markAllPasswordFields = function($chooser, more) {
|
|||
};
|
||||
|
||||
cipDefine.markAllStringFields = function($chooser) {
|
||||
cipDefine.eventFieldClick = function(e) {
|
||||
cipDefine.selection.fields[jQuery(this).data('cip-id')] = true;
|
||||
cipDefine.eventFieldClick = function(e, elem) {
|
||||
const field = elem ? jQuery(elem) : jQuery(this);
|
||||
cipDefine.selection.fields[field.data('cip-id')] = true;
|
||||
const count = Object.keys(cipDefine.selection.fields).length;
|
||||
jQuery(this).addClass('b2c-fixed-string-field').text(tr('defineStringField') + String(count)).unbind('click');
|
||||
field.addClass('b2c-fixed-string-field').text(tr('defineStringField') + String(count)).unbind('click');
|
||||
jQuery('button#b2c-btn-confirm:first').addClass('b2c-btn-primary').attr('disabled', false);
|
||||
};
|
||||
cipDefine.markFields($chooser, cipFields.inputQueryPattern + ', select');
|
||||
};
|
||||
|
||||
cipDefine.markFields = function($chooser, $pattern) {
|
||||
let index = 1;
|
||||
jQuery($pattern).each(function() {
|
||||
if (cipDefine.isFieldSelected(jQuery(this).data('cip-id'))) {
|
||||
return true;
|
||||
|
|
@ -787,27 +753,36 @@ cipDefine.markFields = function($chooser, $pattern) {
|
|||
.css('width', jQuery(this).outerWidth())
|
||||
.css('height', jQuery(this).outerHeight())
|
||||
.attr('data-cip-id', jQuery(this).attr('data-cip-id'))
|
||||
.text(String(index))
|
||||
.click(cipDefine.eventFieldClick)
|
||||
.hover(function() {jQuery(this).addClass('b2c-fixed-hover-field');}, function() {jQuery(this).removeClass('b2c-fixed-hover-field');});
|
||||
.hover(function() {
|
||||
jQuery(this).addClass('b2c-fixed-hover-field');
|
||||
}, function() {
|
||||
jQuery(this).removeClass('b2c-fixed-hover-field');
|
||||
});
|
||||
$chooser.append($field);
|
||||
++index;
|
||||
}
|
||||
});
|
||||
|
||||
$('b2c-fixed-field:first').focus();
|
||||
};
|
||||
|
||||
cipDefine.prepareStep1 = function() {
|
||||
jQuery('div#b2c-help').text('').css('margin-bottom', 0);
|
||||
jQuery('div#b2c-help').text(tr('defineKeyboardText')).css('margin-bottom', '5px');
|
||||
jQuery('div#b2c-cipDefine-fields').removeData('username');
|
||||
jQuery('div#b2c-cipDefine-fields').removeData('password');
|
||||
jQuery('div.b2c-fixed-field', jQuery('div#b2c-cipDefine-fields')).remove();
|
||||
jQuery('div:first', jQuery('div#b2c-cipDefine-description')).text(tr('defineChooseUsername'));
|
||||
jQuery('button#b2c-btn-skip:first').data('step', '1').show();
|
||||
jQuery('button#b2c-btn-confirm:first').removeClass('b2c-btn-primary').attr('disabled', false);
|
||||
jQuery('button#b2c-btn-confirm:first').hide();
|
||||
jQuery('button#b2c-btn-again:first').hide();
|
||||
jQuery('button#b2c-btn-more:first').hide();
|
||||
};
|
||||
|
||||
cipDefine.prepareStep2 = function() {
|
||||
jQuery('div#b2c-help').text('').css('margin-bottom', 0);
|
||||
jQuery('div#b2c-help').text(tr('defineKeyboardText')).css('margin-bottom', '5px');
|
||||
jQuery('div.b2c-fixed-field:not(.b2c-fixed-username-field)', jQuery('div#b2c-cipDefine-fields')).remove();
|
||||
jQuery('div:first', jQuery('div#b2c-cipDefine-description')).text(tr('defineChoosePassword'));
|
||||
jQuery('button#b2c-btn-skip:first').data('step', '2');
|
||||
|
|
@ -828,6 +803,115 @@ cipDefine.prepareStep3 = function() {
|
|||
jQuery('div:first', jQuery('div#b2c-cipDefine-description')).text(tr('defineConfirmSelection'));
|
||||
};
|
||||
|
||||
cipDefine.skip = function() {
|
||||
if ($('button#b2c-btn-skip:first').data('step') === '1') {
|
||||
cipDefine.selection.username = null;
|
||||
cipDefine.prepareStep2();
|
||||
cipDefine.markAllPasswordFields(jQuery('#b2c-cipDefine-fields'), false);
|
||||
} else if ($('button#b2c-btn-skip:first').data('step') === '2') {
|
||||
cipDefine.selection.password = null;
|
||||
cipDefine.prepareStep3();
|
||||
cipDefine.markAllStringFields(jQuery('#b2c-cipDefine-fields'));
|
||||
}
|
||||
};
|
||||
|
||||
cipDefine.again = function() {
|
||||
cipDefine.resetSelection();
|
||||
cipDefine.prepareStep1();
|
||||
cipDefine.markAllUsernameFields(jQuery('#b2c-cipDefine-fields'));
|
||||
};
|
||||
|
||||
cipDefine.more = function() {
|
||||
if ($('button#b2c-btn-skip:first').data('step') === '2') {
|
||||
cipDefine.prepareStep2();
|
||||
cipDefine.markAllPasswordFields(jQuery('#b2c-cipDefine-fields'), true);
|
||||
}
|
||||
};
|
||||
|
||||
cipDefine.confirm = function() {
|
||||
if ($('button#b2c-btn-skip:first').data('step') !== '3') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cip.settings['defined-custom-fields']) {
|
||||
cip.settings['defined-custom-fields'] = {};
|
||||
}
|
||||
|
||||
if (cipDefine.selection.username) {
|
||||
cipDefine.selection.username = cipFields.prepareId(cipDefine.selection.username);
|
||||
}
|
||||
|
||||
if (cipDefine.selection.password) {
|
||||
cipDefine.selection.password = cipFields.prepareId(cipDefine.selection.password);
|
||||
}
|
||||
|
||||
const fieldIds = [];
|
||||
const fieldKeys = Object.keys(cipDefine.selection.fields);
|
||||
for (const i of fieldKeys) {
|
||||
fieldIds.push(cipFields.prepareId(i));
|
||||
}
|
||||
|
||||
const location = cip.getDocumentLocation();
|
||||
cip.settings['defined-custom-fields'][location] = {
|
||||
username: cipDefine.selection.username,
|
||||
password: cipDefine.selection.password,
|
||||
fields: fieldIds
|
||||
};
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'save_settings',
|
||||
args: [ cip.settings ]
|
||||
});
|
||||
|
||||
cipDefine.close();
|
||||
};
|
||||
|
||||
cipDefine.discard = function() {
|
||||
const location = cip.getDocumentLocation();
|
||||
delete cip.settings['defined-custom-fields'][location];
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'save_settings',
|
||||
args: [ cip.settings ]
|
||||
});
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'load_settings'
|
||||
});
|
||||
|
||||
$('p.alreadySelected').remove();
|
||||
};
|
||||
|
||||
// Handle the keyboard events
|
||||
cipDefine.keyDown = function(e) {
|
||||
if (e.key === 'Escape') {
|
||||
cipDefine.close();
|
||||
} else if (e.keyCode >= 49 && e.keyCode <= 57) {
|
||||
// Select input field by number
|
||||
e.preventDefault();
|
||||
const index = e.keyCode - 48;
|
||||
const inputFields = $('div.b2c-fixed-field:not(.b2c-fixed-password-field,.b2c-fixed-username-field)');
|
||||
|
||||
if (inputFields.length >= index) {
|
||||
cipDefine.eventFieldClick(e, inputFields[index - 1]);
|
||||
}
|
||||
} else if (e.key === 's') {
|
||||
e.preventDefault();
|
||||
cipDefine.skip();
|
||||
} else if (e.key === 'a') {
|
||||
e.preventDefault();
|
||||
cipDefine.again();
|
||||
} else if (e.key === 'c') {
|
||||
e.preventDefault();
|
||||
cipDefine.confirm();
|
||||
} else if (e.key === 'm') {
|
||||
e.preventDefault();
|
||||
cipDefine.more();
|
||||
} else if (e.key === 'd') {
|
||||
e.preventDefault();
|
||||
cipDefine.discard();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var cipFields = {};
|
||||
|
|
|
|||
|
|
@ -81,6 +81,13 @@
|
|||
"default": "Alt+Shift+T",
|
||||
"mac": "MacCtrl+Shift+T"
|
||||
}
|
||||
},
|
||||
"show_password_generator": {
|
||||
"description": "__MSG_contextMenuShowPasswordGenerator__",
|
||||
"suggested_key": {
|
||||
"default": "Alt+Shift+G",
|
||||
"mac": "MacCtrl+Shift+G"
|
||||
}
|
||||
}
|
||||
},
|
||||
"web_accessible_resources": [
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@ table td {
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
input:invalid {
|
||||
border: 2px solid red;
|
||||
}
|
||||
|
||||
/* Custom container */
|
||||
.container {
|
||||
margin: 0 auto;
|
||||
|
|
@ -42,7 +46,8 @@ table td {
|
|||
}
|
||||
.navbar-default .navbar-nav > li > a:hover,
|
||||
.navbar-default .navbar-nav > li > a:focus {
|
||||
color: #cccccc;
|
||||
color: #ffffff;
|
||||
background-color: #5f9f40;
|
||||
}
|
||||
.navbar-default .navbar-nav > .active > a,
|
||||
.navbar-default .navbar-nav > .active > a:hover,
|
||||
|
|
|
|||
|
|
@ -5,23 +5,24 @@
|
|||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" href="bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="options.css" />
|
||||
<script type="text/javascript" src="../browser-polyfill.min.js"></script>
|
||||
<script type="text/javascript" src="../global.js"></script>
|
||||
<script type="text/javascript" src="../jquery-3.3.1.min.js"></script>
|
||||
<script type="text/javascript" src="bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="options.js"></script>
|
||||
<script src="../browser-polyfill.min.js"></script>
|
||||
<script src="../global.js"></script>
|
||||
<script src="../jquery-3.3.1.min.js"></script>
|
||||
<script src="bootstrap.min.js"></script>
|
||||
<script src="options.js"></script>
|
||||
<script src="../translate.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h3 class="muted"><img src="/icons/keepassxc_48x48.png" alt="logo" /> KeePassXC-Browser</h3>
|
||||
<h3 class="muted"><img src="/icons/keepassxc_48x48.png" alt="logo"> KeePassXC-Browser</h3>
|
||||
|
||||
<nav class="navbar navbar-default">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="active"><a href="#general-settings"><span data-i18n="optionsMenuGeneral"/></a></li>
|
||||
<li><a href="#connected-databases"><span data-i18n="optionsMenuConnectedDatabases"/></a></li>
|
||||
<li><a href="#custom-fields"><span data-i18n="optionsMenuCustomFields"/></a></li>
|
||||
<li><a href="#site-preferences"><span data-i18n="optionsMenuSitePreferences"></a></li>
|
||||
<li><a href="#about"><span data-i18n="optionsMenuAbout"/></a></li>
|
||||
<li class="active"><a href="#general-settings" tabindex="1"><span data-i18n="optionsMenuGeneral"></span></a></li>
|
||||
<li><a href="#connected-databases" tabindex="2"><span data-i18n="optionsMenuConnectedDatabases"></span></a></li>
|
||||
<li><a href="#custom-fields" tabindex="3"><span data-i18n="optionsMenuCustomFields"></span></a></li>
|
||||
<li><a href="#site-preferences" tabindex="4"><span data-i18n="optionsMenuSitePreferences"></span></a></li>
|
||||
<li><a href="#about" tabindex="5"><span data-i18n="optionsMenuAbout"></span></a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
|
@ -31,18 +32,19 @@
|
|||
<hr />
|
||||
<h3 data-i18n="optionsKeyboardShortcutsHeader"></h3>
|
||||
<p>
|
||||
<span data-i18n="contextMenuFillUsernameAndPassword"></span>: <span id="fill-username-password-shortcut">error</span><br />
|
||||
<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>
|
||||
<span data-i18n="contextMenuFillUsernameAndPassword"></span>: <span id="fill_username_password-shortcut">error</span><br />
|
||||
<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><br />
|
||||
<span data-i18n="contextMenuShowPasswordGenerator"></span>: <span id="show_password_generator-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="optionsConfigureShortcuts"/></button></p>
|
||||
<p id="chrome-only"><button class="btn btn-sm btn-primary" id="configureCommands" type="button" data-i18n="[title]openNewTab"><span class="glyphicon glyphicon-cog"></span><span data-i18n="optionsConfigureShortcuts"></span></button></p>
|
||||
<p>
|
||||
<div class="form-group">
|
||||
<label for="blinkTimeout" data-i18n="optionsLabelBlinkTime"></label>
|
||||
<div class="control-group">
|
||||
<div class="input-append">
|
||||
<input type="number" id="blinkTimeout" placeholder="7500" value="7500" min="-1"/>
|
||||
<button class="btn btn-sm btn-primary" id="blinkTimeoutButton" type="button"><span class="glyphicon glyphicon-floppy-disk"></span> <span data-i18n="optionsButtonSave"/></button>
|
||||
<button class="btn btn-sm btn-primary" id="blinkTimeoutButton" type="button"><span class="glyphicon glyphicon-floppy-disk"></span> <span data-i18n="optionsButtonSave"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
<span class="help-inline">
|
||||
|
|
@ -58,7 +60,7 @@
|
|||
<div class="control-group">
|
||||
<div class="input-append">
|
||||
<input type="number" id="blinkMinTimeout" placeholder="2000" value="2000" min="-1"/>
|
||||
<button class="btn btn-sm btn-primary" id="blinkMinTimeoutButton" type="button"><span class="glyphicon glyphicon-floppy-disk"></span> <span data-i18n="optionsButtonSave"/></button>
|
||||
<button class="btn btn-sm btn-primary" id="blinkMinTimeoutButton" type="button"><span class="glyphicon glyphicon-floppy-disk"></span> <span data-i18n="optionsButtonSave"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
<span class="help-inline">
|
||||
|
|
@ -76,7 +78,7 @@
|
|||
<div class="control-group">
|
||||
<div class="input-append">
|
||||
<input type="number" id="allowedRedirect" placeholder="1" value="1" min="1"/>
|
||||
<button class="btn btn-sm btn-primary" id="allowedRedirectButton" type="button"><span class="glyphicon glyphicon-floppy-disk"></span> <span data-i18n="optionsButtonSave"/></button>
|
||||
<button class="btn btn-sm btn-primary" id="allowedRedirectButton" type="button"><span class="glyphicon glyphicon-floppy-disk"></span> <span data-i18n="optionsButtonSave"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
<span class="help-inline">
|
||||
|
|
@ -114,7 +116,7 @@
|
|||
<p>
|
||||
<div class="checkbox">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="usePasswordGenerator" value="true"/><span data-i18n="optionsCheckboxUsePasswordGenerator"/>
|
||||
<input type="checkbox" name="usePasswordGenerator" value="true"/><span data-i18n="optionsCheckboxUsePasswordGenerator"></span>
|
||||
</label>
|
||||
<span class="help-block">
|
||||
<span data-i18n="optionsUsePasswordGeneratorHelpText"></span>
|
||||
|
|
@ -126,7 +128,7 @@
|
|||
<p>
|
||||
<div class="checkbox">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="autoRetrieveCredentials" value="true" /><span data-i18n="optionsCheckboxAutoRetrieveCredentials"/>
|
||||
<input type="checkbox" name="autoRetrieveCredentials" value="true" /><span data-i18n="optionsCheckboxAutoRetrieveCredentials"></span>
|
||||
</label>
|
||||
<span class="help-block" data-i18n="optionsAutoRetrieveCredentialsHelpText"></span>
|
||||
</div>
|
||||
|
|
@ -135,7 +137,7 @@
|
|||
<p>
|
||||
<div class="checkbox">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="autoFillSingleEntry" value="false" /><span data-i18n="optionsCheckboxAutoFillSingleEntry"/>
|
||||
<input type="checkbox" name="autoFillSingleEntry" value="false" /><span data-i18n="optionsCheckboxAutoFillSingleEntry"></span>
|
||||
</label>
|
||||
<span class="help-block" data-i18n="optionsAutoFillSingleEntryHelpText"></span>
|
||||
<span class="bg-danger" data-i18n="optionsAutoFillSingleEntryWarning"></span>
|
||||
|
|
@ -145,7 +147,7 @@
|
|||
<p>
|
||||
<div class="checkbox">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="autoCompleteUsernames" value="true" /><span data-i18n="optionsCheckboxAutoCompleteUsernames"/>
|
||||
<input type="checkbox" name="autoCompleteUsernames" value="true" /><span data-i18n="optionsCheckboxAutoCompleteUsernames"></span>
|
||||
</label>
|
||||
<span class="help-block" data-i18n="optionsAutocompleteUsernamesHelpText"></span>
|
||||
</div>
|
||||
|
|
@ -154,13 +156,13 @@
|
|||
<p>
|
||||
<div class="checkbox">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="showNotifications" value="true" /><span data-i18n="optionsCheckboxShowNotifications"/>
|
||||
<input type="checkbox" name="showNotifications" value="true" /><span data-i18n="optionsCheckboxShowNotifications"></span>
|
||||
</label>
|
||||
<span class="help-block" data-i18n="optionsShowNotificationsHelpText"></span>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="showLoginNotifications" value="true" /><span data-i18n="optionsCheckboxShowLoginNotifications"/>
|
||||
<input type="checkbox" name="showLoginNotifications" value="true" /><span data-i18n="optionsCheckboxShowLoginNotifications"></span>
|
||||
</label>
|
||||
</div>
|
||||
</p>
|
||||
|
|
@ -168,7 +170,7 @@
|
|||
<p>
|
||||
<div class="checkbox">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="saveDomainOnly" value="true" /><span data-i18n="optionsSaveDomainOnly"/>
|
||||
<input type="checkbox" name="saveDomainOnly" value="true" /><span data-i18n="optionsSaveDomainOnly"></span>
|
||||
</label>
|
||||
<span class="help-block" data-i18n="optionsSaveDomainOnlyHelpText"></span>
|
||||
</div>
|
||||
|
|
@ -176,10 +178,10 @@
|
|||
<hr />
|
||||
<p>
|
||||
<div data-i18n="optionsRadioText"></div>
|
||||
<label class="radio-inline"><input type="radio" name="checkUpdateKeePassXC" value="3" checked="true"/><span data-i18n="optionsRadioThreeDays"/></label>
|
||||
<label class="radio-inline"><input type="radio" name="checkUpdateKeePassXC" value="7" /><span data-i18n="optionsRadioWeek"/></label>
|
||||
<label class="radio-inline"><input type="radio" name="checkUpdateKeePassXC" value="30" /><span data-i18n="optionsRadioMonth"/></label>
|
||||
<label class="radio-inline"><input type="radio" name="checkUpdateKeePassXC" value="0" /><span data-i18n="optionsRadioNever"/></label>
|
||||
<label class="radio-inline"><input type="radio" name="checkUpdateKeePassXC" value="3" checked><span data-i18n="optionsRadioThreeDays"></span></label>
|
||||
<label class="radio-inline"><input type="radio" name="checkUpdateKeePassXC" value="7" /><span data-i18n="optionsRadioWeek"></span></label>
|
||||
<label class="radio-inline"><input type="radio" name="checkUpdateKeePassXC" value="30" /><span data-i18n="optionsRadioMonth"></span></label>
|
||||
<label class="radio-inline"><input type="radio" name="checkUpdateKeePassXC" value="0" /><span data-i18n="optionsRadioNever"></span></label>
|
||||
</p>
|
||||
<div class="help-block kphVersion">
|
||||
<span data-i18n="optionsVersionInfoText"></span>
|
||||
|
|
@ -192,14 +194,14 @@
|
|||
</div>
|
||||
<div>
|
||||
<span data-i18n="optionsLatestVersion" i18n-placeholder="<em class='latestVersion'></em>"></span>
|
||||
<button class="btn btn-sm btn-primary checkUpdateKeePassXC"><span class="glyphicon glyphicon-refresh"></span> <span data-i18n="optionsButtonUpdate"/></button>
|
||||
<button class="btn btn-sm btn-primary checkUpdateKeePassXC"><span class="glyphicon glyphicon-refresh"></span> <span data-i18n="optionsButtonUpdate"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<p>
|
||||
<div class="checkbox">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="autoFillAndSend" value="0" /><span data-i18n="optionsCheckboxAutoFillAndSend"/>
|
||||
<input type="checkbox" name="autoFillAndSend" value="0" /><span data-i18n="optionsCheckboxAutoFillAndSend"></span>
|
||||
</label>
|
||||
<span class="help-block">
|
||||
<span data-i18n="optionsAutoFillAndSendHelpText"></span>
|
||||
|
|
@ -207,7 +209,8 @@
|
|||
<span data-i18n="optionsAutoFillAndSendHelpTextSecond"></span>
|
||||
</span>
|
||||
</div>
|
||||
<img src="/options/http-auth-dialog.png" alt="http-auth-dialog" />
|
||||
<!--<img src="/options/http-auth-dialog.png" alt="http-auth-dialog" />-->
|
||||
<img src="/options/http-auth-dialog.png" data-i18n="[alt]httpAuthDialog"/>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
@ -215,15 +218,15 @@
|
|||
<div class="tab" id="tab-connected-databases">
|
||||
<h2 data-i18n="optionsConnectedDatabasesTab"></h2>
|
||||
<hr />
|
||||
<p data-i18n="optionsConnectedDatabasesText"/>
|
||||
<table class="table table-striped table-bordered table-hover">
|
||||
<caption data-i18n="optionsConnectedDatabasesText"></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><span data-i18n="optionsDatabaseIdentifier"></span></th>
|
||||
<th><span data-i18n="optionsDatabaseKey"></span></th>
|
||||
<th><span data-i18n="optionsDatabaseLastUsed"></span></th>
|
||||
<th><span data-i18n="optionsDatabaseCreated"></span></th>
|
||||
<th><span data-i18n="optionsDatabaseDelete"></span></th>
|
||||
<th scope="col"><span data-i18n="optionsDatabaseIdentifier"></span></th>
|
||||
<th scope="col"><span data-i18n="optionsDatabaseKey"></span></th>
|
||||
<th scope="col"><span data-i18n="optionsDatabaseLastUsed"></span></th>
|
||||
<th scope="col"><span data-i18n="optionsDatabaseCreated"></span></th>
|
||||
<th scope="col"><span data-i18n="optionsDatabaseDelete"></span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
@ -257,7 +260,7 @@
|
|||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true"><span class="glyphicon glyphicon-remove"></span> <span data-i18n="optionsButtonCancel"></span></button>
|
||||
<button class="btn yes btn-primary"><span class="glyphicon glyphicon-ok"></span> <span data-i18n="optionsButtonRemoveNow"></span></button>
|
||||
<button class="btn yes btn-primary" autofocus><span class="glyphicon glyphicon-ok"></span> <span data-i18n="optionsButtonRemoveNow"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -272,14 +275,13 @@
|
|||
<span data-i18n="optionsCustomFieldsTabHelpTextFirst"></span>
|
||||
<br />
|
||||
<span data-i18n="optionsCustomFieldsTabHelpTextSecond"></span><em><span data-i18n="popupChooseCredentialsText"></span></em>.
|
||||
<br />
|
||||
<span data-i18n="optionsCustomFieldsTabHelpTextThird"></span>
|
||||
</p>
|
||||
<table class="table table-striped table-bordered table-hover">
|
||||
<caption data-i18n="optionsCustomFieldsTableCaption"></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><span data-i18n="optionsColumnPageURL"></span></th>
|
||||
<th><span data-i18n="optionsColumnDelete"></span></th>
|
||||
<th scope="col"><span data-i18n="optionsColumnPageURL"></span></th>
|
||||
<th scope="col"><span data-i18n="optionsColumnDelete"></span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
@ -305,7 +307,7 @@
|
|||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true"><span class="glyphicon glyphicon-remove"></span> <span data-i18n="optionsButtonCancel"></span></button>
|
||||
<button class="btn yes btn-primary"><span class="glyphicon glyphicon-ok"></span> <span data-i18n="optionsButtonRemoveNow"></span></button>
|
||||
<button class="btn yes btn-primary" autofocus><span class="glyphicon glyphicon-ok"></span> <span data-i18n="optionsButtonRemoveNow"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -327,22 +329,23 @@
|
|||
</p>
|
||||
<hr />
|
||||
<div class="form-group">
|
||||
<label for="ignoreManualAdd" data-i18n="optionsSitePreferencesManualAddText"></label>
|
||||
<div class="control-group">
|
||||
<label for="manualUrl" data-i18n="optionsSitePreferencesManualAddText"></label>
|
||||
<div class="control-group" id="manualUrlGroup">
|
||||
<div class="input-append">
|
||||
<input type="url" id="manualUrl"/>
|
||||
<input type="url" id="manualUrl" pattern="ftp://.*|http://.*|https://.*" minlength="10">
|
||||
<button class="btn btn-sm btn-primary" id="sitePreferencesManualAdd" type="button"><span class="glyphicon glyphicon-plus-sign"></span> <span data-i18n="optionsButtonAdd"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<table class="table table-striped table-bordered table-hover">
|
||||
<caption data-i18n="optionsSitePreferencesTableCaption"></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><span data-i18n="optionsColumnPageURL"></span></th>
|
||||
<th><span data-i18n="optionsColumnIgnore"></span></th>
|
||||
<th><span data-i18n="optionsColumnUsernameOnly"></span></th>
|
||||
<th><span data-i18n="optionsColumnDelete"></span></th>
|
||||
<th scope="col"><span data-i18n="optionsColumnPageURL"></span></th>
|
||||
<th scope="col"><span data-i18n="optionsColumnIgnore"></span></th>
|
||||
<th scope="col"><span data-i18n="optionsColumnUsernameOnly"></span></th>
|
||||
<th scope="col"><span data-i18n="optionsColumnDelete"></span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
@ -352,13 +355,13 @@
|
|||
<tr class="clone">
|
||||
<td></td>
|
||||
<td>
|
||||
<select name="ignore">
|
||||
<select name="ignore" data-i18n="[title]optionsSitePreferencesSelect">
|
||||
<option value="ignoreNothing" data-i18n="optionsSelectionNothing"></option>
|
||||
<option value="ignoreNormal" data-i18n="optionsSelectionNormal"></option>
|
||||
<option value="ignoreFull" data-i18n="optionsSelectionFull"></option>
|
||||
</select>
|
||||
</td>
|
||||
<td><input type="checkbox" name="usernameOnly" value="false" /></td>
|
||||
<td><input type="checkbox" name="usernameOnly" value="false" data-i18n="[title]optionsColumnUsernameOnly"/></td>
|
||||
<td><button class="btn delete btn-danger btn"><span class="glyphicon glyphicon-remove-sign"></span> <span data-i18n="optionsButtonRemove"></span></button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
@ -376,7 +379,7 @@
|
|||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true"><span class="glyphicon glyphicon-remove"></span> <span data-i18n="optionsButtonCancel"></span></button>
|
||||
<button class="btn yes btn-primary"><span class="glyphicon glyphicon-ok"></span> <span data-i18n="optionsButtonRemoveNow"></span></button>
|
||||
<button class="btn yes btn-primary" autofocus><span class="glyphicon glyphicon-ok"></span> <span data-i18n="optionsButtonRemoveNow"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -388,13 +391,13 @@
|
|||
<h2 data-i18n="optionsAboutTab"></h2>
|
||||
<hr />
|
||||
<p>
|
||||
<a target="_blank" href="https://chrome.google.com/webstore/detail/keepassxc-browser/oboonakemofpalcgghocfoadofidjkkk"><span data-i18n="optionsAboutChrome"/></a>
|
||||
<a target="_blank" href="https://chrome.google.com/webstore/detail/keepassxc-browser/oboonakemofpalcgghocfoadofidjkkk" data-i18n="[title]openNewTab" tabindex="6"><span data-i18n="optionsAboutChrome"></span></a>
|
||||
</p>
|
||||
<p>
|
||||
<a target="_blank" href="https://addons.mozilla.org/en-US/firefox/addon/keepassxc-browser/"><span data-i18n="optionsAboutMozilla"/></a>
|
||||
<a target="_blank" href="https://addons.mozilla.org/en-US/firefox/addon/keepassxc-browser/" data-i18n="[title]openNewTab" tabindex="7"><span data-i18n="optionsAboutMozilla"></span></a>
|
||||
</p>
|
||||
<p>
|
||||
<a target="_blank" href="https://github.com/keepassxreboot/keepassxc-browser"><span data-i18n="optionsAboutGitHub"/></a>.
|
||||
<a target="_blank" href="https://github.com/keepassxreboot/keepassxc-browser" data-i18n="[title]openNewTab" tabindex="8"><span data-i18n="optionsAboutGitHub"></span></a>
|
||||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
|
|
@ -405,14 +408,16 @@
|
|||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
<span data-i18n="optionsAboutContributors"></span><br>
|
||||
<a target="_blank" href="https://github.com/pfn/">Perry Nguyen</a>, <a target="_blank" href="http://lukas-schulze.de">Lukas Schulze</a>,
|
||||
<a target="_blank" href="https://github.com/smorks">Andy Brandt</a>, <a target="_blank" href="https://github.com/varjolintu/">Sami Vänttinen</a>,
|
||||
<a target="_blank" href="https://github.com/keepassxreboot/keepassxc-browser">KeePassXC Team</a>.
|
||||
<span data-i18n="optionsAboutContributors"></span>:<br>
|
||||
<a target="_blank" href="https://github.com/pfn/" data-i18n="[title]openNewTab" tabindex="9">Perry Nguyen</a>,
|
||||
<a target="_blank" href="http://lukas-schulze.de" data-i18n="[title]openNewTab" tabindex="10">Lukas Schulze</a>,
|
||||
<a target="_blank" href="https://github.com/smorks" data-i18n="[title]openNewTab" tabindex="11">Andy Brandt</a>,
|
||||
<a target="_blank" href="https://github.com/varjolintu/" data-i18n="[title]openNewTab" tabindex="12">Sami Vänttinen</a>,
|
||||
<a target="_blank" href="https://github.com/keepassxreboot/keepassxc-browser" data-i18n="[title]openNewTab" tabindex="13">KeePassXC Team</a>.
|
||||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
<span data-i18n="optionsAboutLicenses"></span><br>
|
||||
<span data-i18n="optionsAboutLicenses"></span>:<br>
|
||||
|
||||
<details>
|
||||
<summary>Bootstrap</summary>
|
||||
|
|
@ -569,13 +574,22 @@
|
|||
</pre>
|
||||
</details>
|
||||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
<span data-i18n="optionsAboutReportBugs"></span>:<br>
|
||||
<a target="_blank" href="https://github.com/keepassxreboot/keepassxc-browser/issues/new" tabindex="14"><span data-i18n="optionsAboutCreateNewIssue"></span></a>
|
||||
<p><span data-i18n="optionsAboutDebugInfo"></span>:
|
||||
<p>KeePassXC - <span class="kpxcVersion"></span>
|
||||
<br>KeePassXC-Browser - <span class="kpxcbrVersion"></span>
|
||||
<br>Operating system: <span class="kpxcbrOS"></span>
|
||||
<br>Browser: <span class="kpxcbrBrowser"></span>
|
||||
</p>
|
||||
</p>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="footer">
|
||||
<p>(C) 2017-2018 - KeePassXC Team</p>
|
||||
<p>(C) 2017-2019 - KeePassXC Team</p>
|
||||
</div>
|
||||
</div> <!-- /container -->
|
||||
|
||||
<script type="text/javascript" src="../translate.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ $(function() {
|
|||
options.initAbout();
|
||||
});
|
||||
});
|
||||
|
||||
// Set options page language to HTML element from locale
|
||||
$('html').attr('lang', browser.i18n.getUILanguage());
|
||||
});
|
||||
|
||||
var options = options || {};
|
||||
|
|
@ -140,7 +143,9 @@ options.initGeneralSettings = function() {
|
|||
browser.commands.getAll().then(function(commands) {
|
||||
commands.forEach(function(command) {
|
||||
var shortcut = document.getElementById(`${command.name}-shortcut`);
|
||||
if (!shortcut) return;
|
||||
if (!shortcut) {
|
||||
return;
|
||||
}
|
||||
shortcut.textContent = command.shortcut || 'not configured';
|
||||
});
|
||||
});
|
||||
|
|
@ -152,7 +157,12 @@ options.initGeneralSettings = function() {
|
|||
});
|
||||
|
||||
$('#blinkTimeoutButton').click(function() {
|
||||
const blinkTimeout = $.trim($('#blinkTimeout').val());
|
||||
const input = document.querySelector('#blinkTimeout');
|
||||
if (!input.validity.valid) {
|
||||
options.createWarning(input, tr('optionsErrorInvalidValue'));
|
||||
}
|
||||
|
||||
const blinkTimeout = input.value;
|
||||
const blinkTimeoutval = blinkTimeout !== '' ? Number(blinkTimeout) : defaultSettings.blinkTimeout;
|
||||
|
||||
options.settings['blinkTimeout'] = blinkTimeoutval;
|
||||
|
|
@ -200,6 +210,7 @@ options.showKeePassXCVersions = function(response) {
|
|||
$('#tab-general-settings .kphVersion:first em.yourVersion:first').text(response.current);
|
||||
$('#tab-general-settings .kphVersion:first em.latestVersion:first').text(response.latest);
|
||||
$('#tab-about em.versionKPH').text(response.current);
|
||||
$('#tab-about span.kpxcVersion').text(response.current);
|
||||
$('#tab-general-settings button.checkUpdateKeePassXC:first').attr('disabled', false);
|
||||
};
|
||||
|
||||
|
|
@ -214,6 +225,9 @@ options.initConnectedDatabases = function() {
|
|||
$('#dialogDeleteConnectedDatabase').data('hash', $(this).closest('tr').data('hash'));
|
||||
$('#dialogDeleteConnectedDatabase .modal-body:first span:first').text($(this).closest('tr').children('td:first').text());
|
||||
$('#dialogDeleteConnectedDatabase').modal('show');
|
||||
$('#dialogDeleteConnectedDatabase').on('shown.bs.modal', () => {
|
||||
$('#dialogDeleteConnectedDatabase').find('[autofocus]').focus();
|
||||
});
|
||||
});
|
||||
|
||||
$('#dialogDeleteConnectedDatabase .modal-footer:first button.yes:first').click(function(e) {
|
||||
|
|
@ -273,6 +287,9 @@ options.initCustomCredentialFields = function() {
|
|||
$('#dialogDeleteCustomCredentialFields').data('tr-id', $(this).closest('tr').attr('id'));
|
||||
$('#dialogDeleteCustomCredentialFields .modal-body:first strong:first').text($(this).closest('tr').children('td:first').text());
|
||||
$('#dialogDeleteCustomCredentialFields').modal('show');
|
||||
$('#dialogDeleteCustomCredentialFields').on('shown.bs.modal', () => {
|
||||
$('#dialogDeleteCustomCredentialFields').find('[autofocus]').focus();
|
||||
});
|
||||
});
|
||||
|
||||
$('#dialogDeleteCustomCredentialFields .modal-footer:first button.yes:first').click(function(e) {
|
||||
|
|
@ -320,6 +337,9 @@ options.initSitePreferences = function() {
|
|||
$('#dialogDeleteSite').data('tr-id', $(this).closest('tr').attr('id'));
|
||||
$('#dialogDeleteSite .modal-body:first strong:first').text($(this).closest('tr').children('td:first').text());
|
||||
$('#dialogDeleteSite').modal('show');
|
||||
$('#dialogDeleteSite').on('shown.bs.modal', () => {
|
||||
$('#dialogDeleteSite').find('[autofocus]').focus();
|
||||
});
|
||||
});
|
||||
|
||||
$('#tab-site-preferences tr.clone:first input[type=checkbox]:first').change(function() {
|
||||
|
|
@ -343,15 +363,37 @@ options.initSitePreferences = function() {
|
|||
});
|
||||
|
||||
$('#manualUrl').keyup(function(event) {
|
||||
if (event.keyCode === 13) {
|
||||
if (event.key === 'Enter') {
|
||||
$('#sitePreferencesManualAdd').click();
|
||||
}
|
||||
});
|
||||
|
||||
$('#sitePreferencesManualAdd').click(function(e) {
|
||||
e.preventDefault();
|
||||
let value = $('#manualUrl').val();
|
||||
const manualUrl = document.querySelector('#manualUrl');
|
||||
if (!manualUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Show error for invalid input
|
||||
if (!manualUrl.validity.valid) {
|
||||
options.createWarning(manualUrl, tr('optionsErrorInvalidURL'));
|
||||
return;
|
||||
}
|
||||
|
||||
const errorMessage = tr('optionsErrorValueExists');
|
||||
let value = manualUrl.value;
|
||||
if (value.length > 10 && value.length <= 2000) {
|
||||
// Fills the last / char if needed. This ensures the compatibility with Match Patterns
|
||||
if (slashNeededForUrl(value)) {
|
||||
value += '/';
|
||||
}
|
||||
|
||||
// Check if the URL is already in the list
|
||||
if (options.settings['sitePreferences'].some(s => s.url === value)) {
|
||||
options.createWarning(manualUrl, errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.settings['sitePreferences'] === undefined) {
|
||||
options.settings['sitePreferences'] = [];
|
||||
}
|
||||
|
|
@ -360,11 +402,6 @@ options.initSitePreferences = function() {
|
|||
const trClone = $('#tab-site-preferences table tr.clone:first').clone(true);
|
||||
trClone.removeClass('clone');
|
||||
|
||||
// Fills the last / char if needed. This ensures the compatibility with Match Patterns
|
||||
if (slashNeededForUrl(value)) {
|
||||
value += '/';
|
||||
}
|
||||
|
||||
const tr = trClone.clone(true);
|
||||
tr.data('url', value);
|
||||
tr.attr('id', 'tr-scf' + newValue);
|
||||
|
|
@ -375,8 +412,7 @@ options.initSitePreferences = function() {
|
|||
|
||||
options.settings['sitePreferences'].push({ url: value, ignore: IGNORE_NOTHING, usernameOnly: false });
|
||||
options.saveSettings();
|
||||
|
||||
$('#manualUrl').val('');
|
||||
manualUrl.value = '';
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -426,10 +462,44 @@ options.initSitePreferences = function() {
|
|||
};
|
||||
|
||||
options.initAbout = function() {
|
||||
$('#tab-about em.versionCIP').text(browser.runtime.getManifest().version);
|
||||
const version = browser.runtime.getManifest().version;
|
||||
$('#tab-about em.versionCIP').text(version);
|
||||
$('#tab-about span.kpxcbrVersion').text(version);
|
||||
$('#tab-about span.kpxcbrOS').text(navigator.platform);
|
||||
$('#tab-about span.kpxcbrBrowser').text(getBrowserId());
|
||||
|
||||
// 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();
|
||||
}
|
||||
};
|
||||
|
||||
options.createWarning = function(elem, text) {
|
||||
const banner = document.createElement('div');
|
||||
banner.classList.add('alert', 'alert-dismissible', 'alert-danger', 'fade', 'in');
|
||||
banner.style.position = 'absolute';
|
||||
banner.style.left = String(elem.offsetLeft) + 'px';
|
||||
banner.style.top = String(elem.offsetTop + elem.offsetHeight) + 'px';
|
||||
banner.style.padding = '0px';
|
||||
banner.style.width = '300px';
|
||||
banner.textContent = text;
|
||||
elem.parentElement.append(banner);
|
||||
|
||||
// Destroy the warning after five seconds
|
||||
setTimeout(() => {
|
||||
elem.parentElement.removeChild(banner);
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
const getBrowserId = function() {
|
||||
if (navigator.userAgent.indexOf('Firefox') > -1) {
|
||||
return 'Mozilla Firefox ' + navigator.userAgent.substr(navigator.userAgent.lastIndexOf('/') + 1);
|
||||
} else if (navigator.userAgent.indexOf('Chrome') > -1) {
|
||||
let startPos = navigator.userAgent.indexOf('Chrome');
|
||||
startPos = navigator.userAgent.indexOf('/', startPos) + 1;
|
||||
const version = navigator.userAgent.substring(startPos, navigator.userAgent.indexOf('Safari'));
|
||||
return 'Chrome/Chromium ' + version;
|
||||
}
|
||||
|
||||
return 'Other/Unknown';
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,23 +24,29 @@
|
|||
<hr />
|
||||
<div class="conf-content">
|
||||
<div id="conf-row">
|
||||
<div><span data-i18n="contextMenuFillUsernameAndPassword"></span></div>
|
||||
<input type="text" id="fill-username-password"/>
|
||||
<div><label for="fill_username_password" data-i18n="contextMenuFillUsernameAndPassword"></label></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"/>
|
||||
<div><label for="fill_password" data-i18n="contextMenuFillPassword"></label></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"/>
|
||||
<div><label for="fill_totp" data-i18n="contextMenuFillTOTP"></label></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 id="conf-row">
|
||||
<div><label for="show_password_generator" data-i18n="contextMenuShowPasswordGenerator"></label></div>
|
||||
<input type="text" id="show_password_generator"/>
|
||||
<button class="btn btn-sm btn-primary" id="buttonSaveGenerator" 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>
|
||||
|
|
|
|||
|
|
@ -11,14 +11,14 @@ document.querySelectorAll('input').forEach((b) => {
|
|||
const saveButtons = document.querySelectorAll('.btn-primary');
|
||||
for (const b of saveButtons) {
|
||||
b.addEventListener('click', (e) => {
|
||||
updateShortcut(b.parentElement.children[1].getAttribute('id'))
|
||||
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'))
|
||||
resetShortcut(b.parentElement.children[1].getAttribute('id'));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ async function handleKeyDown(e) {
|
|||
tempArray.push(key);
|
||||
keyArray.push(key);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function handleKeyUp(e) {
|
||||
if (!e.repeat) {
|
||||
|
|
@ -55,7 +55,7 @@ async function handleKeyUp(e) {
|
|||
e.currentTarget.value = text;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function updateKeys() {
|
||||
const commands = await browser.commands.getAll();
|
||||
|
|
@ -65,7 +65,7 @@ async function updateKeys() {
|
|||
elem.value = c.shortcut;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function updateShortcut(shortcut) {
|
||||
try {
|
||||
|
|
@ -78,13 +78,13 @@ async function updateShortcut(shortcut) {
|
|||
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() {
|
||||
|
|
@ -112,6 +112,6 @@ function createBanner(type, shortcut) {
|
|||
setTimeout(() => {
|
||||
document.body.removeChild(banner);
|
||||
}, 5000);
|
||||
};
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', updateKeys);
|
||||
|
|
|
|||
|
|
@ -2,14 +2,33 @@
|
|||
|
||||
const items = document.querySelectorAll('[data-i18n]');
|
||||
for (const item of items) {
|
||||
const key = item.getAttribute('data-i18n');
|
||||
let key = item.getAttribute('data-i18n');
|
||||
if (key) {
|
||||
let attr = '';
|
||||
[ attr, key] = trAttribute(key);
|
||||
|
||||
const placeholder = item.getAttribute('i18n-placeholder');
|
||||
const translation = placeholder ? browser.i18n.getMessage(key, placeholder) : browser.i18n.getMessage(key);
|
||||
if (item.hasAttribute('href')) {
|
||||
if (attr) {
|
||||
item.setAttribute(attr, translation);
|
||||
} else if (item.hasAttribute('href')) {
|
||||
item.text = translation;
|
||||
} else {
|
||||
item.innerHTML = translation;
|
||||
}
|
||||
|
||||
// Remove the translation attribute from the HTML element
|
||||
item.removeAttribute('data-i18n');
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a custom attribute is being translated using [attribute]key
|
||||
function trAttribute(key) {
|
||||
let attr = /\[(\w+)\]/.exec(key);
|
||||
if (attr) {
|
||||
attr = attr[1];
|
||||
key = key.slice(key.indexOf(']') + 1);
|
||||
}
|
||||
|
||||
return [ attr, key ];
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue