mirror of https://github.com/keeweb/keeweb.git
Rank calculation when searching and a new sorter based on that rank.
Rank is calculated as requested in #814. String rank calculation was taken from the auto type filter and moved into a mixin. Fixes #814
This commit is contained in:
parent
5204350453
commit
1b896f3218
|
@ -1,4 +1,5 @@
|
|||
const EntryCollection = require('../collections/entry-collection');
|
||||
const Ranking = require('../mixins/ranking');
|
||||
|
||||
const urlPartsRegex = /^(\w+:\/\/)?(?:(?:www|wwws|secure)\.)?([^\/]+)\/?(.*)/;
|
||||
|
||||
|
@ -78,22 +79,6 @@ AutoTypeFilter.prototype.getEntryRank = function(entry) {
|
|||
return rank;
|
||||
};
|
||||
|
||||
AutoTypeFilter.prototype.getStringRank = function(s1, s2) {
|
||||
let ix = s1.indexOf(s2);
|
||||
if (ix === 0 && s1.length === s2.length) {
|
||||
return 10;
|
||||
} else if (ix === 0) {
|
||||
return 5;
|
||||
} else if (ix > 0) {
|
||||
return 3;
|
||||
}
|
||||
ix = s2.indexOf(s1);
|
||||
if (ix === 0) {
|
||||
return 5;
|
||||
} else if (ix > 0) {
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
_.extend(AutoTypeFilter.prototype, Ranking);
|
||||
|
||||
module.exports = AutoTypeFilter;
|
||||
|
|
|
@ -19,7 +19,9 @@ const EntryCollection = Backbone.Collection.extend({
|
|||
'-created': Comparators.dateComparator('created', false),
|
||||
'updated': Comparators.dateComparator('updated', true),
|
||||
'-updated': Comparators.dateComparator('updated', false),
|
||||
'-attachments': function(x, y) { return this.attachmentSortVal(x).localeCompare(this.attachmentSortVal(y)); }
|
||||
'-attachments': function(x, y) { return this.attachmentSortVal(x).localeCompare(this.attachmentSortVal(y)); },
|
||||
'-rank': Comparators.rankComparator(false),
|
||||
'rank': Comparators.rankComparator(true),
|
||||
},
|
||||
|
||||
defaultComparator: 'title',
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
"help": "Help",
|
||||
"settings": "Settings",
|
||||
"plugins": "Plugins",
|
||||
"rank": "Rank",
|
||||
|
||||
"cache": "cache",
|
||||
"file": "file",
|
||||
|
@ -146,6 +147,9 @@
|
|||
"searchOptions": "Options",
|
||||
"searchCase": "Match case",
|
||||
"searchRegex": "RegEx",
|
||||
"searchRank": "Rank",
|
||||
"searchBestWorst": "Best {} Worst",
|
||||
"searchWorstBest": "Worst {} Best",
|
||||
|
||||
"openOpen": "Open",
|
||||
"openNew": "New",
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const Ranking = {
|
||||
getStringRank: function(s1, s2) {
|
||||
let ix = s1.indexOf(s2);
|
||||
if (ix === 0 && s1.length === s2.length) {
|
||||
return 10;
|
||||
} else if (ix === 0) {
|
||||
return 5;
|
||||
} else if (ix > 0) {
|
||||
return 3;
|
||||
}
|
||||
ix = s2.indexOf(s1);
|
||||
if (ix === 0) {
|
||||
return 5;
|
||||
} else if (ix > 0) {
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Ranking;
|
|
@ -5,6 +5,7 @@ const Color = require('../util/color');
|
|||
const IconUrl = require('../util/icon-url');
|
||||
const Otp = require('../util/otp');
|
||||
const kdbxweb = require('kdbxweb');
|
||||
const Ranking = require('../mixins/ranking');
|
||||
|
||||
const EntryModel = Backbone.Model.extend({
|
||||
defaults: {},
|
||||
|
@ -17,6 +18,7 @@ const EntryModel = Backbone.Model.extend({
|
|||
fieldRefIds: { T: 'Title', U: 'UserName', P: 'Password', A: 'URL', N: 'Notes' },
|
||||
|
||||
initialize: function() {
|
||||
this.set({rank: 0});
|
||||
},
|
||||
|
||||
setEntry: function(entry, group, file) {
|
||||
|
@ -185,6 +187,10 @@ const EntryModel = Backbone.Model.extend({
|
|||
},
|
||||
|
||||
matches: function(filter) {
|
||||
if (filter && filter.textLower && (!filter.advanced || filter.advanced.rank)) {
|
||||
// update rank, when rank calculation is enabled
|
||||
this.updateRank(filter.textLower);
|
||||
}
|
||||
return !filter ||
|
||||
(!filter.tagLower || this.searchTags.indexOf(filter.tagLower) >= 0) &&
|
||||
(!filter.textLower || (filter.advanced ? this.matchesAdv(filter) : this.searchText.indexOf(filter.textLower) >= 0)) &&
|
||||
|
@ -635,6 +641,51 @@ const EntryModel = Backbone.Model.extend({
|
|||
this.entry.times.creationTime = this.entry.times.lastModTime;
|
||||
this.entry.fields.Title = '';
|
||||
this._fillByEntry();
|
||||
},
|
||||
|
||||
updateRank: function(searchString) {
|
||||
let rank = 0;
|
||||
|
||||
const ranking = [
|
||||
{
|
||||
field: 'Title',
|
||||
multiplicator: 10
|
||||
},
|
||||
{
|
||||
field: 'URL',
|
||||
multiplicator: 8
|
||||
},
|
||||
{
|
||||
field: 'UserName',
|
||||
multiplicator: 5
|
||||
},
|
||||
{
|
||||
field: 'Notes',
|
||||
multiplicator: 2
|
||||
}
|
||||
];
|
||||
|
||||
const fieldNames = Object.keys(this.fields);
|
||||
_.forEach(fieldNames, field => {
|
||||
ranking.push(
|
||||
{
|
||||
field: field,
|
||||
multiplicator: 2
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
_.forEach(ranking, rankingEntry => {
|
||||
if (this._getFieldString(rankingEntry.field).toLowerCase() !== '') {
|
||||
const calculatedRank = this.getStringRank(
|
||||
searchString,
|
||||
this._getFieldString(rankingEntry.field).toLowerCase()
|
||||
) * rankingEntry.multiplicator;
|
||||
rank += calculatedRank;
|
||||
}
|
||||
});
|
||||
|
||||
this.set({rank: rank});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -657,4 +708,6 @@ EntryModel.newEntry = function(group, file) {
|
|||
return model;
|
||||
};
|
||||
|
||||
_.extend(EntryModel.prototype, Ranking);
|
||||
|
||||
module.exports = EntryModel;
|
||||
|
|
|
@ -13,6 +13,14 @@ const Comparators = {
|
|||
}
|
||||
},
|
||||
|
||||
rankComparator: function(asc) {
|
||||
if (asc) {
|
||||
return function (x, y) { return x.get('rank') - y.get('rank'); };
|
||||
} else {
|
||||
return function (x, y) { return y.get('rank') - x.get('rank'); };
|
||||
}
|
||||
},
|
||||
|
||||
dateComparator: function(field, asc) {
|
||||
if (asc) {
|
||||
return function (x, y) { return x[field] - y[field]; };
|
||||
|
|
|
@ -43,7 +43,9 @@ const ListSearchView = Backbone.View.extend({
|
|||
{ value: '-created', icon: 'sort-numeric-desc', loc: () => Locale.searchCreated + ' ' + this.addArrow(Locale.searchNO) },
|
||||
{ value: 'updated', icon: 'sort-numeric-asc', loc: () => Locale.searchUpdated + ' ' + this.addArrow(Locale.searchON) },
|
||||
{ value: '-updated', icon: 'sort-numeric-desc', loc: () => Locale.searchUpdated + ' ' + this.addArrow(Locale.searchNO) },
|
||||
{ value: '-attachments', icon: 'sort-amount-desc', loc: () => Locale.searchAttachments }
|
||||
{ value: '-attachments', icon: 'sort-amount-desc', loc: () => Locale.searchAttachments },
|
||||
{ value: '-rank', icon: 'sort-numeric-desc', loc: () => Locale.searchRank + ' ' + this.addArrow(Locale.searchBestWorst) },
|
||||
{ value: 'rank', icon: 'sort-numeric-asc', loc: () => Locale.searchRank + ' ' + this.addArrow(Locale.searchWorstBest) },
|
||||
];
|
||||
this.sortIcons = {};
|
||||
this.sortOptions.forEach(function(opt) {
|
||||
|
@ -55,7 +57,8 @@ const ListSearchView = Backbone.View.extend({
|
|||
url: true, protect: false,
|
||||
notes: true, pass: false,
|
||||
cs: false, regex: false,
|
||||
history: false, title: true
|
||||
history: false, title: true,
|
||||
rank: true
|
||||
};
|
||||
if (this.model.advancedSearch) {
|
||||
this.advancedSearch = _.extend({}, this.model.advancedSearch);
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
{{#if adv.regex}}checked{{/if}}><label for="list__search-adv-check-regex">{{res 'searchRegex'}}</label></div>
|
||||
<div class="list__search-check"><input type="checkbox" id="list__search-adv-check-history" data-id="history"
|
||||
{{#if adv.history}}checked{{/if}}><label for="list__search-adv-check-history">{{Res 'history'}}</label></div>
|
||||
<div class="list__search-check"><input type="checkbox" id="list__search-adv-check-rank" data-id="rank"
|
||||
{{#if adv.rank}}checked{{/if}}><label for="list__search-adv-check-rank">{{Res 'rank'}}</label></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue