Updates Bootstrap library to version 5. Removes jQuery. (#1578)

* Update Bootstrap to V5. Remove jQuery.
This commit is contained in:
Sami Vänttinen 2022-04-05 08:04:15 +03:00 committed by GitHub
parent 646332b2ff
commit b67f05328c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 504 additions and 403 deletions

View file

@ -900,12 +900,17 @@ keepass.compareVersion = function(minimum, current, canBeEqual = true) {
return false;
}
// Handle snapshot builds as stable version
// Handle beta/snapshot builds as stable version
const snapshot = '-snapshot';
const beta = '-beta';
if (current.endsWith(snapshot)) {
current = current.slice(0, -snapshot.length);
}
if (current.endsWith(beta)) {
current = current.slice(0, -beta.length);
}
const min = minimum.split('.', 3).map(s => s.padStart(4, '0')).join('.');
const cur = current.split('.', 3).map(s => s.padStart(4, '0')).join('.');
return (canBeEqual ? (min <= cur) : (min < cur));

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -184,3 +184,11 @@ const getFileAndLine = function() {
return result;
};
HTMLElement.prototype.show = function() {
this.style.display = 'block';
};
HTMLElement.prototype.hide = function() {
this.style.display = 'none';
};

View file

@ -3,6 +3,7 @@
--kpxc-card-background-color: #fff;
--kpxc-card-border-color: rgba(0,0,0,.125);
--kpxc-card-header-color: #fafafa;
--kpxc-checkbox-color: #5b5b5d;
--kpxc-container-border: 1px solid #ccc;
--kpxc-input-active-border-color: #2b4d1a;
--kpxc-input-background-color: #fff;
@ -24,6 +25,7 @@
--kpxc-card-background-color: #2b2a2a;
--kpxc-card-border-color: #292a2a;
--kpxc-card-header-color: #27272a;
--kpxc-checkbox-color: #3b3b3d;
--kpxc-container-border: 1px solid #000;
--kpxc-input-active-border-color: #2b4d1a;
--kpxc-input-background-color: #27272a;
@ -45,6 +47,7 @@
--kpxc-card-background-color: #2b2a2a;
--kpxc-card-border-color: #292a2a;
--kpxc-card-header-color: #27272a;
--kpxc-checkbox-color: #3b3b3d;
--kpxc-container-border: 1px solid #000;
--kpxc-input-active-border-color: #2b4d1a;
--kpxc-input-background-color: #27272a;
@ -64,6 +67,7 @@
--kpxc-card-background-color: #fff;
--kpxc-card-border-color: rgba(0,0,0,.125);
--kpxc-card-header-color: #fafafa;
--kpxc-checkbox-color: #5b5b5d;
--kpxc-container-border: 1px solid #ccc;
--kpxc-input-active-border-color: #2b4d1a;
--kpxc-input-background-color: #fff;

File diff suppressed because one or more lines are too long

View file

@ -10,6 +10,14 @@ a {
text-decoration: none !important;
}
h1, span.menu-item {
font-size: 0.65rem;
}
footer {
font-size: 0.65rem !important;
}
a:hover {
color: var(--kpxc-link-hover-color);
}
@ -23,13 +31,18 @@ main {
background: var(--kpxc-background-color);
}
input,
input[type="checkbox"] {
input {
background-color: var(--kpxc-background-color) !important;
border-color: var(--kpxc-input-main-border-color) !important;
color: var(--kpxc-text-color) !important;
}
input[type="range"] {
background-color: var(--kpxc-card-background-color) !important;
border-color: var(--kpxc-input-main-border-color) !important;
color: var(--kpxc-text-color) !important;
}
input:active {
border-color: var(--kpxc-input-active-border-color);
}
@ -78,8 +91,9 @@ tbody {
color: var(--kpxc-text-color);
}
.table-striped > tbody > tr:nth-of-type(odd) {
.table-striped > tbody > tr:nth-of-type(odd) > * {
background-color: var(--kpxc-table-odd-color);
color: var(--kpxc-text-color);
}
.table tbody td {
@ -115,6 +129,14 @@ table td:last-of-type {
color: var(--kpxc-text-color);
}
.form-check-input:checked {
background-color: var(--kpxc-checkbox-color) !important;
}
.help-text {
margin-left: 1.725em;
}
.invalid-feedback {
color: var(--kpxc-link-color);
}
@ -144,7 +166,6 @@ table td:last-of-type {
background-color: var(--kpxc-sidebar-background-color) !important;
}
h1,
.nav-item,
.sidebar-heading {
font-size: .75rem;

View file

@ -14,7 +14,6 @@
<script src="../common/browser-polyfill.min.js"></script>
<script src="../common/global.js"></script>
<script src="../common/sites.js"></script>
<script src="../bootstrap/jquery-3.4.1.min.js"></script>
<script src="../bootstrap/bootstrap.min.js"></script>
<script src="options.js"></script>
<script src="../common/translate.js" defer></script>
@ -36,14 +35,39 @@
<div class="collapse d-none d-md-block" id="sidebar">
<h1 class="text-uppercase text-white-50 d-none d-md-flex px-3 pb-4 mt-4 mb-1 ">KeePassXC-Browser</h1>
<ul class="nav flex-column mb-2 text-uppercase">
<li class="active nav-item"><a class="nav-link text-light rounded-sm" href="#general-settings" tabindex="1"><i class="fa fa-ellipsis-h fa-lg pr-2" aria-hidden="true"></i><span data-i18n="optionsMenuGeneral"></span></a></li>
<li class="nav-item"><a class="nav-link text-light rounded-sm" href="#connected-databases" tabindex="2"><i class="fa fa-link fa-lg pr-2" aria-hidden="true"></i><span data-i18n="optionsMenuConnectedDatabases"></span></a></li>
<li class="nav-item"><a class="nav-link text-light rounded-sm" href="#custom-fields" tabindex="3"><i class="fa fa-sign-in fa-lg pr-2" aria-hidden="true"></i><span data-i18n="optionsMenuCustomFields"></span></a></li>
<li class="nav-item"><a class="nav-link text-light rounded-sm" href="#site-preferences" tabindex="4"><i class="fa fa-wrench fa-lg pr-2" aria-hidden="true"></i><span data-i18n="optionsMenuSitePreferences"></span></a></li>
<li class="nav-item"><a class="nav-link text-light rounded-sm" href="#about" tabindex="5"><i class="fa fa-info-circle fa-lg pr-2" aria-hidden="true"></i><span data-i18n="optionsMenuAbout"></span></a></li>
<li class="active nav-item">
<a class="nav-link text-light rounded-sm" href="#general-settings" tabindex="1">
<i class="fa fa-ellipsis-h fa-lg pe-2" aria-hidden="true"></i>
<span class="menu-item" data-i18n="optionsMenuGeneral"></span>
</a>
</li>
<li class="nav-item">
<a class="nav-link text-light rounded-sm" href="#connected-databases" tabindex="2">
<i class="fa fa-link fa-lg pe-2" aria-hidden="true"></i>
<span class="menu-item" data-i18n="optionsMenuConnectedDatabases"></span>
</a>
</li>
<li class="nav-item">
<a class="nav-link text-light rounded-sm" href="#custom-fields" tabindex="3">
<i class="fa fa-sign-in fa-lg pe-2" aria-hidden="true"></i>
<span class="menu-item" data-i18n="optionsMenuCustomFields"></span>
</a>
</li>
<li class="nav-item">
<a class="nav-link text-light rounded-sm" href="#site-preferences" tabindex="4">
<i class="fa fa-wrench fa-lg pe-2" aria-hidden="true"></i>
<span class="menu-item" data-i18n="optionsMenuSitePreferences"></span>
</a>
</li>
<li class="nav-item">
<a class="nav-link text-light rounded-sm" href="#about" tabindex="5">
<i class="fa fa-info-circle fa-lg pe-2" aria-hidden="true"></i>
<span class="menu-item" data-i18n="optionsMenuAbout"></span>
</a>
</li>
</ul>
<footer class="d-none d-md-flex px-3 mt-4 mb-1 text-uppercase position-absolute small text-muted">
(C) 2017-2022 - KeePassXC Team
<footer class="px-3 mt-4 mb-1 text-uppercase position-absolute small text-muted">
© 2017-2022 - KeePassXC Team
</footer>
</div>
</nav>
@ -64,8 +88,8 @@
<div class="card-body">
<!-- Color theme -->
<div class="form-group">
<label for="colorTheme" data-i18n="optionsThemeSelectionHeader"></label>
<div class="form-group col-sm-3 pb-2">
<label for="colorTheme" class="form-label" data-i18n="optionsThemeSelectionHeader"></label>
<select class="form-control form-control-sm col-md-3 col-lg-2" id="colorTheme" data-i18n="[title]optionsThemeSelection">
<option value="system" data-i18n="optionsThemeSystem"></option>
<option value="dark" data-i18n="optionsThemeDark"></option>
@ -78,7 +102,7 @@
<div class="form-check">
<input class="form-check-input" type="checkbox" name="showLoginFormIcon" id="usernameIconsCheckBox" value="true" />
<label class="form-check-label" for="usernameIconsCheckBox" data-i18n="optionsCheckboxUsernameIcons"></label>
<span class="form-text text-muted" data-i18n="optionsShowLoginFormIconHelpText"></span>
<div id="passwordHelpBlock" class="form-text" data-i18n="optionsShowLoginFormIconHelpText"></div>
</div>
</div>
@ -87,8 +111,8 @@
<div class="form-check">
<input class="form-check-input" type="checkbox" name="usePasswordGeneratorIcons" id="passwordIconsCheckBox" value="true" />
<label class="form-check-label" for="passwordIconsCheckBox" data-i18n="optionsCheckboxUsePasswordGenerator"></label>
<span class="form-text text-muted" data-i18n="optionsUsePasswordGeneratorHelpText"></span>
<span class="form-text text-muted" data-i18n="optionsUsePasswordGeneratorHelpTextSecond"></span>
<div class="form-text" data-i18n="optionsUsePasswordGeneratorHelpText"></div>
<div class="form-text" data-i18n="optionsUsePasswordGeneratorHelpTextSecond"></div>
</div>
</div>
@ -97,7 +121,7 @@
<div class="form-check">
<input class="form-check-input" type="checkbox" name="showOTPIcon" id="totpIconsCheckBox" value="true" />
<label class="form-check-label" for="totpIconsCheckBox" data-i18n="optionsCheckboxOTPIcons"></label>
<span class="form-text text-muted" data-i18n="optionsShowOTPIconHelpText"></span>
<div class="form-text" data-i18n="optionsShowOTPIconHelpText"></div>
</div>
</div>
@ -106,7 +130,7 @@
<div class="form-check">
<input class="form-check-input" type="checkbox" name="showNotifications" id="notificationCheckBox" value="true" />
<label class="form-check-label" for="notificationCheckBox" data-i18n="optionsCheckboxShowNotifications"></label>
<span class="form-text text-muted" data-i18n="optionsShowNotificationsHelpText"></span>
<div class="form-text" data-i18n="optionsShowNotificationsHelpText"></div>
</div>
</div>
</div>
@ -146,7 +170,7 @@
<div class="form-check">
<input class="form-check-input" type="checkbox" name="autoRetrieveCredentials" id="autoRetrieveCredentials" value="true" />
<label class="form-check-label" for="autoRetrieveCredentials" data-i18n="optionsCheckboxAutoRetrieveCredentials"></label>
<span class="form-text text-muted" data-i18n="optionsAutoRetrieveCredentialsHelpText"></span>
<div class="form-text" data-i18n="optionsAutoRetrieveCredentialsHelpText"></div>
</div>
</div>
@ -155,28 +179,27 @@
<div class="form-check">
<input class="form-check-input" type="checkbox" name="autoCompleteUsernames" id="autoCompleteUsernames" value="true" />
<label class="form-check-label" for="autoCompleteUsernames" data-i18n="optionsCheckboxAutoCompleteUsernames"></label>
<span class="form-text text-muted" data-i18n="optionsAutocompleteUsernamesHelpText"></span>
<div class="form-text" data-i18n="optionsAutocompleteUsernamesHelpText"></div>
</div>
</div>
<!-- Sort credentials by -->
<div class="form-group col-sm-3 pb-2">
<label for="credentialSorting" class="py-2" data-i18n="optionsCredentialSortSelectionHeader"></label>
<select class="form-control form-control-sm col-md-2" id="credentialSorting" data-i18n="[title]optionsCredentialSortSelection">
<option value="sortByTitle" data-i18n="optionsSortByTitle"></option>
<option value="sortByUsername" data-i18n="optionsSortByUsername"></option>
<option value="sortByGroupAndTitle" data-i18n="optionsSortByGroupAndTitle"></option>
<option value="sortByGroupAndUsername" data-i18n="optionsSortByGroupAndUsername"></option>
</select>
</div>
<!-- Use Auto-Submit -->
<div class="form-group">
<div class="form-check">
<label for="credentialSorting" data-i18n="optionsCredentialSortSelectionHeader"></label>
<select class="form-control form-control-sm col-md-2" id="credentialSorting" data-i18n="[title]optionsCredentialSortSelection">
<option value="sortByTitle" data-i18n="optionsSortByTitle"></option>
<option value="sortByUsername" data-i18n="optionsSortByUsername"></option>
<option value="sortByGroupAndTitle" data-i18n="optionsSortByGroupAndTitle"></option>
<option value="sortByGroupAndUsername" data-i18n="optionsSortByGroupAndUsername"></option>
</select>
</div>
</div>
<div class="form-group">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="autoSubmit" id="autoSubmit" value="true" />
<label class="form-check-label" for="autoSubmit" data-i18n="optionsCheckboxAutoSubmit"></label>
<span class="form-text text-muted" data-i18n="optionsAutoSubmitHelpText"></span>
<div class="form-text" data-i18n="optionsAutoSubmitHelpText"></div>
</div>
</div>
@ -185,7 +208,7 @@
<div class="form-check">
<input class="form-check-input" type="checkbox" name="autoFillSingleEntry" id="autoFillSingleEntry" value="true" />
<label class="form-check-label" for="autoFillSingleEntry" data-i18n="optionsCheckboxAutoFillSingleEntry"></label>
<span class="form-text text-muted" data-i18n="optionsAutoFillSingleEntryHelpText"></span>
<div class="form-text" data-i18n="optionsAutoFillSingleEntryHelpText"></div>
<div class="alert alert-warning mt-3 col-lg-9" role="alert">
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
<span data-i18n="optionsAutoFillSingleEntryWarning"></span>
@ -198,8 +221,8 @@
<div class="form-check">
<input class="form-check-input" type="checkbox" name="autoFillAndSend" id="autoFillAndSend" value="true">
<label class="form-check-label" for="autoFillAndSend" data-i18n="optionsCheckboxAutoFillAndSend"></label>
<span class="form-text text-muted" data-i18n="optionsAutoFillAndSendHelpText"></span>
<span class="form-text text-muted" data-i18n="optionsAutoFillAndSendHelpTextSecond"></span>
<div class="form-text" data-i18n="optionsAutoFillAndSendHelpText"></div>
<div class="form-text" data-i18n="optionsAutoFillAndSendHelpTextSecond"></div>
<img src="/options/http-auth-dialog.png" data-i18n="[alt]httpAuthDialog" class="img-fluid mt-2"/>
</div>
</div>
@ -227,21 +250,19 @@
<div class="form-check">
<input class="form-check-input" type="checkbox" name="defaultGroupAlwaysAsk" id="defaultGroupAlwaysAsk" value="true">
<label class="form-check-label" for="defaultGroupAlwaysAsk" data-i18n="optionsLabelDefaultGroupCheckboxText"></label>
<span class="form-text text-muted" data-i18n="optionsLabelDefaultGroupCheckboxHelpText"></span>
<div class="form-text" data-i18n="optionsLabelDefaultGroupCheckboxHelpText"></div>
</div>
</div>
<!-- Default group for saving -->
<div class="form-group">
<label for="defaultGroup" data-i18n="optionsLabelDefaultGroup"></label>
<div class="input-group">
<input class="form-control form-control-sm col-md-8 col-lg-6" type="text" id="defaultGroup" placeholder="KeePassXC-Browser Passwords">
<div class="input-group-append">
<button class="btn btn-sm btn-primary" type="button" id="defaultGroupButton"><i class="fa fa-save" aria-hidden="true"></i><span data-i18n="optionsButtonSave"></span></button>
<button class="btn btn-sm btn-danger" type="button" id="defaultGroupButtonReset"><i class="fa fa-remove" aria-hidden="true"></i><span data-i18n="optionsButtonReset"></span></button>
</div>
<span class="form-text text-muted w-100" data-i18n="optionsDefaultGroupHelpText"></span>
<div class="form-group pb-2">
<label for="defaultGroup" class="pb-2" data-i18n="optionsLabelDefaultGroup"></label>
<div class="input-group w-75">
<input class="form-control form-control-sm" type="text" id="defaultGroup" placeholder="KeePassXC-Browser Passwords">
<button class="btn btn-sm btn-primary" type="button" id="defaultGroupButton"><i class="fa fa-save" aria-hidden="true"></i><span data-i18n="optionsButtonSave"></span></button>
<button class="btn btn-sm btn-danger" type="button" id="defaultGroupButtonReset"><i class="fa fa-remove" aria-hidden="true"></i><span data-i18n="optionsButtonReset"></span></button>
</div>
<div class="form-text help-text" data-i18n="optionsDefaultGroupHelpText"></div>
</div>
<!-- Save domain only -->
@ -249,7 +270,7 @@
<div class="form-check">
<input class="form-check-input" type="checkbox" name="saveDomainOnlyNewCreds" id="saveDomainOnlyNewCreds" value="true">
<label class="form-check-label" for="saveDomainOnlyNewCreds" data-i18n="optionsSaveDomainOnly"></label>
<span class="form-text text-muted" data-i18n="optionsSaveDomainOnlyHelpText"></span>
<div class="form-text" data-i18n="optionsSaveDomainOnlyHelpText"></div>
</div>
</div>
@ -258,16 +279,16 @@
<div class="form-check">
<input class="form-check-input" type="checkbox" name="downloadFaviconAfterSave" id="downloadFaviconAfterSave" value="true">
<label class="form-check-label" for="downloadFaviconAfterSave" data-i18n="optionsDownloadFaviconAfterSave"></label>
<span class="form-text text-muted" data-i18n="optionsDownloadFaviconAfterSaveHelpText"></span>
<div class="form-text" data-i18n="optionsDownloadFaviconAfterSaveHelpText"></div>
</div>
</div>
<!-- Number of allowed redirects -->
<div class="form-group">
<div class="form-group w-50">
<label id="redirectAllowanceLabel" class="font-weight-normal" for="redirectAllowance" data-i18n="optionsRedirectAllowance" i18n-placeholder="1"></label>
<input type="range" class="form-control-range col-md-6 col-lg-4" id="redirectAllowance" name="redirectAllowance" min="1" max="11" step="1" value="1" />
<input type="range" class="form-range" id="redirectAllowance" name="redirectAllowance" min="1" max="11" step="1" value="1" />
<div class="form-text help-text" data-i18n="optionsRedirectAllowanceHelpText"></div>
</div>
<span class="form-text text-muted" data-i18n="optionsRedirectAllowanceHelpText"></span>
</div>
</div>
@ -327,7 +348,7 @@
<div class="form-check">
<input class="form-check-input" type="checkbox" name="useObserver" id="useObserver" value="true" />
<label class="form-check-label" for="useObserver" data-i18n="optionsUseObserver"></label>
<span class="form-text text-muted" data-i18n="optionsUseObserverHelpText"></span>
<div class="form-text" data-i18n="optionsUseObserverHelpText"></div>
</div>
</div>
@ -336,7 +357,7 @@
<div class="form-check">
<input class="form-check-input" type="checkbox" name="showGroupNameInAutocomplete" id="showGroupNameInAutocomplete" value="true" />
<label class="form-check-label" for="showGroupNameInAutocomplete" data-i18n="optionsCheckboxShowGroupNameInAutocomplete"></label>
<span class="form-text text-muted" data-i18n="optionsShowGroupNameInAutocompleteHelpText"></span>
<div class="form-text" data-i18n="optionsShowGroupNameInAutocompleteHelpText"></div>
<div class="alert alert-info mt-3 col-lg-9" role="alert" id="versionRequiredAlert">
<i class="fa fa-exclamation-circle" aria-hidden="true"></i>
<span data-i18n="optionsKeePassXCVersionRequired" i18n-placeholder="2.6.0"></span>
@ -349,7 +370,7 @@
<div class="form-check">
<input class="form-check-input" type="checkbox" name="autoReconnect" id="autoReconnect" value="true" />
<label class="form-check-label" for="autoReconnect" data-i18n="optionsCheckboxAutomaticReconnect"></label>
<span class="form-text text-muted" data-i18n="optionsAutomaticReconnectHelpText"></span>
<div class="form-text" data-i18n="optionsAutomaticReconnectHelpText"></div>
<div class="alert alert-warning mt-3 col-lg-9" role="alert">
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
<span data-i18n="optionsAutomaticReconnectWarning"></span>
@ -362,7 +383,7 @@
<div class="form-check">
<input class="form-check-input" type="checkbox" name="saveDomainOnly" id="saveDomainOnly" value="true" />
<label class="form-check-label" for="saveDomainOnly" data-i18n="optionsSaveDomainOnly"></label>
<span class="form-text text-muted" data-i18n="optionsSaveDomainOnlyCustomLoginHelpText"></span>
<div class="form-text" data-i18n="optionsSaveDomainOnlyCustomLoginHelpText"></div>
</div>
</div>
@ -371,7 +392,7 @@
<div class="form-check">
<input class="form-check-input" type="checkbox" name="usePredefinedSites" id="usePredefinedSites" value="true" />
<label class="form-check-label" for="usePredefinedSites" data-i18n="optionsUsePredefinedSites"></label>
<span class="form-text text-muted" data-i18n="optionsUsePredefinedSitesHelpText"></span>
<div class="form-text" data-i18n="optionsUsePredefinedSitesHelpText"></div>
<details id="predefinedSiteList">
<summary><span data-i18n="optionsPredefinedSiteList"></span></summary>
</details>
@ -380,11 +401,11 @@
<!-- Clear credential timeout -->
<div class="form-group">
<form>
<form class="pt-2">
<label for="clearCredentialTimeout" data-i18n="optionsClearCredentialsTimeout"></label>
<div class="form-check">
<div class="form-check py-2">
<input class="form-input" type="number" id="clearCredentialTimeout" min="0" max="3600" required/>
<span class="form-text text-muted" data-i18n="optionsClearCredentialsTimeoutHelpText"></span>
<div class="form-text" data-i18n="optionsClearCredentialsTimeoutHelpText"></div>
</div>
</form>
</div>
@ -394,7 +415,7 @@
<div class="form-check">
<input class="form-check-input" type="checkbox" name="debugLogging" id="debugLogging" value="false" />
<label class="form-check-label" for="debugLogging" data-i18n="optionsDebugLogging"></label>
<span class="form-text text-muted" data-i18n="optionsDebugLoggingHelpText"></span>
<div class="form-text" data-i18n="optionsDebugLoggingHelpText"></div>
</div>
</div>
</div>
@ -420,14 +441,14 @@
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="myModalLabel" data-i18n="optionsImportSettingsDialogTitle"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p data-i18n="optionsImportSettingsDialogText"></p>
</div>
<div class="modal-footer">
<button class="btn btn-sm btn-secondary" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove" aria-hidden="true"></i><span data-i18n="optionsButtonCancel"></span></button>
<button class="btn btn-sm yes btn-success" autofocus><i class="fa fa-check" aria-hidden="true"></i><span data-i18n="optionsButtonImport"></span></button>
<button class="btn btn-sm btn-secondary" data-bs-dismiss="modal" aria-hidden="true"><i class="fa fa-remove" aria-hidden="true"></i><span data-i18n="optionsButtonCancel"></span></button>
<button class="btn btn-sm yes btn-success"><i class="fa fa-check" aria-hidden="true"></i><span data-i18n="optionsButtonImport"></span></button>
</div>
</div>
</div>
@ -475,15 +496,15 @@
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" data-i18n="optionsDatabasesRemoveIdentifier"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p><span data-i18n="optionsDatabasesRemoveIdentifierConfirmFirst" i18n-placeholder="<strong></strong>"></span></p>
<p class="help-block" data-i18n="optionsDatabasesRemoveIdentifierConfirmSecond"></p>
</div>
<div class="modal-footer">
<button class="btn btn-sm btn-secondary" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove" aria-hidden="true"></i><span data-i18n="optionsButtonCancel"></span></button>
<button class="btn btn-sm yes btn-success" autofocus><i class="fa fa-check" aria-hidden="true"></i><span data-i18n="optionsButtonRemoveNow"></span></button>
<button class="btn btn-sm btn-secondary" data-bs-dismiss="modal" aria-hidden="true"><i class="fa fa-remove" aria-hidden="true"></i><span data-i18n="optionsButtonCancel"></span></button>
<button class="btn btn-sm yes btn-success"><i class="fa fa-check" aria-hidden="true"></i><span data-i18n="optionsButtonRemoveNow"></span></button>
</div>
</div>
</div>
@ -524,20 +545,20 @@
</table>
</div>
<div id="dialogDeleteCustomCredentialFields" class="modal fade" tabindex="-1" role="dialog">
<div id="dialogDeleteCustomLoginFields" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 data-i18n="optionsCustomFieldsRemove"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p><span data-i18n="optionsCustomFieldsConfirmation" i18n-placeholder="<strong></strong>"></span></p>
<p class="help-block" data-i18n="optionsCustomFieldsConfirmationHelpText"></p>
</div>
<div class="modal-footer">
<button class="btn btn-sm btn-secondary" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove" aria-hidden="true"></i><span data-i18n="optionsButtonCancel"></span></button>
<button class="btn btn-sm yes btn-success" autofocus><i class="fa fa-check" aria-hidden="true"></i><span data-i18n="optionsButtonRemoveNow"></span></button>
<button class="btn btn-sm btn-secondary" data-bs-dismiss="modal" aria-hidden="true"><i class="fa fa-remove" aria-hidden="true"></i><span data-i18n="optionsButtonCancel"></span></button>
<button class="btn btn-sm yes btn-success"><i class="fa fa-check" aria-hidden="true"></i><span data-i18n="optionsButtonRemoveNow"></span></button>
</div>
</div>
</div>
@ -566,11 +587,9 @@
<form class="was-validated">
<div class="form-group">
<label for="manualUrl" data-i18n="optionsSitePreferencesManualAddText"></label>
<div class="input-group" id="manualUrlGroup">
<input class="form-control form-control-sm col-lg-10" type="url" id="manualUrl" aria-label="Manual URL" pattern="file://.*|ftp://.*|http://.*|https://.*" minlength="5" maxlength="2000" required>
<div class="input-group-append">
<button class="btn btn-sm btn-primary" type="button" id="sitePreferencesManualAdd"><i class="fa fa-plus" aria-hidden="true"></i><span data-i18n="optionsButtonAdd"></span></button>
</div>
<div class="input-group w-75" id="manualUrlGroup">
<input class="form-control form-control-sm" type="url" id="manualUrl" aria-label="Manual URL" pattern="file://.*|ftp://.*|http://.*|https://.*" minlength="5" maxlength="2000" required>
<button class="btn btn-sm btn-primary" type="button" id="sitePreferencesManualAdd"><i class="fa fa-plus" aria-hidden="true"></i><span data-i18n="optionsButtonAdd"></span></button>
</div>
<span class="invalid-feedback d-block" data-i18n="optionsSitePreferencesManualAddHelp"></span>
</div>
@ -601,7 +620,7 @@
<option value="ignoreFull" data-i18n="optionsSelectionFull"></option>
</select>
</td>
<td><input type="checkbox" name="usernameOnly" value="false" data-i18n="[title]optionsColumnUsernameOnly"/></td>
<td><input class="form-check-input" type="checkbox" name="usernameOnly" value="false" data-i18n="[title]optionsColumnUsernameOnly"/></td>
<td class="text-nowrap"><button class="btn btn-sm delete btn-danger btn"><i class="fa fa-remove" aria-hidden="true"></i><span data-i18n="optionsButtonRemove"></span></button></td>
</tr>
</tbody>
@ -613,15 +632,15 @@
<div class="modal-content">
<div class="modal-header">
<h5 data-i18n="optionsSitePreferencesRemove"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p><span data-i18n="optionsSitePreferencesConfirmation" i18n-placeholder="<strong></strong>"></span></p>
<p class="help-block" data-i18n="optionsSitePreferencesConfirmationHelpText"></p>
</div>
<div class="modal-footer">
<button class="btn btn-sm btn-secondary" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove" aria-hidden="true"></i><span data-i18n="optionsButtonCancel"></span></button>
<button class="btn btn-sm yes btn-success" autofocus><i class="fa fa-check" aria-hidden="true"></i><span data-i18n="optionsButtonRemoveNow"></span></button>
<button class="btn btn-sm btn-secondary" data-bs-dismiss="modal" aria-hidden="true"><i class="fa fa-remove" aria-hidden="true"></i><span data-i18n="optionsButtonCancel"></span></button>
<button class="btn btn-sm yes btn-success"><i class="fa fa-check" aria-hidden="true"></i><span data-i18n="optionsButtonRemoveNow"></span></button>
</div>
</div>
</div>
@ -630,7 +649,6 @@
</div>
</div>
<!-- About -->
<div class="tab d-none" id="tab-about">
<h2 class="pb-3 mt-0" data-i18n="optionsAboutTab"></h2>
@ -713,8 +731,8 @@
<pre>
The MIT License (MIT)
Copyright (c) 2011-2018 Twitter, Inc.
Copyright (c) 2011-2018 The Bootstrap Authors
Copyright (c) 2011-2022 Twitter, Inc.
Copyright (c) 2011-2022 The Bootstrap Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -736,32 +754,6 @@
</pre>
</details>
<details>
<summary>jQuery</summary>
<pre>
Copyright JS Foundation and other contributors, https://js.foundation/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</pre>
</details>
<details>
<summary>Fork Awesome</summary>
<pre>

View file

@ -1,10 +1,10 @@
'use strict';
if (jQuery) {
var $ = jQuery.noConflict(true);
}
const $ = function(elem) {
return document.querySelector(elem);
};
$(async function() {
(async() => {
try {
const settings = await browser.runtime.sendMessage({ action: 'load_settings' });
options.settings = settings;
@ -14,27 +14,36 @@ $(async function() {
options.initMenu();
options.initGeneralSettings();
options.initConnectedDatabases();
options.initCustomCredentialFields();
options.initCustomLoginFields();
options.initSitePreferences();
options.initAbout();
options.initTheme();
} catch (err) {
console.log('Error loading options page: ' + err);
}
});
})();
var options = options || {};
options.initMenu = function() {
$('.sidebar:first ul.nav:first li a').click(function(e) {
e.preventDefault();
$('.sidebar:first ul.nav:first li').removeClass('active');
$(this).parent('li').addClass('active');
$('div.tab').hide();
$('div.tab#tab-' + $(this).attr('href').substring(1)).removeClass('d-none').fadeIn();
const tabs = [].slice.call(document.querySelectorAll('div.tab'));
const sideBarLinks = [].slice.call(document.querySelectorAll('.sidebar ul.nav li a'));
sideBarLinks.forEach(function(elem) {
elem.addEventListener('click', function(e) {
e.preventDefault();
sideBarLinks.forEach(t => t.parentElement.classList.remove('active'));
elem.parentElement.classList.add('active');
tabs.forEach(t => t.hide());
const activatedTab = $('div.tab#tab-' + elem.getAttribute('href').substring(1));
activatedTab.classList.remove('d-none');
activatedTab.show();
});
});
$('div.tab:first').show();
$('div.tab').show();
};
options.saveSetting = async function(name) {
@ -67,71 +76,84 @@ options.saveKeyRing = async function() {
};
options.initGeneralSettings = function() {
const changeCheckboxValue = async function(e) {
const name = e.currentTarget.name;
const isChecked = e.currentTarget.checked;
options.settings[name] = isChecked;
const updated = await options.saveSettings();
if (name === 'autoFillAndSend') {
browser.runtime.sendMessage({ action: 'init_http_auth' });
} else if (name === 'defaultGroupAlwaysAsk') {
$('#defaultGroup').disabled = isChecked;
$('#defaultGroupButton').disabled = isChecked;
$('#defaultGroupButtonReset').disabled = isChecked;
} else if (name === 'autoReconnect') {
const message = updated.autoReconnect ? 'enable_automatic_reconnect' : 'disable_automatic_reconnect';
browser.runtime.sendMessage({ action: message });
}
};
const changeRadioValue = function(e) {
options.settings[e.currentTarget.name] = Number(e.currentTarget.value);
options.saveSettings();
};
if (options.settings['colorTheme'] === undefined) {
$('#tab-general-settings select#colorTheme').val('system');
$('#tab-general-settings select#colorTheme').value = 'system';
} else {
$('#tab-general-settings select#colorTheme').val(options.settings['colorTheme']);
$('#tab-general-settings select#colorTheme').value = options.settings['colorTheme'];
}
$('#tab-general-settings select#colorTheme').change(async function() {
options.settings['colorTheme'] = $(this).val();
const generalSettingsCheckboxes = document.querySelectorAll('#tab-general-settings input[type=checkbox]');
for (const checkbox of generalSettingsCheckboxes) {
checkbox.checked = options.settings[checkbox.name];
if (checkbox.name === 'defaultGroupAlwaysAsk' && checkbox.checked) {
$('#defaultGroup').disabled = true;
$('#defaultGroupButton').disabled = true;
$('#defaultGroupButtonReset').disabled = true;
}
checkbox.addEventListener('click', changeCheckboxValue);
}
$('#tab-general-settings input[type=radio]#checkUpdateThreeDays').value = CHECK_UPDATE_THREE_DAYS;
$('#tab-general-settings input[type=radio]#checkUpdateOneWeek').value = CHECK_UPDATE_ONE_WEEK;
$('#tab-general-settings input[type=radio]#checkUpdateOneMonth').value = CHECK_UPDATE_ONE_MONTH;
$('#tab-general-settings input[type=radio]#checkUpdateNever').value = CHECK_UPDATE_NEVER;
$('#tab-general-settings input[type=range]').value = options.settings['redirectAllowance'];
$('#redirectAllowanceLabel').textContent = tr('optionsRedirectAllowance',
options.settings['redirectAllowance'] === 11 ? 'Infinite' : String(options.settings['redirectAllowance']));
$('#tab-general-settings select#credentialSorting').value = options.settings['credentialSorting'];
$('#tab-general-settings input#defaultGroup').value = options.settings['defaultGroup'];
$('#tab-general-settings input#clearCredentialTimeout').value = options.settings['clearCredentialsTimeout'];
const generalSettingsRadioInputs = document.querySelectorAll('#tab-general-settings input[type=radio]');
for (const radio of generalSettingsRadioInputs) {
if (radio.value === String(options.settings[radio.name])) {
radio.checked = true;
}
radio.addEventListener('click', changeRadioValue);
}
$('#tab-general-settings select#colorTheme').addEventListener('change', async function(e) {
options.settings['colorTheme'] = e.currentTarget.value;
// The theme is also stored in localStorage to prevent a white flash when the settings are first opened
localStorage.setItem('colorTheme', options.settings['colorTheme']);
await options.saveSettings();
location.reload();
});
$('#tab-general-settings select#credentialSorting').change(async function() {
options.settings['credentialSorting'] = $(this).val();
$('#tab-general-settings select#credentialSorting').addEventListener('change', async function(e) {
options.settings['credentialSorting'] = e.currentTarget.value;
await options.saveSettings();
});
$('#tab-general-settings input[type=checkbox]').each(function() {
$(this).attr('checked', options.settings[$(this).attr('name')]);
if ($(this).attr('name') === 'defaultGroupAlwaysAsk' && $(this).attr('checked')) {
$('#defaultGroup').prop('disabled', true);
$('#defaultGroupButton').prop('disabled', true);
$('#defaultGroupButtonReset').prop('disabled', true);
}
});
$('#tab-general-settings input[type=radio]#checkUpdateThreeDays').val(CHECK_UPDATE_THREE_DAYS);
$('#tab-general-settings input[type=radio]#checkUpdateOneWeek').val(CHECK_UPDATE_ONE_WEEK);
$('#tab-general-settings input[type=radio]#checkUpdateOneMonth').val(CHECK_UPDATE_ONE_MONTH);
$('#tab-general-settings input[type=radio]#checkUpdateNever').val(CHECK_UPDATE_NEVER);
$('#tab-general-settings input[type=range]').val(options.settings['redirectAllowance']);
$('#redirectAllowanceLabel').text(tr('optionsRedirectAllowance',
options.settings['redirectAllowance'] === 11 ? 'Infinite' : String(options.settings['redirectAllowance'])));
$('#tab-general-settings input[type=checkbox]').change(async function() {
const name = $(this).attr('name');
options.settings[name] = $(this).is(':checked');
const updated = await options.saveSettings();
if (name === 'autoFillAndSend') {
browser.runtime.sendMessage({ action: 'init_http_auth' });
} else if (name === 'defaultGroupAlwaysAsk') {
if ($(this).is(':checked')) {
$('#defaultGroup').prop('disabled', true);
$('#defaultGroupButton').prop('disabled', true);
$('#defaultGroupButtonReset').prop('disabled', true);
} else {
$('#defaultGroup').prop('disabled', false);
$('#defaultGroupButton').prop('disabled', false);
$('#defaultGroupButtonReset').prop('disabled', false);
}
} else if (name === 'autoReconnect') {
const message = updated.autoReconnect ? 'enable_automatic_reconnect' : 'disable_automatic_reconnect';
browser.runtime.sendMessage({ action: message });
}
});
$('#tab-general-settings select#credentialSorting').val(options.settings['credentialSorting']);
$('#tab-general-settings input#defaultGroup').val(options.settings['defaultGroup']);
$('#tab-general-settings input#clearCredentialTimeout').val(options.settings['clearCredentialsTimeout']);
$('#tab-general-settings input#clearCredentialTimeout').change(async function(e) {
$('#tab-general-settings input#clearCredentialTimeout').addEventListener('change', async function(e) {
if (e.target.valueAsNumber < 0 || e.target.valueAsNumber > 3600) {
return;
}
@ -140,25 +162,14 @@ options.initGeneralSettings = function() {
await options.saveSettings();
});
$('#tab-general-settings input[type=radio]').each(function() {
if ($(this).val() === String(options.settings[$(this).attr('name')])) {
$(this).attr('checked', options.settings[$(this).attr('name')]);
}
});
$('#tab-general-settings input[type=radio]').change(function() {
options.settings[$(this).attr('name')] = Number($(this).val());
options.saveSettings();
});
// Change label text dynamically with the range input
$('#tab-general-settings input[type=range]').on('propertychange input', function(e) {
$('#tab-general-settings input[type=range]').addEventListener('input', function(e) {
const currentValue = e.target.valueAsNumber === 11 ? 'Infinite' : e.target.value;
$('#redirectAllowanceLabel').text(tr('optionsRedirectAllowance', currentValue));
$('#redirectAllowanceLabel').textContent = tr('optionsRedirectAllowance', currentValue);
});
// Only save the setting when mouse is released from the range input
$('#tab-general-settings input[type=range]').change(async function(e) {
$('#tab-general-settings input[type=range]').addEventListener('change', async function(e) {
options.settings['redirectAllowance'] = e.target.valueAsNumber;
await options.saveSettings();
});
@ -167,9 +178,10 @@ options.initGeneralSettings = function() {
action: 'get_keepassxc_versions'
}).then(options.showKeePassXCVersions);
$('#tab-general-settings button.checkUpdateKeePassXC:first').click(function(e) {
$('#tab-general-settings button.checkUpdateKeePassXC').addEventListener('click', function(e) {
e.preventDefault();
$(this).attr('disabled', true);
e.disabled = true;
browser.runtime.sendMessage({
action: 'check_update_keepassxc'
}).then(options.showKeePassXCVersions);
@ -185,28 +197,30 @@ options.initGeneralSettings = function() {
});
});
$('#configureCommands').click(function() {
$('#configureCommands').addEventListener('click', function() {
const scheme = isEdge() ? 'edge' : 'chrome';
browser.tabs.create({
url: isFirefox() ? browser.runtime.getURL('options/shortcuts.html') : `${scheme}://extensions/shortcuts`
});
});
$('#defaultGroupButton').click(async function() {
const value = $('#defaultGroup').val();
$('#defaultGroupButton').addEventListener('click', async function() {
const value = $('#defaultGroup').value;
options.settings['defaultGroup'] = (value.length > 0 ? value : '');
await options.saveSettings();
});
$('#defaultGroupButtonReset').click(async function() {
$('#defaultGroup').val('');
$('#defaultGroupButtonReset').addEventListener('click', async function() {
$('#defaultGroup').value = '';
options.settings['defaultGroup'] = '';
await options.saveSettings();
});
let temporarySettings;
$('#dialogImportSettings').modal({ keyboard: true, show: false, backdrop: true });
$('#importSettingsButton').click(function() {
const dialogImportSettingsModal = new bootstrap.Modal($('#dialogImportSettings'),
{ keyboard: true, show: false, backdrop: true });
$('#importSettingsButton').addEventListener('click', function(e) {
var link = document.createElement('input');
link.setAttribute('type', 'file');
link.onchange = function(e) {
@ -230,11 +244,9 @@ options.initGeneralSettings = function() {
// Verify the import
temporarySettings = contents;
$('#dialogImportSettings').data('hash', $(this).closest('tr').data('hash'));
$('#dialogImportSettings .modal-body:first span:first').text($(this).closest('tr').children('td:first').text());
$('#dialogImportSettings').modal('show');
$('#dialogImportSettings').on('shown.bs.modal', () => {
$('#dialogImportSettings').find('[autofocus]').focus();
dialogImportSettingsModal.show();
$('#dialogImportSettings').addEventListener('shown.bs.modal', function(modalEvent) {
modalEvent.currentTarget.querySelector('.modal-footer .btn-success').focus();
});
} catch (err) {
console.log('Error loading JSON settings file.');
@ -245,7 +257,7 @@ options.initGeneralSettings = function() {
link.click();
});
$('#exportSettingsButton').click(function() {
$('#exportSettingsButton').addEventListener('click', function() {
const link = document.createElement('a');
const file = new Blob([ JSON.stringify(options.settings) ], { type: 'application/json' });
link.href = URL.createObjectURL(file);
@ -253,8 +265,8 @@ options.initGeneralSettings = function() {
link.click();
});
$('#dialogImportSettings .modal-footer:first button.yes:first').click(function(e) {
$('#dialogImportSettings').modal('hide');
$('#dialogImportSettings .modal-footer button.yes').addEventListener('click', function(e) {
dialogImportSettingsModal.hide();
if (temporarySettings) {
options.settings = temporarySettings;
@ -262,7 +274,7 @@ options.initGeneralSettings = function() {
}
});
$('#copyVersionToClipboard').on('click', function () {
$('#copyVersionToClipboard').addEventListener('click', function () {
const copyText = document.getElementById('versionInfo').innerText;
navigator.clipboard.writeText(copyText);
});
@ -274,8 +286,10 @@ options.initGeneralSettings = function() {
for (const site of PREDEFINED_SITELIST) {
const elem = document.createElement('span');
elem.textContent = site;
siteListing.append(document.createElement('br'));
elem.classList.add('form-text');
elem.classList.add('px-3');
siteListing.append(elem);
siteListing.append(document.createElement('br'));
}
}
};
@ -288,11 +302,12 @@ options.showKeePassXCVersions = async function(response) {
if (response.latest === '') {
response.latest = 'unknown';
}
$('#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);
$('#tab-general-settings .kphVersion em.yourVersion').textContent = response.current;
$('#tab-general-settings .kphVersion em.latestVersion').textContent = response.latest;
$('#tab-about em.versionKPH').textContent = response.current;
$('#tab-about span.kpxcVersion').textContent = response.current;
$('#tab-general-settings button.checkUpdateKeePassXC').disabled = false;
// Hide/disable certain options with older KeePassXC versions than 2.6.0
const version260Result = await browser.runtime.sendMessage({
@ -303,7 +318,7 @@ options.showKeePassXCVersions = async function(response) {
if (version260Result) {
$('#tab-general-settings #versionRequiredAlert').hide();
} else {
$('#tab-general-settings #showGroupNameInAutocomplete').attr('disabled', true);
$('#tab-general-settings #showGroupNameInAutocomplete').disabled = true;
}
// Hide certain options with older KeePassXC versions than 2.7.0
@ -322,21 +337,21 @@ options.getPartiallyHiddenKey = function(key) {
};
options.initConnectedDatabases = function() {
$('#dialogDeleteConnectedDatabase').modal({ keyboard: true, show: false, backdrop: true });
$('#tab-connected-databases tr.clone:first button.delete:first').click(function(e) {
e.preventDefault();
$('#dialogDeleteConnectedDatabase').data('hash', $(this).closest('tr').data('hash'));
$('#dialogDeleteConnectedDatabase .modal-body:first strong:first').text($(this).closest('tr').children('td:first').text());
$('#dialogDeleteConnectedDatabase').modal('show');
$('#dialogDeleteConnectedDatabase').on('shown.bs.modal', () => {
$('#dialogDeleteConnectedDatabase').find('[autofocus]').focus();
});
});
const dialogDeleteConnectedDatabaseModal = new bootstrap.Modal($('#dialogDeleteConnectedDatabase'),
{ keyboard: true, show: false, backdrop: true });
$('#dialogDeleteConnectedDatabase .modal-footer:first button.yes:first').click(async function(e) {
$('#dialogDeleteConnectedDatabase').modal('hide');
const hideEmptyMessageRow = function() {
if ($('#tab-connected-databases table tbody').children.length > 2) {
$('#tab-connected-databases table tbody tr.empty').hide();
} else {
$('#tab-connected-databases table tbody tr.empty').style.display = '';
}
};
const hash = $('#dialogDeleteConnectedDatabase').data('hash');
$('#dialogDeleteConnectedDatabase .modal-footer button.yes').addEventListener('click', async function(e) {
dialogDeleteConnectedDatabaseModal.hide();
const hash = $('#dialogDeleteConnectedDatabase').getAttribute('hash');
$('#tab-connected-databases #tr-cd-' + hash).remove();
delete options.keyRing[hash];
@ -348,33 +363,41 @@ options.initConnectedDatabases = function() {
console.log(err);
});
if ($('#tab-connected-databases table tbody:first tr').length > 2) {
$('#tab-connected-databases table tbody:first tr.empty:first').hide();
} else {
$('#tab-connected-databases table tbody:first tr.empty:first').show();
}
hideEmptyMessageRow();
});
$('#tab-connected-databases tr.clone:first .dropdown-menu:first').width('230px');
const removeButtonClicked = function(e) {
e.preventDefault();
const rowClone = $('#tab-connected-databases table tr.clone:first').clone(true);
rowClone.removeClass('clone d-none');
const closestTr = this.closest('tr');
$('#dialogDeleteConnectedDatabase').setAttribute('hash', closestTr.getAttribute('hash'));
$('#dialogDeleteConnectedDatabase').setAttribute('tr-id', closestTr.getAttribute('id'));
$('#dialogDeleteConnectedDatabase .modal-body strong').textContent = closestTr.children[0].textContent;
dialogDeleteConnectedDatabaseModal.show();
$('#dialogDeleteConnectedDatabase').addEventListener('shown.bs.modal', function(modalEvent) {
modalEvent.currentTarget.querySelector('.modal-footer .btn-success').focus();
});
};
const rowClone = $('#tab-connected-databases table tr.clone').cloneNode(true);
rowClone.classList.remove('clone', 'd-none');
const addHashToTable = function(hash) {
$('#tab-connected-databases table tbody:first tr.empty:first').hide();
const row = rowClone.clone(true);
row.data('hash', hash);
row.attr('id', 'tr-cd-' + hash);
const row = rowClone.cloneNode(true);
row.setAttribute('hash', hash);
row.setAttribute('id', 'tr-cd-' + hash);
$('a.dropdown-toggle:first img:first', row).attr('src', '/icons/toolbar/icon_normal.png');
row.children('td:first').text(options.keyRing[hash].id);
row.children('td:eq(1)').text(options.getPartiallyHiddenKey(options.keyRing[hash].key));
const lastUsed = (options.keyRing[hash].lastUsed) ? new Date(options.keyRing[hash].lastUsed).toLocaleString() : 'unknown';
row.children('td:eq(2)').text(lastUsed);
const date = (options.keyRing[hash].created) ? new Date(options.keyRing[hash].created).toLocaleDateString() : 'unknown';
row.children('td:eq(3)').text(date);
$('#tab-connected-databases table tbody:first').append(row);
row.children[0].textContent = options.keyRing[hash].id;
row.children[1].textContent = options.getPartiallyHiddenKey(options.keyRing[hash].key);
row.children[2].textContent = lastUsed;
row.children[3].textContent = date;
row.children[4].addEventListener('click', removeButtonClicked);
$('#tab-connected-databases table tbody').append(row);
};
let hashList = options.keyRing;
@ -382,13 +405,7 @@ options.initConnectedDatabases = function() {
addHashToTable(hash);
}
if ($('#tab-connected-databases table tbody:first tr').length > 2) {
$('#tab-connected-databases table tbody:first tr.empty:first').hide();
} else {
$('#tab-connected-databases table tbody:first tr.empty:first').show();
}
$('#connect-button').click(async function() {
$('#connect-button').addEventListener('click', async function() {
const result = await browser.runtime.sendMessage({ action: 'associate' });
if (result === AssociatedAction.NEW_ASSOCIATION) {
@ -408,56 +425,65 @@ options.initConnectedDatabases = function() {
}
}
});
hideEmptyMessageRow();
};
options.initCustomCredentialFields = function() {
$('#dialogDeleteCustomCredentialFields').modal({ keyboard: true, show: false, backdrop: true });
$('#tab-custom-fields tr.clone:first button.delete:first').click(function(e) {
options.initCustomLoginFields = function() {
const dialogDeleteCustomLoginFieldsModal = new bootstrap.Modal($('#dialogDeleteCustomLoginFields'),
{ keyboard: true, show: false, backdrop: true });
const hideEmptyMessageRow = function() {
if ($('#tab-custom-fields table tbody').children.length > 2) {
$('#tab-custom-fields table tbody tr.empty').hide();
} else {
$('#tab-custom-fields table tbody tr.empty').style.display = '';
}
};
const removeButtonClicked = function(e) {
e.preventDefault();
$('#dialogDeleteCustomCredentialFields').data('url', $(this).closest('tr').data('url'));
$('#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();
const closestTr = this.closest('tr');
$('#dialogDeleteCustomLoginFields').setAttribute('url', closestTr.getAttribute('url'));
$('#dialogDeleteCustomLoginFields').setAttribute('tr-id', closestTr.getAttribute('id'));
$('#dialogDeleteCustomLoginFields .modal-body strong').textContent = closestTr.children[0].textContent;
dialogDeleteCustomLoginFieldsModal.show();
$('#dialogDeleteCustomLoginFields').addEventListener('shown.bs.modal', function(modalEvent) {
modalEvent.currentTarget.querySelector('.modal-footer .btn-success').focus();
});
});
};
$('#dialogDeleteCustomCredentialFields .modal-footer:first button.yes:first').click(function(e) {
$('#dialogDeleteCustomCredentialFields').modal('hide');
$('#dialogDeleteCustomLoginFields .modal-footer button.yes').addEventListener('click', function(e) {
dialogDeleteCustomLoginFieldsModal.hide();
const url = $('#dialogDeleteCustomCredentialFields').data('url');
const trId = $('#dialogDeleteCustomCredentialFields').data('tr-id');
const url = $('#dialogDeleteCustomLoginFields').getAttribute('url');
const trId = $('#dialogDeleteCustomLoginFields').getAttribute('tr-id');
$('#tab-custom-fields #' + trId).remove();
delete options.settings['defined-custom-fields'][url];
options.saveSettings();
if ($('#tab-custom-fields table tbody:first tr').length > 2) {
$('#tab-custom-fields table tbody:first tr.empty:first').hide();
} else {
$('#tab-custom-fields table tbody:first tr.empty:first').show();
}
hideEmptyMessageRow();
});
const rowClone = $('#tab-custom-fields table tr.clone:first').clone(true);
rowClone.removeClass('clone d-none');
const rowClone = $('#tab-custom-fields table tr.clone').cloneNode(true);
rowClone.classList.remove('clone', 'd-none');
let counter = 1;
for (const url in options.settings['defined-custom-fields']) {
const row = rowClone.clone(true);
row.data('url', url);
row.attr('id', 'tr-scf' + counter);
const row = rowClone.cloneNode(true);
row.setAttribute('url', url);
row.setAttribute('id', 'tr-clf' + counter);
++counter;
row.children('td:first').text(url);
$('#tab-custom-fields table tbody:first').append(row);
row.children[0].textContent = url;
row.children[1].addEventListener('click', removeButtonClicked);
$('#tab-custom-fields table tbody').append(row);
}
if ($('#tab-custom-fields table tbody:first tr').length > 2) {
$('#tab-custom-fields table tbody:first tr.empty:first').hide();
} else {
$('#tab-custom-fields table tbody:first tr.empty:first').show();
}
hideEmptyMessageRow();
};
options.initSitePreferences = function() {
@ -465,49 +491,99 @@ options.initSitePreferences = function() {
options.settings['sitePreferences'] = [];
}
$('#dialogDeleteSite').modal({ keyboard: true, show: false, backdrop: true });
$('#tab-site-preferences tr.clone:first button.delete:first').click(function(e) {
const dialogDeleteSiteModal = new bootstrap.Modal($('#dialogDeleteSite'),
{ keyboard: true, show: false, backdrop: true });
const removeButtonClicked = function(e) {
e.preventDefault();
$('#dialogDeleteSite').data('url', $(this).closest('tr').data('url'));
$('#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();
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;
dialogDeleteSiteModal.show();
$('#dialogDeleteSite').addEventListener('shown.bs.modal', function(modalEvent) {
modalEvent.currentTarget.querySelector('.modal-footer .btn-success').focus();
});
});
};
const checkboxClicked = function() {
const closestTr = this.closest('tr');
const url = closestTr.getAttribute('url');
$('#tab-site-preferences tr.clone:first input[type=checkbox]:first').change(function() {
const url = $(this).closest('tr').data('url');
for (const site of options.settings['sitePreferences']) {
if (site.url === url) {
site.usernameOnly = $(this).is(':checked');
site.usernameOnly = this.checked;
}
}
options.saveSettings();
});
$('#tab-site-preferences tr.clone:first select:first').change(function() {
const url = $(this).closest('tr').data('url');
options.saveSettings();
};
const selectionChanged = function() {
const closestTr = this.closest('tr');
const url = closestTr.getAttribute('url');
for (const site of options.settings['sitePreferences']) {
if (site.url === url) {
site.ignore = $(this).val();
site.ignore = this.value;
}
}
options.saveSettings();
};
const hideEmptyMessageRow = function() {
if ($('#tab-site-preferences table tbody').children.length > 2) {
$('#tab-site-preferences table tbody tr.empty').hide();
} else {
$('#tab-site-preferences table tbody tr.empty').style.display = '';
}
};
const addNewRow = function(rowClone, newIndex, url, ignore, usernameOnly) {
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].addEventListener('click', removeButtonClicked);
$('#tab-site-preferences table tbody').append(row);
};
$('#dialogDeleteSite .modal-footer button.yes').addEventListener('click', function(e) {
dialogDeleteSiteModal.hide();
const url = $('#dialogDeleteSite').getAttribute('url');
const trId = $('#dialogDeleteSite').getAttribute('tr-id');
$('#tab-site-preferences #' + trId).remove();
for (let i = 0; i < options.settings['sitePreferences'].length; ++i) {
if (options.settings['sitePreferences'][i].url === url) {
options.settings['sitePreferences'].splice(i, 1);
}
}
options.saveSettings();
hideEmptyMessageRow();
});
$('.was-validated').submit(function(e) {
$('.was-validated').addEventListener('submit', function(e) {
e.preventDefault();
});
$('#manualUrl').keyup(function(event) {
$('#manualUrl').addEventListener('keyup', function(event) {
if (event.key === 'Enter') {
$('#sitePreferencesManualAdd').click();
}
});
$('#sitePreferencesManualAdd').click(function(e) {
$('#sitePreferencesManualAdd').addEventListener('click', function(e) {
const manualUrl = document.querySelector('#manualUrl');
if (!manualUrl) {
return;
@ -536,66 +612,29 @@ options.initSitePreferences = function() {
options.settings['sitePreferences'] = [];
}
const newValue = options.settings['sitePreferences'].length + 1;
const rowClone = $('#tab-site-preferences table tr.clone:first').clone(true);
rowClone.removeClass('clone d-none');
const newIndex = options.settings['sitePreferences'].length + 1;
const rowClone = $('#tab-site-preferences table tr.clone').cloneNode(true);
rowClone.classList.remove('clone', 'd-none');
const row = rowClone.clone(true);
row.data('url', value);
row.attr('id', 'tr-scf' + newValue);
row.children('td:first').text(value);
row.children('td:nth-child(2)').children('select').val(IGNORE_NOTHING);
$('#tab-site-preferences table tbody:first').append(row);
$('#tab-site-preferences table tbody:first tr.empty:first').hide();
addNewRow(rowClone, newIndex, value, IGNORE_NOTHING, false);
$('#tab-site-preferences table tbody tr.empty').hide();
options.settings['sitePreferences'].push({ url: value, ignore: IGNORE_NOTHING, usernameOnly: false });
options.saveSettings();
manualUrl.value = '';
});
$('#dialogDeleteSite .modal-footer:first button.yes:first').click(function(e) {
$('#dialogDeleteSite').modal('hide');
const url = $('#dialogDeleteSite').data('url');
const trId = $('#dialogDeleteSite').data('tr-id');
$('#tab-site-preferences #' + trId).remove();
for (let i = 0; i < options.settings['sitePreferences'].length; ++i) {
if (options.settings['sitePreferences'][i].url === url) {
options.settings['sitePreferences'].splice(i, 1);
}
}
options.saveSettings();
if ($('#tab-site-preferences table tbody:first tr').length > 2) {
$('#tab-site-preferences table tbody:first tr.empty:first').hide();
} else {
$('#tab-site-preferences table tbody:first tr.empty:first').show();
}
});
const rowClone = $('#tab-site-preferences table tr.clone:first').clone(true);
rowClone.removeClass('clone d-none');
const rowClone = $('#tab-site-preferences table tr.clone').cloneNode(true);
rowClone.classList.remove('clone', 'd-none');
let counter = 1;
if (options.settings['sitePreferences']) {
for (const site of options.settings['sitePreferences']) {
const row = rowClone.clone(true);
row.data('url', site.url);
row.attr('id', 'tr-scf' + counter);
addNewRow(rowClone, counter, site.url, site.ignore, site.usernameOnly);
++counter;
row.children('td:first').text(site.url);
row.children('td:nth-child(2)').children('select').val(site.ignore);
row.children('td:nth-child(3)').children('input[type=checkbox]').attr('checked', site.usernameOnly);
$('#tab-site-preferences table tbody:first').append(row);
}
}
if ($('#tab-site-preferences table tbody:first tr').length > 2) {
$('#tab-site-preferences table tbody:first tr.empty:first').hide();
} else {
$('#tab-site-preferences table tbody:first tr.empty:first').show();
}
hideEmptyMessageRow();
};
options.initAbout = function() {
@ -605,10 +644,10 @@ options.initAbout = function() {
platform = 'Win64';
}
$('#tab-about em.versionCIP').text(version);
$('#tab-about span.kpxcbrVersion').text(version);
$('#tab-about span.kpxcbrOS').text(platform);
$('#tab-about span.kpxcbrBrowser').text(getBrowserId());
$('#tab-about em.versionCIP').textContent = version;
$('#tab-about span.kpxcbrVersion').textContent = version;
$('#tab-about span.kpxcbrOS').textContent = platform;
$('#tab-about span.kpxcbrBrowser').textContent = 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) {

View file

@ -9,7 +9,6 @@
<link rel="stylesheet" href="../fonts/fork-awesome.min.css" />
<script src="../common/browser-polyfill.min.js"></script>
<script src="../common/global.js"></script>
<script src="../bootstrap/jquery-3.4.1.min.js"></script>
<script src="../bootstrap/bootstrap.min.js"></script>
<script src="popup_functions.js"></script>
<script src="popup.js"></script>

View file

@ -1,5 +1,13 @@
'use strict';
HTMLElement.prototype.show = function() {
this.style.display = 'block';
};
HTMLElement.prototype.hide = function() {
this.style.display = 'none';
};
function statusResponse(r) {
$('#initial-state').hide();
$('#error-encountered').hide();
@ -10,25 +18,25 @@ function statusResponse(r) {
$('#lock-database-button').hide();
if (!r.keePassXCAvailable) {
$('#error-message').html(r.error);
$('#error-message').textContent = r.error;
$('#error-encountered').show();
} else if (r.keePassXCAvailable && r.databaseClosed) {
$('#database-error-message').html(r.error);
$('#database-error-message').textContent = r.error;
$('#database-not-opened').show();
} else if (!r.configured) {
$('#not-configured').show();
} else if (r.encryptionKeyUnrecognized) {
$('#need-reconfigure').show();
$('#need-reconfigure-message').html(r.error);
$('#need-reconfigure-message').textContent = r.error;
} else if (!r.associated) {
$('#need-reconfigure').show();
$('#need-reconfigure-message').html(r.error);
$('#need-reconfigure-message').textContent = r.error;
} else if (r.error !== null) {
$('#error-encountered').show();
$('#error-message').html(r.error);
$('#error-message').textContent = r.error;
} else {
$('#configured-and-associated').show();
$('#associated-identifier').html(r.identifier);
$('#associated-identifier').textContent = r.identifier;
$('#lock-database-button').show();
if (r.usernameFieldDetected) {
@ -50,10 +58,10 @@ const sendMessageToTab = async function(message) {
return true;
};
$(async () => {
(async () => {
await initColorTheme();
$('#connect-button').click(async () => {
$('#connect-button').addEventListener('click', async () => {
await browser.runtime.sendMessage({
action: 'associate'
});
@ -63,27 +71,27 @@ $(async () => {
close();
});
$('#reconnect-button').click(async () => {
$('#reconnect-button').addEventListener('click', async () => {
await browser.runtime.sendMessage({
action: 'associate'
});
close();
});
$('#reload-status-button').click(async () => {
$('#reload-status-button').addEventListener('click', async () => {
statusResponse(await browser.runtime.sendMessage({
action: 'reconnect'
}));
});
$('#reopen-database-button').click(async () => {
$('#reopen-database-button').addEventListener('click', async () => {
statusResponse(await browser.runtime.sendMessage({
action: 'get_status',
args: [ false, true ] // Set forcePopup to true
}));
});
$('#redetect-fields-button').click(async () => {
$('#redetect-fields-button').addEventListener('click', async () => {
const res = await sendMessageToTab('redetect_fields');
if (!res) {
return;
@ -94,13 +102,13 @@ $(async () => {
}));
});
$('#lock-database-button').click(async () => {
$('#lock-database-button').addEventListener('click', async () => {
statusResponse(await browser.runtime.sendMessage({
action: 'lock_database'
}));
});
$('#username-only-button').click(async () => {
$('#username-only-button').addEventListener('click', async () => {
await sendMessageToTab('add_username_only_option');
await sendMessageToTab('redetect_fields');
$('#username-field-detected').hide();
@ -111,4 +119,4 @@ $(async () => {
}).catch((err) => {
logError('Could not get status: ' + err);
}));
});
})();

View file

@ -1,6 +1,8 @@
'use strict';
var $ = jQuery.noConflict(true);
const $ = function(elem) {
return document.querySelector(elem);
};
function updateAvailableResponse(available) {
if (available) {
@ -9,11 +11,11 @@ function updateAvailableResponse(available) {
}
async function initSettings() {
$('#settings #btn-options').click(() => {
$('#settings #btn-options').addEventListener('click', () => {
browser.runtime.openOptionsPage().then(close());
});
$('#settings #btn-choose-credential-fields').click(async () => {
$('#settings #btn-choose-credential-fields').addEventListener('click', async () => {
await browser.windows.getCurrent();
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
const tab = tabs[0];
@ -40,9 +42,14 @@ async function initColorTheme() {
}
$(async () => {
await initSettings();
(async () => {
if (document.readyState === 'complete' || (document.readyState !== 'loading' && !document.documentElement.doScroll)) {
await initSettings();
} else {
document.addEventListener('DOMContentLoaded', initSettings);
}
updateAvailableResponse(await browser.runtime.sendMessage({
action: 'update_available_keepassxc'
}));
});
})();

View file

@ -36,6 +36,16 @@
<button id="btn-dismiss" class="btn btn-sm btn-danger"><i class="fa fa-remove" aria-hidden="true"></i> <span data-i18n="popupButtonDismissHttpAuth"></span></button>
</p>
</div>
<div id="database-not-opened" style="display: none">
<p data-i18n="popupErrorEncountered"/>
<p style="margin-left: 1em">
<code id="database-error-message"></code>
</p>
<div style="text-align: right">
<button id="reopen-database-button" class="btn btn-sm btn-primary"><i class="fa fa-lock" aria-hidden="true"></i> <span data-i18n="popupReopenButton"></span></button>
</div>
</div>
</div>
</body>
</html>

View file

@ -6,7 +6,7 @@ const getLoginData = async () => {
return global.page.tabs[tabs[0].id].loginList;
};
$(async () => {
(async () => {
await initColorTheme();
const data = await getLoginData();
@ -15,10 +15,16 @@ $(async () => {
const a = document.createElement('a');
a.setAttribute('class', 'list-group-item');
a.textContent = data.logins[i].login + ' (' + data.logins[i].name + ')';
$(a).data('creds', data.logins[i]);
$(a).click(function() {
a.setAttribute('id', '' + i);
a.addEventListener('click', (e) => {
if (!e.isTrusted) {
return;
}
if (data.resolve) {
const creds = $(this).data('creds');
const id = e.target.id;
const creds = data.logins[Number(id)];
data.resolve({
authCredentials: {
username: creds.login,
@ -31,13 +37,18 @@ $(async () => {
ll.appendChild(a);
}
$('#lock-database-button').click(function() {
$('#lock-database-button').addEventListener('click', function() {
browser.runtime.sendMessage({
action: 'lock_database'
}).then(statusResponse);
});
$('.credentials').hide();
$('#btn-dismiss').hide();
$('#database-not-opened').show();
$('#database-error-message').textContent = tr('errorMessageDatabaseNotOpened');
});
$('#btn-dismiss').click(async () => {
$('#btn-dismiss').addEventListener('click', async () => {
const loginData = await getLoginData();
// Using reject won't work with every browser. So return empty credentials instead.
if (loginData.resolve) {
@ -50,4 +61,4 @@ $(async () => {
}
close();
});
});
})();

View file

@ -9,7 +9,6 @@
<link rel="stylesheet" href="../fonts/fork-awesome.min.css" />
<script src="../common/browser-polyfill.min.js"></script>
<script src="../common/global.js"></script>
<script src="../bootstrap/jquery-3.4.1.min.js"></script>
<script src="../bootstrap/bootstrap.min.js"></script>
<script src="popup_functions.js"></script>
<script src="popup_login.js"></script>

View file

@ -1,6 +1,6 @@
'use strict';
$(async () => {
(async () => {
await initColorTheme();
const global = await browser.runtime.getBackgroundPage();
@ -60,13 +60,14 @@ $(async () => {
filter.focus();
}
$('#lock-database-button').click((e) => {
$('#lock-database-button').addEventListener('click', (e) => {
browser.runtime.sendMessage({
action: 'lock_database'
});
$('#credentialsList').hide();
$('#database-not-opened').show();
$('#database-error-message').html(tr('errorMessageDatabaseNotOpened'));
$('#database-error-message').textContent = tr('errorMessageDatabaseNotOpened');
});
$('#reopen-database-button').click((e) => {
@ -75,4 +76,4 @@ $(async () => {
args: [ false, true ] // Set forcePopup to true
});
});
});
})();