This commit is contained in:
AKORA 2024-12-05 10:06:24 -05:00 committed by GitHub
commit 1f9db49c2c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 212 additions and 67 deletions

View file

@ -316,7 +316,7 @@ kpxcFill.fillInStringFields = function(fields, stringFields) {
// Performs Auto-Submit. If filling single credentials is enabled, a 5 second timeout will be needed for fill
kpxcFill.performAutoSubmit = async function(combination, skipAutoSubmit) {
if (!kpxc.settings.autoSubmit) {
if (!kpxc.settings.autoSubmit && !kpxc.preferencesForPage?.autoSubmit) {
return;
}

View file

@ -26,6 +26,7 @@ kpxc.detectedFields = 0;
kpxc.improvedFieldDetectionEnabledForPage = false;
kpxc.inputs = [];
kpxc.settings = {};
kpxc.preferencesForPage = null;
kpxc.singleInputEnabledForPage = false;
kpxc.submitUrl = null;
kpxc.url = null;
@ -506,15 +507,38 @@ kpxc.prepareCredentials = async function() {
return;
}
if (kpxc.settings.autoFillSingleEntry && kpxc.credentials.length === 1) {
if (kpxc.credentials.length === 1) {
if (kpxc.preferencesForPage?.autoFillSingleEntry || kpxc.settings.autoFillSingleEntry) {
kpxcFill.fillFromAutofill();
return;
}
}
kpxc.initLoginPopup();
kpxc.initAutocomplete();
};
kpxc.retrieveSitePreference = function() {
// Check for autofill site preferences
for (const site of kpxc.settings.sitePreferences) {
let currentLocation;
try {
currentLocation = window.top.location.href;
} catch (err) {
// Cross-domain security error inspecting window.top.location.href.
// This catches an error when an iframe is being accessed from another (sub)domain
// -> use the iframe URL instead.
currentLocation = window.self.location.href;
}
if (siteMatch(site.url, currentLocation) || site.url === currentLocation) {
return site;
}
}
return null;
}
/**
* Gets the credential list and shows the update banner
* @param {string} usernameValue Submitted username
@ -958,6 +982,7 @@ const initContentScript = async function() {
}
kpxc.settings = settings;
kpxc.preferencesForPage = kpxc.retrieveSitePreference();
if (await kpxc.siteIgnored()) {
logDebug('This site is ignored in Site Preferences.');

View file

@ -106,7 +106,7 @@ class TOTPFieldIcon extends Icon {
// Fill TOTP automatically if option is enabled
TOTPFieldIcon.prototype.autoFillSingleTotp = async function(field) {
if (kpxc.settings.autoFillSingleTotp) {
if (kpxc.preferencesForPage?.autoFillSingleTotp || kpxc.settings.autoFillSingleTotp) {
if (kpxc.credentials.length === 0) {
await kpxc.receiveCredentialsIfNecessary();
}

View file

@ -2,7 +2,6 @@ body {
background-color: var(--kpxc-background-color);
color: var(--kpxc-text-color);
font-size: 14px;
max-width: 1440px;
}
a {
@ -123,7 +122,7 @@ table tbody tr.empty:not(:nth-last-child(2)) {
#tab-site-preferences td:nth-of-type(2),
#tab-site-preferences td:nth-of-type(2) select {
width: 200px;
min-width: 200px;
}
#tab-site-preferences td:nth-of-type(3),
@ -227,8 +226,44 @@ table td:last-of-type {
.sidebar {
width: 240px;
}
main {
margin-left: 240px !important;
min-width: calc(0.8333333333 * 1440px) !important;
max-width: calc(100% - 240px) !important;
width: unset !important;
}
footer {
display: block;
}
.form-text, .form-group {
max-width: calc(0.8333333333 * 1440px);
}
}
#sitePreferencesTable > li > details > summary {
list-style: none;
vertical-align: middle;
}
#sitePreferencesTable > li > details > summary::-webkit-details-marker {
display: none;
}
#sitePreferencesTable > li > details > summary > div > div:first-child{
display: flex;
align-items: center;
}
#sitePreferencesTable > li > details > summary > div > div:first-child::before {
content: '►';
padding-right: 1rem;
}
#sitePreferencesTable > li > details[open] > summary > div > div:first-child::before {
content: '▼';
padding-right: 1rem;
}

View file

@ -731,45 +731,107 @@
<span class="invalid-feedback d-block" data-i18n="optionsSitePreferencesManualAddHelp"></span>
</div>
<div class="table-responsive">
<table class="table table-sm table-striped table-bordered">
<div class="table-responsive mt-3">
<ul id="sitePreferencesTable" class="list-group list-group-flush">
<caption data-i18n="optionsSitePreferencesTableCaption"></caption>
<thead>
<tr>
<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="optionsColumnImprovedInputFieldDetection"></span></th>
<th scope="col"><span data-i18n="optionsColumnAllowIframes"></span></th>
<th scope="col"><span data-i18n="optionsColumnDelete"></span></th>
</tr>
</thead>
<tbody>
<tr class="empty">
<td colspan="5"><span data-i18n="optionsSitePreferencesNotFound"></span></td>
</tr>
<tr class="clone d-none">
<td class="text-nowrap"></td>
<td>
<select class="form-select form-select-sm" name="ignore" data-i18n="[title]optionsSitePreferencesSelect">
<option value="ignoreNothing" data-i18n="optionsSelectionNothing"></option>
<option value="ignoreNormal" data-i18n="optionsSelectionNormal"></option>
<option value="ignoreAutoSubmit" data-i18n="optionsSelectionAutoSubmit"></option>
<option value="ignoreFull" data-i18n="optionsSelectionFull"></option>
</select>
</td>
<td><input class="form-check-input" type="checkbox" name="usernameOnly" value="false" data-i18n="[title]optionsColumnUsernameOnly"></td>
<td><input class="form-check-input" type="checkbox" name="improvedFieldDetection" value="false" data-i18n="[title]optionsColumnImprovedInputFieldDetection"></td>
<td><input class="form-check-input" type="checkbox" name="allowIframes" value="false" data-i18n="[title]optionsColumnAllowIframes"></td>
<td class="text-nowrap">
<button class="btn btn-sm delete btn-danger btn" data-i18n="[title]removeSitePreferencesButtonTitle">
<i class="fa fa-remove" aria-hidden="true"></i>
<span data-i18n="optionsButtonRemove"></span>
</button>
</td>
</tr>
</tbody>
</table>
<li class="empty list-group-item">
<span data-i18n="optionsSitePreferencesNotFound"></span>
</li>
<!-- Template row -->
<li class="clone d-none list-group-item">
<details>
<summary>
<div class="row justify-content-between">
<!-- Text field for the URL -->
<div class="col-auto pe-0" style="word-break: break-all;"></div>
<!-- Delete button -->
<div class="col-auto" style="margin-left: auto;">
<button id="deleteButton" class="btn btn-sm delete btn-danger btn" data-i18n="[title]removeSitePreferencesButtonTitle">
<i class="fa fa-remove" aria-hidden="true"></i>
<span data-i18n="optionsButtonRemove"></span>
</button>
</div>
</div>
</summary>
<!-- Site preference settings -->
<div class="container m-3">
<div class="row align-items-start gx-5">
<!-- Ignore settings -->
<div class="col-auto">
<div class="form-group mb-3">
<label for="ignore" class="form-label" data-i18n="optionsColumnIgnore"></label>
<select class="form-select" id="ignore" name="ignore" data-i18n="[title]optionsSitePreferencesSelect">
<option value="ignoreNothing" data-i18n="optionsSelectionNothing"></option>
<option value="ignoreNormal" data-i18n="optionsSelectionNormal"></option>
<option value="ignoreAutoSubmit" data-i18n="optionsSelectionAutoSubmit"></option>
<option value="ignoreFull" data-i18n="optionsSelectionFull"></option>
</select>
</div>
</div>
<!-- Filling credentials -->
<div class="col-auto">
<!-- Username only detection -->
<div class="form-group">
<div class="form-check">
<label for="usernameOnly" data-i18n="optionsColumnUsernameOnly"></label>
<input class="form-check-input" type="checkbox" id="usernameOnly" name="usernameOnly" value="false" data-i18n="[title]optionsColumnUsernameOnly">
</div>
</div>
<!-- Improved input field detection -->
<div class="form-group">
<div class="form-check">
<label for="improvedFieldDetection" data-i18n="optionsColumnImprovedInputFieldDetection"></label>
<input class="form-check-input" type="checkbox" id="improvedFieldDetection" name="improvedFieldDetection" value="false" data-i18n="[title]optionsColumnImprovedInputFieldDetection">
</div>
</div>
<!-- Allow iFrames -->
<div class="form-group">
<div class="form-check">
<label for="allowIframes" data-i18n="optionsColumnAllowIframes"></label>
<input class="form-check-input" type="checkbox" id="allowIframes" name="allowIframes" value="false" data-i18n="[title]optionsColumnAllowIframes">
</div>
</div>
</div>
<!-- Filling credentials -->
<div class="col-auto">
<!-- Use Auto-Submit -->
<div class="form-group">
<div class="form-check" data-i18n="[title]optionsAutoSubmitHelpText">
<label for="autoSubmit" data-i18n="optionsCheckboxAutoSubmit"></label>
<input class="form-check-input" type="checkbox" id="autoSubmit" name="autoSubmit" value="false" data-i18n="[title]optionsAutoSubmitHelpText">
</div>
</div>
<!-- Automatically fill single-credential entries -->
<div class="form-group">
<div class="form-check" data-i18n="[title]optionsAutoFillSingleEntryHelpText">
<label for="autoFillSingleEntry" data-i18n="optionsCheckboxAutoFillSingleEntry"></label>
<input class="form-check-input" type="checkbox" id="autoFillSingleEntry" name="autoFillSingleEntry" value="false" data-i18n="[title]optionsAutoFillSingleEntryHelpText">
</div>
</div>
<!-- Automatically fill single-credential TOTP fields -->
<div class="form-group">
<div class="form-check" data-i18n="[title]optionsAutoFillSingleTotpHelpText">
<label for="autoFillSingleTotp" data-i18n="optionsCheckboxAutoFillSingleTotp"></label>
<input class="form-check-input" type="checkbox" id="autoFillSingleTotp" name="autoFillSingleTotp" value="false" data-i18n="[title]optionsAutoFillSingleTotpHelpText">
</div>
</div>
</div>
</div>
</div>
</details>
</li>
</ul>
</div>
<div id="dialogDeleteSite" class="modal fade" tabindex="-1" role="dialog">

View file

@ -517,17 +517,17 @@ options.initSitePreferences = function() {
const removeButtonClicked = function(e) {
e.preventDefault();
const closestTr = this.closest('tr');
$('#dialogDeleteSite').setAttribute('url', closestTr.getAttribute('url'));
$('#dialogDeleteSite').setAttribute('tr-id', closestTr.getAttribute('id'));
$('#dialogDeleteSite .modal-body strong').textContent = closestTr.children[0].textContent;
const closestLi = this.closest('li');
$('#dialogDeleteSite').setAttribute('url', closestLi.getAttribute('url'));
$('#dialogDeleteSite').setAttribute('tr-id', closestLi.getAttribute('id'));
$('#dialogDeleteSite .modal-body strong').textContent = closestLi.children[0].children[0].children[0].children[0].textContent;
dialogDeleteSiteModal.show();
};
const checkboxClicked = function() {
const closestTr = this.closest('tr');
const url = closestTr.getAttribute('url');
const closestLi = this.closest('li');
const url = closestLi.getAttribute('url');
for (const site of options.settings['sitePreferences']) {
if (site.url === url) {
@ -537,6 +537,12 @@ options.initSitePreferences = function() {
site.improvedFieldDetection = this.checked;
} else if (this.name === 'allowIframes') {
site.allowIframes = this.checked;
} else if (this.name === 'autoSubmit') {
site.autoSubmit = this.checked;
} else if (this.name === 'autoFillSingleEntry') {
site.autoFillSingleEntry = this.checked;
} else if (this.name === 'autoFillSingleTotp') {
site.autoFillSingleTotp = this.checked;
}
}
}
@ -545,8 +551,8 @@ options.initSitePreferences = function() {
};
const selectionChanged = function() {
const closestTr = this.closest('tr');
const url = closestTr.getAttribute('url');
const closestLi = this.closest('li');
const url = closestLi.getAttribute('url');
for (const site of options.settings['sitePreferences']) {
if (site.url === url) {
@ -557,22 +563,30 @@ options.initSitePreferences = function() {
options.saveSettings();
};
const addNewRow = function(rowClone, newIndex, url, ignore, usernameOnly, improvedFieldDetection, allowIframes) {
const addNewRow = function(rowClone, newIndex, url, ignore, usernameOnly, improvedFieldDetection, allowIframes, autoSubmit, autoFillSingleEntry, autoFillSingleTotp) {
const row = rowClone.cloneNode(true);
row.setAttribute('url', url);
row.setAttribute('id', 'tr-scf' + newIndex);
row.children[0].textContent = url;
row.children[1].children[0].value = ignore;
row.children[1].children[0].addEventListener('change', selectionChanged);
row.children[2].children['usernameOnly'].checked = usernameOnly;
row.children[2].children['usernameOnly'].addEventListener('change', checkboxClicked);
row.children[3].children['improvedFieldDetection'].checked = improvedFieldDetection;
row.children[3].children['improvedFieldDetection'].addEventListener('change', checkboxClicked);
row.children[4].children['allowIframes'].checked = allowIframes;
row.children[4].children['allowIframes'].addEventListener('change', checkboxClicked);
row.children[5].addEventListener('click', removeButtonClicked);
$('#tab-site-preferences table tbody').append(row);
const details = row.children[0];
details.children[0].children[0].children[0].textContent = url;
details.querySelector('#ignore').value = ignore;
details.querySelector('#ignore').addEventListener('change', selectionChanged);
details.querySelector('#usernameOnly').checked = usernameOnly;
details.querySelector('#usernameOnly').addEventListener('change', checkboxClicked);
details.querySelector('#improvedFieldDetection').checked = improvedFieldDetection;
details.querySelector('#improvedFieldDetection').addEventListener('change', checkboxClicked);
details.querySelector('#allowIframes').checked = allowIframes;
details.querySelector('#allowIframes').addEventListener('change', checkboxClicked);
details.querySelector('#autoSubmit').checked = autoSubmit;
details.querySelector('#autoSubmit').addEventListener('change', checkboxClicked);
details.querySelector('#autoFillSingleEntry').checked = autoFillSingleEntry;
details.querySelector('#autoFillSingleEntry').addEventListener('change', checkboxClicked);
details.querySelector('#autoFillSingleTotp').checked = autoFillSingleTotp;
details.querySelector('#autoFillSingleTotp').addEventListener('change', checkboxClicked);
details.querySelector('#deleteButton').addEventListener('click', removeButtonClicked);
$('#tab-site-preferences #sitePreferencesTable').append(row);
};
$('#dialogDeleteSite .modal-footer button.yes').addEventListener('click', function(e) {
@ -627,11 +641,13 @@ options.initSitePreferences = function() {
}
const newIndex = options.settings['sitePreferences'].length + 1;
const rowClone = $('#tab-site-preferences table tr.clone').cloneNode(true);
const rowClone = $('#tab-site-preferences #sitePreferencesTable li.clone').cloneNode(true);
rowClone.classList.remove('clone', 'd-none');
addNewRow(rowClone, newIndex, value, IGNORE_NOTHING, false, false, false);
$('#tab-site-preferences table tbody tr.empty').hide();
addNewRow(rowClone, newIndex, value, IGNORE_NOTHING, false, false, false, false, false, false);
$('#tab-site-preferences #sitePreferencesTable li.empty').hide();
options.settings['sitePreferences'].push({
url: value,
@ -644,7 +660,7 @@ options.initSitePreferences = function() {
manualUrl.value = '';
});
const rowClone = $('#tab-site-preferences table tr.clone').cloneNode(true);
const rowClone = $('#tab-site-preferences ul li.clone').cloneNode(true);
rowClone.classList.remove('clone', 'd-none');
let counter = 1;
if (options.settings['sitePreferences']) {
@ -657,10 +673,17 @@ options.initSitePreferences = function() {
site.usernameOnly,
site.improvedFieldDetection,
site.allowIframes,
site.autoSubmit,
site.autoFillSingleEntry,
site.autoFillSingleTotp,
);
++counter;
}
}
if (counter > 1) {
$('#tab-site-preferences #sitePreferencesTable li.empty').hide();
}
};
options.initAbout = function() {