Skip to content

Commit 39bc14f

Browse files
committed
feat(editor): added file upload and file removal for Jodit Editor
1 parent dc6bd2b commit 39bc14f

File tree

7 files changed

+230
-181
lines changed

7 files changed

+230
-181
lines changed

phpmyfaq/admin/assets/src/content/editor.js

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,29 @@
1414
*/
1515

1616
import { Jodit } from 'jodit';
17-
import 'jodit/esm/plugins/image/image.js';
18-
import 'jodit/esm/plugins/video/video.js';
19-
import 'jodit/esm/plugins/indent/indent.js';
20-
import 'jodit/esm/plugins/print/print.js';
17+
import 'jodit/esm/plugins/class-span/class-span.js';
18+
import 'jodit/esm/plugins/clean-html/clean-html.js';
19+
import 'jodit/esm/plugins/clipboard/clipboard.js';
2120
import 'jodit/esm/plugins/copy-format/copy-format.js';
22-
import 'jodit/esm/plugins/line-height/line-height.js';
23-
import 'jodit/esm/plugins/fullsize/fullsize.js';
24-
import 'jodit/esm/plugins/symbols/symbols.js';
2521
import 'jodit/esm/plugins/delete/delete.js';
26-
import 'jodit/esm/plugins/source/source.js';
22+
import 'jodit/esm/plugins/fullsize/fullsize.js';
2723
import 'jodit/esm/plugins/hr/hr.js';
28-
import 'jodit/esm/plugins/preview/preview.js';
29-
import 'jodit/esm/plugins/clean-html/clean-html.js';
30-
import 'jodit/esm/plugins/search/search.js';
31-
import 'jodit/esm/plugins/select/select.js';
32-
import 'jodit/esm/plugins/justify/justify.js';
33-
import 'jodit/esm/plugins/clipboard/clipboard.js';
34-
import 'jodit/esm/plugins/media/media.js';
3524
import 'jodit/esm/plugins/image/image.js';
3625
import 'jodit/esm/plugins/image-processor/image-processor.js';
3726
import 'jodit/esm/plugins/image-properties/image-properties.js';
27+
import 'jodit/esm/plugins/indent/indent.js';
28+
import 'jodit/esm/plugins/justify/justify.js';
29+
import 'jodit/esm/plugins/line-height/line-height.js';
30+
import 'jodit/esm/plugins/media/media.js';
31+
import 'jodit/esm/plugins/preview/preview.js';
32+
import 'jodit/esm/plugins/print/print.js';
3833
import 'jodit/esm/plugins/resizer/resizer.js';
39-
import 'jodit/esm/plugins/class-span/class-span.js';
40-
import { FileSelectorWidget } from 'jodit/esm/modules/widget/file-selector/file-selector.js';
34+
import 'jodit/esm/plugins/search/search.js';
35+
import 'jodit/esm/plugins/select/select.js';
36+
import 'jodit/esm/plugins/source/source.js';
37+
import 'jodit/esm/plugins/symbols/symbols.js';
38+
import 'jodit/esm/modules/uploader/uploader.js';
39+
import 'jodit/esm/plugins/video/video.js';
4140

4241
export const renderEditor = () => {
4342
const editor = document.getElementById('editor');
@@ -209,26 +208,27 @@ export const renderEditor = () => {
209208
],
210209
events: {},
211210
textIcons: false,
211+
uploader: {
212+
url: '/admin/api/content/images?csrf=' + document.getElementById('pmf-csrf-token').value,
213+
format: 'json',
214+
isSuccess: (response) => {
215+
return !response.error;
216+
},
217+
getMessage: (response) => {
218+
return response.msg;
219+
},
220+
},
212221
filebrowser: {
213222
ajax: {
214-
url: '/admin/assets/src/api/filebrowser.php',
223+
url: '/admin/api/media-browser',
224+
contentType: 'application/json; charset=UTF-8',
215225
},
226+
createNewFolder: false,
227+
deleteFolder: false,
228+
moveFolder: false,
229+
showFoldersPanel: false,
230+
showFileSize: true,
231+
showFileName: true,
216232
},
217233
});
218-
219-
FileSelectorWidget(
220-
joditEditor,
221-
{
222-
filebrowser(data) {
223-
console.log(data);
224-
},
225-
upload: true,
226-
url(url, text) {
227-
console.log(url);
228-
},
229-
},
230-
null,
231-
() => {},
232-
true
233-
);
234234
};

phpmyfaq/assets/templates/admin/content/media.browser.twig

Lines changed: 0 additions & 39 deletions
This file was deleted.

phpmyfaq/src/admin-api-routes.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
use phpMyFAQ\Controller\Administration\Api\ImageController;
3131
use phpMyFAQ\Controller\Administration\Api\InstanceController;
3232
use phpMyFAQ\Controller\Administration\Api\MarkdownController;
33+
use phpMyFAQ\Controller\Administration\Api\MediaBrowserController;
3334
use phpMyFAQ\Controller\Administration\Api\NewsController;
3435
use phpMyFAQ\Controller\Administration\Api\QuestionController;
3536
use phpMyFAQ\Controller\Administration\Api\SearchController;
@@ -193,6 +194,12 @@
193194
'controller' => [MarkdownController::class, 'renderMarkdown'],
194195
'methods' => 'POST'
195196
],
197+
198+
'admin.api.media.browser' => [
199+
'path' => '/media-browser',
200+
'controller' => [MediaBrowserController::class, 'index'],
201+
'methods' => 'GET'
202+
],
196203
// Dashboard API
197204
'admin.api.dashboard.topten' => [
198205
'path' => '/dashboard/topten',

phpmyfaq/src/admin-routes.php

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
use phpMyFAQ\Controller\Administration\GroupController;
3232
use phpMyFAQ\Controller\Administration\ImportController;
3333
use phpMyFAQ\Controller\Administration\InstanceController;
34-
use phpMyFAQ\Controller\Administration\MediaBrowserController;
3534
use phpMyFAQ\Controller\Administration\NewsController;
3635
use phpMyFAQ\Controller\Administration\OpenQuestionsController;
3736
use phpMyFAQ\Controller\Administration\PasswordChangeController;
@@ -273,11 +272,6 @@
273272
'controller' => [InstanceController::class, 'index'],
274273
'methods' => 'GET'
275274
],
276-
'admin.media.browser' => [
277-
'path' => '/media-browser',
278-
'controller' => [MediaBrowserController::class, 'index'],
279-
'methods' => 'GET'
280-
],
281275
'admin.news' => [
282276
'path' => '/news',
283277
'controller' => [NewsController::class, 'index'],

phpmyfaq/src/phpMyFAQ/Controller/Administration/Api/ImageController.php

Lines changed: 75 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
namespace phpMyFAQ\Controller\Administration\Api;
1919

20+
use DateTime;
2021
use phpMyFAQ\Controller\AbstractController;
2122
use phpMyFAQ\Core\Exception;
2223
use phpMyFAQ\Enums\PermissionType;
@@ -30,56 +31,96 @@
3031
class ImageController extends AbstractController
3132
{
3233
/**
33-
* @throws Exception
34+
* @throws Exception|\Exception
3435
*/
3536
#[Route('admin/api/content/images')]
3637
public function upload(Request $request): JsonResponse
3738
{
3839
$this->userHasPermission(PermissionType::FAQ_EDIT);
3940

41+
$session = $this->container->get('session');
42+
4043
$uploadDir = PMF_CONTENT_DIR . '/user/images/';
4144
$validFileExtensions = ['gif', 'jpg', 'jpeg', 'png'];
4245
$timestamp = time();
4346

44-
if (
45-
!Token::getInstance($this->container->get('session'))
46-
->verifyToken('edit-faq', $request->query->get('csrf'))
47-
) {
48-
return $this->json(['error' => Translation::get('msgNoPermission')], Response::HTTP_UNAUTHORIZED);
47+
if (!Token::getInstance($session)->verifyToken('edit-faq', $request->query->get('csrf'))) {
48+
return $this->json(
49+
[
50+
'success' => false,
51+
'data' => ['code' => Response::HTTP_UNAUTHORIZED],
52+
'messages' => [Translation::get('msgNoPermission')]
53+
],
54+
Response::HTTP_UNAUTHORIZED
55+
);
4956
}
5057

51-
$file = $request->files->get('file');
52-
$headers = [];
53-
if ($file && $file->isValid()) {
54-
if (
55-
$request->server->get('HTTP_ORIGIN') !== null &&
56-
$request->server->get('HTTP_ORIGIN') . '/' === $this->configuration->getDefaultUrl()
57-
) {
58-
$headers = ['Access-Control-Allow-Origin', $request->server->get('HTTP_ORIGIN')];
59-
}
58+
$files = $request->files->get('files');
6059

61-
// Sanitize input
62-
if (preg_match("/([^\w\s\d\-_~,;:\[\]\(\).])|([\.]{2,})/", $file->getClientOriginalName())) {
63-
return $this->json([], Response::HTTP_BAD_REQUEST, $headers);
64-
}
60+
$uploadedFiles = [];
61+
foreach ($files as $file) {
62+
$headers = [];
63+
if ($file && $file->isValid()) {
64+
if (
65+
$request->server->get('HTTP_ORIGIN') !== null &&
66+
$request->server->get('HTTP_ORIGIN') . '/' === $this->configuration->getDefaultUrl()
67+
) {
68+
$headers = ['Access-Control-Allow-Origin', $request->server->get('HTTP_ORIGIN')];
69+
}
6570

66-
// Verify extension
67-
if (!in_array(strtolower($file->getClientOriginalExtension()), $validFileExtensions)) {
68-
return $this->json([], Response::HTTP_BAD_REQUEST, $headers);
69-
}
71+
// Sanitize input
72+
if (preg_match("/([^\w\s\d\-_~,;:\[\]\(\).])|([\.]{2,})/", $file->getClientOriginalName())) {
73+
return $this->json(
74+
[
75+
'success' => false,
76+
'data' => ['code' => Response::HTTP_BAD_REQUEST],
77+
'messages' => ['Data contains invalid characters']
78+
],
79+
Response::HTTP_BAD_REQUEST,
80+
$headers
81+
);
82+
}
7083

71-
// Accept upload if there was no origin, or if it is an accepted origin
72-
$fileName = $timestamp . '_' . $file->getClientOriginalName();
73-
$file->move($uploadDir, $fileName);
84+
// Verify extension
85+
if (!in_array(strtolower($file->getClientOriginalExtension()), $validFileExtensions)) {
86+
return $this->json(
87+
[
88+
'success' => false,
89+
'data' => ['code' => Response::HTTP_BAD_REQUEST],
90+
'messages' => ['File extension not allowed']
91+
],
92+
Response::HTTP_BAD_REQUEST,
93+
$headers
94+
);
95+
}
7496

75-
// Respond to the successful upload with JSON with the full URL of the uploaded image.
76-
return $this->json(
77-
['location' => $this->configuration->getDefaultUrl() . 'content/user/images/' . $fileName],
78-
Response::HTTP_OK,
79-
$headers
80-
);
81-
} else {
82-
return $this->json([], Response::HTTP_BAD_REQUEST, $headers);
97+
// Accept upload if there was no origin, or if it is an accepted origin
98+
$fileName = $timestamp . '_' . $file->getClientOriginalName();
99+
$file->move($uploadDir, $fileName);
100+
101+
// Add to the list of uploaded files
102+
$uploadedFiles[] = $fileName;
103+
} else {
104+
return $this->json(['success' => false], Response::HTTP_BAD_REQUEST, $headers);
105+
}
83106
}
107+
108+
$response = [
109+
'success' => true,
110+
'time' => (new DateTime())->format('Y-m-d H:i:s'),
111+
'data' => [
112+
'sources' => [
113+
[
114+
'baseurl' => $this->configuration->getDefaultUrl(),
115+
'path' => 'content/user/images/',
116+
'files' => $uploadedFiles,
117+
'name' => 'default'
118+
]
119+
],
120+
'code' => 220
121+
]
122+
];
123+
124+
return $this->json($response, Response::HTTP_OK);
84125
}
85126
}

0 commit comments

Comments
 (0)