Skip to content

Commit bf04162

Browse files
committed
Add bulk actions; Add AJAX support; Inject Dropzone tags
1 parent 62c01c4 commit bf04162

14 files changed

Lines changed: 191 additions & 85 deletions

File tree

src/Controllers/Files.php

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,12 @@ public function index()
4545
'format' => $this->getFormat(),
4646
'access' => $access,
4747
'exports' => $exports->getByExtensions(),
48+
'bulks' => $exports->where('bulk', 1)->findAll(),
4849
];
50+
51+
// AJAX calls skip the wrapping
52+
if ($this->request->isAJAX())
53+
return view("Tatter\Files\Views\\formats\\{$data['format']}", $data);
4954
return view('Tatter\Files\Views\index', $data);
5055
}
5156

@@ -95,7 +100,12 @@ public function user($userId = null)
95100
'access' => $access,
96101
'username' => $username,
97102
'exports' => $exports->getByExtensions(),
103+
'bulks' => $exports->where('bulk', 1)->findAll(),
98104
];
105+
106+
// AJAX calls skip the wrapping
107+
if ($this->request->isAJAX())
108+
return view("Tatter\Files\Views\\formats\\{$data['format']}", $data);
99109
return view('Tatter\Files\Views\index', $data);
100110
}
101111

@@ -195,6 +205,59 @@ public function delete($fileId)
195205
return redirect()->back();
196206
}
197207

208+
// Handle bulk actions
209+
public function bulk()
210+
{
211+
// Load post data
212+
$post = $this->request->getPost();
213+
214+
// Harvest file IDs and the requested action
215+
$action = '';
216+
$fileIds = [];
217+
foreach ($post as $key => $value):
218+
if (is_numeric($value)):
219+
$fileIds[] = $value;
220+
else:
221+
$action = $key;
222+
endif;
223+
endforeach;
224+
225+
// Make sure some files where checked
226+
if (empty($fileIds)):
227+
alert('warning', lang('File.nofile'));
228+
return redirect()->back();
229+
endif;
230+
231+
// Handle actions
232+
switch ($action):
233+
case '':
234+
alert('warning', 'No valid action.');
235+
break;
236+
237+
// Bulk delete request
238+
case 'delete':
239+
$this->model->delete($fileIds);
240+
alert('success', 'Deleted ' . count($fileIds) . ' files.');
241+
break;
242+
243+
default:
244+
// Match the export handler
245+
$exports = new ExportModel();
246+
$handler = $exports->where('uid', $action)->first();
247+
if (empty($handler)):
248+
alert('warning', 'No handler found for ' . $uid);
249+
return redirect()->back();
250+
endif;
251+
252+
// Pass to the handler
253+
//$response = $handler->process($file->path, $file->filename);
254+
255+
alert('success', 'Processed ' . count($fileIds) . ' files.');
256+
endswitch;
257+
258+
return redirect()->back();
259+
}
260+
198261
// Receives uploads from Dropzone
199262
public function upload()
200263
{
@@ -357,16 +420,22 @@ public function export($uid, $fileId)
357420
return redirect()->back();
358421
endif;
359422

360-
// Load the file and pass to the handler
423+
// Load the file
361424
$file = $this->model->find($fileId);
425+
if (empty($file)):
426+
alert('warning', lang('Files.noFile'));
427+
return redirect()->back();
428+
endif;
429+
430+
// Pass to the handler
362431
$response = $handler->process($file->path, $file->filename);
363432

364433
// If the handler returned a response then we're done
365434
if ($response instanceof ResponseInterface)
366435
return $response;
367436

368437
if ($response === true):
369-
alert('success', ucfirst($uid) . ' export was successful.');
438+
alert('success', lang('Files.noFile', [ucfirst($uid)]) );
370439
elseif ($response === false):
371440
$error = implode('. ', $handler->getErrors());
372441
alert('error', $error);

src/Language/en/Files.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
'noFile' => 'No file provided',
88
'newFileFail' => 'Unable to create file for merging: {0}',
99
'writeFileFail' => 'Unable to open file for merging: {0}',
10+
'exportSuccess' => '{0} export was successful',
1011
'renameSuccess' => 'File renamed to {0}',
11-
];
12+
];

src/Models/FileModel.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public function getForUser(int $userId): array
5151
->select('files.*')
5252
->join('files_users', 'files_users.file_id = files.id', 'left')
5353
->where('user_id', $userId)
54+
->where('deleted_at IS NULL')
5455
->get()->getResult($this->returnType);
5556
}
5657
}

src/Views/actions/bulk.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
// Make sure there is something to display
3+
if (empty($bulks) && $access == 'display')
4+
return;
5+
?>
6+
<button class="btn btn-primary btn-sm mb-3 dropdown-toggle" type="button" id="export-bulk" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
7+
<i class="fas fa-share-square"></i> Actions
8+
</button>
9+
<div class="dropdown-menu" aria-labelledby="export-bulk">
10+
11+
<?php if (! empty($bulks)): ?>
12+
<h6 class="dropdown-header">Send To</h6>
13+
<?php foreach ($bulks as $export): ?>
14+
<?php if ($export->ajax): ?>
15+
<input name="<?= $export->uid ?>" type="submit" class="dropdown-item" value="<?= $export->name ?>" onclick="$('#globalModal .modal-body').load('<?= site_url('files/bulk/' . $export->uid) ?>'); $('#globalModal').modal(); return false;">
16+
17+
<?php else: ?>
18+
<input name="<?= $export->uid ?>" type="submit" class="dropdown-item" value="<?= $export->name ?>">
19+
20+
<?php endif; ?>
21+
<?php endforeach; ?>
22+
<?php endif; ?>
23+
24+
<?php if ($access == 'manage'): ?>
25+
<div class="dropdown-divider"></div>
26+
<h6 class="dropdown-header">Manage</h6>
27+
<input name="delete" type="submit" class="dropdown-item" value="Delete">
28+
<?php endif; ?>
29+
30+
</div>
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,42 @@
1+
<?php
2+
// Determine eligible exports for this file
3+
$extension = pathinfo($file->filename, PATHINFO_EXTENSION);
4+
$matched = [];
5+
6+
// Universally-available exports
7+
if (isset($exports['*']))
8+
$matched = array_merge($matched, $exports['*']);
9+
// Exports specific to this extension
10+
if (isset($exports[$extension]))
11+
$matched = array_merge($matched, $exports[$extension]);
12+
13+
// Make sure there is something to display
14+
if (empty($matched) && $access == 'display')
15+
return;
16+
?>
117
<button class="btn btn-secondary btn-sm dropdown-toggle" type="button" id="export-<?= $file->id ?>" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
2-
<i class="fas fa-share-square"></i> Options
18+
<i class="fas fa-share-square"></i> Actions
319
</button>
420
<div class="dropdown-menu" aria-labelledby="export-<?= $file->id ?>">
21+
22+
<?php if (! empty($matched)): ?>
523
<h6 class="dropdown-header">Send To</h6>
6-
<a class="dropdown-item" href="#">Preview</a>
7-
<?php
8-
// Universally available exports
9-
if (isset($exports['*'])):
10-
foreach ($exports['*'] as $export):
11-
?>
24+
<?php foreach ($matched as $export): ?>
25+
<?php if ($export->ajax): ?>
26+
<a class="dropdown-item" href="<?= site_url('files/export/' . $export->uid . '/' . $file->id) ?>" onclick="$('#globalModal .modal-body').load('<?= site_url('files/export/' . $export->uid . '/' . $file->id) ?>'); $('#globalModal').modal(); return false;"><?= $export->name ?></a>
27+
28+
<?php else: ?>
1229
<a class="dropdown-item" href="<?= site_url('files/export/' . $export->uid . '/' . $file->id) ?>"><?= $export->name ?></a>
13-
<?php
14-
endforeach;
15-
endif;
30+
31+
<?php endif; ?>
32+
<?php endforeach; ?>
33+
<?php endif; ?>
1634

17-
// Exports specific to this extension
18-
$extension = pathinfo($file->filename, PATHINFO_EXTENSION);
19-
if (isset($exports[$extension])):
20-
foreach ($exports[$extension] as $export):
21-
?>
22-
<a class="dropdown-item" href="<?= site_url('files/export/' . $export->uid . '/' . $file->id) ?>"><?= $export->name ?></a>
23-
<?php
24-
endforeach;
25-
endif;
26-
?>
27-
<?php if ($access == 'manage'): ?>
35+
<?php if ($access == 'manage'): ?>
2836
<div class="dropdown-divider"></div>
2937
<h6 class="dropdown-header">Manage</h6>
3038
<a class="dropdown-item" href="<?= site_url('files/rename/' . $file->id) ?>" onclick="$('#globalModal .modal-body').load('<?= site_url('files/rename/' . $file->id) ?>'); $('#globalModal').modal(); return false;">Rename</a>
3139
<a class="dropdown-item" href="<?= site_url('files/delete/' . $file->id) ?>">Delete</a>
32-
<?php endif; ?>
40+
<?php endif; ?>
41+
3342
</div>

src/Views/dropzone/config.php

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
<!-- DropzoneJS CSS -->
2+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.1/min/dropzone.min.css" integrity="sha256-e47xOkXs1JXFbjjpoRr1/LhVcqSzRmGmPqsrUQeVs+g=" crossorigin="anonymous" />
3+
<!-- DropzoneJS JavaScript -->
4+
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.1/min/dropzone.min.js" integrity="sha256-cs4thShDfjkqFGk5s2Lxj35sgSRr4MRcyccmi0WKqCM=" crossorigin="anonymous"></script>
15
<script>
26
<?php
37
// Determine upload limit from PHP settings
@@ -10,26 +14,31 @@
1014
// Limit files to the MB equivalent of 500 chunks
1115
$maxFileSize = round($chunkSize * 500 / 1024 / 1024, 1);
1216
?>
13-
$(document).ready(function() {
14-
Dropzone.options.filesDropzone = {
15-
16-
// Maximum file size in MB
17-
maxFilesize: <?= $maxFileSize ?>,
18-
19-
// Disable parallel uploads
20-
// (CodeIgniter4 Sessions chokes on interspersed AJAX calls)
21-
parallelUploads: 1,
22-
23-
// Enable chunking
24-
chunking: true,
25-
chunkSize: <?= $chunkSize ?>, // bytes
26-
retryChunks: true,
27-
retryChunksLimit: 3,
28-
29-
// When chunking include chunk data as POST fields
30-
params: function(files, xhr, chunk) {
31-
return chunk ? { uuid: chunk.file.upload.uuid, totalChunks: chunk.file.upload.totalChunkCount, chunkIndex: chunk.index } : null;
32-
}
33-
};
34-
});
17+
Dropzone.options.filesDropzone = {
18+
19+
// Reload file list after uploads
20+
init: function() {
21+
this.on("queuecomplete", function() {
22+
$("#files-wrapper").load('<?= current_url() ?>');
23+
});
24+
},
25+
26+
// Maximum file size in MB
27+
maxFilesize: <?= $maxFileSize ?>,
28+
29+
// Disable parallel uploads
30+
// (CodeIgniter4 Sessions chokes on interspersed AJAX calls)
31+
parallelUploads: 1,
32+
33+
// Enable chunking
34+
chunking: true,
35+
chunkSize: <?= $chunkSize ?>, // bytes
36+
retryChunks: true,
37+
retryChunksLimit: 3,
38+
39+
// When chunking include chunk data as POST fields
40+
params: function(files, xhr, chunk) {
41+
return chunk ? { uuid: chunk.file.upload.uuid, totalChunks: chunk.file.upload.totalChunkCount, chunkIndex: chunk.index } : null;
42+
}
43+
};
3544
</script>

src/Views/formats/cards.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<div class="card mb-4" style="min-width: 10rem; max-width: 200px;">
77
<img src="<?= $file->thumbnail ?>" class="card-img-top img-thumbnail" alt="<?= $file->filename ?>">
88
<div class="card-header">
9-
<?= view('Tatter\Files\Views\templates\actions', ['file' => $file, 'access' => $access]) ?>
9+
<?= view('Tatter\Files\Views\actions\single', ['file' => $file, 'access' => $access]) ?>
1010
</div>
1111
<div class="card-body">
1212
<h6 class="card-title"><?= bytes2human($file->size) ?></h6>

src/Views/formats/list.php

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,7 @@
2121
<td class="align-middle"><?= bytes2human($file->size) ?></td>
2222
<td class="align-middle"><?= $file->created_at->humanize(); ?></td>
2323
<td class="align-middle">
24-
<button class="btn btn-secondary btn-sm dropdown-toggle" type="button" id="export-<?= $file->id ?>" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
25-
<i class="fas fa-share-square"></i> Options
26-
</button>
27-
<div class="dropdown-menu" aria-labelledby="export-<?= $file->id ?>">
28-
<h6 class="dropdown-header">Send To</h6>
29-
<a class="dropdown-item" href="#">Preview</a>
30-
<a class="dropdown-item" href="<?= site_url('files/export/download/' . $file->id) ?>">Download</a>
31-
<?php if ($access == 'manage'): ?>
32-
<div class="dropdown-divider"></div>
33-
<h6 class="dropdown-header">Manage</h6>
34-
<a class="dropdown-item" href="<?= site_url('files/rename/' . $file->id) ?>">Rename</a>
35-
<a class="dropdown-item" href="<?= site_url('files/delete/' . $file->id) ?>">Delete</a>
36-
<?php endif; ?>
37-
</div>
24+
<?= view('Tatter\Files\Views\actions\single', ['file' => $file, 'access' => $access]) ?>
3825
</td>
3926
</tr>
4027
<?php endforeach; ?>

src/Views/formats/select.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
<table class="table table-sm table-striped">
55
<thead>
66
<tr>
7-
<th scope="col"></th>
87
<th scope="col">Filename</th>
98
<th scope="col">Type</th>
109
<th scope="col">Size</th>
@@ -14,8 +13,12 @@
1413
<tbody>
1514
<?php foreach ($files as $file): ?>
1615
<tr>
17-
<td><input name="file_<?= $file->id ?>" type="checkbox" class="class="form-check-input" value="1"></td>
18-
<td class="align-middle"><?= $file->filename ?></td>
16+
<td>
17+
<div class="form-check">
18+
<input class="form-check-input" name="file<?= $file->id ?>" id="file<?= $file->id ?>" type="checkbox" value="<?= $file->id ?>">
19+
<label class="form-check-label" for="file<?= $file->id ?>"><?= $file->filename ?></label>
20+
</div>
21+
</td>
1922
<td class="align-middle"><?= $file->type ?></td>
2023
<td class="align-middle"><?= bytes2human($file->size) ?></td>
2124
<td class="align-middle"><?= $file->created_at->humanize(); ?></td>
Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
1+
<h6><?= $file->filename ?></h6>
22
<form name="file-rename" class="form-inline" action="<?= site_url('files/rename') ?>" method="post">
33
<div class="form-group mr-2">
4-
<label for="filename" class="form-label mr-2">New filename:</label>
5-
<input name="filename" type="text" class="form-control" id="filename" value="<?= $file->filename ?>" onclick="this.select();" autofocus>
4+
<input name="filename" type="text" class="form-control" id="filename" value="<?= $file->filename ?>" autofocus>
65
</div>
76
<div class="form-group">
87
<input name="file_id" type="hidden" value="<?= $file->id ?>">
9-
<button type="submit" class="btn btn-primary">Submit</button>
8+
<button type="submit" class="btn btn-primary">Rename</button>
109
</div>
1110
</form>

0 commit comments

Comments
 (0)