Merge pull request #11573 from nextcloud/gridview-table
Files grid view
This commit is contained in:
commit
37782b1084
|
@ -61,6 +61,16 @@ $application->registerRoutes(
|
||||||
'url' => '/api/v1/showhidden',
|
'url' => '/api/v1/showhidden',
|
||||||
'verb' => 'POST'
|
'verb' => 'POST'
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'name' => 'API#showGridView',
|
||||||
|
'url' => '/api/v1/showgridview',
|
||||||
|
'verb' => 'POST'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'API#getGridView',
|
||||||
|
'url' => '/api/v1/showgridview',
|
||||||
|
'verb' => 'GET'
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'name' => 'view#index',
|
'name' => 'view#index',
|
||||||
'url' => '/',
|
'url' => '/',
|
||||||
|
|
|
@ -172,7 +172,7 @@ table th, table th a {
|
||||||
color: var(--color-text-maxcontrast);
|
color: var(--color-text-maxcontrast);
|
||||||
}
|
}
|
||||||
table.multiselect th a {
|
table.multiselect th a {
|
||||||
color: #000;
|
color: var(--color-main-text);
|
||||||
}
|
}
|
||||||
table th .columntitle {
|
table th .columntitle {
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -262,8 +262,7 @@ table.multiselect thead {
|
||||||
}
|
}
|
||||||
|
|
||||||
table.multiselect thead th {
|
table.multiselect thead th {
|
||||||
background-color: rgba(255, 255, 255, 0.95); /* like controls bar */
|
background-color: var(--color-main-background);
|
||||||
color: #000;
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
}
|
}
|
||||||
|
@ -595,7 +594,13 @@ a.action > img {
|
||||||
.summary {
|
.summary {
|
||||||
opacity: .3;
|
opacity: .3;
|
||||||
/* add whitespace to bottom of files list to correctly show dropdowns */
|
/* add whitespace to bottom of files list to correctly show dropdowns */
|
||||||
height: 300px;
|
height: 250px;
|
||||||
|
}
|
||||||
|
/* Less whitespace needed on link share page
|
||||||
|
* as there is a footer and action menus have fewer entries.
|
||||||
|
*/
|
||||||
|
#body-public .summary {
|
||||||
|
height: 180px;
|
||||||
}
|
}
|
||||||
.summary:hover,
|
.summary:hover,
|
||||||
.summary:focus,
|
.summary:focus,
|
||||||
|
@ -723,3 +728,277 @@ table.dragshadow td.size {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* GRID */
|
||||||
|
#filestable.view-grid:not(.hidden) {
|
||||||
|
$grid-size: 160px;
|
||||||
|
$grid-pad: 14px;
|
||||||
|
|
||||||
|
/* HEADER and MULTISELECT */
|
||||||
|
thead {
|
||||||
|
tr {
|
||||||
|
display: block;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
background-color: var(--color-main-background);
|
||||||
|
th {
|
||||||
|
width: auto;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MAIN FILE LIST */
|
||||||
|
tbody {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, $grid-size);
|
||||||
|
justify-content: space-around;
|
||||||
|
row-gap: 15px;
|
||||||
|
margin: 15px 0;
|
||||||
|
|
||||||
|
tr {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
height: $grid-size + 44px - $grid-pad;
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
|
||||||
|
&:hover, &:focus, &:active,
|
||||||
|
&.selected,
|
||||||
|
&.searchresult,
|
||||||
|
.name:focus,
|
||||||
|
&.highlighted {
|
||||||
|
background-color: transparent;
|
||||||
|
|
||||||
|
.thumbnail-wrapper,
|
||||||
|
.nametext,
|
||||||
|
.fileactions {
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
background-color: var(--color-background-dark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
display: inline;
|
||||||
|
border-bottom: none;
|
||||||
|
|
||||||
|
&.filename {
|
||||||
|
.thumbnail-wrapper {
|
||||||
|
min-width: 0;
|
||||||
|
max-width: none;
|
||||||
|
position: absolute;
|
||||||
|
width: $grid-size;
|
||||||
|
height: $grid-size;
|
||||||
|
padding: $grid-pad; // same as action icon bottom and right padding
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: -1; // make sure the default click is the link
|
||||||
|
|
||||||
|
.thumbnail {
|
||||||
|
width: calc(100% - 2 * #{$grid-pad});
|
||||||
|
height: calc(100% - 2 * #{$grid-pad}); //action icon padding
|
||||||
|
background-size: contain;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
|
||||||
|
/* Position favorite star related to checkbox to left and 3-dot menu below
|
||||||
|
* Position is inherited from the selection while in grid view
|
||||||
|
*/
|
||||||
|
.favorite-mark {
|
||||||
|
padding: $grid-pad;
|
||||||
|
left: auto;
|
||||||
|
top: -22px; // center in corner of thumbnail
|
||||||
|
right: -22px; // center in corner of thumbnail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
height: 100%;
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
// since we're using thumbnail, name and actions bg
|
||||||
|
// we need to hide the overflow for the radius to show
|
||||||
|
// luckily the popovermenu is outside .name
|
||||||
|
overflow: hidden;
|
||||||
|
// we but the thumbnail in background to ensure
|
||||||
|
// the name is the default click handler
|
||||||
|
// force back the cursor which have been overrided
|
||||||
|
// and disabled for some reason...
|
||||||
|
cursor: pointer !important;
|
||||||
|
|
||||||
|
.nametext {
|
||||||
|
display: flex;
|
||||||
|
height: 44px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-top: $grid-size - $grid-pad;
|
||||||
|
padding-right: 0;
|
||||||
|
text-align: right;
|
||||||
|
line-height: 44px;
|
||||||
|
padding-left: $grid-pad; // same as action icon right padding
|
||||||
|
|
||||||
|
.innernametext {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No space for extension in grid view */
|
||||||
|
.extension {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fileactions {
|
||||||
|
height: initial;
|
||||||
|
margin-top: $grid-size - $grid-pad;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.action {
|
||||||
|
padding: $grid-pad;
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
&.action-share.permanent.shared-style span {
|
||||||
|
/* Do not show "Shared" text next to icon as there is no space */
|
||||||
|
&:not(.icon) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If an avatar is present, show that instead of the icon */
|
||||||
|
&.avatar {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In "Deleted files", do not show "Restore" text next to icon as there is no space */
|
||||||
|
&.action-restore.permanent span {
|
||||||
|
&:not(.icon) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there is a comment, show it instead of the share icon */
|
||||||
|
&.action-comment ~ .action-share {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No space for filesize and date in grid view */
|
||||||
|
&.filesize,
|
||||||
|
&.date {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selection,
|
||||||
|
&.filename .favorite-mark {
|
||||||
|
position: absolute;
|
||||||
|
top: -8px; // half the checkbox width, center on corner of thumbnail
|
||||||
|
left: -8px; // half the checkbox width, center on corner of thumbnail
|
||||||
|
display: flex;
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
z-index: 10;
|
||||||
|
background: transparent;
|
||||||
|
|
||||||
|
label {
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
display: inline-flex;
|
||||||
|
padding: $grid-pad; // like any action icon
|
||||||
|
&::before {
|
||||||
|
margin: 0;
|
||||||
|
width: $grid-pad; // 16px - border
|
||||||
|
height: $grid-pad; // 16px - border
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Position actions menu below file */
|
||||||
|
.popovermenu {
|
||||||
|
left: 0;
|
||||||
|
width: $grid-size - 10px; // 2 * margin
|
||||||
|
margin: 0 5px;
|
||||||
|
|
||||||
|
/* Ellipsize long entries, normally menu width is adjusted but for grid we use fixed width. */
|
||||||
|
.menuitem span:not(.icon) {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Center align the footer file number & size summary */
|
||||||
|
tfoot {
|
||||||
|
display: grid;
|
||||||
|
|
||||||
|
.summary:not(.hidden) {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0 auto;
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding-top: 50px;
|
||||||
|
|
||||||
|
&:first-child,
|
||||||
|
&.date {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grid view toggle */
|
||||||
|
#view-toggle {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 22px;
|
||||||
|
opacity: .5;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
#showgridview:focus + & {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjustments for link share page */
|
||||||
|
#body-public {
|
||||||
|
#filestable.view-grid:not(.hidden) tbody td {
|
||||||
|
/* More space for filename since there is no share icon */
|
||||||
|
&.filename .name .nametext .innernametext {
|
||||||
|
max-width: 124px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Position actions menu correctly below 3-dot-menu */
|
||||||
|
.popovermenu {
|
||||||
|
left: -80px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Right-align view toggle on link share page */
|
||||||
|
#view-toggle {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide legacy Gallery toggle */
|
||||||
|
#gallery-button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
|
@ -331,6 +331,11 @@
|
||||||
|
|
||||||
this.$el.find('thead th .columntitle').click(_.bind(this._onClickHeader, this));
|
this.$el.find('thead th .columntitle').click(_.bind(this._onClickHeader, this));
|
||||||
|
|
||||||
|
// Toggle for grid view
|
||||||
|
this.$showGridView = $('input#showgridview');
|
||||||
|
this.$showGridView.on('change', _.bind(this._onGridviewChange, this));
|
||||||
|
$('#view-toggle').tooltip({placement: 'bottom', trigger: 'hover'});
|
||||||
|
|
||||||
this._onResize = _.debounce(_.bind(this._onResize, this), 250);
|
this._onResize = _.debounce(_.bind(this._onResize, this), 250);
|
||||||
$('#app-content').on('appresized', this._onResize);
|
$('#app-content').on('appresized', this._onResize);
|
||||||
$(window).resize(this._onResize);
|
$(window).resize(this._onResize);
|
||||||
|
@ -591,6 +596,26 @@
|
||||||
this.$table.find('>thead').width($('#app-content').width() - OC.Util.getScrollBarWidth());
|
this.$table.find('>thead').width($('#app-content').width() - OC.Util.getScrollBarWidth());
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle showing gridview by default or not
|
||||||
|
*
|
||||||
|
* @returns {undefined}
|
||||||
|
*/
|
||||||
|
_onGridviewChange: function() {
|
||||||
|
var show = this.$showGridView.is(':checked');
|
||||||
|
// only save state if user is logged in
|
||||||
|
if (OC.currentUser) {
|
||||||
|
$.post(OC.generateUrl('/apps/files/api/v1/showgridview'), {
|
||||||
|
show: show
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.$showGridView.next('#view-toggle')
|
||||||
|
.removeClass('icon-toggle-filelist icon-toggle-pictures')
|
||||||
|
.addClass(show ? 'icon-toggle-filelist' : 'icon-toggle-pictures')
|
||||||
|
|
||||||
|
$('.list-container').toggleClass('view-grid', show);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event handler when leaving previously hidden state
|
* Event handler when leaving previously hidden state
|
||||||
*/
|
*/
|
||||||
|
@ -2776,7 +2801,9 @@
|
||||||
var permissions = this.getDirectoryPermissions();
|
var permissions = this.getDirectoryPermissions();
|
||||||
var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0;
|
var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0;
|
||||||
this.$el.find('#emptycontent').toggleClass('hidden', !this.isEmpty);
|
this.$el.find('#emptycontent').toggleClass('hidden', !this.isEmpty);
|
||||||
|
this.$el.find('#emptycontent').toggleClass('hidden', !this.isEmpty);
|
||||||
this.$el.find('#emptycontent .uploadmessage').toggleClass('hidden', !isCreatable || !this.isEmpty);
|
this.$el.find('#emptycontent .uploadmessage').toggleClass('hidden', !isCreatable || !this.isEmpty);
|
||||||
|
this.$el.find('#filestable').toggleClass('hidden', this.isEmpty);
|
||||||
this.$el.find('#filestable thead th').toggleClass('hidden', this.isEmpty);
|
this.$el.find('#filestable thead th').toggleClass('hidden', this.isEmpty);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -38,6 +38,7 @@ use OCP\Files\NotFoundException;
|
||||||
use OCP\IConfig;
|
use OCP\IConfig;
|
||||||
use OCP\IRequest;
|
use OCP\IRequest;
|
||||||
use OCP\AppFramework\Http\DataResponse;
|
use OCP\AppFramework\Http\DataResponse;
|
||||||
|
use OCP\AppFramework\Http\JSONResponse;
|
||||||
use OCP\AppFramework\Http\FileDisplayResponse;
|
use OCP\AppFramework\Http\FileDisplayResponse;
|
||||||
use OCP\AppFramework\Http\Response;
|
use OCP\AppFramework\Http\Response;
|
||||||
use OCA\Files\Service\TagService;
|
use OCA\Files\Service\TagService;
|
||||||
|
@ -267,6 +268,28 @@ class ApiController extends Controller {
|
||||||
return new Response();
|
return new Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle default for files grid view
|
||||||
|
*
|
||||||
|
* @NoAdminRequired
|
||||||
|
*
|
||||||
|
* @param bool $show
|
||||||
|
*/
|
||||||
|
public function showGridView($show) {
|
||||||
|
$this->config->setUserValue($this->userSession->getUser()->getUID(), 'files', 'show_grid', (int)$show);
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get default settings for the grid view
|
||||||
|
*
|
||||||
|
* @NoAdminRequired
|
||||||
|
*/
|
||||||
|
public function getGridView() {
|
||||||
|
$status = $this->config->getUserValue($this->userSession->getUser()->getUID(), 'files', 'show_grid', '1') === '1';
|
||||||
|
return new JSONResponse(['gridview' => $status]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggle default for showing/hiding xxx folder
|
* Toggle default for showing/hiding xxx folder
|
||||||
*
|
*
|
||||||
|
|
|
@ -22,11 +22,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$config = \OC::$server->getConfig();
|
$config = \OC::$server->getConfig();
|
||||||
|
$userSession = \OC::$server->getUserSession();
|
||||||
// TODO: move this to the generated config.js
|
// TODO: move this to the generated config.js
|
||||||
$publicUploadEnabled = $config->getAppValue('core', 'shareapi_allow_public_upload', 'yes');
|
$publicUploadEnabled = $config->getAppValue('core', 'shareapi_allow_public_upload', 'yes');
|
||||||
|
$showgridview = $config->getUserValue($userSession->getUser()->getUID(), 'files', 'show_grid', true);
|
||||||
|
|
||||||
// renders the controls and table headers template
|
// renders the controls and table headers template
|
||||||
$tmpl = new OCP\Template('files', 'list', '');
|
$tmpl = new OCP\Template('files', 'list', '');
|
||||||
$tmpl->assign('publicUploadEnabled', $publicUploadEnabled);
|
$tmpl->assign('publicUploadEnabled', $publicUploadEnabled);
|
||||||
|
$tmpl->assign('showgridview', $showgridview);
|
||||||
$tmpl->printPage();
|
$tmpl->printPage();
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,10 @@
|
||||||
<?php endif;?>
|
<?php endif;?>
|
||||||
<input type="hidden" class="max_human_file_size"
|
<input type="hidden" class="max_human_file_size"
|
||||||
value="(max <?php isset($_['uploadMaxHumanFilesize']) ? p($_['uploadMaxHumanFilesize']) : ''; ?>)">
|
value="(max <?php isset($_['uploadMaxHumanFilesize']) ? p($_['uploadMaxHumanFilesize']) : ''; ?>)">
|
||||||
|
<input type="checkbox" class="hidden-visually" id="showgridview"
|
||||||
|
<?php if($_['showgridview']) { ?>checked="checked" <?php } ?>/>
|
||||||
|
<label id="view-toggle" for="showgridview" class="button <?php p($_['showgridview'] ? 'icon-toggle-filelist' : 'icon-toggle-pictures') ?>"
|
||||||
|
title="<?php p($l->t('Toggle grid view'))?>"></label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="emptycontent" class="hidden">
|
<div id="emptycontent" class="hidden">
|
||||||
|
@ -38,7 +42,7 @@
|
||||||
<p></p>
|
<p></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table id="filestable" data-allow-public-upload="<?php p($_['publicUploadEnabled'])?>" data-preview-x="32" data-preview-y="32">
|
<table id="filestable" class="list-container <?php p($_['showgridview'] ? 'view-grid' : '') ?>" data-allow-public-upload="<?php p($_['publicUploadEnabled'])?>" data-preview-x="250" data-preview-y="250">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th id="headerSelection" class="hidden column-selection">
|
<th id="headerSelection" class="hidden column-selection">
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<p></p>
|
<p></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table id="filestable">
|
<table id="filestable" class="list-container view-grid">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th id='headerName' class="hidden column-name">
|
<th id='headerName' class="hidden column-name">
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<h2><?php p($l->t('No entries found in this folder')); ?></h2>
|
<h2><?php p($l->t('No entries found in this folder')); ?></h2>
|
||||||
<p></p>
|
<p></p>
|
||||||
</div>
|
</div>
|
||||||
<table id="filestable">
|
<table id="filestable" class="list-container view-grid">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th id='headerName' class="hidden column-name">
|
<th id='headerName' class="hidden column-name">
|
||||||
|
|
|
@ -25,7 +25,7 @@ describe('OCA.Files.FavoritesFileList tests', function() {
|
||||||
'</div>' +
|
'</div>' +
|
||||||
// dummy table
|
// dummy table
|
||||||
// TODO: at some point this will be rendered by the fileList class itself!
|
// TODO: at some point this will be rendered by the fileList class itself!
|
||||||
'<table id="filestable">' +
|
'<table id="filestable" class="list-container view-grid">' +
|
||||||
'<thead><tr>' +
|
'<thead><tr>' +
|
||||||
'<th id="headerName" class="hidden column-name">' +
|
'<th id="headerName" class="hidden column-name">' +
|
||||||
'<a class="name columntitle" data-sort="name"><span>Name</span><span class="sort-indicator"></span></a>' +
|
'<a class="name columntitle" data-sort="name"><span>Name</span><span class="sort-indicator"></span></a>' +
|
||||||
|
|
|
@ -117,7 +117,7 @@ describe('OC.Upload tests', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
$('#testArea').append(
|
$('#testArea').append(
|
||||||
'<div id="tableContainer">' +
|
'<div id="tableContainer">' +
|
||||||
'<table id="filestable">' +
|
'<table id="filestable" class="list-container view-grid">' +
|
||||||
'<thead><tr>' +
|
'<thead><tr>' +
|
||||||
'<th id="headerName" class="hidden column-name">' +
|
'<th id="headerName" class="hidden column-name">' +
|
||||||
'<input type="checkbox" id="select_all_files" class="select-all">' +
|
'<input type="checkbox" id="select_all_files" class="select-all">' +
|
||||||
|
|
|
@ -28,7 +28,7 @@ describe('OCA.Files.FileActions tests', function() {
|
||||||
var $body = $('#testArea');
|
var $body = $('#testArea');
|
||||||
$body.append('<input type="hidden" id="dir" value="/subdir"></input>');
|
$body.append('<input type="hidden" id="dir" value="/subdir"></input>');
|
||||||
$body.append('<input type="hidden" id="permissions" value="31"></input>');
|
$body.append('<input type="hidden" id="permissions" value="31"></input>');
|
||||||
$body.append('<table id="filestable"><tbody id="fileList"></tbody></table>');
|
$body.append('<table id="filestable" class="list-container view-grid"><tbody id="fileList"></tbody></table>');
|
||||||
// dummy files table
|
// dummy files table
|
||||||
fileActions = new OCA.Files.FileActions();
|
fileActions = new OCA.Files.FileActions();
|
||||||
fileActions.registerAction({
|
fileActions.registerAction({
|
||||||
|
|
|
@ -88,7 +88,7 @@ describe('OCA.Files.FileList tests', function() {
|
||||||
'<input type="file" id="file_upload_start" name="files[]" multiple="multiple">' +
|
'<input type="file" id="file_upload_start" name="files[]" multiple="multiple">' +
|
||||||
// dummy table
|
// dummy table
|
||||||
// TODO: at some point this will be rendered by the fileList class itself!
|
// TODO: at some point this will be rendered by the fileList class itself!
|
||||||
'<table id="filestable">' +
|
'<table id="filestable" class="list-container view-grid">' +
|
||||||
'<thead><tr>' +
|
'<thead><tr>' +
|
||||||
'<th id="headerName" class="hidden column-name">' +
|
'<th id="headerName" class="hidden column-name">' +
|
||||||
'<input type="checkbox" id="select_all_files" class="select-all checkbox">' +
|
'<input type="checkbox" id="select_all_files" class="select-all checkbox">' +
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
<input type="hidden" name="dir" value="" id="dir">
|
<input type="hidden" name="dir" value="" id="dir">
|
||||||
|
|
||||||
<table id="filestable">
|
<table id="filestable" class="list-container view-grid">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th id='headerName' class="hidden column-name">
|
<th id='headerName' class="hidden column-name">
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#preview {
|
#preview {
|
||||||
background: var(--color-main-background);
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -229,10 +229,10 @@ OCA.Sharing.PublicApp = {
|
||||||
this.fileList.generatePreviewUrl = function (urlSpec) {
|
this.fileList.generatePreviewUrl = function (urlSpec) {
|
||||||
urlSpec = urlSpec || {};
|
urlSpec = urlSpec || {};
|
||||||
if (!urlSpec.x) {
|
if (!urlSpec.x) {
|
||||||
urlSpec.x = 32;
|
urlSpec.x = this.$table.data('preview-x') || 32;
|
||||||
}
|
}
|
||||||
if (!urlSpec.y) {
|
if (!urlSpec.y) {
|
||||||
urlSpec.y = 32;
|
urlSpec.y = this.$table.data('preview-y') || 32;
|
||||||
}
|
}
|
||||||
urlSpec.x *= window.devicePixelRatio;
|
urlSpec.x *= window.devicePixelRatio;
|
||||||
urlSpec.y *= window.devicePixelRatio;
|
urlSpec.y *= window.devicePixelRatio;
|
||||||
|
|
|
@ -357,6 +357,7 @@ class ShareController extends AuthPublicShareController {
|
||||||
$folder->assign('isPublic', true);
|
$folder->assign('isPublic', true);
|
||||||
$folder->assign('hideFileList', $hideFileList);
|
$folder->assign('hideFileList', $hideFileList);
|
||||||
$folder->assign('publicUploadEnabled', 'no');
|
$folder->assign('publicUploadEnabled', 'no');
|
||||||
|
$folder->assign('showgridview', true);
|
||||||
$folder->assign('uploadMaxFilesize', $maxUploadFilesize);
|
$folder->assign('uploadMaxFilesize', $maxUploadFilesize);
|
||||||
$folder->assign('uploadMaxHumanFilesize', \OCP\Util::humanFileSize($maxUploadFilesize));
|
$folder->assign('uploadMaxHumanFilesize', \OCP\Util::humanFileSize($maxUploadFilesize));
|
||||||
$folder->assign('freeSpace', $freeSpace);
|
$folder->assign('freeSpace', $freeSpace);
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<h2><?php p($l->t('No entries found in this folder')); ?></h2>
|
<h2><?php p($l->t('No entries found in this folder')); ?></h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table id="filestable">
|
<table id="filestable" class="list-container view-grid">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th id='headerName' class="hidden column-name">
|
<th id='headerName' class="hidden column-name">
|
||||||
|
|
|
@ -60,7 +60,7 @@ describe('OCA.Sharing.PublicApp tests', function() {
|
||||||
'<input type="file" id="file_upload_start" name="files[]" multiple="multiple">' +
|
'<input type="file" id="file_upload_start" name="files[]" multiple="multiple">' +
|
||||||
// dummy table
|
// dummy table
|
||||||
// TODO: at some point this will be rendered by the fileList class itself!
|
// TODO: at some point this will be rendered by the fileList class itself!
|
||||||
'<table id="filestable">' +
|
'<table id="filestable" class="list-container view-grid">' +
|
||||||
'<thead><tr>' +
|
'<thead><tr>' +
|
||||||
'<th id="headerName" class="hidden column-name">' +
|
'<th id="headerName" class="hidden column-name">' +
|
||||||
'<input type="checkbox" id="select_all_files" class="select-all">' +
|
'<input type="checkbox" id="select_all_files" class="select-all">' +
|
||||||
|
|
|
@ -28,7 +28,7 @@ describe('OCA.Sharing.Util tests', function() {
|
||||||
// dummy file list
|
// dummy file list
|
||||||
var $div = $(
|
var $div = $(
|
||||||
'<div id="listContainer">' +
|
'<div id="listContainer">' +
|
||||||
'<table id="filestable">' +
|
'<table id="filestable" class="list-container view-grid">' +
|
||||||
'<thead></thead>' +
|
'<thead></thead>' +
|
||||||
'<tbody id="fileList"></tbody>' +
|
'<tbody id="fileList"></tbody>' +
|
||||||
'</table>' +
|
'</table>' +
|
||||||
|
|
|
@ -28,7 +28,7 @@ describe('OCA.Sharing.FileList tests', function() {
|
||||||
'</div>' +
|
'</div>' +
|
||||||
// dummy table
|
// dummy table
|
||||||
// TODO: at some point this will be rendered by the fileList class itself!
|
// TODO: at some point this will be rendered by the fileList class itself!
|
||||||
'<table id="filestable">' +
|
'<table id="filestable" class="list-container view-grid">' +
|
||||||
'<thead><tr>' +
|
'<thead><tr>' +
|
||||||
'<th id="headerName" class="hidden column-name">' +
|
'<th id="headerName" class="hidden column-name">' +
|
||||||
'<input type="checkbox" id="select_all_files" class="select-all">' +
|
'<input type="checkbox" id="select_all_files" class="select-all">' +
|
||||||
|
@ -701,7 +701,7 @@ describe('OCA.Sharing.FileList tests', function() {
|
||||||
// dummy file list
|
// dummy file list
|
||||||
var $div = $(
|
var $div = $(
|
||||||
'<div>' +
|
'<div>' +
|
||||||
'<table id="filestable">' +
|
'<table id="filestable" class="list-container view-grid">' +
|
||||||
'<thead></thead>' +
|
'<thead></thead>' +
|
||||||
'<tbody id="fileList"></tbody>' +
|
'<tbody id="fileList"></tbody>' +
|
||||||
'</table>' +
|
'</table>' +
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
<p></p>
|
<p></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table id="filestable">
|
<table id="filestable" class="list-container view-grid">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th id="headerSelection" class="hidden column-selection">
|
<th id="headerSelection" class="hidden column-selection">
|
||||||
|
|
|
@ -48,7 +48,7 @@ describe('OCA.Trashbin.FileList tests', function () {
|
||||||
'</div>' +
|
'</div>' +
|
||||||
// dummy table
|
// dummy table
|
||||||
// TODO: at some point this will be rendered by the fileList class itself!
|
// TODO: at some point this will be rendered by the fileList class itself!
|
||||||
'<table id="filestable">' +
|
'<table id="filestable" class="list-container view-grid">' +
|
||||||
'<thead><tr><th id="headerName" class="hidden">' +
|
'<thead><tr><th id="headerName" class="hidden">' +
|
||||||
'<input type="checkbox" id="select_all_trash" class="select-all">' +
|
'<input type="checkbox" id="select_all_trash" class="select-all">' +
|
||||||
'<span class="name">Name</span>' +
|
'<span class="name">Name</span>' +
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
:root {
|
:root {
|
||||||
--color-main-text: $color-main-text;
|
--color-main-text: $color-main-text;
|
||||||
--color-main-background: $color-main-background;
|
--color-main-background: $color-main-background;
|
||||||
|
--color-main-background-translucent: $color-main-background-translucent;
|
||||||
|
|
||||||
--color-background-dark: $color-background-dark;
|
--color-background-dark: $color-background-dark;
|
||||||
--color-background-darker: $color-background-darker;
|
--color-background-darker: $color-background-darker;
|
||||||
|
|
|
@ -297,6 +297,7 @@ img, object, video, button, textarea, input, select, div[contenteditable='true']
|
||||||
@include icon-black-white('toggle', 'actions', 1, true);
|
@include icon-black-white('toggle', 'actions', 1, true);
|
||||||
@include icon-black-white('toggle-background', 'actions', 1, true);
|
@include icon-black-white('toggle-background', 'actions', 1, true);
|
||||||
@include icon-black-white('toggle-pictures', 'actions', 1, true);
|
@include icon-black-white('toggle-pictures', 'actions', 1, true);
|
||||||
|
@include icon-black-white('toggle-filelist', 'actions', 1, true);
|
||||||
@include icon-black-white('triangle-e', 'actions', 1, true);
|
@include icon-black-white('triangle-e', 'actions', 1, true);
|
||||||
@include icon-black-white('triangle-n', 'actions', 1, true);
|
@include icon-black-white('triangle-n', 'actions', 1, true);
|
||||||
@include icon-black-white('triangle-s', 'actions', 1, true);
|
@include icon-black-white('triangle-s', 'actions', 1, true);
|
||||||
|
|
|
@ -167,7 +167,7 @@ body {
|
||||||
height: 44px;
|
height: 44px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
background-color: var(--color-main-background);
|
background-color: var(--color-main-background-translucent);
|
||||||
z-index: 60;
|
z-index: 60;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
|
@ -697,12 +697,15 @@ code {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- DIALOGS ---- */
|
/* ---- DIALOGS ---- */
|
||||||
|
|
||||||
#oc-dialog-filepicker-content {
|
#oc-dialog-filepicker-content {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
.dirtree {
|
.dirtree {
|
||||||
width: 96%;
|
width: 100%;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
|
padding-right: 44px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
div:first-child a {
|
div:first-child a {
|
||||||
background-image: url('../img/places/home.svg?v=1');
|
background-image: url('../img/places/home.svg?v=1');
|
||||||
|
@ -722,6 +725,28 @@ code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Grid view toggle */
|
||||||
|
#picker-view-toggle {
|
||||||
|
position: absolute;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 22px;
|
||||||
|
opacity: .5;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// keyboard focus
|
||||||
|
#picker-showgridview:focus + #picker-view-toggle {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.filelist-container {
|
.filelist-container {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -771,9 +796,54 @@ code {
|
||||||
.filesize {
|
.filesize {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
&.view-grid {
|
||||||
|
$grid-size: 120px;
|
||||||
|
$grid-pad: 10px;
|
||||||
|
$name-height: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
tbody {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, $grid-size);
|
||||||
|
justify-content: space-around;
|
||||||
|
row-gap: 15px;
|
||||||
|
margin: 15px 0;
|
||||||
|
|
||||||
|
tr {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
padding: $grid-pad;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: $grid-size - 2 * $grid-pad;
|
||||||
|
|
||||||
|
td {
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&.filename {
|
||||||
|
padding: #{$grid-size - 2 * $grid-pad} 0 0 0;
|
||||||
|
background-position: center top;
|
||||||
|
background-size: contain;
|
||||||
|
line-height: $name-height;
|
||||||
|
height: $name-height;
|
||||||
|
}
|
||||||
|
&.filesize {
|
||||||
|
line-height: $name-height;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
&.date {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.filepicker_element_selected {
|
.filepicker_element_selected {
|
||||||
background-color: lightblue;
|
background-color: var(--color-background-darker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
// DEPRECATED, please use CSS4 vars
|
// DEPRECATED, please use CSS4 vars
|
||||||
$color-main-text: #222 !default; // Not #000 for better readability
|
$color-main-text: #222 !default; // Not #000 for better readability
|
||||||
$color-main-background: #fff !default;
|
$color-main-background: #fff !default;
|
||||||
|
$color-main-background-translucent: rgba($color-main-background, .97) !default;
|
||||||
|
|
||||||
// used for different active/disabled states
|
// used for different active/disabled states
|
||||||
$color-background-dark: nc-darken($color-main-background, 7%) !default;
|
$color-background-dark: nc-darken($color-main-background, 7%) !default;
|
||||||
|
|
|
@ -208,6 +208,7 @@ var OCdialogs = {
|
||||||
|
|
||||||
this.filepicker.loading = true;
|
this.filepicker.loading = true;
|
||||||
this.filepicker.filesClient = (OCA.Sharing && OCA.Sharing.PublicApp && OCA.Sharing.PublicApp.fileList)? OCA.Sharing.PublicApp.fileList.filesClient: OC.Files.getClient();
|
this.filepicker.filesClient = (OCA.Sharing && OCA.Sharing.PublicApp && OCA.Sharing.PublicApp.fileList)? OCA.Sharing.PublicApp.fileList.filesClient: OC.Files.getClient();
|
||||||
|
|
||||||
$.when(this._getFilePickerTemplate()).then(function($tmpl) {
|
$.when(this._getFilePickerTemplate()).then(function($tmpl) {
|
||||||
self.filepicker.loading = false;
|
self.filepicker.loading = false;
|
||||||
var dialogName = 'oc-dialog-filepicker-content';
|
var dialogName = 'oc-dialog-filepicker-content';
|
||||||
|
@ -237,6 +238,11 @@ var OCdialogs = {
|
||||||
|
|
||||||
$('body').append(self.$filePicker);
|
$('body').append(self.$filePicker);
|
||||||
|
|
||||||
|
self.$showGridView = $('input#picker-showgridview');
|
||||||
|
self.$showGridView.on('change', _.bind(self._onGridviewChange, self));
|
||||||
|
|
||||||
|
self._getGridSettings();
|
||||||
|
|
||||||
self.$filePicker.ready(function() {
|
self.$filePicker.ready(function() {
|
||||||
self.$filelist = self.$filePicker.find('.filelist tbody');
|
self.$filelist = self.$filePicker.find('.filelist tbody');
|
||||||
self.$dirTree = self.$filePicker.find('.dirtree');
|
self.$dirTree = self.$filePicker.find('.dirtree');
|
||||||
|
@ -779,6 +785,31 @@ var OCdialogs = {
|
||||||
//}
|
//}
|
||||||
return dialogDeferred.promise();
|
return dialogDeferred.promise();
|
||||||
},
|
},
|
||||||
|
// get the gridview setting and set the input accordingly
|
||||||
|
_getGridSettings: function() {
|
||||||
|
var self = this;
|
||||||
|
$.get(OC.generateUrl('/apps/files/api/v1/showgridview'), function(response) {
|
||||||
|
self.$showGridView.checked = response.gridview;
|
||||||
|
self.$showGridView.next('#picker-view-toggle')
|
||||||
|
.removeClass('icon-toggle-filelist icon-toggle-pictures')
|
||||||
|
.addClass(response.gridview ? 'icon-toggle-filelist' : 'icon-toggle-pictures')
|
||||||
|
$('.list-container').toggleClass('view-grid', response.gridview);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_onGridviewChange: function() {
|
||||||
|
var show = this.$showGridView.is(':checked');
|
||||||
|
// only save state if user is logged in
|
||||||
|
if (OC.currentUser) {
|
||||||
|
$.post(OC.generateUrl('/apps/files/api/v1/showgridview'), {
|
||||||
|
show: show
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.$showGridView.next('#picker-view-toggle')
|
||||||
|
.removeClass('icon-toggle-filelist icon-toggle-pictures')
|
||||||
|
.addClass(show ? 'icon-toggle-filelist' : 'icon-toggle-pictures')
|
||||||
|
|
||||||
|
$('.list-container').toggleClass('view-grid', show);
|
||||||
|
},
|
||||||
_getFilePickerTemplate: function() {
|
_getFilePickerTemplate: function() {
|
||||||
var defer = $.Deferred();
|
var defer = $.Deferred();
|
||||||
if(!this.$filePickerTemplate) {
|
if(!this.$filePickerTemplate) {
|
||||||
|
@ -899,6 +930,8 @@ var OCdialogs = {
|
||||||
if (entry.type === 'file') {
|
if (entry.type === 'file') {
|
||||||
var urlSpec = {
|
var urlSpec = {
|
||||||
file: dir + '/' + entry.name,
|
file: dir + '/' + entry.name,
|
||||||
|
x: 100,
|
||||||
|
y: 100
|
||||||
};
|
};
|
||||||
var img = new Image();
|
var img = new Image();
|
||||||
var previewUrl = OC.generateUrl('/core/preview.png?') + $.param(urlSpec);
|
var previewUrl = OC.generateUrl('/core/preview.png?') + $.param(urlSpec);
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
<div id="{dialog_name}" title="{title}">
|
<div id="{dialog_name}" title="{title}">
|
||||||
<span class="dirtree breadcrumb"></span>
|
<span class="dirtree breadcrumb"></span>
|
||||||
|
<input type="checkbox" class="hidden-visually" id="picker-showgridview" checked="checked" />
|
||||||
|
<label id="picker-view-toggle" for="picker-showgridview" class="button icon-toggle-filelist"></label>
|
||||||
<div class="filelist-container">
|
<div class="filelist-container">
|
||||||
<div class="emptycontent">
|
<div class="emptycontent">
|
||||||
<div class="icon-folder"></div>
|
<div class="icon-folder"></div>
|
||||||
<h2>{emptytext}</h2>
|
<h2>{emptytext}</h2>
|
||||||
</div>
|
</div>
|
||||||
<table id="filestable" class="filelist">
|
<table id="filestable" class="filelist list-container view-grid">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr data-entryname="{filename}" data-type="{type}">
|
<tr data-entryname="{filename}" data-type="{type}">
|
||||||
<td class="filename"
|
<td class="filename"
|
||||||
|
|
Loading…
Reference in New Issue