2015-10-17 23:49:24 +02:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
var Backbone = require('backbone'),
|
|
|
|
Keys = require('../const/keys'),
|
2015-10-25 10:44:19 +01:00
|
|
|
KeyHandler = require('../comp/key-handler'),
|
2015-10-17 23:49:24 +02:00
|
|
|
DropdownView = require('./dropdown-view'),
|
2015-12-17 19:25:25 +01:00
|
|
|
FeatureDetector = require('../util/feature-detector'),
|
2016-08-23 22:20:13 +02:00
|
|
|
Format = require('../util/format'),
|
2015-12-17 19:25:25 +01:00
|
|
|
Locale = require('../util/locale');
|
2015-10-17 23:49:24 +02:00
|
|
|
|
|
|
|
var ListSearchView = Backbone.View.extend({
|
2015-12-16 22:50:45 +01:00
|
|
|
template: require('templates/list-search.hbs'),
|
2015-10-17 23:49:24 +02:00
|
|
|
|
|
|
|
events: {
|
|
|
|
'keydown .list__search-field': 'inputKeyDown',
|
|
|
|
'keypress .list__search-field': 'inputKeyPress',
|
|
|
|
'input .list__search-field': 'inputChange',
|
2016-08-11 19:51:54 +02:00
|
|
|
'focus .list__search-field': 'inputFocus',
|
2015-10-17 23:49:24 +02:00
|
|
|
'click .list__search-btn-new': 'createOptionsClick',
|
|
|
|
'click .list__search-btn-sort': 'sortOptionsClick',
|
2015-10-24 11:15:54 +02:00
|
|
|
'click .list__search-icon-search': 'advancedSearchClick',
|
2016-01-13 21:33:14 +01:00
|
|
|
'click .list__search-btn-menu': 'toggleMenu',
|
|
|
|
'change .list__search-adv input[type=checkbox]': 'toggleAdvCheck'
|
2015-10-17 23:49:24 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
views: null,
|
|
|
|
|
|
|
|
inputEl: null,
|
|
|
|
sortOptions: null,
|
|
|
|
sortIcons: null,
|
|
|
|
createOptions: null,
|
2016-01-13 21:33:14 +01:00
|
|
|
advancedSearchEnabled: false,
|
|
|
|
advancedSearch: null,
|
2015-10-17 23:49:24 +02:00
|
|
|
|
|
|
|
initialize: function () {
|
|
|
|
this.sortOptions = [
|
2016-08-25 18:30:22 +02:00
|
|
|
{ value: 'title', icon: 'sort-alpha-asc', loc: () => Format.capFirst(Locale.title) + ' ' + this.addArrow(Locale.searchAZ) },
|
|
|
|
{ value: '-title', icon: 'sort-alpha-desc', loc: () => Format.capFirst(Locale.title) + ' ' + this.addArrow(Locale.searchZA) },
|
|
|
|
{ value: 'website', icon: 'sort-alpha-asc', loc: () => Format.capFirst(Locale.website) + ' ' + this.addArrow(Locale.searchAZ) },
|
|
|
|
{ value: '-website', icon: 'sort-alpha-desc', loc: () => Format.capFirst(Locale.website) + ' ' + this.addArrow(Locale.searchZA) },
|
|
|
|
{ value: 'user', icon: 'sort-alpha-asc', loc: () => Format.capFirst(Locale.user) + ' ' + this.addArrow(Locale.searchAZ) },
|
|
|
|
{ value: '-user', icon: 'sort-alpha-desc', loc: () => Format.capFirst(Locale.user) + ' ' + this.addArrow(Locale.searchZA) },
|
|
|
|
{ value: 'created', icon: 'sort-numeric-asc', loc: () => Locale.searchCreated + ' ' + this.addArrow(Locale.searchON) },
|
|
|
|
{ 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 }
|
2015-10-17 23:49:24 +02:00
|
|
|
];
|
|
|
|
this.sortIcons = {};
|
|
|
|
this.sortOptions.forEach(function(opt) {
|
|
|
|
this.sortIcons[opt.value] = opt.icon;
|
|
|
|
}, this);
|
|
|
|
this.views = {};
|
2016-01-13 21:33:14 +01:00
|
|
|
this.advancedSearch = {
|
|
|
|
user: true, other: true,
|
|
|
|
url: true, protect: false,
|
|
|
|
notes: true, pass: false,
|
|
|
|
cs: false, regex: false,
|
2016-02-25 20:50:31 +01:00
|
|
|
history: false, title: true
|
2016-01-13 21:33:14 +01:00
|
|
|
};
|
2016-08-25 18:30:22 +02:00
|
|
|
this.setLocale();
|
2015-10-17 23:49:24 +02:00
|
|
|
KeyHandler.onKey(Keys.DOM_VK_F, this.findKeyPress, this, KeyHandler.SHORTCUT_ACTION);
|
|
|
|
KeyHandler.onKey(Keys.DOM_VK_N, this.newKeyPress, this, KeyHandler.SHORTCUT_OPT);
|
|
|
|
KeyHandler.onKey(Keys.DOM_VK_DOWN, this.downKeyPress, this);
|
|
|
|
KeyHandler.onKey(Keys.DOM_VK_UP, this.upKeyPress, this);
|
|
|
|
this.listenTo(this, 'show', this.viewShown);
|
|
|
|
this.listenTo(this, 'hide', this.viewHidden);
|
|
|
|
this.listenTo(Backbone, 'filter', this.filterChanged);
|
2016-08-25 18:30:22 +02:00
|
|
|
this.listenTo(Backbone, 'set-locale', this.setLocale);
|
2016-09-05 21:14:50 +02:00
|
|
|
this.listenTo(Backbone, 'page-blur', this.pageBlur);
|
2015-10-17 23:49:24 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
remove: function() {
|
|
|
|
KeyHandler.offKey(Keys.DOM_VK_F, this.findKeyPress, this);
|
|
|
|
KeyHandler.offKey(Keys.DOM_VK_N, this.newKeyPress, this);
|
|
|
|
KeyHandler.offKey(Keys.DOM_VK_DOWN, this.downKeyPress, this);
|
|
|
|
KeyHandler.offKey(Keys.DOM_VK_UP, this.upKeyPress, this);
|
|
|
|
Backbone.View.prototype.remove.apply(this, arguments);
|
|
|
|
},
|
|
|
|
|
2016-08-25 18:30:22 +02:00
|
|
|
setLocale: function() {
|
2016-08-25 18:45:01 +02:00
|
|
|
this.sortOptions.forEach(opt => { opt.text = opt.loc(); });
|
2016-08-25 18:30:22 +02:00
|
|
|
var entryDesc = FeatureDetector.isMobile ? '' : (' <span class="muted-color">(' + Locale.searchShiftClickOr + ' ' +
|
|
|
|
FeatureDetector.altShortcutSymbol(true) + 'N)</span>');
|
|
|
|
this.createOptions = [
|
|
|
|
{ value: 'entry', icon: 'key', text: Format.capFirst(Locale.entry) + entryDesc },
|
|
|
|
{ value: 'group', icon: 'folder', text: Format.capFirst(Locale.group) }
|
|
|
|
];
|
2016-09-04 23:51:01 +02:00
|
|
|
this.render();
|
2016-08-25 18:30:22 +02:00
|
|
|
},
|
|
|
|
|
2016-09-05 21:14:50 +02:00
|
|
|
pageBlur: function() {
|
|
|
|
this.inputEl.blur();
|
|
|
|
},
|
|
|
|
|
2015-10-17 23:49:24 +02:00
|
|
|
viewShown: function() {
|
|
|
|
this.listenTo(KeyHandler, 'keypress', this.documentKeyPress);
|
|
|
|
},
|
|
|
|
|
|
|
|
viewHidden: function() {
|
|
|
|
this.stopListening(KeyHandler, 'keypress', this.documentKeyPress);
|
|
|
|
},
|
|
|
|
|
|
|
|
render: function () {
|
2016-09-04 23:51:01 +02:00
|
|
|
let searchVal;
|
|
|
|
if (this.inputEl) {
|
|
|
|
searchVal = this.inputEl.val();
|
|
|
|
}
|
|
|
|
this.renderTemplate({
|
|
|
|
adv: this.advancedSearch,
|
|
|
|
advEnabled: this.advancedSearchEnabled
|
|
|
|
});
|
2015-10-17 23:49:24 +02:00
|
|
|
this.inputEl = this.$el.find('.list__search-field');
|
2016-09-04 23:51:01 +02:00
|
|
|
if (searchVal) {
|
|
|
|
this.inputEl.val(searchVal);
|
|
|
|
}
|
2015-10-17 23:49:24 +02:00
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
inputKeyDown: function(e) {
|
|
|
|
switch (e.which) {
|
|
|
|
case Keys.DOM_VK_UP:
|
|
|
|
case Keys.DOM_VK_DOWN:
|
|
|
|
break;
|
|
|
|
case Keys.DOM_VK_RETURN:
|
|
|
|
e.target.blur();
|
|
|
|
break;
|
|
|
|
case Keys.DOM_VK_ESCAPE:
|
|
|
|
if (this.inputEl.val()) {
|
|
|
|
this.inputEl.val('');
|
|
|
|
this.inputChange();
|
|
|
|
}
|
|
|
|
e.target.blur();
|
|
|
|
break;
|
2016-01-10 23:20:42 +01:00
|
|
|
case Keys.DOM_VK_A:
|
|
|
|
if (e.metaKey || e.ctrlKey) {
|
|
|
|
e.stopPropagation();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
return;
|
2015-10-17 23:49:24 +02:00
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
e.preventDefault();
|
|
|
|
},
|
|
|
|
|
|
|
|
inputKeyPress: function(e) {
|
|
|
|
e.stopPropagation();
|
|
|
|
},
|
|
|
|
|
|
|
|
inputChange: function() {
|
|
|
|
Backbone.trigger('add-filter', { text: this.inputEl.val() });
|
|
|
|
},
|
|
|
|
|
2016-08-11 19:51:54 +02:00
|
|
|
inputFocus: function(e) {
|
|
|
|
$(e.target).select();
|
|
|
|
},
|
|
|
|
|
2015-10-17 23:49:24 +02:00
|
|
|
documentKeyPress: function(e) {
|
|
|
|
if (this._hidden) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var code = e.charCode;
|
|
|
|
if (!code) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.hideSearchOptions();
|
|
|
|
this.inputEl.val(String.fromCharCode(code)).focus();
|
|
|
|
this.inputEl[0].setSelectionRange(1, 1);
|
|
|
|
this.inputChange();
|
|
|
|
e.preventDefault();
|
|
|
|
},
|
|
|
|
|
|
|
|
findKeyPress: function(e) {
|
|
|
|
if (!this._hidden) {
|
|
|
|
e.preventDefault();
|
|
|
|
this.hideSearchOptions();
|
2016-07-18 19:18:19 +02:00
|
|
|
this.inputEl.select().focus();
|
2015-10-17 23:49:24 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
newKeyPress: function(e) {
|
|
|
|
if (!this._hidden) {
|
|
|
|
e.preventDefault();
|
|
|
|
this.hideSearchOptions();
|
|
|
|
this.trigger('create-entry');
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
downKeyPress: function(e) {
|
|
|
|
e.preventDefault();
|
|
|
|
this.hideSearchOptions();
|
|
|
|
this.trigger('select-next');
|
|
|
|
},
|
|
|
|
|
|
|
|
upKeyPress: function(e) {
|
|
|
|
e.preventDefault();
|
|
|
|
this.hideSearchOptions();
|
|
|
|
this.trigger('select-prev');
|
|
|
|
},
|
|
|
|
|
|
|
|
filterChanged: function(filter) {
|
|
|
|
this.hideSearchOptions();
|
|
|
|
if (filter.filter.text !== this.inputEl.val()) {
|
|
|
|
this.inputEl.val(filter.text || '');
|
|
|
|
}
|
|
|
|
var sortIconCls = this.sortIcons[filter.sort] || 'sort';
|
|
|
|
this.$el.find('.list__search-btn-sort>i').attr('class', 'fa fa-' + sortIconCls);
|
2016-01-16 15:19:33 +01:00
|
|
|
var adv = !!filter.filter.advanced;
|
|
|
|
if (this.advancedSearchEnabled !== adv) {
|
|
|
|
this.advancedSearchEnabled = adv;
|
2016-01-14 18:35:17 +01:00
|
|
|
this.$el.find('.list__search-adv').toggleClass('hide', !this.advancedSearchEnabled);
|
|
|
|
}
|
2015-10-17 23:49:24 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
createOptionsClick: function(e) {
|
|
|
|
e.stopImmediatePropagation();
|
|
|
|
if (e.shiftKey) {
|
|
|
|
this.hideSearchOptions();
|
|
|
|
this.trigger('create-entry');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.toggleCreateOptions();
|
|
|
|
},
|
|
|
|
|
|
|
|
sortOptionsClick: function(e) {
|
|
|
|
this.toggleSortOptions();
|
|
|
|
e.stopImmediatePropagation();
|
|
|
|
},
|
|
|
|
|
|
|
|
advancedSearchClick: function() {
|
2016-01-13 21:33:14 +01:00
|
|
|
this.advancedSearchEnabled = !this.advancedSearchEnabled;
|
|
|
|
this.$el.find('.list__search-adv').toggleClass('hide', !this.advancedSearchEnabled);
|
|
|
|
Backbone.trigger('add-filter', { advanced: this.advancedSearchEnabled ? this.advancedSearch : false });
|
2015-10-17 23:49:24 +02:00
|
|
|
},
|
|
|
|
|
2015-10-24 11:15:54 +02:00
|
|
|
toggleMenu: function() {
|
|
|
|
Backbone.trigger('toggle-menu');
|
|
|
|
},
|
|
|
|
|
2016-01-13 21:33:14 +01:00
|
|
|
toggleAdvCheck: function(e) {
|
|
|
|
var setting = $(e.target).data('id');
|
|
|
|
this.advancedSearch[setting] = e.target.checked;
|
|
|
|
Backbone.trigger('add-filter', { advanced: this.advancedSearch });
|
|
|
|
},
|
|
|
|
|
2015-10-17 23:49:24 +02:00
|
|
|
hideSearchOptions: function() {
|
|
|
|
if (this.views.searchDropdown) {
|
|
|
|
this.views.searchDropdown.remove();
|
|
|
|
this.views.searchDropdown = null;
|
|
|
|
this.$el.find('.list__search-btn-sort,.list__search-btn-new').removeClass('sel--active');
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
toggleSortOptions: function() {
|
|
|
|
if (this.views.searchDropdown && this.views.searchDropdown.options === this.sortOptions) {
|
|
|
|
this.hideSearchOptions();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.hideSearchOptions();
|
|
|
|
this.$el.find('.list__search-btn-sort').addClass('sel--active');
|
|
|
|
var view = new DropdownView();
|
|
|
|
this.listenTo(view, 'cancel', this.hideSearchOptions);
|
|
|
|
this.listenTo(view, 'select', this.sortDropdownSelect);
|
|
|
|
this.sortOptions.forEach(function(opt) {
|
|
|
|
opt.active = this.model.sort === opt.value;
|
|
|
|
}, this);
|
|
|
|
view.render({
|
|
|
|
position: {
|
|
|
|
top: this.$el.find('.list__search-btn-sort')[0].getBoundingClientRect().bottom,
|
|
|
|
right: this.$el[0].getBoundingClientRect().right + 1
|
|
|
|
},
|
|
|
|
options: this.sortOptions
|
|
|
|
});
|
|
|
|
this.views.searchDropdown = view;
|
|
|
|
},
|
|
|
|
|
|
|
|
toggleCreateOptions: function() {
|
|
|
|
if (this.views.searchDropdown && this.views.searchDropdown.options === this.createOptions) {
|
|
|
|
this.hideSearchOptions();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.hideSearchOptions();
|
|
|
|
this.$el.find('.list__search-btn-new').addClass('sel--active');
|
|
|
|
var view = new DropdownView();
|
|
|
|
this.listenTo(view, 'cancel', this.hideSearchOptions);
|
|
|
|
this.listenTo(view, 'select', this.createDropdownSelect);
|
|
|
|
view.render({
|
|
|
|
position: {
|
|
|
|
top: this.$el.find('.list__search-btn-new')[0].getBoundingClientRect().bottom,
|
|
|
|
right: this.$el[0].getBoundingClientRect().right + 1
|
|
|
|
},
|
|
|
|
options: this.createOptions
|
|
|
|
});
|
|
|
|
this.views.searchDropdown = view;
|
|
|
|
},
|
|
|
|
|
|
|
|
sortDropdownSelect: function(e) {
|
|
|
|
this.hideSearchOptions();
|
|
|
|
Backbone.trigger('set-sort', e.item);
|
|
|
|
},
|
|
|
|
|
|
|
|
createDropdownSelect: function(e) {
|
|
|
|
this.hideSearchOptions();
|
|
|
|
switch (e.item) {
|
|
|
|
case 'entry':
|
|
|
|
this.trigger('create-entry');
|
|
|
|
break;
|
|
|
|
case 'group':
|
|
|
|
this.trigger('create-group');
|
|
|
|
break;
|
|
|
|
}
|
2016-07-30 11:25:22 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
addArrow(str) {
|
|
|
|
return str.replace('{}', '→');
|
2015-10-17 23:49:24 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
module.exports = ListSearchView;
|