redesigned Dropbox chooser

This commit is contained in:
antelle 2017-11-26 17:26:58 +01:00
parent 577d23e212
commit 7d13b49093
11 changed files with 184 additions and 23 deletions

View File

@ -186,6 +186,7 @@
"openErrorDescription": "There was an error opening file",
"openErrorFileNotFound": "File not found",
"openListErrorBody": "There was an error loading file list",
"openShowAllFiles": "Show all files",
"detAttDownload": "Shift-click attachment button to download or",
"detAttDelToRemove": "Delete to remove",

View File

@ -273,23 +273,23 @@ const StorageDropbox = StorageBase.extend({
});
},
list: function(callback) {
list: function(dir, callback) {
this.logger.debug('List');
const ts = this.logger.ts();
this._apiCall({
method: 'files/list_folder',
data: {
path: this._toFullPath(''),
path: this._toFullPath(dir || ''),
recursive: false
},
success: data => {
this.logger.debug('Listed', this.logger.ts(ts));
const fileList = data.entries
.filter(f => f['.tag'] === 'file' && f.rev && UrlUtil.isKdbx(f.name))
.map(f => ({
name: f.name,
path: this._toRelPath(f['path_display']),
ref: f.rev
rev: f.rev,
dir: f['.tag'] !== 'file'
}));
callback(null, fileList);
},

View File

@ -126,7 +126,7 @@ const StorageGDrive = StorageBase.extend({
});
},
list: function(callback) {
list: function(dir, callback) {
this._oauthAuthorize((err) => {
if (err) { return callback && callback(err); }
this.logger.debug('List');

View File

@ -136,7 +136,7 @@ const StorageOneDrive = StorageBase.extend({
});
},
list: function(callback) {
list: function(dir, callback) {
this._oauthAuthorize(err => {
if (err) { return callback && callback(err); }
this.logger.debug('List');

View File

@ -39,6 +39,10 @@ const ModalView = Backbone.View.extend({
el.removeClass('modal--hidden');
document.activeElement.blur();
}, 20);
if (this.model.view) {
this.model.view.setElement(this.$el.find('.modal__body'));
this.model.view.render();
}
return this;
},

View File

@ -5,11 +5,13 @@ const Keys = require('../const/keys');
const Alerts = require('../comp/alerts');
const SecureInput = require('../comp/secure-input');
const DropboxChooser = require('../comp/dropbox-chooser');
const StorageFileListView = require('../views/storage-file-list-view');
const FeatureDetector = require('../util/feature-detector');
const Logger = require('../util/logger');
const Locale = require('../util/locale');
const UrlUtil = require('../util/url-util');
const InputFx = require('../util/input-fx');
const Comparators = require('../util/comparators');
const Storage = require('../storage');
const Launcher = require('../comp/launcher');
@ -594,7 +596,7 @@ const OpenView = Backbone.View.extend({
}
},
listStorage: function(storage) {
listStorage: function(storage, config) {
if (this.busy) {
return;
}
@ -602,7 +604,7 @@ const OpenView = Backbone.View.extend({
const icon = this.$el.find('.open__icon-storage[data-storage=' + storage.name + ']');
this.busy = true;
icon.toggleClass('flip3d', true);
storage.list((err, files) => {
storage.list(config && config.dir, (err, files) => {
icon.toggleClass('flip3d', false);
this.busy = false;
if (err || !files) {
@ -615,32 +617,53 @@ const OpenView = Backbone.View.extend({
}
return;
}
const buttons = [];
const allStorageFiles = {};
files.forEach(file => {
const fileName = UrlUtil.getDataFileName(file.name);
buttons.push({result: file.path, title: fileName});
allStorageFiles[file.path] = file;
});
if (!buttons.length) {
if (!files.length) {
Alerts.error({
header: Locale.openNothingFound,
body: Locale.openNothingFoundBody
});
return;
}
buttons.push({result: '', title: Locale.alertCancel});
const fileNameComparator = Comparators.stringComparator('path', true);
files.sort((x, y) => {
if (x.dir !== y.dir) {
return !!y.dir - !!x.dir;
}
return fileNameComparator(x, y);
});
if (config && config.dir) {
files.unshift({
path: config.prevDir,
name: '..',
dir: true
});
}
const listView = new StorageFileListView({
model: {
files,
showHiddenFiles: config && config.showHiddenFiles
}
});
listView.on('selected', file => {
if (file.dir) {
this.listStorage(storage, {
dir: file.path,
prevDir: config && config.dir || '',
showHiddenFiles: true
});
} else {
this.openStorageFile(storage, file);
}
});
Alerts.alert({
header: Locale.openSelectFile,
body: Locale.openSelectFileBody,
icon: storage.icon || 'files-o',
buttons: buttons,
buttons: [{result: '', title: Locale.alertCancel}],
esc: '',
click: '',
success: file => {
this.openStorageFile(storage, allStorageFiles[file]);
}
view: listView
});
});
},

View File

@ -239,7 +239,7 @@ const SettingsFileView = Backbone.View.extend({
return;
}
this.model.set('syncing', true);
storage.list((err, files) => {
storage.list('', (err, files) => {
this.model.set('syncing', false);
if (err) {
return;

View File

@ -0,0 +1,56 @@
const Backbone = require('backbone');
const UrlUtil = require('../util/url-util');
const StorageFileListView = Backbone.View.extend({
template: require('templates/storage-file-list.hbs'),
events: {
'click .open-list__file': 'fileClick',
'click .open-list__check-wrap': 'showAllCheckClick'
},
initialize() {
this.allStorageFiles = {};
this.showHiddenFiles = !!this.model.showHiddenFiles;
},
render() {
let files = this.model.files.map(file => {
this.allStorageFiles[file.path] = file;
return {
path: file.path,
name: UrlUtil.getDataFileName(file.name),
kdbx: UrlUtil.isKdbx(file.name),
dir: file.dir
};
});
let hasHiddenFiles = this.showHiddenFiles;
if (!this.showHiddenFiles) {
const allFilesLength = files.length;
files = files.filter(f => !f.dir && f.kdbx);
hasHiddenFiles = files.length - allFilesLength;
}
const density = files.length > 14 ? 3 : files.length > 7 ? 2 : 1;
this.renderTemplate({
files,
density,
showHiddenFiles: this.showHiddenFiles,
hasHiddenFiles: hasHiddenFiles
});
return this;
},
fileClick(e) {
const result = $(e.target).closest('.open-list__file').data('path');
const file = this.allStorageFiles[result];
this.trigger('selected', file);
},
showAllCheckClick(e) {
e.stopPropagation();
this.showHiddenFiles = !this.showHiddenFiles;
this.render();
}
});
module.exports = StorageFileListView;

View File

@ -231,3 +231,47 @@
}
}
}
.open-list {
&__content {
margin: $base-padding-v 0 $base-padding-v (-$base-padding-h);
max-height: calc(100vh - 22em);
position: relative;
overflow: hidden;
}
&__scrollable {
max-height: calc(100vh - 22em);
width: calc(100% + 50px);
overflow-y: auto;
overflow-x: hidden;
}
&__files {
display: flex;
flex-wrap: wrap;
width: calc(100% - 50px);
}
&__file {
cursor: pointer;
padding: $base-padding;
border-radius: $base-border-radius;
box-sizing: border-box;
flex-basis: 100%;
@include nomobile {
.open-list--density2 & { flex-basis: 50%; }
.open-list--density3 & { flex-basis: 33.33333%; }
}
&:hover {
@include th { background-color: th(action-background-color-focus-tr); }
}
&-icon {
margin-right: .3em;
}
&--another {
@include th { color: th(medium-color); }
}
}
&__check-label {
width: 100%;
display: inline-block;
}
}

View File

@ -0,0 +1,32 @@
<div class="open-list open-list--density{{density}}">
<div class="open-list__content">
<div class="open-list__scrollable">
<div class="open-list__files">
{{#each files as |file|}}
{{#if file.dir}}
<div class="open-list__file" data-path="{{file.path}}">
<i class="open-list__file-icon fa fa-{{#ifeq file.name '..'}}arrow-left{{else}}folder-o{{/ifeq}}"></i>
<span class="open-list__file-text">{{file.name}}</span>
</div>
{{/if}}
{{/each}}
</div>
<div class="open-list__files">
{{#each files as |file|}}
{{#unless file.dir}}
<div class="open-list__file {{#unless file.kdbx}}open-list__file--another{{/unless}}" data-path="{{file.path}}">
<i class="open-list__file-icon fa fa-{{#if file.kdbx}}key{{else}}file-text-o{{/if}}"></i>
<span class="open-list__file-text">{{file.name}}</span>
</div>
{{/unless}}
{{/each}}
</div>
</div>
</div>
{{#if hasHiddenFiles}}
<div class="open-list__check-wrap">
<input type="checkbox" id="open-list__check" {{#if showHiddenFiles}}checked{{/if}}
/><label class="open-list__check-label" for="open-list__check">{{res 'openShowAllFiles'}}</label>
</div>
{{/if}}
</div>

View File

@ -3,6 +3,7 @@ Release notes
##### v1.6.0 (WIP)
`+` desktop apps integrity protection
`+` auto-lock on computer lock
`+` redesigned Dropbox chooser
`+` safari tab icons
`*` prevent master password autocomplete
`*` build with node.js 8