diff --git a/app/api.rb b/app/api.rb
index 429c566c..89b7ea9f 100644
--- a/app/api.rb
+++ b/app/api.rb
@@ -102,12 +102,12 @@ post '/api/upload' do
end
if current_site.too_many_files?(files.length)
- api_error 400, 'too_many_files', "cannot exceed the maximum site files limit (#{current_site.plan_feature(:maximum_site_files)}), #{current_site.supporter? ? 'please contact support' : 'please upgrade to a supporter account'}"
+ api_error 400, 'too_many_files', "cannot exceed the maximum site files limit (#{current_site.plan_feature(:maximum_site_files)})"
end
files.each do |file|
if !current_site.okay_to_upload?(file)
- api_error 400, 'invalid_file_type', "#{file[:filename]} is not a valid file type (or contains not allowed content) for this site, please upgrade to a supporter account to upload this file type"
+ api_error 400, 'invalid_file_type', "#{file[:filename]} is not a allowed file type for free sites, supporter required"
end
if File.directory? file[:filename]
diff --git a/app/dashboard.rb b/app/dashboard.rb
index f7616472..cbba9701 100644
--- a/app/dashboard.rb
+++ b/app/dashboard.rb
@@ -8,7 +8,7 @@ get '/dashboard' do
current_site.save_changes validate: false
end
- erb :'dashboard'
+ erb :'dashboard/index'
end
def dashboard_init
@@ -30,3 +30,11 @@ def dashboard_init
@dir = params[:dir]
@file_list = current_site.file_list @dir
end
+
+get '/dashboard/files' do
+ require_login
+ dashboard_init
+ dont_browser_cache
+
+ erb :'dashboard/files', layout: false
+end
\ No newline at end of file
diff --git a/app/site_files.rb b/app/site_files.rb
index ea9e7dcb..d60be51b 100644
--- a/app/site_files.rb
+++ b/app/site_files.rb
@@ -177,7 +177,16 @@ get %r{\/site_files\/text_editor\/(.+)} do
dont_browser_cache
@filename = params[:captures].first
+ redirect '/site_files/text_editor?filename=' + Rack::Utils.escape(@filename)
+end
+
+get '/site_files/text_editor' do
+ require_login
+ dont_browser_cache
+
+ @filename = params[:filename]
extname = File.extname @filename
+
@ace_mode = case extname
when /htm|html/ then 'html'
when /js/ then 'javascript'
@@ -217,4 +226,4 @@ end
get '/site_files/mount_info' do
@title = 'Site Mount Information'
erb :'site_files/mount_info'
-end
+end
\ No newline at end of file
diff --git a/public/js/dashboard.js b/public/js/dashboard.js
index 39abe669..c7b7c773 100644
--- a/public/js/dashboard.js
+++ b/public/js/dashboard.js
@@ -11,13 +11,16 @@ function uploadFileFromButton() {
formData.append('from_button', $(form).find('input[name="from_button"]').val());
formData.append('dir', dirValue);
+ uploadFilesCount = 0
// Append files with modified filenames
$.each($('#uploadFiles')[0].files, function(i, file) {
var modifiedFileName = dirValue + '/' + file.name;
formData.append(modifiedFileName, file);
+ uploadFilesCount++;
});
- // Submit the form data using jQuery's AJAX
+ alertClear();
+
$.ajax({
url: '/api/upload',
type: 'POST',
@@ -25,12 +28,15 @@ function uploadFileFromButton() {
contentType: false, // This is required for FormData
processData: false, // This is required for FormData
success: function(data) {
- console.log('Files successfully uploaded.');
- location.reload()
+ alertType('success');
+ alertAdd(uploadFilesCount+' files uploaded successfully.');
+ reloadDashboardFiles();
},
error: function(xhr, status, error) {
- console.error('Upload failed: ' + error);
- location.reload()
+ var responseBody = JSON.parse(xhr.responseText);
+ alertType('error');
+ alertAdd(responseBody.message);
+ reloadDashboardFiles();
}
});
}
@@ -40,125 +46,106 @@ $('#uploadFiles').change(function() {
});
var uploadForm = $('#uploadFilesButtonForm')[0];
- var deleteForm = $('#deleteFilenameForm')[0];
+var deleteForm = $('#deleteFilenameForm')[0];
- function moveFileToFolder(event) {
- var link = event.dataTransfer.getData("Text");
- if(link) link = link.trim();
- if(!link || link.startsWith('https://neocities.org/dashboard')) return;
- event.preventDefault();
- var name = link.split('.neocities.org/').slice(1).join('.neocities.org/');
- var oReq = new XMLHttpRequest();
- oReq.open("GET", "/site_files/download/" + name, true);
- oReq.responseType = "arraybuffer";
-
- $('#movingOverlay').css('display', 'block')
+function moveFileToFolder(event) {
+ var link = event.dataTransfer.getData("Text");
+ if(link) link = link.trim();
+ if(!link || link.startsWith('https://neocities.org/dashboard')) return;
+ event.preventDefault();
+ var name = link.split('.neocities.org/').slice(1).join('.neocities.org/');
+ var oReq = new XMLHttpRequest();
+ oReq.open("GET", "/site_files/download/" + name, true);
+ oReq.responseType = "arraybuffer";
- oReq.onload = function() {
- var newFile = new File([oReq.response], name);
- var dataTransfer = new DataTransfer();
- var currentFolder = new URL(location.href).searchParams.get('dir');
- if(!currentFolder) currentFolder = '';
- else currentFolder = currentFolder + '/';
+ $('#movingOverlay').css('display', 'block')
- dataTransfer.items.add(newFile);
- $('#uploadFilesButtonForm > input[name="dir"]')[0].value = currentFolder + event.target.parentElement.parentElement.getElementsByClassName('title')[0].innerText.trim();
- $('#uploadFiles')[0].files = dataTransfer.files;
- $.ajax({
- type: uploadForm.method,
- url: uploadForm.action,
- data: new FormData(uploadForm),
- processData: false,
- contentType: false,
- success: function() {
- let csrf = $('#uploadFilesButtonForm > input[name="csrf_token"]')[0].value;
- var dReq = new XMLHttpRequest();
- dReq.open(deleteForm.method, deleteForm.action, true);
- dReq.onload = function() {
- location.reload()
- }
- dReq.setRequestHeader("content-type", 'application/x-www-form-urlencoded');
- dReq.send("csrf_token=" + encodeURIComponent(csrf) + "&filename=" + name.replace(/\s/g, '+'));
- },
- error: function() {
+ oReq.onload = function() {
+ var newFile = new File([oReq.response], name);
+ var dataTransfer = new DataTransfer();
+ var currentFolder = new URL(location.href).searchParams.get('dir');
+ if(!currentFolder) currentFolder = '';
+ else currentFolder = currentFolder + '/';
+
+ dataTransfer.items.add(newFile);
+ $('#uploadFilesButtonForm > input[name="dir"]')[0].value = currentFolder + event.target.parentElement.parentElement.getElementsByClassName('title')[0].innerText.trim();
+ $('#uploadFiles')[0].files = dataTransfer.files;
+ $.ajax({
+ type: uploadForm.method,
+ url: uploadForm.action,
+ data: new FormData(uploadForm),
+ processData: false,
+ contentType: false,
+ success: function() {
+ let csrf = $('#uploadFilesButtonForm > input[name="csrf_token"]')[0].value;
+ var dReq = new XMLHttpRequest();
+ dReq.open(deleteForm.method, deleteForm.action, true);
+ dReq.onload = function() {
location.reload()
}
- });
- };
- oReq.send();
- }
+ dReq.setRequestHeader("content-type", 'application/x-www-form-urlencoded');
+ dReq.send("csrf_token=" + encodeURIComponent(csrf) + "&filename=" + name.replace(/\s/g, '+'));
+ },
+ error: function() {
+ location.reload()
+ }
+ });
+ };
+ oReq.send();
+}
- function confirmFileRename(path) {
- console.log(path)
- $('#renamePathInput').val(path);
- $('#renameNewPathInput').val(path);
- $('#renameModal').modal();
- }
+function confirmFileRename(path) {
+ $('#renamePathInput').val(path);
+ $('#renameNewPathInput').val(path);
+ $('#renameModal').modal();
+}
- function confirmFileDelete(name) {
- $('#deleteFileName').text(name);
- $('#deleteConfirmModal').modal();
- }
+function confirmFileDelete(name) {
+ $('#deleteFileName').text(name);
+ $('#deleteConfirmModal').modal();
+}
- function fileDelete() {
- $('#deleteFilenameInput').val($('#deleteFileName').html());
- $('#deleteFilenameForm').submit();
- }
+function fileDelete() {
+ $('#deleteFilenameInput').val($('#deleteFileName').html());
+ $('#deleteFilenameForm').submit();
+}
- function clickUploadFiles() {
- $("input[id='uploadFiles']").click()
- }
+function clickUploadFiles() {
+ $("input[id='uploadFiles']").click()
+}
- function showUploadProgress() {
- $('#uploadingOverlay').css('display', 'block')
- }
+function showUploadProgress() {
+ $('#uploadingOverlay').css('display', 'block')
+}
- function hideUploadProgress() {
- $('#progressBar').css('display', 'none')
- $('#uploadingOverlay').css('display', 'none')
- }
+function hideUploadProgress() {
+ $('#progressBar').css('display', 'none')
+ $('#uploadingOverlay').css('display', 'none')
+}
+allUploadsComplete = false
-/*
- this.on("totaluploadprogress", function(progress, totalBytes, totalBytesSent) {
- if(progress == 100)
- allUploadsComplete = true
-
- showUploadProgress()
- $('#progressBar').css('display', 'block')
- $('#uploadingProgress').css('width', progress+'%')
- })
-*/
-
- allUploadsComplete = false
-
- $('#createDir').on('shown', function () {
- $('#newDirInput').focus();
- })
-
- $('#createFile').on('shown', function () {
- $('#newFileInput').focus();
- })
-
- function listView() {
- if(localStorage)
- localStorage.setItem('viewType', 'list')
-
- $('#filesDisplay').addClass('list-view')
- }
-
- function iconView() {
- if(localStorage)
- localStorage.removeItem('viewType')
-
- $('#filesDisplay').removeClass('list-view')
- }
-
+$('#createDir').on('shown', function () {
+ $('#newDirInput').focus();
+})
+$('#createFile').on('shown', function () {
+ $('#newFileInput').focus();
+})
+function listView() {
+ if(localStorage)
+ localStorage.setItem('viewType', 'list')
+ $('#filesDisplay').addClass('list-view')
+}
+function iconView() {
+ if(localStorage)
+ localStorage.removeItem('viewType')
+ $('#filesDisplay').removeClass('list-view')
+}
// Drop handler function to get all files
async function getAllFileEntries(dataTransferItemList) {
@@ -210,8 +197,21 @@ async function uploadFile(file, dir, additionalFormData) {
formData.append(key, value);
}
- // Append the file to the FormData, using the file name as key
- var modifiedFileName = dir + '/' + file.webkitRelativePath || file.name;
+ var modifiedFileName;
+
+ if (file.webkitRelativePath === '') {
+ modifiedFileName = file.name;
+ } else {
+ modifiedFileName = file.webkitRelativePath;
+ }
+
+ if (dir && dir !== '/') {
+ modifiedFileName = dir.replace(/^\//, '') + '/' + modifiedFileName;
+ }
+
+ modifiedFileName = modifiedFileName.replace(/^\//, '');
+
+ console.log('modifiedFileName: '+modifiedFileName)
formData.append(modifiedFileName, file, modifiedFileName);
$('#uploadFileName').text(modifiedFileName).prepend(' ');
@@ -223,9 +223,17 @@ async function uploadFile(file, dir, additionalFormData) {
body: formData,
});
const result = await response.json();
- console.log('Upload successful for', file.name, result);
+
+ if (result.result == 'error') {
+ fileUploadErrorCount++;
+ if(fileUploadErrorCount == 1) {
+ alertType('error');
+ }
+ alertAdd(result.message);
+ } else {
+ fileUploadSuccessCount++;
+ }
} catch (err) {
- console.error('Upload error for', file.name, err);
}
}
@@ -238,6 +246,8 @@ async function processEntry(entry, dir, additionalFormData) {
}
async function uploadFiles(fileEntries) {
+ alertClear();
+
// Collect additional form data
const form = document.getElementById('dropzone');
let additionalFormData = {};
@@ -254,6 +264,8 @@ async function uploadFiles(fileEntries) {
$('#progressBar').css('display', 'block')
fileUploadCount = 0
+ fileUploadErrorCount = 0
+ fileUploadSuccessCount = 0
for (let entry of fileEntries) {
await processEntry(entry, dir, additionalFormData);
@@ -263,18 +275,57 @@ async function uploadFiles(fileEntries) {
}
allUploadsComplete = true
- location.reload();
+
+ if(fileUploadErrorCount > 0) {
+ alertAdd(fileUploadSuccessCount+'/'+fileUploadCount+' files uploaded successfully.');
+ } else {
+ alertType('success')
+ alertAdd(fileUploadSuccessCount+' files uploaded successfully.');
+ }
+
+ reloadDashboardFiles();
}
-var elDrop = document.getElementById('dropzone');
+function reInitDashboardFiles() {
+ var elDrop = document.getElementById('dropzone');
-elDrop.addEventListener('dragover', function (event) {
- event.preventDefault();
-});
+ elDrop.addEventListener('dragover', function (event) {
+ event.preventDefault();
+ });
+
+ elDrop.addEventListener('drop', async function (event) {
+ event.preventDefault();
+ showUploadProgress();
+ let items = await getAllFileEntries(event.dataTransfer.items);
+ await uploadFiles(items);
+ });
+}
-elDrop.addEventListener('drop', async function (event) {
- event.preventDefault();
- showUploadProgress();
- let items = await getAllFileEntries(event.dataTransfer.items);
- await uploadFiles(items);
-});
+function reloadDashboardFiles() {
+ $.get('/dashboard/files?dir='+encodeURIComponent($("#dir").val()), function(data) {
+ $('#filesDisplay').html(data);
+ reInitDashboardFiles();
+ });
+}
+
+function alertAdd(text) {
+ var a = $('#alertDialogue');
+ a.css('display', 'block');
+ a.append(text+'
');
+}
+
+function alertClear(){
+ var a = $('#alertDialogue');
+ a.css('display', 'none');
+ a.text('');
+}
+
+function alertType(type){
+ var a = $('#alertDialogue');
+ a.removeClass('alert-success');
+ a.removeClass('alert-error');
+ a.addClass('alert-'+type);
+}
+
+// for first time load
+reInitDashboardFiles();
\ No newline at end of file
diff --git a/sass/_project-sass/_project-Base.scss b/sass/_project-sass/_project-Base.scss
index 0d82fa65..f3a7cc7b 100644
--- a/sass/_project-sass/_project-Base.scss
+++ b/sass/_project-sass/_project-Base.scss
@@ -60,7 +60,7 @@ a{
@import 'project-Footer'; // Project Specific Footer Styling
.alert-error {
- background-color:#F5BA00; color:#fff;
+ background-color:#f39c12; color:#fff;
}
.modal {
@@ -89,4 +89,4 @@ a{
border: 0;
background: none;
padding: 0 23px 19px 0;
-}
\ No newline at end of file
+}
diff --git a/tests/site_file_tests.rb b/tests/site_file_tests.rb
index 0be81427..772cc4d5 100644
--- a/tests/site_file_tests.rb
+++ b/tests/site_file_tests.rb
@@ -410,7 +410,7 @@ describe 'site_files' do
it 'fails with unsupported file' do
upload 'flowercrime.wav' => Rack::Test::UploadedFile.new('./tests/files/flowercrime.wav', 'audio/x-wav')
- _(JSON.parse(last_response.body)['message']).must_match /please upgrade to a supporter account/i
+ _(JSON.parse(last_response.body)['error_type']).must_equal 'invalid_file_type'
_(File.exists?(@site.files_path('flowercrime.wav'))).must_equal false
_(@site.site_changed).must_equal false
end
diff --git a/views/dashboard.erb b/views/dashboard.erb
deleted file mode 100644
index 6dcd2d7e..00000000
--- a/views/dashboard.erb
+++ /dev/null
@@ -1,271 +0,0 @@
-
-
-
- <%= current_site.host %> - '> Share -
-