improved ranking search

This commit is contained in:
antelle 2019-08-18 16:14:47 +02:00
parent 7c5b76fda3
commit a69cf5cd85
6 changed files with 90 additions and 48 deletions

View File

@ -174,7 +174,7 @@
"searchOptions": "Options",
"searchCase": "Match case",
"searchRegex": "RegEx",
"searchRank": "Rank",
"searchRank": "Auto",
"openOpen": "Open",
"openNew": "New",

View File

@ -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;

View File

@ -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);
}
});

View File

@ -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);
};
},

View File

@ -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;

View File

@ -2,6 +2,7 @@ Release notes
-------------
##### v1.9.1 (TBD)
`-` fix #1231: tooltip arrow positioning
`+` improved ranking search
##### v1.9.0 (2019-08-18)
`-` fix #1221: added '30 min' lock option