mirror of https://github.com/keeweb/keeweb.git
entries list display table layout
This commit is contained in:
parent
7cf2f6634d
commit
898000c936
3
TODO.md
3
TODO.md
|
@ -8,7 +8,7 @@ Nov
|
|||
- [x] trim history by rules
|
||||
- [ ] custom icons, favicons
|
||||
- [x] drag to trash
|
||||
- [ ] switch view
|
||||
- [x] switch view
|
||||
- [x] option to check updates without install
|
||||
|
||||
## v0.5
|
||||
|
@ -40,6 +40,7 @@ Feb
|
|||
- [ ] generation templates
|
||||
- [ ] entry templates
|
||||
- [ ] drag entries across files
|
||||
- [ ] customizable table view
|
||||
- [ ] i18n
|
||||
- [ ] allow to increase font size
|
||||
- [ ] different storage options
|
||||
|
|
|
@ -16,7 +16,8 @@ var AppSettingsModel = Backbone.Model.extend({
|
|||
clipboardSeconds: 0,
|
||||
autoSave: true,
|
||||
idleMinutes: 15,
|
||||
minimizeOnClose: false
|
||||
minimizeOnClose: false,
|
||||
tableView: false
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
|
|
|
@ -28,6 +28,7 @@ EntryPresenter.prototype = {
|
|||
get created() { return this.entry ? Format.dtStr(this.entry.created) : undefined; },
|
||||
get updated() { return this.entry ? Format.dtStr(this.entry.updated) : undefined; },
|
||||
get expired() { return this.entry ? this.entry.expired : false; },
|
||||
get tags() { return this.entry ? this.entry.tags : false; },
|
||||
get description() {
|
||||
if (!this.entry) {
|
||||
return '[Group]';
|
||||
|
|
|
@ -4,6 +4,12 @@ var FeatureDetector = {
|
|||
isMac: function() {
|
||||
return navigator.platform.indexOf('Mac') >= 0;
|
||||
},
|
||||
isMobile: function() {
|
||||
return typeof window.orientation !== 'undefined';
|
||||
},
|
||||
isDesktop: function() {
|
||||
return !this.isMobile();
|
||||
},
|
||||
actionShortcutSymbol: function(formatting) {
|
||||
return this.isMac() ? '⌘' : formatting ? '<span class="thin">ctrl + </span>' : 'ctrl-';
|
||||
},
|
||||
|
|
|
@ -5,6 +5,7 @@ var Backbone = require('backbone'),
|
|||
MenuView = require('../views/menu/menu-view'),
|
||||
FooterView = require('../views/footer-view'),
|
||||
ListView = require('../views/list-view'),
|
||||
ListWrapView = require('../views/list-wrap-view'),
|
||||
DetailsView = require('../views/details/details-view'),
|
||||
GrpView = require('../views/grp-view'),
|
||||
OpenView = require('../views/open-view'),
|
||||
|
@ -37,8 +38,10 @@ var AppView = Backbone.View.extend({
|
|||
this.views.menu = new MenuView({ model: this.model.menu });
|
||||
this.views.menuDrag = new DragView('x');
|
||||
this.views.footer = new FooterView({ model: this.model });
|
||||
this.views.listWrap = new ListWrapView({ model: this.model });
|
||||
this.views.list = new ListView({ model: this.model });
|
||||
this.views.listDrag = new DragView('x');
|
||||
this.views.list.dragView = this.views.listDrag;
|
||||
this.views.details = new DetailsView();
|
||||
this.views.details.appModel = this.model;
|
||||
this.views.grp = new GrpView();
|
||||
|
@ -55,7 +58,6 @@ var AppView = Backbone.View.extend({
|
|||
this.listenTo(Backbone, 'show-file', this.showFileSettings);
|
||||
this.listenTo(Backbone, 'open-file', this.toggleOpenFile);
|
||||
this.listenTo(Backbone, 'save-all', this.saveAll);
|
||||
this.listenTo(Backbone, 'switch-view', this.switchView);
|
||||
this.listenTo(Backbone, 'toggle-settings', this.toggleSettings);
|
||||
this.listenTo(Backbone, 'toggle-menu', this.toggleMenu);
|
||||
this.listenTo(Backbone, 'toggle-details', this.toggleDetails);
|
||||
|
@ -73,8 +75,9 @@ var AppView = Backbone.View.extend({
|
|||
},
|
||||
|
||||
render: function () {
|
||||
this.setTheme();
|
||||
this.$el.html(this.template());
|
||||
this.setTheme();
|
||||
this.views.listWrap.setElement(this.$el.find('.app__list-wrap')).render();
|
||||
this.views.menu.setElement(this.$el.find('.app__menu')).render();
|
||||
this.views.menuDrag.setElement(this.$el.find('.app__menu-drag')).render();
|
||||
this.views.footer.setElement(this.$el.find('.app__footer')).render();
|
||||
|
@ -88,6 +91,7 @@ var AppView = Backbone.View.extend({
|
|||
showOpenFile: function(filePath) {
|
||||
this.views.menu.hide();
|
||||
this.views.menuDrag.hide();
|
||||
this.views.listWrap.hide();
|
||||
this.views.list.hide();
|
||||
this.views.listDrag.hide();
|
||||
this.views.details.hide();
|
||||
|
@ -119,6 +123,7 @@ var AppView = Backbone.View.extend({
|
|||
showEntries: function() {
|
||||
this.views.menu.show();
|
||||
this.views.menuDrag.show();
|
||||
this.views.listWrap.show();
|
||||
this.views.list.show();
|
||||
this.views.listDrag.show();
|
||||
this.views.details.show();
|
||||
|
@ -147,6 +152,7 @@ var AppView = Backbone.View.extend({
|
|||
this.model.menu.setMenu('settings');
|
||||
this.views.menu.show();
|
||||
this.views.menuDrag.show();
|
||||
this.views.listWrap.hide();
|
||||
this.views.list.hide();
|
||||
this.views.listDrag.hide();
|
||||
this.views.details.hide();
|
||||
|
@ -162,6 +168,7 @@ var AppView = Backbone.View.extend({
|
|||
},
|
||||
|
||||
showEditGroup: function() {
|
||||
this.views.listWrap.hide();
|
||||
this.views.list.hide();
|
||||
this.views.listDrag.hide();
|
||||
this.views.details.hide();
|
||||
|
@ -413,10 +420,6 @@ var AppView = Backbone.View.extend({
|
|||
this.views.menu.switchVisibility();
|
||||
},
|
||||
|
||||
switchView: function() {
|
||||
Alerts.notImplemented();
|
||||
},
|
||||
|
||||
toggleDetails: function(visible) {
|
||||
this.$el.find('.app__list').toggleClass('app__list--details-visible', visible);
|
||||
this.views.menu.switchVisibility(false);
|
||||
|
|
|
@ -8,12 +8,16 @@ var DragView = Backbone.View.extend({
|
|||
},
|
||||
|
||||
initialize: function (coord) {
|
||||
this.coord = coord;
|
||||
this.offsetProp = 'page' + coord.toUpperCase();
|
||||
this.setCoord(coord);
|
||||
this.mouseDownTime = -1;
|
||||
this.mouseDownCount = 0;
|
||||
},
|
||||
|
||||
setCoord: function(coord) {
|
||||
this.coord = coord;
|
||||
this.offsetProp = 'page' + coord.toUpperCase();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
$('<div/>').addClass('drag-handle__inner').appendTo(this.$el);
|
||||
},
|
||||
|
|
|
@ -12,7 +12,6 @@ var FooterView = Backbone.View.extend({
|
|||
events: {
|
||||
'click .footer__db-item': 'showFile',
|
||||
'click .footer__db-open': 'openFile',
|
||||
'click .footer__btn-view': 'switchView',
|
||||
'click .footer__btn-help': 'toggleHelp',
|
||||
'click .footer__btn-settings': 'toggleSettings',
|
||||
'click .footer__btn-generate': 'genPass',
|
||||
|
@ -75,10 +74,6 @@ var FooterView = Backbone.View.extend({
|
|||
Backbone.trigger('save-all');
|
||||
},
|
||||
|
||||
switchView: function() {
|
||||
Backbone.trigger('switch-view');
|
||||
},
|
||||
|
||||
toggleHelp: function() {
|
||||
Backbone.trigger('toggle-settings', 'help');
|
||||
},
|
||||
|
|
|
@ -11,7 +11,6 @@ var Backbone = require('backbone'),
|
|||
|
||||
var ListView = Backbone.View.extend({
|
||||
template: require('templates/list.html'),
|
||||
itemTemplate: require('templates/list-item-short.html'),
|
||||
emptyTemplate: require('templates/list-empty.html'),
|
||||
|
||||
events: {
|
||||
|
@ -22,7 +21,9 @@ var ListView = Backbone.View.extend({
|
|||
views: null,
|
||||
|
||||
minWidth: 200,
|
||||
minHeight: 200,
|
||||
maxWidth: 500,
|
||||
maxHeight: 500,
|
||||
|
||||
itemsEl: null,
|
||||
|
||||
|
@ -41,6 +42,8 @@ var ListView = Backbone.View.extend({
|
|||
this.listenTo(Backbone, 'filter', this.filterChanged);
|
||||
this.listenTo(Backbone, 'entry-updated', this.entryUpdated);
|
||||
|
||||
this.listenTo(this.model.settings, 'change:tableView', this.setTableView);
|
||||
|
||||
this.items = [];
|
||||
},
|
||||
|
||||
|
@ -49,6 +52,7 @@ var ListView = Backbone.View.extend({
|
|||
this.$el.html(this.template());
|
||||
this.itemsEl = this.$el.find('.list__items>.scroller');
|
||||
this.views.search.setElement(this.$el.find('.list__header')).render();
|
||||
this.setTableView();
|
||||
|
||||
this.scroll = baron({
|
||||
root: this.$el.find('.list__items')[0],
|
||||
|
@ -60,23 +64,43 @@ var ListView = Backbone.View.extend({
|
|||
this.scrollerBarWrapper = this.$el.find('.scroller__bar-wrapper');
|
||||
}
|
||||
if (this.items.length) {
|
||||
var itemTemplate = this.getItemTemplate();
|
||||
var itemsTemplate = this.getItemsTemplate();
|
||||
var presenter = new EntryPresenter(this.getDescField());
|
||||
var itemsHtml = '';
|
||||
this.items.forEach(function (item) {
|
||||
presenter.present(item);
|
||||
itemsHtml += this.itemTemplate(presenter);
|
||||
itemsHtml += itemTemplate(presenter);
|
||||
}, this);
|
||||
this.itemsEl.html(itemsHtml).scrollTop(0);
|
||||
var html = itemsTemplate({ items: itemsHtml });
|
||||
this.itemsEl.html(html).scrollTop(0);
|
||||
} else {
|
||||
this.itemsEl.html(this.emptyTemplate());
|
||||
}
|
||||
if (typeof AppSettingsModel.instance.get('listViewWidth') === 'number') {
|
||||
this.$el.width(AppSettingsModel.instance.get('listViewWidth'));
|
||||
}
|
||||
this.pageResized();
|
||||
return this;
|
||||
},
|
||||
|
||||
getItemsTemplate: function() {
|
||||
if (this.model.settings.get('tableView')) {
|
||||
return require('templates/list-table.html');
|
||||
} else {
|
||||
return this.renderPlainItems;
|
||||
}
|
||||
},
|
||||
|
||||
renderPlainItems: function(itemsHtml) {
|
||||
return itemsHtml.items;
|
||||
},
|
||||
|
||||
getItemTemplate: function() {
|
||||
if (this.model.settings.get('tableView')) {
|
||||
return require('templates/list-item-table.html');
|
||||
} else {
|
||||
return require('templates/list-item-short.html');
|
||||
}
|
||||
},
|
||||
|
||||
getDescField: function() {
|
||||
return this.model.sort.replace('-', '');
|
||||
},
|
||||
|
@ -142,7 +166,31 @@ var ListView = Backbone.View.extend({
|
|||
this.views.search.hide();
|
||||
},
|
||||
|
||||
viewResized: _.throttle(function(size) {
|
||||
setTableView: function() {
|
||||
var isTable = this.model.settings.get('tableView');
|
||||
this.dragView.setCoord(isTable ? 'y' : 'x');
|
||||
this.setDefaultSize();
|
||||
},
|
||||
|
||||
setDefaultSize: function() {
|
||||
this.setSize(this.model.settings.get('listViewWidth'));
|
||||
},
|
||||
|
||||
setSize: function(size) {
|
||||
this.$el.css({ width: null, height: null });
|
||||
if (size) {
|
||||
this.$el.css('flex', '0 0 ' + size + 'px');
|
||||
} else {
|
||||
this.$el.css('flex', null);
|
||||
}
|
||||
},
|
||||
|
||||
viewResized: function(size) {
|
||||
this.setSize(size);
|
||||
this.throttleSetViewSizeSetting(size);
|
||||
},
|
||||
|
||||
throttleSetViewSizeSetting: _.throttle(function(size) {
|
||||
AppSettingsModel.instance.set('listViewWidth', size);
|
||||
}, 1000),
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
'use strict';
|
||||
|
||||
var Backbone = require('backbone');
|
||||
|
||||
var ListWrapView = Backbone.View.extend({
|
||||
events: {
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
this.listenTo(this.model.settings, 'change:tableView', this.setListLayout);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
this.setListLayout();
|
||||
},
|
||||
|
||||
setListLayout: function() {
|
||||
var tableView = this.model.settings.get('tableView');
|
||||
this.$el.toggleClass('app__list-wrap--table', tableView);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = ListWrapView;
|
|
@ -7,6 +7,7 @@ var Backbone = require('backbone'),
|
|||
AppSettingsModel = require('../../models/app-settings-model'),
|
||||
UpdateModel = require('../../models/update-model'),
|
||||
RuntimeInfo = require('../../comp/runtime-info'),
|
||||
FeatureDetector = require('../../util/feature-detector'),
|
||||
Links = require('../../const/links');
|
||||
|
||||
var SettingsGeneralView = Backbone.View.extend({
|
||||
|
@ -20,6 +21,7 @@ var SettingsGeneralView = Backbone.View.extend({
|
|||
'change .settings__general-clipboard': 'changeClipboard',
|
||||
'change .settings__general-auto-save': 'changeAutoSave',
|
||||
'change .settings__general-minimize': 'changeMinimize',
|
||||
'change .settings__general-table-view': 'changeTableView',
|
||||
'click .settings__general-update-btn': 'checkUpdate',
|
||||
'click .settings__general-restart-btn': 'restartApp',
|
||||
'click .settings__general-download-update-btn': 'downloadUpdate',
|
||||
|
@ -51,6 +53,8 @@ var SettingsGeneralView = Backbone.View.extend({
|
|||
devTools: Launcher && Launcher.devTools,
|
||||
canAutoUpdate: !!Launcher,
|
||||
canMinimizeOnClose: Launcher && Launcher.canMinimize(),
|
||||
tableView: AppSettingsModel.instance.get('tableView'),
|
||||
canSetTableView: FeatureDetector.isDesktop(),
|
||||
autoUpdate: Updater.getAutoUpdateType(),
|
||||
updateInProgress: Updater.updateInProgress(),
|
||||
updateInfo: this.getUpdateInfo(),
|
||||
|
@ -134,6 +138,12 @@ var SettingsGeneralView = Backbone.View.extend({
|
|||
AppSettingsModel.instance.set('minimizeOnClose', minimizeOnClose);
|
||||
},
|
||||
|
||||
changeTableView: function(e) {
|
||||
var tableView = e.target.checked || false;
|
||||
AppSettingsModel.instance.set('tableView', tableView);
|
||||
Backbone.trigger('refresh');
|
||||
},
|
||||
|
||||
restartApp: function() {
|
||||
if (Launcher) {
|
||||
Launcher.requestRestart();
|
||||
|
|
|
@ -25,13 +25,30 @@
|
|||
}
|
||||
}
|
||||
|
||||
&__list-wrap {
|
||||
@include flex(1);
|
||||
@include display(flex);
|
||||
@include align-items(stretch);
|
||||
@include flex-direction(row);
|
||||
@include justify-content(flex-start);
|
||||
&.app__list-wrap--table {
|
||||
@include flex-direction(column);
|
||||
}
|
||||
}
|
||||
|
||||
&__menu-drag, &__list-drag {
|
||||
@include drag-handle;
|
||||
@include flex(0 0 auto);
|
||||
width: 1px;
|
||||
cursor: col-resize;
|
||||
@include mobile {
|
||||
display: none;
|
||||
@include mobile { display: none; }
|
||||
}
|
||||
|
||||
&__list-drag {
|
||||
.app__list-wrap--table & {
|
||||
width: auto;
|
||||
height: 1px;
|
||||
cursor: row-resize;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,12 +57,13 @@
|
|||
}
|
||||
|
||||
&__list {
|
||||
@include flex(0 0 auto);
|
||||
@include flex(0 0 250px);
|
||||
@include display(flex);
|
||||
@include align-items(stretch);
|
||||
@include flex-direction(column);
|
||||
width: 250px;
|
||||
overflow-y: auto;
|
||||
.app__list-wrap--table & {
|
||||
}
|
||||
@include mobile {
|
||||
width: 100vw;
|
||||
&.app__list--details-visible {
|
||||
|
|
|
@ -73,18 +73,26 @@
|
|||
}
|
||||
}
|
||||
|
||||
&__table {
|
||||
width: calc(100% - 1px);
|
||||
td, th {
|
||||
padding: $base-padding;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
&__item {
|
||||
@include area-selectable(right);
|
||||
padding: $base-padding-px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
height: 32px;
|
||||
|
||||
@include area-selectable(right);
|
||||
&--active, &--active:hover {
|
||||
@include nomobile {
|
||||
@include area-selected(right);
|
||||
}
|
||||
@include nomobile { @include area-selected(right); }
|
||||
}
|
||||
|
||||
&:not(.list__item--table) {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
&--expired {
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
<div class="app__body">
|
||||
<div class="app__menu"></div>
|
||||
<div class="app__menu-drag"></div>
|
||||
<div class="app__list"></div>
|
||||
<div class="app__list-drag"></div>
|
||||
<div class="app__details"></div>
|
||||
<div class="app__list-wrap">
|
||||
<div class="app__list"></div>
|
||||
<div class="app__list-drag"></div>
|
||||
<div class="app__details"></div>
|
||||
</div>
|
||||
<div class="app__grp"></div>
|
||||
</div>
|
||||
<div class="app__footer"></div>
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
</div>
|
||||
<% }); %>
|
||||
<div class="footer__db footer__db--dimmed footer__db--expanded footer__db-open"><i class="fa fa-plus"></i> Open / New</div>
|
||||
<!--<div class="footer__btn footer__btn-view"><i class="fa fa-list-ul"></i></div>-->
|
||||
<div class="footer__btn footer__btn-help"><i class="fa fa-question"></i></div>
|
||||
<div class="footer__btn footer__btn-settings">
|
||||
<% if (updateAvailable) { %>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<tr class="list__item list__item--table <%= active ? 'list__item--active' : '' %> <%= expired ? 'list__item--expired' : '' %>" id="<%= id %>" draggable="true">
|
||||
<td><% if (customIcon) { %><img src="data:image/png;base64,<%= customIcon %>" class="list__item-icon list__item-icon--custom <%= color || '' %>" /><% }
|
||||
else { %><i class="fa fa-<%= icon %> <%= color ? color+'-color' : '' %> list__item-icon"></i><% } %></td>
|
||||
<td><%- title || '(no title)' %></td>
|
||||
<td><%- description %></td>
|
||||
<td><%- url %></td>
|
||||
<td><%- tags %></td>
|
||||
<td><%- notes %></td>
|
||||
</tr>
|
|
@ -0,0 +1,15 @@
|
|||
<table class="list__table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Title</th>
|
||||
<th>User</th>
|
||||
<th>Website</th>
|
||||
<th>Tags</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%= items %>
|
||||
</tbody>
|
||||
</table>
|
|
@ -50,6 +50,12 @@
|
|||
<input type="checkbox" class="settings__input input-base settings__general-expand" id="settings__general-expand" <%- expandGroups ? 'checked' : '' %> />
|
||||
<label for="settings__general-expand">Show entries from all subgroups</label>
|
||||
</div>
|
||||
<% if (canSetTableView) { %>
|
||||
<div>
|
||||
<input type="checkbox" class="settings__input input-base settings__general-table-view" id="settings__general-table-view" <%- tableView ? 'checked' : '' %> />
|
||||
<label for="settings__general-table-view">Entries list table view</label>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<h2>Function</h2>
|
||||
<div>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
Release notes
|
||||
-------------
|
||||
##### vNext
|
||||
Locking, better Dropbox, security enhancements, bugfixes
|
||||
Locking, better Dropbox, security enhancements, bugfixes
|
||||
`+` lock flow, auto-lock
|
||||
`+` entries list display table layout
|
||||
`+` minimize to tray on windows
|
||||
`+` desktop Dropbox
|
||||
`+` Dropbox notification in self-hosted apps
|
||||
|
|
Loading…
Reference in New Issue