Showing
7 changed files
with
305 additions
and
77 deletions
| ... | @@ -58,6 +58,70 @@ class FileController extends Controller | ... | @@ -58,6 +58,70 @@ class FileController extends Controller |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | /** | 60 | /** |
| 61 | + * Update an uploaded file. | ||
| 62 | + * @param int $fileId | ||
| 63 | + * @param Request $request | ||
| 64 | + * @return mixed | ||
| 65 | + */ | ||
| 66 | + public function uploadUpdate($fileId, Request $request) | ||
| 67 | + { | ||
| 68 | + $this->validate($request, [ | ||
| 69 | + 'uploaded_to' => 'required|integer|exists:pages,id', | ||
| 70 | + 'file' => 'required|file' | ||
| 71 | + ]); | ||
| 72 | + | ||
| 73 | + $pageId = $request->get('uploaded_to'); | ||
| 74 | + $page = $this->pageRepo->getById($pageId); | ||
| 75 | + $file = $this->file->findOrFail($fileId); | ||
| 76 | + | ||
| 77 | + $this->checkOwnablePermission('page-update', $page); | ||
| 78 | + $this->checkOwnablePermission('file-create', $file); | ||
| 79 | + | ||
| 80 | + if (intval($pageId) !== intval($file->uploaded_to)) { | ||
| 81 | + return $this->jsonError('Page mismatch during attached file update'); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + $uploadedFile = $request->file('file'); | ||
| 85 | + | ||
| 86 | + try { | ||
| 87 | + $file = $this->fileService->saveUpdatedUpload($uploadedFile, $file); | ||
| 88 | + } catch (FileUploadException $e) { | ||
| 89 | + return response($e->getMessage(), 500); | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + return response()->json($file); | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + /** | ||
| 96 | + * Update the details of an existing file. | ||
| 97 | + * @param $fileId | ||
| 98 | + * @param Request $request | ||
| 99 | + * @return File|mixed | ||
| 100 | + */ | ||
| 101 | + public function update($fileId, Request $request) | ||
| 102 | + { | ||
| 103 | + $this->validate($request, [ | ||
| 104 | + 'uploaded_to' => 'required|integer|exists:pages,id', | ||
| 105 | + 'name' => 'string|max:255', | ||
| 106 | + 'link' => 'url' | ||
| 107 | + ]); | ||
| 108 | + | ||
| 109 | + $pageId = $request->get('uploaded_to'); | ||
| 110 | + $page = $this->pageRepo->getById($pageId); | ||
| 111 | + $file = $this->file->findOrFail($fileId); | ||
| 112 | + | ||
| 113 | + $this->checkOwnablePermission('page-update', $page); | ||
| 114 | + $this->checkOwnablePermission('file-create', $file); | ||
| 115 | + | ||
| 116 | + if (intval($pageId) !== intval($file->uploaded_to)) { | ||
| 117 | + return $this->jsonError('Page mismatch during attachment update'); | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + $file = $this->fileService->updateFile($file, $request->all()); | ||
| 121 | + return $file; | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + /** | ||
| 61 | * Attach a link to a page as a file. | 125 | * Attach a link to a page as a file. |
| 62 | * @param Request $request | 126 | * @param Request $request |
| 63 | * @return mixed | 127 | * @return mixed |
| ... | @@ -66,8 +130,8 @@ class FileController extends Controller | ... | @@ -66,8 +130,8 @@ class FileController extends Controller |
| 66 | { | 130 | { |
| 67 | $this->validate($request, [ | 131 | $this->validate($request, [ |
| 68 | 'uploaded_to' => 'required|integer|exists:pages,id', | 132 | 'uploaded_to' => 'required|integer|exists:pages,id', |
| 69 | - 'name' => 'string', | 133 | + 'name' => 'string|max:255', |
| 70 | - 'link' => 'url' | 134 | + 'link' => 'url|max:255' |
| 71 | ]); | 135 | ]); |
| 72 | 136 | ||
| 73 | $pageId = $request->get('uploaded_to'); | 137 | $pageId = $request->get('uploaded_to'); | ... | ... |
| ... | @@ -32,26 +32,7 @@ class FileService extends UploadService | ... | @@ -32,26 +32,7 @@ class FileService extends UploadService |
| 32 | public function saveNewUpload(UploadedFile $uploadedFile, $page_id) | 32 | public function saveNewUpload(UploadedFile $uploadedFile, $page_id) |
| 33 | { | 33 | { |
| 34 | $fileName = $uploadedFile->getClientOriginalName(); | 34 | $fileName = $uploadedFile->getClientOriginalName(); |
| 35 | - $fileData = file_get_contents($uploadedFile->getRealPath()); | 35 | + $filePath = $this->putFileInStorage($fileName, $uploadedFile); |
| 36 | - | ||
| 37 | - $storage = $this->getStorage(); | ||
| 38 | - $fileBasePath = 'uploads/files/' . Date('Y-m-M') . '/'; | ||
| 39 | - $storageBasePath = $this->getStorageBasePath() . $fileBasePath; | ||
| 40 | - | ||
| 41 | - $uploadFileName = $fileName; | ||
| 42 | - while ($storage->exists($storageBasePath . $uploadFileName)) { | ||
| 43 | - $uploadFileName = str_random(3) . $uploadFileName; | ||
| 44 | - } | ||
| 45 | - | ||
| 46 | - $filePath = $fileBasePath . $uploadFileName; | ||
| 47 | - $fileStoragePath = $this->getStorageBasePath() . $filePath; | ||
| 48 | - | ||
| 49 | - try { | ||
| 50 | - $storage->put($fileStoragePath, $fileData); | ||
| 51 | - } catch (Exception $e) { | ||
| 52 | - throw new FileUploadException('File path ' . $fileStoragePath . ' could not be uploaded to. Ensure it is writable to the server.'); | ||
| 53 | - } | ||
| 54 | - | ||
| 55 | $largestExistingOrder = File::where('uploaded_to', '=', $page_id)->max('order'); | 36 | $largestExistingOrder = File::where('uploaded_to', '=', $page_id)->max('order'); |
| 56 | 37 | ||
| 57 | $file = File::forceCreate([ | 38 | $file = File::forceCreate([ |
| ... | @@ -67,6 +48,30 @@ class FileService extends UploadService | ... | @@ -67,6 +48,30 @@ class FileService extends UploadService |
| 67 | } | 48 | } |
| 68 | 49 | ||
| 69 | /** | 50 | /** |
| 51 | + * Store a upload, saving to a file and deleting any existing uploads | ||
| 52 | + * attached to that file. | ||
| 53 | + * @param UploadedFile $uploadedFile | ||
| 54 | + * @param File $file | ||
| 55 | + * @return File | ||
| 56 | + * @throws FileUploadException | ||
| 57 | + */ | ||
| 58 | + public function saveUpdatedUpload(UploadedFile $uploadedFile, File $file) | ||
| 59 | + { | ||
| 60 | + if (!$file->external) { | ||
| 61 | + $this->deleteFileInStorage($file); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + $fileName = $uploadedFile->getClientOriginalName(); | ||
| 65 | + $filePath = $this->putFileInStorage($fileName, $uploadedFile); | ||
| 66 | + | ||
| 67 | + $file->name = $fileName; | ||
| 68 | + $file->path = $filePath; | ||
| 69 | + $file->external = false; | ||
| 70 | + $file->save(); | ||
| 71 | + return $file; | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + /** | ||
| 70 | * Save a new File attachment from a given link and name. | 75 | * Save a new File attachment from a given link and name. |
| 71 | * @param string $name | 76 | * @param string $name |
| 72 | * @param string $link | 77 | * @param string $link |
| ... | @@ -109,8 +114,29 @@ class FileService extends UploadService | ... | @@ -109,8 +114,29 @@ class FileService extends UploadService |
| 109 | } | 114 | } |
| 110 | } | 115 | } |
| 111 | 116 | ||
| 117 | + | ||
| 118 | + /** | ||
| 119 | + * Update the details of a file. | ||
| 120 | + * @param File $file | ||
| 121 | + * @param $requestData | ||
| 122 | + * @return File | ||
| 123 | + */ | ||
| 124 | + public function updateFile(File $file, $requestData) | ||
| 125 | + { | ||
| 126 | + $file->name = $requestData['name']; | ||
| 127 | + if (isset($requestData['link']) && trim($requestData['link']) !== '') { | ||
| 128 | + $file->path = $requestData['link']; | ||
| 129 | + if (!$file->external) { | ||
| 130 | + $this->deleteFileInStorage($file); | ||
| 131 | + $file->external = true; | ||
| 132 | + } | ||
| 133 | + } | ||
| 134 | + $file->save(); | ||
| 135 | + return $file; | ||
| 136 | + } | ||
| 137 | + | ||
| 112 | /** | 138 | /** |
| 113 | - * Delete a file and any empty folders the deletion leaves. | 139 | + * Delete a File from the database and storage. |
| 114 | * @param File $file | 140 | * @param File $file |
| 115 | */ | 141 | */ |
| 116 | public function deleteFile(File $file) | 142 | public function deleteFile(File $file) |
| ... | @@ -120,6 +146,17 @@ class FileService extends UploadService | ... | @@ -120,6 +146,17 @@ class FileService extends UploadService |
| 120 | return; | 146 | return; |
| 121 | } | 147 | } |
| 122 | 148 | ||
| 149 | + $this->deleteFileInStorage($file); | ||
| 150 | + $file->delete(); | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + /** | ||
| 154 | + * Delete a file from the filesystem it sits on. | ||
| 155 | + * Cleans any empty leftover folders. | ||
| 156 | + * @param File $file | ||
| 157 | + */ | ||
| 158 | + protected function deleteFileInStorage(File $file) | ||
| 159 | + { | ||
| 123 | $storedFilePath = $this->getStorageBasePath() . $file->path; | 160 | $storedFilePath = $this->getStorageBasePath() . $file->path; |
| 124 | $storage = $this->getStorage(); | 161 | $storage = $this->getStorage(); |
| 125 | $dirPath = dirname($storedFilePath); | 162 | $dirPath = dirname($storedFilePath); |
| ... | @@ -128,8 +165,37 @@ class FileService extends UploadService | ... | @@ -128,8 +165,37 @@ class FileService extends UploadService |
| 128 | if (count($storage->allFiles($dirPath)) === 0) { | 165 | if (count($storage->allFiles($dirPath)) === 0) { |
| 129 | $storage->deleteDirectory($dirPath); | 166 | $storage->deleteDirectory($dirPath); |
| 130 | } | 167 | } |
| 168 | + } | ||
| 131 | 169 | ||
| 132 | - $file->delete(); | 170 | + /** |
| 171 | + * Store a file in storage with the given filename | ||
| 172 | + * @param $fileName | ||
| 173 | + * @param UploadedFile $uploadedFile | ||
| 174 | + * @return string | ||
| 175 | + * @throws FileUploadException | ||
| 176 | + */ | ||
| 177 | + protected function putFileInStorage($fileName, UploadedFile $uploadedFile) | ||
| 178 | + { | ||
| 179 | + $fileData = file_get_contents($uploadedFile->getRealPath()); | ||
| 180 | + | ||
| 181 | + $storage = $this->getStorage(); | ||
| 182 | + $fileBasePath = 'uploads/files/' . Date('Y-m-M') . '/'; | ||
| 183 | + $storageBasePath = $this->getStorageBasePath() . $fileBasePath; | ||
| 184 | + | ||
| 185 | + $uploadFileName = $fileName; | ||
| 186 | + while ($storage->exists($storageBasePath . $uploadFileName)) { | ||
| 187 | + $uploadFileName = str_random(3) . $uploadFileName; | ||
| 188 | + } | ||
| 189 | + | ||
| 190 | + $filePath = $fileBasePath . $uploadFileName; | ||
| 191 | + $fileStoragePath = $this->getStorageBasePath() . $filePath; | ||
| 192 | + | ||
| 193 | + try { | ||
| 194 | + $storage->put($fileStoragePath, $fileData); | ||
| 195 | + } catch (Exception $e) { | ||
| 196 | + throw new FileUploadException('File path ' . $fileStoragePath . ' could not be uploaded to. Ensure it is writable to the server.'); | ||
| 197 | + } | ||
| 198 | + return $filePath; | ||
| 133 | } | 199 | } |
| 134 | 200 | ||
| 135 | } | 201 | } |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -536,6 +536,14 @@ module.exports = function (ngApp, events) { | ... | @@ -536,6 +536,14 @@ module.exports = function (ngApp, events) { |
| 536 | const pageId = $scope.uploadedTo = $attrs.pageId; | 536 | const pageId = $scope.uploadedTo = $attrs.pageId; |
| 537 | let currentOrder = ''; | 537 | let currentOrder = ''; |
| 538 | $scope.files = []; | 538 | $scope.files = []; |
| 539 | + $scope.editFile = false; | ||
| 540 | + $scope.file = getCleanFile(); | ||
| 541 | + | ||
| 542 | + function getCleanFile() { | ||
| 543 | + return { | ||
| 544 | + page_id: pageId | ||
| 545 | + }; | ||
| 546 | + } | ||
| 539 | 547 | ||
| 540 | // Angular-UI-Sort options | 548 | // Angular-UI-Sort options |
| 541 | $scope.sortOptions = { | 549 | $scope.sortOptions = { |
| ... | @@ -559,15 +567,16 @@ module.exports = function (ngApp, events) { | ... | @@ -559,15 +567,16 @@ module.exports = function (ngApp, events) { |
| 559 | currentOrder = newOrder; | 567 | currentOrder = newOrder; |
| 560 | $http.put(`/files/sort/page/${pageId}`, {files: $scope.files}).then(resp => { | 568 | $http.put(`/files/sort/page/${pageId}`, {files: $scope.files}).then(resp => { |
| 561 | events.emit('success', resp.data.message); | 569 | events.emit('success', resp.data.message); |
| 562 | - }); | 570 | + }, checkError); |
| 563 | } | 571 | } |
| 564 | 572 | ||
| 565 | /** | 573 | /** |
| 566 | * Used by dropzone to get the endpoint to upload to. | 574 | * Used by dropzone to get the endpoint to upload to. |
| 567 | * @returns {string} | 575 | * @returns {string} |
| 568 | */ | 576 | */ |
| 569 | - $scope.getUploadUrl = function () { | 577 | + $scope.getUploadUrl = function (file) { |
| 570 | - return window.baseUrl('/files/upload'); | 578 | + let suffix = (typeof file !== 'undefined') ? `/${file.id}` : ''; |
| 579 | + return window.baseUrl(`/files/upload${suffix}`); | ||
| 571 | }; | 580 | }; |
| 572 | 581 | ||
| 573 | /** | 582 | /** |
| ... | @@ -578,7 +587,7 @@ module.exports = function (ngApp, events) { | ... | @@ -578,7 +587,7 @@ module.exports = function (ngApp, events) { |
| 578 | $http.get(url).then(resp => { | 587 | $http.get(url).then(resp => { |
| 579 | $scope.files = resp.data; | 588 | $scope.files = resp.data; |
| 580 | currentOrder = resp.data.map(file => {return file.id}).join(':'); | 589 | currentOrder = resp.data.map(file => {return file.id}).join(':'); |
| 581 | - }); | 590 | + }, checkError); |
| 582 | } | 591 | } |
| 583 | getFiles(); | 592 | getFiles(); |
| 584 | 593 | ||
| ... | @@ -596,6 +605,24 @@ module.exports = function (ngApp, events) { | ... | @@ -596,6 +605,24 @@ module.exports = function (ngApp, events) { |
| 596 | }; | 605 | }; |
| 597 | 606 | ||
| 598 | /** | 607 | /** |
| 608 | + * Upload and overwrite an existing file. | ||
| 609 | + * @param file | ||
| 610 | + * @param data | ||
| 611 | + */ | ||
| 612 | + $scope.uploadSuccessUpdate = function (file, data) { | ||
| 613 | + $scope.$apply(() => { | ||
| 614 | + let search = filesIndexOf(data); | ||
| 615 | + if (search !== -1) $scope.files[search] = file; | ||
| 616 | + | ||
| 617 | + if ($scope.editFile) { | ||
| 618 | + $scope.editFile = data; | ||
| 619 | + data.link = ''; | ||
| 620 | + } | ||
| 621 | + }); | ||
| 622 | + events.emit('success', 'File updated'); | ||
| 623 | + }; | ||
| 624 | + | ||
| 625 | + /** | ||
| 599 | * Delete a file from the server and, on success, the local listing. | 626 | * Delete a file from the server and, on success, the local listing. |
| 600 | * @param file | 627 | * @param file |
| 601 | */ | 628 | */ |
| ... | @@ -603,21 +630,77 @@ module.exports = function (ngApp, events) { | ... | @@ -603,21 +630,77 @@ module.exports = function (ngApp, events) { |
| 603 | $http.delete(`/files/${file.id}`).then(resp => { | 630 | $http.delete(`/files/${file.id}`).then(resp => { |
| 604 | events.emit('success', resp.data.message); | 631 | events.emit('success', resp.data.message); |
| 605 | $scope.files.splice($scope.files.indexOf(file), 1); | 632 | $scope.files.splice($scope.files.indexOf(file), 1); |
| 606 | - }); | 633 | + }, checkError); |
| 607 | }; | 634 | }; |
| 608 | 635 | ||
| 609 | - $scope.attachLinkSubmit = function(fileName, fileLink) { | 636 | + /** |
| 610 | - $http.post('/files/link', { | 637 | + * Attach a link to a page. |
| 611 | - uploaded_to: pageId, | 638 | + * @param fileName |
| 612 | - name: fileName, | 639 | + * @param fileLink |
| 613 | - link: fileLink | 640 | + */ |
| 614 | - }).then(resp => { | 641 | + $scope.attachLinkSubmit = function(file) { |
| 642 | + $http.post('/files/link', file).then(resp => { | ||
| 615 | $scope.files.unshift(resp.data); | 643 | $scope.files.unshift(resp.data); |
| 616 | events.emit('success', 'Link attached'); | 644 | events.emit('success', 'Link attached'); |
| 645 | + $scope.file = getCleanFile(); | ||
| 646 | + }, checkError); | ||
| 647 | + }; | ||
| 648 | + | ||
| 649 | + /** | ||
| 650 | + * Start the edit mode for a file. | ||
| 651 | + * @param fileId | ||
| 652 | + */ | ||
| 653 | + $scope.startEdit = function(file) { | ||
| 654 | + $scope.editFile = angular.copy(file); | ||
| 655 | + if (!file.external) $scope.editFile.link = ''; | ||
| 656 | + }; | ||
| 657 | + | ||
| 658 | + /** | ||
| 659 | + * Cancel edit mode | ||
| 660 | + */ | ||
| 661 | + $scope.cancelEdit = function() { | ||
| 662 | + $scope.editFile = false; | ||
| 663 | + }; | ||
| 664 | + | ||
| 665 | + /** | ||
| 666 | + * Update the name and link of a file. | ||
| 667 | + * @param file | ||
| 668 | + */ | ||
| 669 | + $scope.updateFile = function(file) { | ||
| 670 | + $http.put(`/files/${file.id}`, file).then(resp => { | ||
| 671 | + let search = filesIndexOf(resp.data); | ||
| 672 | + if (search !== -1) $scope.files[search] = file; | ||
| 673 | + | ||
| 674 | + if ($scope.editFile && !file.external) { | ||
| 675 | + $scope.editFile.link = ''; | ||
| 676 | + } | ||
| 677 | + events.emit('success', 'Attachment details updated'); | ||
| 617 | }); | 678 | }); |
| 618 | - $scope.fileName = $scope.fileLink = ''; | ||
| 619 | }; | 679 | }; |
| 620 | 680 | ||
| 681 | + /** | ||
| 682 | + * Search the local files via another file object. | ||
| 683 | + * Used to search via object copies. | ||
| 684 | + * @param file | ||
| 685 | + * @returns int | ||
| 686 | + */ | ||
| 687 | + function filesIndexOf(file) { | ||
| 688 | + for (let i = 0; i < $scope.files.length; i++) { | ||
| 689 | + if ($scope.files[i].id == file.id) return file.id; | ||
| 690 | + } | ||
| 691 | + return -1; | ||
| 692 | + } | ||
| 693 | + | ||
| 694 | + /** | ||
| 695 | + * Check for an error response in a ajax request. | ||
| 696 | + * @param response | ||
| 697 | + */ | ||
| 698 | + function checkError(response) { | ||
| 699 | + if (typeof response.data !== 'undefined' && typeof response.data.error !== 'undefined') { | ||
| 700 | + events.emit('error', response.data.error); | ||
| 701 | + } | ||
| 702 | + } | ||
| 703 | + | ||
| 621 | }]); | 704 | }]); |
| 622 | 705 | ||
| 623 | }; | 706 | }; | ... | ... |
| ... | @@ -116,6 +116,7 @@ module.exports = function (ngApp, events) { | ... | @@ -116,6 +116,7 @@ module.exports = function (ngApp, events) { |
| 116 | uploadedTo: '@' | 116 | uploadedTo: '@' |
| 117 | }, | 117 | }, |
| 118 | link: function (scope, element, attrs) { | 118 | link: function (scope, element, attrs) { |
| 119 | + if (attrs.placeholder) element[0].querySelector('.dz-message').textContent = attrs.placeholder; | ||
| 119 | var dropZone = new DropZone(element[0].querySelector('.dropzone-container'), { | 120 | var dropZone = new DropZone(element[0].querySelector('.dropzone-container'), { |
| 120 | url: scope.uploadUrl, | 121 | url: scope.uploadUrl, |
| 121 | init: function () { | 122 | init: function () { | ... | ... |
| ... | @@ -228,21 +228,6 @@ | ... | @@ -228,21 +228,6 @@ |
| 228 | padding-top: $-s; | 228 | padding-top: $-s; |
| 229 | position: relative; | 229 | position: relative; |
| 230 | } | 230 | } |
| 231 | - button.pos { | ||
| 232 | - position: absolute; | ||
| 233 | - bottom: 0; | ||
| 234 | - display: block; | ||
| 235 | - width: 100%; | ||
| 236 | - padding: $-s; | ||
| 237 | - height: 45px; | ||
| 238 | - border: 0; | ||
| 239 | - margin: 0; | ||
| 240 | - box-shadow: none; | ||
| 241 | - border-radius: 0; | ||
| 242 | - &:hover{ | ||
| 243 | - box-shadow: none; | ||
| 244 | - } | ||
| 245 | - } | ||
| 246 | .handle { | 231 | .handle { |
| 247 | user-select: none; | 232 | user-select: none; |
| 248 | cursor: move; | 233 | cursor: move; | ... | ... |
| ... | @@ -4,7 +4,9 @@ | ... | @@ -4,7 +4,9 @@ |
| 4 | <div class="tabs primary-background-light"> | 4 | <div class="tabs primary-background-light"> |
| 5 | <span toolbox-toggle><i class="zmdi zmdi-caret-left-circle"></i></span> | 5 | <span toolbox-toggle><i class="zmdi zmdi-caret-left-circle"></i></span> |
| 6 | <span tab-button="tags" title="Page Tags" class="active"><i class="zmdi zmdi-tag"></i></span> | 6 | <span tab-button="tags" title="Page Tags" class="active"><i class="zmdi zmdi-tag"></i></span> |
| 7 | - <span tab-button="files" title="Attachments"><i class="zmdi zmdi-attachment"></i></span> | 7 | + @if(userCan('file-create-all')) |
| 8 | + <span tab-button="files" title="Attachments"><i class="zmdi zmdi-attachment"></i></span> | ||
| 9 | + @endif | ||
| 8 | </div> | 10 | </div> |
| 9 | 11 | ||
| 10 | <div tab-content="tags" ng-controller="PageTagController" page-id="{{ $page->id or 0 }}"> | 12 | <div tab-content="tags" ng-controller="PageTagController" page-id="{{ $page->id or 0 }}"> |
| ... | @@ -35,35 +37,60 @@ | ... | @@ -35,35 +37,60 @@ |
| 35 | </div> | 37 | </div> |
| 36 | </div> | 38 | </div> |
| 37 | 39 | ||
| 38 | - <div tab-content="files" ng-controller="PageAttachmentController" page-id="{{ $page->id or 0 }}"> | 40 | + @if(userCan('file-create-all')) |
| 39 | - <h4>Attached Files</h4> | 41 | + <div tab-content="files" ng-controller="PageAttachmentController" page-id="{{ $page->id or 0 }}"> |
| 40 | - <div class="padded files"> | 42 | + <h4>Attached Files</h4> |
| 41 | - <p class="muted small">Upload some files to display on your page. This are visible in the page sidebar.</p> | 43 | + <div class="padded files"> |
| 42 | - <drop-zone upload-url="@{{getUploadUrl()}}" uploaded-to="@{{uploadedTo}}" event-success="uploadSuccess"></drop-zone> | ||
| 43 | 44 | ||
| 44 | - <hr class="even"> | 45 | + <div id="file-list" ng-show="!editFile"> |
| 46 | + <p class="muted small">Upload some files to display on your page. This are visible in the page sidebar.</p> | ||
| 47 | + <drop-zone upload-url="@{{getUploadUrl()}}" uploaded-to="@{{uploadedTo}}" event-success="uploadSuccess"></drop-zone> | ||
| 45 | 48 | ||
| 46 | - <div class="form-group"> | 49 | + <hr class="even"> |
| 47 | - <label for="attachment-via-link">File Name</label> | ||
| 48 | - <input type="text" placeholder="File name" ng-model="fileName"> | ||
| 49 | - </div> | ||
| 50 | - <div class="form-group"> | ||
| 51 | - <label for="attachment-via-link">Link to file</label> | ||
| 52 | - <input type="text" placeholder="File url" ng-model="fileLink"> | ||
| 53 | - </div> | ||
| 54 | - <button type="button" ng-click="attachLinkSubmit(fileName, fileLink)" class="button pos">Attach</button> | ||
| 55 | 50 | ||
| 51 | + <div class="form-group"> | ||
| 52 | + <label for="attachment-via-link">File Name</label> | ||
| 53 | + <input type="text" placeholder="File name" ng-model="file.name"> | ||
| 54 | + </div> | ||
| 55 | + <div class="form-group"> | ||
| 56 | + <label for="attachment-via-link">Link to file</label> | ||
| 57 | + <input type="text" placeholder="File url" ng-model="file.link"> | ||
| 58 | + </div> | ||
| 59 | + <button type="button" ng-click="attachLinkSubmit(file)" class="button pos">Attach</button> | ||
| 56 | 60 | ||
| 57 | - <table class="no-style" tag-autosuggestions style="width: 100%;"> | 61 | + |
| 58 | - <tbody ui-sortable="sortOptions" ng-model="files" > | 62 | + <table class="no-style" tag-autosuggestions style="width: 100%;"> |
| 59 | - <tr ng-repeat="file in files track by $index"> | 63 | + <tbody ui-sortable="sortOptions" ng-model="files" > |
| 60 | - <td width="20" ><i class="handle zmdi zmdi-menu"></i></td> | 64 | + <tr ng-repeat="file in files track by $index"> |
| 61 | - <td ng-bind="file.name"></td> | 65 | + <td width="20" ><i class="handle zmdi zmdi-menu"></i></td> |
| 62 | - <td width="10" ng-click="deleteFile(file)" class="text-center text-neg" style="padding: 0;"><i class="zmdi zmdi-close"></i></td> | 66 | + <td ng-bind="file.name"></td> |
| 63 | - </tr> | 67 | + <td width="10" ng-click="deleteFile(file)" class="text-center text-neg" style="padding: 0;"><i class="zmdi zmdi-close"></i></td> |
| 64 | - </tbody> | 68 | + <td width="10" ng-click="startEdit(file)" class="text-center text-neg" style="padding: 0;"><i class="zmdi zmdi-edit"></i></td> |
| 65 | - </table> | 69 | + </tr> |
| 70 | + </tbody> | ||
| 71 | + </table> | ||
| 72 | + </div> | ||
| 73 | + | ||
| 74 | + <div id="file-edit" ng-if="editFile"> | ||
| 75 | + <h5>Edit File</h5> | ||
| 76 | + <div class="form-group"> | ||
| 77 | + <label for="attachment-name-edit">File Name</label> | ||
| 78 | + <input type="text" id="attachment-name-edit" placeholder="File name" ng-model="editFile.name"> | ||
| 79 | + </div> | ||
| 80 | + <hr class="even"> | ||
| 81 | + <drop-zone upload-url="@{{getUploadUrl(editFile)}}" uploaded-to="@{{uploadedTo}}" placeholder="Drop files or click here to upload and overwrite" event-success="uploadSuccessUpdate"></drop-zone> | ||
| 82 | + <hr class="even"> | ||
| 83 | + <div class="form-group"> | ||
| 84 | + <label for="attachment-link-edit">Link to file</label> | ||
| 85 | + <input type="text" id="attachment-link-edit" placeholder="File url" ng-model="editFile.link"> | ||
| 86 | + </div> | ||
| 87 | + | ||
| 88 | + <button type="button" class="button" ng-click="cancelEdit()">Back</button> | ||
| 89 | + <button type="button" class="button pos" ng-click="updateFile(editFile)">Save</button> | ||
| 90 | + </div> | ||
| 91 | + | ||
| 92 | + </div> | ||
| 66 | </div> | 93 | </div> |
| 67 | - </div> | 94 | + @endif |
| 68 | 95 | ||
| 69 | </div> | 96 | </div> |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -90,7 +90,9 @@ Route::group(['middleware' => 'auth'], function () { | ... | @@ -90,7 +90,9 @@ Route::group(['middleware' => 'auth'], function () { |
| 90 | // File routes | 90 | // File routes |
| 91 | Route::get('/files/{id}', 'FileController@get'); | 91 | Route::get('/files/{id}', 'FileController@get'); |
| 92 | Route::post('/files/upload', 'FileController@upload'); | 92 | Route::post('/files/upload', 'FileController@upload'); |
| 93 | + Route::post('/files/upload/{id}', 'FileController@uploadUpdate'); | ||
| 93 | Route::post('/files/link', 'FileController@attachLink'); | 94 | Route::post('/files/link', 'FileController@attachLink'); |
| 95 | + Route::put('/files/{id}', 'FileController@update'); | ||
| 94 | Route::get('/files/get/page/{pageId}', 'FileController@listForPage'); | 96 | Route::get('/files/get/page/{pageId}', 'FileController@listForPage'); |
| 95 | Route::put('/files/sort/page/{pageId}', 'FileController@sortForPage'); | 97 | Route::put('/files/sort/page/{pageId}', 'FileController@sortForPage'); |
| 96 | Route::delete('/files/{id}', 'FileController@delete'); | 98 | Route::delete('/files/{id}', 'FileController@delete'); | ... | ... |
-
Please register or sign in to post a comment