amcms_filemanager 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +78 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/config/amcms_filemanager_manifest.js +1 -0
  6. data/app/assets/images/amcms_filemanager/folder.png +0 -0
  7. data/app/assets/stylesheets/amcms_filemanager/application.css +34 -0
  8. data/app/assets/stylesheets/amcms_filemanager/filemanager.css +4 -0
  9. data/app/controllers/amcms_filemanager/application_controller.rb +11 -0
  10. data/app/controllers/amcms_filemanager/filemanager_controller.rb +93 -0
  11. data/app/controllers/amcms_filemanager/imagemanager_controller.rb +34 -0
  12. data/app/helpers/amcms_filemanager/application_helper.rb +4 -0
  13. data/app/helpers/amcms_filemanager/filemanager_helper.rb +4 -0
  14. data/app/jobs/amcms_filemanager/application_job.rb +4 -0
  15. data/app/lib/amcms_filemanager/filemanager.rb +181 -0
  16. data/app/lib/amcms_filemanager/imagemanager.rb +5 -0
  17. data/app/mailers/amcms_filemanager/application_mailer.rb +6 -0
  18. data/app/models/amcms_filemanager/application_record.rb +5 -0
  19. data/app/uploaders/amcms_filemanager/filemanager_uploader.rb +56 -0
  20. data/app/views/amcms_filemanager/filemanager/index.html.erb +168 -0
  21. data/app/views/layouts/amcms_filemanager/application.html.erb +497 -0
  22. data/config/locales/en.yml +4 -0
  23. data/config/routes.rb +12 -0
  24. data/lib/amcms_filemanager/configuration.rb +9 -0
  25. data/lib/amcms_filemanager/engine.rb +25 -0
  26. data/lib/amcms_filemanager/version.rb +3 -0
  27. data/lib/amcms_filemanager.rb +6 -0
  28. data/lib/tasks/amcms_filemanager_tasks.rake +4 -0
  29. metadata +127 -0
@@ -0,0 +1,168 @@
1
+ <div id="amcms-filemanager-container" data-routes="<%= @config[:routes].to_json %>" data-type="<%= @config[:type] %>">
2
+ <nav class="navbar fixed-top navbar-expand-lg navbar-light bg-light mb-3 fm">
3
+ <div class="collapse navbar-collapse">
4
+ <ul class="navbar-nav me-auto mb-2 mb-lg-0">
5
+ <li class="nav-item dropdown">
6
+ <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
7
+ <i class="bi bi-plus-lg"></i>
8
+ </a>
9
+ <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
10
+ <li id="fm-mkdir-item">
11
+ <a class="dropdown-item" data-bs-toggle="modal" data-bs-target="#createFolderModal" href="#">
12
+ <i class="bi bi-folder-plus"></i>
13
+ Create Folder
14
+ </a>
15
+ </li>
16
+ <li id="fm-upload-item">
17
+ <a class="dropdown-item" data-bs-toggle="modal" data-bs-target="#uploadModal" href="#">
18
+ <i class="bi bi-cloud-arrow-up"></i>
19
+ Upload
20
+ </a>
21
+ </li>
22
+ </ul>
23
+ </li>
24
+ <li class="nav-item"><a class="nav-link" id="pwd-display"></a></li>
25
+ </ul>
26
+ <ul class="navbar-nav ms-auto" id="file-list-type">
27
+ <% if @config[:type] == 'image' %>
28
+ <li class="nav-item">
29
+ <a class="nav-link active" aria-current="page" href="#" id="thumbnail-view-btn" onclick="switchViewHandler(this, 'thumbnail')">
30
+ <i class="bi bi-grid-fill"></i>
31
+ Thumbnails
32
+ </a>
33
+ </li>
34
+ <% end %>
35
+ <li class="nav-item">
36
+ <a class="nav-link<%= @config[:type] == 'file' ? ' active' : '' %>" aria-current="page" href="#" id="list-view-btn" onclick="switchViewHandler(this, 'list')">
37
+ <i class="bi bi-list-ul"></i>
38
+ List
39
+ </a>
40
+ </li>
41
+ </ul>
42
+ </div>
43
+ </nav>
44
+ <div class="fm-file-panel">
45
+ <div class="row" style="padding: 0 15px;">
46
+ <div id="fm-directory-structure" class="col-md-3 ">
47
+ <ul id="fm-directories-list" class="list-group position-static">
48
+
49
+ </ul>
50
+ </div>
51
+ <div id="fm-directory-listing" class="col-md-9" style="overflow: auto">
52
+ <div class="row" id="fm-file-list">
53
+
54
+ </div>
55
+ </div>
56
+ </div>
57
+ </div>
58
+ <!-- Create Folder Modal -->
59
+ <div class="modal fade" id="createFolderModal" tabindex="-1" aria-labelledby="createFolderModalLabel" aria-hidden="true">
60
+ <div class="modal-dialog">
61
+ <div class="modal-content">
62
+ <div class="modal-header">
63
+ <h5 class="modal-title" id="createFolderModalLabel">Create Folder</h5>
64
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
65
+ </div>
66
+ <div class="modal-body">
67
+ <form id="fm-new-folder-form">
68
+ <input type="text" name="item_name" id="new-folder-name" class="form-control" placeholder="Folder Name">
69
+ </form>
70
+ </div>
71
+ <div class="modal-footer">
72
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
73
+ <button type="button" class="btn btn-primary" onclick="createDirectory()">Create</button>
74
+ </div>
75
+ </div>
76
+ </div>
77
+ </div>
78
+ <!-- Rename Item Modal -->
79
+ <div class="modal fade" id="renameItemModal" tabindex="-1" aria-labelledby="renameItemModalLabel" aria-hidden="true">
80
+ <div class="modal-dialog">
81
+ <div class="modal-content">
82
+ <div class="modal-header">
83
+ <h5 class="modal-title" id="renameItemModalLabel">Rename Item</h5>
84
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
85
+ </div>
86
+ <div class="modal-body">
87
+ <form id="fm-rename-item-form">
88
+ <input type="text" name="item_name" id="new-filename" class="form-control" placeholder="Rename">
89
+ <input type="hidden" name="original_filename" id="original-filename">
90
+ </form>
91
+ </div>
92
+ <div class="modal-footer">
93
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
94
+ <button type="button" class="btn btn-primary" onclick="renameFilename()">Rename</button>
95
+ </div>
96
+ </div>
97
+ </div>
98
+ </div>
99
+ <!-- Warning Modal -->
100
+ <div class="modal" tabindex="-1" id="fmModal" aria-labelledby="fmModal" aria-hidden="true">
101
+ <div class="modal-dialog">
102
+ <div class="modal-content">
103
+ <div class="modal-header alert" id="fm-modal-header">
104
+ <h5 class="modal-title fm-modal-title">Title</h5>
105
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
106
+ </div>
107
+ <div class="modal-body fm-modal-body">
108
+ </div>
109
+ <div class="modal-footer fm-modal-footer">
110
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
111
+ <div class="fm-modal-footer-buttons"></div>
112
+ </div>
113
+ </div>
114
+ </div>
115
+ </div>
116
+ <!-- Upload Modal -->
117
+ <div class="modal fade" tabindex="-1" id="uploadModal" aria-labelledby="uploadModalLabel" aria-hidden="true">
118
+ <div class="modal-dialog modal-lg">
119
+ <div class="modal-content">
120
+ <div class="modal-header alert" id="fm-upload-header">
121
+ <h5 class="modal-title upload-modal-title">Upload Files</h5>
122
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
123
+ </div>
124
+ <div class="modal-body upload-modal-body">
125
+ <form action="<%= filemanager_upload_path(type: @config[:type]) %>" class="dropzone" id="fm-uploader">
126
+ <%= hidden_field_tag :authenticity_token, form_authenticity_token %>
127
+ <input type="hidden" name="dir" id="upload_to_dir">
128
+ </form>
129
+ </div>
130
+ <div class="modal-footer upload-modal-footer">
131
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
132
+ </div>
133
+ </div>
134
+ </div>
135
+ </div>
136
+
137
+ <!-- Resize Image Modal -->
138
+ <div class="modal fade" id="resizeImageModal" tabindex="-1" aria-labelledby="resizeImageModalLabel" aria-hidden="true">
139
+ <div class="modal-dialog modal-fullscreen modal-dialog-scrollable">
140
+ <div class="modal-content">
141
+ <div class="modal-header">
142
+ <h5 class="modal-title" id="imageResizeModalLabel">Resize Image</h5>
143
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
144
+ </div>
145
+ <div class="modal-body">
146
+ <div class="row">
147
+ <div class="col-8" id="image-preview-panel">
148
+ <img src="" alt="" id="original_image">
149
+ </div>
150
+ <div class="col-4">
151
+ <form id="fm-resize-image-form">
152
+ <h6>Image Details</h6>
153
+ <div id="image-info-container">
154
+ </div>
155
+ </form>
156
+ </div>
157
+ </div>
158
+ </div>
159
+ <div class="modal-footer">
160
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
161
+ <button type="button" class="btn btn-secondary" onclick="resizeImageHandler(true)">Resize and Save Copy</button>
162
+ <button type="button" class="btn btn-primary" onclick="resizeImageHandler(false)">Resize and Save</button>
163
+ </div>
164
+ </div>
165
+ </div>
166
+ </div>
167
+
168
+ </div>
@@ -0,0 +1,497 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Amcms filemanager</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
9
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
10
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/dropzone.min.css" integrity="sha512-jU/7UFiaW5UBGODEopEqnbIAHOI8fO6T99m7Tsmqs2gkdujByJfkCbbfPSN4Wlqlb9TGnsuC0YgUgWkRBK7B9A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
11
+ <%= stylesheet_link_tag "amcms_filemanager/application", media: "all" %>
12
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
13
+ <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
14
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.js" integrity="sha512-oQq8uth41D+gIH/NJvSJvVB85MFk1eWpMK6glnkg6I7EdMqC1XVkW7RxLheXwmFdG03qScCM7gKS/Cx3FYt7Tg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
15
+ </head>
16
+ <body>
17
+ <%= yield %>
18
+
19
+ <script>
20
+ const csrf = document.querySelector("meta[name='csrf-token']").getAttribute("content");
21
+ const mkdirModal = new bootstrap.Modal(document.getElementById('createFolderModal'));
22
+ const renameItemModal = new bootstrap.Modal(document.getElementById('renameItemModal'));
23
+ const resizeImageModal = new bootstrap.Modal(document.getElementById('resizeImageModal'));
24
+ let pwd = '';
25
+ const type = document.getElementById('amcms-filemanager-container').getAttribute('data-type');
26
+
27
+ Dropzone.options.fmUploader = {
28
+ init: function() {
29
+ this.on("complete", file => {
30
+ changeDirectory(pwd)
31
+ });
32
+ }
33
+ };
34
+
35
+ getTargetOrigin = () => {
36
+ // return wilcard(*) if debug on and testing locally
37
+ // if (allowDebugOrigin && window.location.origin.match(regex)) return "*";
38
+ //
39
+ // // since we're not testing locally, return required origin
40
+ // return targetOrigin;
41
+ return '*';
42
+ }
43
+
44
+ const routes = (path) => {
45
+ const config = document.getElementById('amcms-filemanager-container');
46
+ const routes = JSON.parse(config.dataset.routes);
47
+ return routes[path];
48
+ };
49
+
50
+ sendMessage = (filename) => {
51
+
52
+ window.parent.postMessage(
53
+ {
54
+ mceAction: "customAction",
55
+ data: {
56
+ location: filename
57
+ }
58
+ },
59
+ getTargetOrigin()
60
+ );
61
+ };
62
+
63
+ directoryListing = (response) => {
64
+ html = activeView() === 'thumbnail-view-btn' && type == 'image' ? thumbnailListing(response) : listViewLiisting(response);
65
+ document.getElementById('fm-file-list').innerHTML = html;
66
+ }
67
+
68
+ thumbnailListing = (response) => {
69
+ let html = '';
70
+ for (const file of response.data.files) {
71
+ const onClick = file.directory ? `changeDirectory('${file.filepath}')` : `sendMessage('${file.filepath}')`;
72
+
73
+ html += `<div class="col-md-3 mb-3">
74
+ <div class="card text-center d-flex mb-3">
75
+ <div class="row align-items-center item-name">
76
+ <a
77
+ data-filename="${file.filename}"
78
+ data-filepath="${file.filepath}"
79
+ data-directory="${file.directory}"
80
+ data-size="${file.size}"
81
+ data-date-modified="${file.date_modified}"
82
+ class="fm-${file.directory ? 'folder' : 'file'}-item"
83
+ onClick="${onClick}"
84
+ >
85
+ <img
86
+ src="${file.directory ? '/assets/amcms_filemanager/folder.png' : file.filepath}"
87
+ alt="${file.filename}"
88
+ class="fm-image-thumbnail"
89
+ style="border: none; max-width: 90%"
90
+ >
91
+ </a>
92
+ </div>
93
+ </div>
94
+ <div class="btn-group d-flex w-100 mb-3">
95
+ <button type="button" class="btn btn-sm btn-primary item-name" style="width:85%" onclick="${onClick}">${file.filename}</button>
96
+ <button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" style="width:15%" data-bs-toggle="dropdown" aria-expanded="false">
97
+ <span class="visually-hidden">Toggle Dropdown</span>
98
+ </button>
99
+ <ul class="dropdown-menu dropdown-menu-end">
100
+ ${fileMenuOptions(file)}
101
+ </ul>
102
+ </div>
103
+ </div>`;
104
+ }
105
+ return html;
106
+ };
107
+
108
+ listViewLiisting = (response) => {
109
+ let html = '<ul class="list-group list-group-flush">';
110
+ for (const file of response.data.files) {
111
+ const onClick = file.directory ? `changeDirectory('${file.filepath}')` : `sendMessage('${file.filepath}')`;
112
+ const fileCopyMenuItem = !file.directory ? `<li><a class="dropdown-item" data-filepath="${file.filepath}" data-filename="${file.filename}" href="#" onclick="copyFileHandler(this)"><i class="bi bi-copy"></i> Copy</a></li>` : '';
113
+ html += `
114
+ <li class="list-group-item">
115
+ <div class="row">
116
+ <div class="col">
117
+ <a onclick="${onClick}">
118
+ <i class="bi bi-${file.directory ? 'folder-fill' : 'file-earmark-text-fill'}"></i>
119
+ ${file.filename}
120
+ </a>
121
+ </div>
122
+ <div class="col text-end">
123
+ ${file.directory ? '' : file.size}
124
+ </div>
125
+ <div class="col col-auto text-end">
126
+ ${file.date_modified}
127
+ <div class="btn-group" role="group">
128
+ <button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false"></button>
129
+ <ul class="dropdown-menu">
130
+ ${fileMenuOptions(file)}
131
+ </ul>
132
+ </div>
133
+ </div>
134
+ </div>
135
+ </li>
136
+ `;
137
+ }
138
+ html += `</ul>`
139
+ return html;
140
+ };
141
+
142
+ directories = (response) => {
143
+ // console.log(response.data.root_directory);
144
+ let html = '';
145
+ if (pwd != response.data.parent_directory) {
146
+ html += `<li class="list-group-item">
147
+ <div onclick="changeDirectory('${response.data.parent_directory}', '${routes('cd_path')}')" class="w-100">
148
+ <i class="bi bi-folder-fill"></i>
149
+ ..
150
+ </div>
151
+ </li>`;
152
+ }
153
+ html += `<li class="list-group-item">
154
+ <div onclick="changeDirectory('${pwd}', '${routes('cd_path')}')" class="w-100">
155
+ <i class="bi bi-folder-fill"></i>
156
+ ${response.data.pwd_name}
157
+ </div>
158
+ <ul class="list-group">
159
+ `;
160
+ for (const file of response.data.files) {
161
+ if (file.directory) {
162
+ html += `
163
+ <li class="list-group-item">
164
+ <div onclick="changeDirectory('${file.filepath}')" class="w-100">
165
+ <i class="bi bi-folder-fill"></i>
166
+ ${file.filename}
167
+ </div>
168
+ </li>
169
+ `;
170
+ }
171
+ }
172
+ html += '</ul></li>';
173
+ document.getElementById('fm-directories-list').innerHTML = html;
174
+ document.getElementById('pwd-display').innerHTML = `/${pwd}`;
175
+ }
176
+
177
+ activeView = () => {
178
+ return document.querySelector('#file-list-type .nav-link.active').id;
179
+ };
180
+
181
+ fileMenuOptions = (file) => {
182
+ const fileCopyMenuItem = !file.directory ? `<li><a class="dropdown-item" data-filepath="${file.filepath}" data-filename="${file.filename}" href="#" onclick="copyFileHandler(this)"><i class="bi bi-copy"></i> Copy</a></li>` : '';
183
+ const filedownloadMenuItem = !file.directory ? `<li><a class="dropdown-item" data-filename="${file.filename}" href="${file.filepath}" target="_blank"><i class="bi bi-download"></i> Download</a></li>` : '';
184
+ const imageResizeMenuItem = file.image ? `<li><a class="dropdown-item" data-filepath="${file.filepath}" href="# " onclick="openImageDialogHandler(this)"><i class="bi bi-arrows-move"></i> Resize</a></li>` : '';
185
+ html = fileCopyMenuItem;
186
+ html += `
187
+ <li><a class="dropdown-item" data-filepath="${file.filepath}" data-filename="${file.filename}" href="#" onclick="openRenameDialogHandler(this)"><i class="bi bi-pencil"></i> Rename</a></li>
188
+ <li><a class="dropdown-item" data-filepath="${file.filepath}" href="#" onclick="deleteFileHandler(this)"><i class="bi bi-trash"></i> Delete</a></li>`
189
+ html += imageResizeMenuItem;
190
+ html += filedownloadMenuItem;
191
+ return html;
192
+ }
193
+
194
+ switchViewHandler = (e, listType) => {
195
+ e.classList.add('active');
196
+ deSelectedListClass = `#${listType == 'thumbnail' ? 'list' : 'thumbnail'}-view-btn`;
197
+ document.querySelector(deSelectedListClass).classList.remove('active');
198
+ changeDirectory(pwd);
199
+ };
200
+
201
+ copyFileHandler = (e) => {
202
+ const filepath = e.getAttribute('data-filepath');
203
+ axios.post(
204
+ routes('copy_path'),
205
+ {
206
+ item_name: filepath
207
+ },
208
+ {
209
+ headers: {
210
+ 'Content-Type': 'application/json',
211
+ 'X-CSRF-Token': csrf
212
+ }
213
+ }
214
+ )
215
+ .then(function(response) {
216
+ if(response.data.success) {
217
+ mkdirModal.hide();
218
+ document.getElementById('new-folder-name').value = '';
219
+ changeDirectory(pwd);
220
+ } else {
221
+ fmModalDialog(response.data.message);
222
+ }
223
+ });
224
+ };
225
+
226
+ createDirectory = () => {
227
+ const directoryName = document.getElementById('new-folder-name').value;
228
+ if (directoryName === null || directoryName === '') {
229
+ fmModalDialog(
230
+ {
231
+ title: 'Error',
232
+ body: 'Please enter a folder name',
233
+ status: 'danger'
234
+ }
235
+ )
236
+ return ;
237
+ }
238
+ axios.post(
239
+ routes('mkdir_path'),
240
+ {
241
+ pwd: pwd,
242
+ item_name: directoryName
243
+ },
244
+ {
245
+ headers: {
246
+ 'Content-Type': 'application/json',
247
+ 'X-CSRF-Token': csrf
248
+ }
249
+ }
250
+ )
251
+ .then(function(response) {
252
+ if(response.data.success) {
253
+ mkdirModal.hide();
254
+ document.getElementById('new-folder-name').value = '';
255
+ changeDirectory(pwd);
256
+ } else {
257
+ fmModalDialog(response.data.message);
258
+ }
259
+ });
260
+ };
261
+
262
+ changeDirectory = (filePath) => {
263
+ axios.get(`${routes('cd_path')}?type=${type}&cd=${filePath}`)
264
+ .then(function (response) {
265
+ // handle success
266
+ pwd = response.data.pwd;
267
+ document.getElementById('upload_to_dir').value = pwd
268
+ directoryListing(response);
269
+ directories(response);
270
+ })
271
+ .catch(function (error) {
272
+ // handle error
273
+ console.log(error);
274
+ })
275
+ .then(function () {
276
+ // always executed
277
+ });
278
+ }
279
+
280
+ fmModalDialog = (content) => {
281
+ const fmModal = new bootstrap.Modal(document.getElementById('fmModal'));
282
+ let header = document.getElementById('fm-modal-header');
283
+ header.className = 'modal-header'
284
+
285
+ if(content.status !== undefined || content.status) {
286
+ header.classList.add("alert");
287
+ header.classList.add(`alert-${content.status}`);
288
+ }
289
+ document.querySelector('.fm-modal-title').innerHTML = content.title
290
+ document.querySelector('.fm-modal-body').innerHTML = content.body;
291
+
292
+ fmModalDialogButtons(content.buttons);
293
+
294
+ fmModal.show();
295
+ }
296
+
297
+ fmModalDialogButtons = (buttons) => {
298
+ if(buttons === undefined) return;
299
+
300
+ let btnContainer = document.querySelector('.fm-modal-footer-buttons');
301
+ btnContainer.innerHTML = '';
302
+ for (const btn of buttons) {
303
+ let node = document.createElement('button');
304
+ let textNode = document.createTextNode(btn.name);
305
+ node.appendChild(textNode);
306
+ node.classList.add('btn');
307
+ node.classList.add(`btn-${btn.type}`);
308
+ node.onclick = btn.onclick;
309
+ node.setAttribute('data-bs-dismiss', 'modal');
310
+ btnContainer.appendChild(node);
311
+ }
312
+ }
313
+
314
+ deleteFileHandler = (e) => {
315
+ const filepath = e.getAttribute('data-filepath');
316
+ fmModalDialog({
317
+ title: 'Please confirm',
318
+ body: 'Are you sure you wish to delete this item?',
319
+ buttons: [
320
+ { name: 'Ok', onclick: () => { deleteFile(`${filepath}`) }, type: 'primary' }
321
+ ]
322
+ });
323
+ }
324
+
325
+ deleteFile = (file) => {
326
+ axios.delete(
327
+ routes('rm_path'),
328
+ {
329
+ data: { file: file },
330
+ headers: {
331
+ 'Content-Type': 'application/json',
332
+ 'X-CSRF-Token': csrf
333
+ }
334
+ },
335
+ ).then(function (response) {
336
+ changeDirectory(pwd);
337
+ })
338
+ .catch(function (error) {
339
+ console.log(error);
340
+ })
341
+ }
342
+
343
+ openImageDialogHandler = (e) => {
344
+ document.getElementById('original_image').src = e.getAttribute('data-filepath');
345
+ document.getElementById('original_image').setAttribute('width', '');
346
+ document.getElementById('original_image').setAttribute('height', '');
347
+
348
+ const filepath = encodeURIComponent(e.getAttribute('data-filepath'));
349
+
350
+ axios.get(
351
+ routes('image_info_path').replace(':id', filepath),
352
+ {
353
+ },
354
+ {
355
+ headers: {
356
+ 'Content-Type': 'application/json',
357
+ 'X-CSRF-Token': csrf
358
+ }
359
+ }
360
+ )
361
+ .then(function(response) {
362
+ if(response.status === 200) {
363
+ html = `
364
+ <table class="table table-striped">
365
+ <tr>
366
+ <td>File:</td>
367
+ <td>
368
+ <input type="hidden" id="orig_file_path" value="${response.data.filepath}">
369
+ ${response.data.filepath}
370
+ </td>
371
+ </tr>
372
+ <tr>
373
+ <td>Width:</td>
374
+ <td>
375
+ <input type="hidden" id="original_image_width" value="${response.data.width}">
376
+ <input type="text" name="image_width_text" id="image_width_text" onblur="changeImageHeight('width')" value="${response.data.width}"> px
377
+ </td>
378
+ </tr>
379
+ <tr>
380
+ <td>Height:</td>
381
+ <td>
382
+ <input type="hidden" id="original_image_height" value="${response.data.height}">
383
+ <input type="text" name="image_height_text" id="image_height_text" onblur="changeImageHeight('height')" value="${response.data.height}"> px
384
+ </td>
385
+ </tr>
386
+ </table>
387
+ `;
388
+ document.getElementById('image-info-container').innerHTML = html;
389
+ } else {
390
+
391
+ }
392
+ });
393
+
394
+ resizeImageModal.show();
395
+ };
396
+
397
+ changeImageHeight = (attrib) => {
398
+ const oWidth = document.getElementById("original_image_width").value
399
+ const oHeight = document.getElementById("original_image_height").value;
400
+ let nWidth, nHeight;
401
+
402
+ const ratio = oWidth / oHeight;
403
+
404
+ if(attrib === 'width') {
405
+ nWidth = document.getElementById("image_width_text").value
406
+ nHeight = nWidth / ratio;
407
+ document.getElementById("image_height_text").value = Math.round(nHeight);
408
+ }
409
+ else {
410
+ nHeight = document.getElementById("image_height_text").value;
411
+ nWidth = nHeight * ratio;
412
+ document.getElementById("image_width_text").value = Math.round(nWidth);
413
+ }
414
+
415
+ document.getElementById('original_image').setAttribute('width', nWidth);
416
+ document.getElementById('original_image').setAttribute('height', nHeight);
417
+ };
418
+
419
+ resizeImageHandler = (copy) => {
420
+ const filepath = encodeURIComponent(document.getElementById('orig_file_path').value);
421
+ axios.put(
422
+ routes('image_info_path').replace(':id', filepath),
423
+ {
424
+ width: document.getElementById("image_width_text").value,
425
+ height: document.getElementById("image_height_text").value,
426
+ copy
427
+ },
428
+ {
429
+ headers: {
430
+ 'Content-Type': 'application/json',
431
+ 'X-CSRF-Token': csrf
432
+ }
433
+ }
434
+ )
435
+ .then(function(response) {
436
+ if(response.data.success) {
437
+ resizeImageModal.hide();
438
+ changeDirectory(pwd);
439
+ } else {
440
+
441
+ }
442
+ })
443
+ .catch(function (error) {
444
+ console.log(error);
445
+ });
446
+ };
447
+
448
+ openRenameDialogHandler = (e) => {
449
+ document.getElementById('new-filename').value = e.getAttribute('data-filename');
450
+ document.getElementById('original-filename').value = e.getAttribute('data-filename');
451
+ renameItemModal.show();
452
+ }
453
+
454
+ renameFilename = () => {
455
+ const newFilename = document.getElementById('new-filename').value;
456
+ if (newFilename === null || newFilename === '') {
457
+ fmModalDialog(
458
+ {
459
+ title: 'Error',
460
+ body: 'Please enter a filename',
461
+ status: 'danger'
462
+ }
463
+ )
464
+ return ;
465
+ }
466
+ axios.put(
467
+ routes('rename_path'),
468
+ {
469
+ pwd: pwd,
470
+ original_filename: document.getElementById('original-filename').value,
471
+ item_name: newFilename
472
+ },
473
+ {
474
+ headers: {
475
+ 'Content-Type': 'application/json',
476
+ 'X-CSRF-Token': csrf
477
+ }
478
+ }
479
+ )
480
+ .then(function(response) {
481
+ if(response.data.success) {
482
+ renameItemModal.hide();
483
+ document.getElementById('new-filename').value = '';
484
+ changeDirectory(pwd);
485
+ } else {
486
+ fmModalDialog(response.data.message);
487
+ }
488
+ })
489
+ .catch(function (error) {
490
+ console.log(error);
491
+ });
492
+ }
493
+
494
+ changeDirectory('');
495
+ </script>
496
+ </body>
497
+ </html>
@@ -0,0 +1,4 @@
1
+ en:
2
+ errors:
3
+ messages:
4
+ extension_whitelist_error: "You are not allowed to upload %{extension} files, allowed types: %{allowed_types}"
data/config/routes.rb ADDED
@@ -0,0 +1,12 @@
1
+ AmcmsFilemanager::Engine.routes.draw do
2
+ get :filemanager, to: 'filemanager#index'
3
+ namespace :filemanager do
4
+ get :change_directory
5
+ post :mkdir
6
+ post :copy
7
+ post :upload
8
+ put :rename
9
+ delete :destroy
10
+ end
11
+ resources :imagemanager
12
+ end