mirror of https://github.com/keeweb/keeweb.git
Merge branch 'master' into release-1.9
This commit is contained in:
commit
f5b4a2a887
|
@ -221,7 +221,7 @@ const Launcher = {
|
|||
spawn(config) {
|
||||
const ts = logger.ts();
|
||||
let complete = config.complete;
|
||||
const ps = this.req('child_process').spawn(config.cmd, config.args);
|
||||
const ps = this.remReq('child_process').spawn(config.cmd, config.args);
|
||||
[ps.stdin, ps.stdout, ps.stderr].forEach(s => s.setEncoding('utf-8'));
|
||||
let stderr = '';
|
||||
let stdout = '';
|
||||
|
|
|
@ -174,7 +174,7 @@
|
|||
"searchOptions": "Options",
|
||||
"searchCase": "Match case",
|
||||
"searchRegex": "RegEx",
|
||||
"searchRank": "Rank",
|
||||
"searchRank": "Auto",
|
||||
|
||||
"openOpen": "Open",
|
||||
"openNew": "New",
|
||||
|
|
|
@ -109,6 +109,8 @@
|
|||
"genPresetMac": "MAC-Adresse",
|
||||
"genPresetHash128": "128-Bit Hash",
|
||||
"genPresetHash256": "256-Bit Hash",
|
||||
"genHidePass": "Password ausblenden",
|
||||
"genShowPass": "Passwort einblenden",
|
||||
"grpTitle": "Gruppe",
|
||||
"grpSearch": "Suche für Einträge in dieser Gruppe aktivieren",
|
||||
"grpAutoType": "Auto-Type aktivieren",
|
||||
|
@ -174,6 +176,7 @@
|
|||
"searchOptions": "Suchoptionen",
|
||||
"searchCase": "Groß/klein",
|
||||
"searchRegex": "RegEx",
|
||||
"searchRank": "Automatisch",
|
||||
"openOpen": "Öffnen",
|
||||
"openNew": "Neu",
|
||||
"openMore": "Mehr",
|
||||
|
@ -215,6 +218,7 @@
|
|||
"openErrorFileNotFound": "Datei nicht gefunden",
|
||||
"openListErrorBody": "Dateien konnten nicht geladen werden",
|
||||
"openShowAllFiles": "Alle Dateien anzeigen",
|
||||
"openFileNoCacheError": "Die Datei wurde im Cache-Speicher nicht gefunden. Möglicherweise wurde Ihr Browser-Speicher geleert. Um die Datei zu öffnen, entfernen Sie sie aus KeeWeb und fügen Sie sie erneut hinzu",
|
||||
"detAttDownload": "Umschalttaste + Klick auf den Anhang-Button zum Herunterladen oder",
|
||||
"detAttDelToRemove": "Backspace zum entfernen",
|
||||
"detEmpty": "Ihre Passwörter werden hier angezeigt",
|
||||
|
@ -236,8 +240,8 @@
|
|||
"detHistoryRevertAlertBody": "Ihr aktueller Stand wird in der Historie gesichert.",
|
||||
"detHistoryDeleteAlert": "Diesen Stand löschen?",
|
||||
"detHistoryDeleteAlertBody": "Sie können ihn nicht wiederherstellen.",
|
||||
"detHistoryDiscardChangesAlert": "Änderung verwerfen?",
|
||||
"detHistoryDiscardChangesAlertBody": "Ungesicherte Änderungen sind unwiderruflich verloren.",
|
||||
"detHistoryDiscardChangesAlert": "Änderungen an diesem Eintrag verwerfen?",
|
||||
"detHistoryDiscardChangesAlertBody": "Ungespeicherte Änderungen gehen dabei unwiderruflich verloren.",
|
||||
"detBackToList": "zurück zur Liste",
|
||||
"detSetIconColor": "Farbe ändern",
|
||||
"detSetIcon": "Icon ändern",
|
||||
|
@ -325,8 +329,8 @@
|
|||
"appSaveErrorBody": "Automatisches Speichern fehlgeschlagen",
|
||||
"appSaveErrorBodyMul": "Automatisches Speichern fehlgeschlagen:",
|
||||
"appSettingsError": "Fehler beim Laden der App",
|
||||
"appSettingsErrorBody": "Es gab einen Fehler beim Laden der App-Einstellungen. Bitte überprüfen Sie die App URL oder kontaktieren Sie Ihren Systemadministrator.",
|
||||
"appNotSupportedError": "Ihr Browser wird nicht unterstützt.",
|
||||
"appSettingsErrorBody": "Es gab einen Fehler beim Laden der App-Einstellungen. Bitte überprüfen Sie die App-URL oder kontaktieren Sie Ihren Systemadministrator.",
|
||||
"appNotSupportedError": "Ihr Browser unterstützt einige wichtige Funktionen nicht, die für diese App benötigt werden.",
|
||||
"appTabWarn": "Zu viele Tabs",
|
||||
"appTabWarnBody": "KeeWeb kann nicht in mehreren Browser-Tabs gleichzeitig genutzt werden, bitte schließen Sie diesen Tab.",
|
||||
"appRightsAlert": "Schreibschutz für KeeWeb wird eingerichtet",
|
||||
|
@ -378,6 +382,7 @@
|
|||
"setGenShowSubgroups": "Einträge aus allen Untergruppen anzeigen",
|
||||
"setGenTableView": "Einträge in Tabellenansicht anzeigen",
|
||||
"setGenColorfulIcons": "Eigene Icons in der Listenansicht farbig anzeigen",
|
||||
"setGenDirectAutotype": "Wenn nur ein passender Eintrag gefunden wird, diesen automatisch für Auto-Type auswählen",
|
||||
"setGenFunction": "Arbeitsweise",
|
||||
"setGenAutoSyncOnClose": "Beim Schließen speichern und synchronisieren",
|
||||
"setGenAutoSyncTimer": "Regelmäßig speichern und synchronisieren",
|
||||
|
@ -387,7 +392,7 @@
|
|||
"setGenNoRememberKeyFiles": "Nicht merken",
|
||||
"setGenRememberKeyFilesData": "Im internen App-Speicher ablegen",
|
||||
"setGenRememberKeyFilesPath": "Nur Speicherort der Schlüsseldateien merken",
|
||||
"setGenLockInactive": "Automatisch sperren, wenn die App inaktiv ist",
|
||||
"setGenLockInactive": "Wenn die App inaktiv ist",
|
||||
"setGenNoAutoLock": "Nicht automatisch sperren",
|
||||
"setGenLockMinutes": "Nach {} Minuten",
|
||||
"setGenLockHour": "In einer Stunde",
|
||||
|
@ -399,7 +404,7 @@
|
|||
"setGenClearMinute": "Nach einer Minute",
|
||||
"setGenMinInstead": "App beim Schließen stattdessen minimieren",
|
||||
"setGenLock": "Automatisch sperren",
|
||||
"setGenLockMinimize": "Beim Minimieren automatisch sperren",
|
||||
"setGenLockMinimize": "Beim Minimieren der App",
|
||||
"setGenLockCopy": "Nach dem Kopieren eines Passworts",
|
||||
"setGenLockAutoType": "Bei Auto-Type",
|
||||
"setGenLockOrSleep": "Bei Aktivierung von Bildschirmsperre oder Ruhezustand",
|
||||
|
@ -410,6 +415,7 @@
|
|||
"setGenTryBetaWarning": "Ungespeicherte Dateien",
|
||||
"setGenTryBetaWarningBody": "Bitte speichern Sie alle Dateien und Klicken Sie erneut auf diesen Button",
|
||||
"setGenShowAppLogs": "App-Logs anzeigen",
|
||||
"setGenReloadApp": "App neu laden",
|
||||
"setFilePath": "Dateipfad",
|
||||
"setFileStorage": "Diese Datei wird von {} geladen.",
|
||||
"setFileIntl": "Diese Datei ist im internen App-Speicher abgelegt",
|
||||
|
@ -491,7 +497,7 @@
|
|||
"setShGen": "Passwort generieren",
|
||||
"setShSet": "App-Einstellungen",
|
||||
"setShCopyPassGlobal": "Passwort kopieren (wenn die App im Hintergrund ist)",
|
||||
"setShCopyUserGlobal": "Usernamen kopieren (wenn die App im Hintergrund ist)",
|
||||
"setShCopyUserGlobal": "Benutzer kopieren (wenn die App im Hintergrund ist)",
|
||||
"setShCopyUrlGlobal": "Website kopieren (wenn die App im Hintergrund ist)",
|
||||
"setShAutoTypeGlobal": "Auto-Type (wenn die App im Hintergrund ist)",
|
||||
"setShLock": "Datenbank sperren",
|
||||
|
|
|
@ -63,6 +63,12 @@ kdbxweb.ProtectedValue.prototype.forEachChar = function(fn) {
|
|||
}
|
||||
};
|
||||
|
||||
Object.defineProperty(kdbxweb.ProtectedValue.prototype, 'length', {
|
||||
get() {
|
||||
return this.textLength;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(kdbxweb.ProtectedValue.prototype, 'textLength', {
|
||||
get() {
|
||||
let textLength = 0;
|
||||
|
@ -74,12 +80,18 @@ Object.defineProperty(kdbxweb.ProtectedValue.prototype, 'textLength', {
|
|||
});
|
||||
|
||||
kdbxweb.ProtectedValue.prototype.includesLower = function(findLower) {
|
||||
let matches = false;
|
||||
return this.indexOfLower(findLower) !== -1;
|
||||
};
|
||||
|
||||
kdbxweb.ProtectedValue.prototype.indexOfLower = function(findLower) {
|
||||
let index = -1;
|
||||
const foundSeqs = [];
|
||||
const len = findLower.length;
|
||||
let chIndex = -1;
|
||||
this.forEachChar(ch => {
|
||||
chIndex++;
|
||||
ch = String.fromCharCode(ch).toLowerCase();
|
||||
if (matches) {
|
||||
if (index !== -1) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < foundSeqs.length; i++) {
|
||||
|
@ -90,17 +102,45 @@ kdbxweb.ProtectedValue.prototype.includesLower = function(findLower) {
|
|||
continue;
|
||||
}
|
||||
if (seqIx === len - 1) {
|
||||
matches = true;
|
||||
index = chIndex - len + 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (findLower[0] === ch) {
|
||||
foundSeqs.push(0);
|
||||
if (len === 1) {
|
||||
index = chIndex - len + 1;
|
||||
} else {
|
||||
foundSeqs.push(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
return matches;
|
||||
return index;
|
||||
};
|
||||
|
||||
kdbxweb.ProtectedValue.prototype.indexOfSelfInLower = function(targetLower) {
|
||||
let firstCharIndex = -1;
|
||||
let found = false;
|
||||
do {
|
||||
let chIndex = -1;
|
||||
this.forEachChar(ch => {
|
||||
chIndex++;
|
||||
ch = String.fromCharCode(ch).toLowerCase();
|
||||
if (chIndex === 0) {
|
||||
firstCharIndex = targetLower.indexOf(ch, firstCharIndex + 1);
|
||||
found = firstCharIndex !== -1;
|
||||
return;
|
||||
}
|
||||
if (!found) {
|
||||
return;
|
||||
}
|
||||
found = targetLower[firstCharIndex + chIndex] === ch;
|
||||
});
|
||||
} while (!found && firstCharIndex >= 0);
|
||||
return firstCharIndex;
|
||||
};
|
||||
|
||||
window.PV = kdbxweb.ProtectedValue;
|
||||
|
||||
kdbxweb.ProtectedValue.prototype.equals = function(other) {
|
||||
if (!other) {
|
||||
return false;
|
||||
|
|
|
@ -671,53 +671,39 @@ const EntryModel = Backbone.Model.extend({
|
|||
this._fillByEntry();
|
||||
},
|
||||
|
||||
getRank(searchString) {
|
||||
getRank(filter) {
|
||||
const searchString = filter.textLower;
|
||||
|
||||
if (!searchString) {
|
||||
// no search string given, so rank all items the same
|
||||
return 0;
|
||||
}
|
||||
|
||||
let rank = 0;
|
||||
const checkProtectedFields = filter.advanced && filter.advanced.protect;
|
||||
|
||||
const ranking = [
|
||||
{
|
||||
field: 'Title',
|
||||
multiplicator: 10
|
||||
},
|
||||
{
|
||||
field: 'URL',
|
||||
multiplicator: 8
|
||||
},
|
||||
{
|
||||
field: 'UserName',
|
||||
multiplicator: 5
|
||||
},
|
||||
{
|
||||
field: 'Notes',
|
||||
multiplicator: 2
|
||||
const fieldWeights = {
|
||||
'Title': 10,
|
||||
'URL': 8,
|
||||
'UserName': 5,
|
||||
'Notes': 2
|
||||
};
|
||||
|
||||
const defaultFieldWeight = 2;
|
||||
|
||||
const allFields = Object.keys(fieldWeights).concat(Object.keys(this.fields));
|
||||
|
||||
return allFields.reduce((rank, fieldName) => {
|
||||
const val = this.entry.fields[fieldName];
|
||||
if (!val) {
|
||||
return rank;
|
||||
}
|
||||
];
|
||||
|
||||
const fieldNames = Object.keys(this.fields);
|
||||
_.forEach(fieldNames, field => {
|
||||
ranking.push({
|
||||
field,
|
||||
multiplicator: 2
|
||||
});
|
||||
});
|
||||
|
||||
_.forEach(ranking, rankingEntry => {
|
||||
if (this._getFieldString(rankingEntry.field).toLowerCase() !== '') {
|
||||
const calculatedRank =
|
||||
Ranking.getStringRank(
|
||||
searchString,
|
||||
this._getFieldString(rankingEntry.field).toLowerCase()
|
||||
) * rankingEntry.multiplicator;
|
||||
rank += calculatedRank;
|
||||
if (val.isProtected && (!checkProtectedFields || !val.length)) {
|
||||
return rank;
|
||||
}
|
||||
});
|
||||
|
||||
return rank;
|
||||
const stringRank = Ranking.getStringRank(searchString, val);
|
||||
const fieldWeight = fieldWeights[fieldName] || defaultFieldWeight;
|
||||
return rank + stringRank * fieldWeight;
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ const Comparators = {
|
|||
|
||||
rankComparator() {
|
||||
return function(x, y) {
|
||||
return y.getRank(this.filter.textLower) - x.getRank(this.filter.textLower);
|
||||
return y.getRank(this.filter) - x.getRank(this.filter);
|
||||
};
|
||||
},
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
const Ranking = {
|
||||
getStringRank(s1, s2) {
|
||||
let ix = s1.indexOf(s2);
|
||||
if (!s1 || !s2) {
|
||||
return 0;
|
||||
}
|
||||
let ix = indexOf(s1, s2);
|
||||
if (ix === 0 && s1.length === s2.length) {
|
||||
return 10;
|
||||
} else if (ix === 0) {
|
||||
|
@ -8,7 +11,7 @@ const Ranking = {
|
|||
} else if (ix > 0) {
|
||||
return 3;
|
||||
}
|
||||
ix = s2.indexOf(s1);
|
||||
ix = indexOf(s2, s1);
|
||||
if (ix === 0) {
|
||||
return 5;
|
||||
} else if (ix > 0) {
|
||||
|
@ -18,4 +21,16 @@ const Ranking = {
|
|||
}
|
||||
};
|
||||
|
||||
function indexOf(target, search) {
|
||||
if (target.isProtected) {
|
||||
return target.indexOfLower(search);
|
||||
}
|
||||
if (search.isProtected) {
|
||||
return search.indexOfSelfInLower(target);
|
||||
}
|
||||
return target.indexOf(search);
|
||||
}
|
||||
|
||||
window.Ranking = Ranking;
|
||||
|
||||
module.exports = Ranking;
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
$arrow-offset-large: 11px;
|
||||
|
||||
&.tip--bottom:after {
|
||||
@include position(absolute, -nth($arrow-size-small, 2) null null 50%);
|
||||
@include position(absolute, -(nth($arrow-size-small, 2)) null null 50%);
|
||||
@include transform(translate(-50%, 0));
|
||||
@include th {
|
||||
@include triangle($arrow-size-small, th(background-color), up);
|
||||
|
@ -69,7 +69,7 @@
|
|||
}
|
||||
}
|
||||
&.tip--right:after {
|
||||
@include position(absolute, 50% null null (-nth($arrow-size-small, 2)));
|
||||
@include position(absolute, 50% null null (-(nth($arrow-size-small, 2))));
|
||||
@include transform(translate(0, -50%));
|
||||
@include th {
|
||||
@include triangle($arrow-size-small, th(background-color), left);
|
||||
|
@ -77,7 +77,7 @@
|
|||
}
|
||||
|
||||
&.tip--bottom:before {
|
||||
@include position(absolute, -nth($arrow-size-large, 2) null null 50%);
|
||||
@include position(absolute, (-(nth($arrow-size-large, 2))) null null 50%);
|
||||
@include transform(translate(-50%, 0));
|
||||
@include th {
|
||||
@include triangle($arrow-size-large, th(light-border-color), up);
|
||||
|
@ -105,7 +105,7 @@
|
|||
}
|
||||
}
|
||||
&.tip--right:before {
|
||||
@include position(absolute, 50% null null (-nth($arrow-size-large, 2)));
|
||||
@include position(absolute, 50% null null (-(nth($arrow-size-large, 2))));
|
||||
@include transform(translate(0, -50%));
|
||||
@include th {
|
||||
@include triangle($arrow-size-large, th(light-border-color), left);
|
||||
|
|
|
@ -345,6 +345,8 @@ function setMenu() {
|
|||
];
|
||||
const menu = electron.Menu.buildFromTemplate(template);
|
||||
electron.Menu.setApplicationMenu(menu);
|
||||
} else {
|
||||
mainWindow.setMenuBarVisibility(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "KeeWeb",
|
||||
"version": "1.9.0",
|
||||
"version": "1.9.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "KeeWeb",
|
||||
"version": "1.9.0",
|
||||
"version": "1.9.1",
|
||||
"description": "Free cross-platform password manager compatible with KeePass",
|
||||
"main": "main.js",
|
||||
"homepage": "https://keeweb.info",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "keeweb",
|
||||
"version": "1.9.0",
|
||||
"version": "1.9.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "keeweb",
|
||||
"version": "1.9.0",
|
||||
"version": "1.9.1",
|
||||
"description": "Free cross-platform password manager compatible with KeePass",
|
||||
"main": "Gruntfile.js",
|
||||
"private": true,
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
Release notes
|
||||
-------------
|
||||
##### v1.9.1 (2019-08-19)
|
||||
`-` fix #1231: tooltip arrow positioning
|
||||
`+` improved ranking search
|
||||
`-` fix #1232: removed an unwanted menubar on windows and linux
|
||||
`-` fix #1234: auto-type not working on linux
|
||||
|
||||
##### v1.9.0 (2019-08-18)
|
||||
`-` fix #1221: added '30 min' lock option
|
||||
`-` fixed generator style issues in Firefox
|
||||
|
|
Loading…
Reference in New Issue