mirror of https://github.com/keeweb/keeweb.git
usernames autocomplete
This commit is contained in:
parent
35bd1ab3be
commit
8f35f64148
|
@ -224,6 +224,25 @@ var AppModel = Backbone.Model.extend({
|
|||
return { group: group, file: file };
|
||||
},
|
||||
|
||||
completeUserNames: function(part) {
|
||||
var userNames = {};
|
||||
this.files.forEach(function(file) {
|
||||
file.forEachEntry({ text: part, textLower: part.toLowerCase(), advanced: { user: true } }, function(entry) {
|
||||
var userName = entry.user;
|
||||
if (userName) {
|
||||
userNames[userName] = (userNames[userName] || 0) + 1;
|
||||
}
|
||||
});
|
||||
});
|
||||
var matches = _.pairs(userNames);
|
||||
matches.sort(function(x, y) { return y[1] - x[1]; });
|
||||
var maxResults = 5;
|
||||
if (matches.length > maxResults) {
|
||||
matches.length = maxResults;
|
||||
}
|
||||
return matches.map(function(m) { return m[0]; });
|
||||
},
|
||||
|
||||
createNewEntry: function() {
|
||||
var sel = this.getFirstSelectedGroup();
|
||||
return EntryModel.newEntry(sel.group, sel.file);
|
||||
|
|
|
@ -5,6 +5,7 @@ var Backbone = require('backbone'),
|
|||
AppSettingsModel = require('../../models/app-settings-model'),
|
||||
Scrollable = require('../../mixins/scrollable'),
|
||||
FieldViewText = require('../fields/field-view-text'),
|
||||
FieldViewAutocomplete = require('../fields/field-view-autocomplete'),
|
||||
FieldViewDate = require('../fields/field-view-date'),
|
||||
FieldViewTags = require('../fields/field-view-tags'),
|
||||
FieldViewUrl = require('../fields/field-view-url'),
|
||||
|
@ -118,8 +119,8 @@ var DetailsView = Backbone.View.extend({
|
|||
|
||||
addFieldViews: function() {
|
||||
var model = this.model;
|
||||
this.userEditView = new FieldViewText({ model: { name: '$UserName', title: Locale.detUser,
|
||||
value: function() { return model.user; } } });
|
||||
this.userEditView = new FieldViewAutocomplete({ model: { name: '$UserName', title: Locale.detUser,
|
||||
value: function() { return model.user; }, getCompletions: this.getUserNameCompletions.bind(this) } });
|
||||
this.fieldViews.push(this.userEditView);
|
||||
this.passEditView = new FieldViewText({ model: { name: '$Password', title: Locale.detPassword, canGen: true,
|
||||
value: function() { return model.password; } } });
|
||||
|
@ -167,6 +168,10 @@ var DetailsView = Backbone.View.extend({
|
|||
}, this);
|
||||
},
|
||||
|
||||
getUserNameCompletions: function(part) {
|
||||
return this.appModel.completeUserNames(part);
|
||||
},
|
||||
|
||||
setSelectedColor: function(color) {
|
||||
this.$el.find('.details__colors-popup > .details__colors-popup-item').removeClass('details__colors-popup-item--active');
|
||||
var colorEl = this.$el.find('.details__header-color')[0];
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
'use strict';
|
||||
|
||||
var FieldViewText = require('./field-view-text');
|
||||
|
||||
var FieldViewAutocomplete = FieldViewText.extend({
|
||||
endEdit: function(newVal, extra) {
|
||||
if (this.autocomplete) {
|
||||
this.autocomplete.remove();
|
||||
this.autocomplete = null;
|
||||
}
|
||||
FieldViewText.prototype.endEdit.call(this, newVal, extra);
|
||||
},
|
||||
|
||||
startEdit: function() {
|
||||
FieldViewText.prototype.startEdit.call(this);
|
||||
var fieldRect = this.input[0].getBoundingClientRect();
|
||||
this.autocomplete = $('<div class="details__field-autocomplete"></div>').appendTo('body');
|
||||
this.autocomplete.css({
|
||||
top: fieldRect.bottom,
|
||||
left: fieldRect.left,
|
||||
width: fieldRect.width - 2
|
||||
});
|
||||
this.autocomplete.mousedown(this.autocompleteClick.bind(this));
|
||||
if (!this.input.val()) {
|
||||
this.updateAutocomplete();
|
||||
}
|
||||
},
|
||||
|
||||
fieldValueInput: function(e) {
|
||||
e.stopPropagation();
|
||||
this.updateAutocomplete();
|
||||
FieldViewText.prototype.fieldValueInput.call(this, e);
|
||||
},
|
||||
|
||||
updateAutocomplete: function() {
|
||||
var completions = this.model.getCompletions(this.input.val());
|
||||
var completionsHtml = completions.map(function(item) {
|
||||
return '<div class="details__field-autocomplete-item">' + _.escape(item) + '</div>';
|
||||
}).join('');
|
||||
this.autocomplete.html(completionsHtml);
|
||||
this.autocomplete.toggle(!!completionsHtml);
|
||||
},
|
||||
|
||||
autocompleteClick: function(e) {
|
||||
e.stopPropagation();
|
||||
if (e.target.classList.contains('details__field-autocomplete-item')) {
|
||||
var selectedItem = $(e.target).text();
|
||||
this.input.val(selectedItem);
|
||||
this.endEdit(selectedItem);
|
||||
} else {
|
||||
this.afterPaint(function () { this.input.focus(); });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = FieldViewAutocomplete;
|
|
@ -35,7 +35,7 @@ var FieldViewTags = FieldViewText.extend({
|
|||
startEdit: function() {
|
||||
FieldViewText.prototype.startEdit.call(this);
|
||||
var fieldRect = this.input[0].getBoundingClientRect();
|
||||
this.tagsAutocomplete = $('<div class="details__tags-autocomplete"></div>').appendTo('body');
|
||||
this.tagsAutocomplete = $('<div class="details__field-autocomplete"></div>').appendTo('body');
|
||||
this.tagsAutocomplete.css({
|
||||
top: fieldRect.bottom,
|
||||
left: fieldRect.left,
|
||||
|
@ -63,7 +63,7 @@ var FieldViewTags = FieldViewText.extend({
|
|||
setTags: function() {
|
||||
var availableTags = this.getAvailableTags();
|
||||
var tagsHtml = availableTags.map(function(tag) {
|
||||
return '<div class="details__tags-autocomplete-tag">' + _.escape(tag) + '</div>';
|
||||
return '<div class="details__field-autocomplete-item">' + _.escape(tag) + '</div>';
|
||||
}).join('');
|
||||
this.tagsAutocomplete.html(tagsHtml);
|
||||
this.tagsAutocomplete.toggle(!!tagsHtml);
|
||||
|
@ -71,7 +71,7 @@ var FieldViewTags = FieldViewText.extend({
|
|||
|
||||
tagsAutocompleteClick: function(e) {
|
||||
e.stopPropagation();
|
||||
if (e.target.classList.contains('details__tags-autocomplete-tag')) {
|
||||
if (e.target.classList.contains('details__field-autocomplete-item')) {
|
||||
var selectedTag = $(e.target).text(), newVal = this.input.val();
|
||||
if (newVal) {
|
||||
var tags = this.valueToTags(newVal);
|
||||
|
|
|
@ -485,10 +485,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
&__tags-autocomplete {
|
||||
&__field-autocomplete {
|
||||
position: absolute;
|
||||
@include common-dropdown;
|
||||
&-tag {
|
||||
&-item {
|
||||
padding: $base-padding;
|
||||
display: inline-block;
|
||||
@include area-selectable(bottom);
|
||||
|
|
|
@ -11,6 +11,7 @@ Storage providers, usability improvements
|
|||
`+` regenerate password button
|
||||
`+` option to search in title
|
||||
`+` open files created without password
|
||||
`+` usernames autocomplete
|
||||
`-` fix #88: capslock indicator
|
||||
|
||||
##### v1.0.4 (2016-02-25)
|
||||
|
|
Loading…
Reference in New Issue