]> git.immae.eu Git - perso/Immae/Projets/Nodejs/Surfer.git/blobdiff - app/js/app.js
ensure we deal with encoding of paths correctly on the client
[perso/Immae/Projets/Nodejs/Surfer.git] / app / js / app.js
index 823e4f7a23f9a515749dc708cc7573af0b216910..b26a2a6c037b86833af219b24521bd1834ca5d6a 100644 (file)
@@ -21,14 +21,14 @@ function login(username, password) {
         localStorage.username = username;
         localStorage.password = password;
 
-        loadDirectory(app.path);
+        loadDirectory(window.location.hash.slice(1));
     });
 }
 
 function logout() {
     app.session.valid = false;
-    app.session.username = username;
-    app.session.password = password;
+    app.session.username = null;
+    app.session.password = null;
 
     delete localStorage.username;
     delete localStorage.password;
@@ -43,6 +43,31 @@ function encode(filePath) {
     return filePath.split('/').map(encodeURIComponent).join('/');
 }
 
+function decode(filePath) {
+    return filePath.split('/').map(decodeURIComponent).join('/');
+}
+
+var mimeTypes = {
+    images: [ '.png', '.jpg', '.jpeg', '.tiff', '.gif' ],
+    text: [ '.txt', '.md' ],
+    pdf: [ '.pdf' ],
+    html: [ '.html', '.htm', '.php' ],
+    video: [ '.mp4', '.mpg', '.mpeg', '.ogg', '.mkv' ]
+};
+
+function getPreviewUrl(entry, basePath) {
+    var path = '/_admin/img/';
+
+    if (entry.isDirectory) return path + 'directory.png';
+    if (mimeTypes.images.some(function (e) { return entry.filePath.endsWith(e); })) return sanitize(basePath + '/' + entry.filePath);
+    if (mimeTypes.text.some(function (e) { return entry.filePath.endsWith(e); })) return path +'text.png';
+    if (mimeTypes.pdf.some(function (e) { return entry.filePath.endsWith(e); })) return path + 'pdf.png';
+    if (mimeTypes.html.some(function (e) { return entry.filePath.endsWith(e); })) return path + 'html.png';
+    if (mimeTypes.video.some(function (e) { return entry.filePath.endsWith(e); })) return path + 'video.png';
+
+    return path + 'unknown.png';
+}
+
 function refresh() {
     loadDirectory(app.path);
 }
@@ -57,31 +82,50 @@ function loadDirectory(filePath) {
     superagent.get('/api/files/' + filePath).query({ username: app.session.username, password: app.session.password }).end(function (error, result) {
         app.busy = false;
 
+        if (result && result.statusCode === 401) return logout();
         if (error) return console.error(error);
-        if (result.statusCode === 401) return logout();
 
-        app.entries = result.body.entries;
+        result.body.entries.sort(function (a, b) { return a.isDirectory && b.isFile ? -1 : 1; });
+        app.entries = result.body.entries.map(function (entry) {
+            entry.previewUrl = getPreviewUrl(entry, filePath);
+            return entry;
+        });
         app.path = filePath;
-        app.pathParts = filePath.split('/').filter(function (e) { return !!e; });
+        app.pathParts = decode(filePath).split('/').filter(function (e) { return !!e; });
+
+        // update in case this was triggered from code
+        window.location.hash = app.path;
+
+        Vue.nextTick(function () {
+            $(function () {
+                $('[data-toggle="tooltip"]').tooltip();
+            });
+        });
     });
 }
 
 function open(entry) {
     var path = sanitize(app.path + '/' + entry.filePath);
 
-    if (entry.isDirectory) return loadDirectory(path);
+    if (entry.isDirectory) {
+        window.location.hash = path;
+        return;
+    }
 
-    window.open(path);
+    window.open(encode(path));
 }
 
 function up() {
-    loadDirectory(app.path.split('/').slice(0, -1).filter(function (p) { return !!p; }).join('/'));
+    window.location.hash = sanitize(app.path.split('/').slice(0, -1).filter(function (p) { return !!p; }).join('/'));
 }
 
 function upload() {
-    $(app.$els.upload).change(function () {
+    $(app.$els.upload).on('change', function () {
         app.busy = true;
 
+        // detach event handler
+        $(app.$els.upload).off('change');
+
         var file = app.$els.upload.files[0];
         var path = encode(sanitize(app.path + '/' + file.name));
 
@@ -91,13 +135,17 @@ function upload() {
         superagent.put('/api/files' + path).query({ username: app.session.username, password: app.session.password }).send(formData).end(function (error, result) {
             app.busy = false;
 
+            if (result && result.statusCode === 401) return logout();
+            if (result && result.statusCode !== 201) return console.error('Error uploading file: ', result.statusCode);
             if (error) return console.error(error);
-            if (result.statusCode !== 201) return console.error('Error uploading file: ', result.statusCode);
 
             refresh();
         });
     });
 
+    // reset the form first to make the change handler retrigger even on the same file selected
+    $('#fileUploadForm')[0].reset();
+
     app.$els.upload.click();
 }
 
@@ -114,8 +162,9 @@ function del(entry) {
     superagent.del('/api/files' + path).query({ username: app.session.username, password: app.session.password, recursive: true }).end(function (error, result) {
         app.busy = false;
 
+        if (result && result.statusCode === 401) return logout();
+        if (result && result.statusCode !== 200) return console.error('Error deleting file: ', result.statusCode);
         if (error) return console.error(error);
-        if (result.statusCode !== 200) return console.error('Error deleting file: ', result.statusCode);
 
         refresh();
 
@@ -123,6 +172,49 @@ function del(entry) {
     });
 }
 
+function createDirectoryAsk() {
+    $('#modalcreateDirectory').modal('show');
+    app.createDirectoryData = '';
+    app.createDirectoryError = null;
+}
+
+function createDirectory(name) {
+    app.busy = true;
+    app.createDirectoryError = null;
+
+    var path = encode(sanitize(app.path + '/' + name));
+
+    superagent.put('/api/files' + path).query({ username: app.session.username, password: app.session.password, directory: true }).end(function (error, result) {
+        app.busy = false;
+
+        if (result && result.statusCode === 401) return logout();
+        if (result && result.statusCode === 403) {
+            app.createDirectoryError = 'Name not allowed';
+            return;
+        }
+        if (result && result.statusCode === 409) {
+            app.createDirectoryError = 'Directory already exists';
+            return;
+        }
+        if (result && result.statusCode !== 201) return console.error('Error creating directory: ', result.statusCode);
+        if (error) return console.error(error);
+
+        app.createDirectoryData = '';
+        refresh();
+
+        $('#modalcreateDirectory').modal('hide');
+    });
+}
+
+Vue.filter('prettyDate', function (value) {
+    var d = new Date(value);
+    return d.toDateString();
+});
+
+Vue.filter('prettyFileSize', function (value) {
+    return filesize(value);
+});
+
 var app = new Vue({
     el: '#app',
     data: {
@@ -134,6 +226,8 @@ var app = new Vue({
         },
         loginData: {},
         deleteData: {},
+        createDirectoryData: '',
+        createDirectoryError: null,
         entries: []
     },
     methods: {
@@ -144,7 +238,9 @@ var app = new Vue({
         up: up,
         upload: upload,
         delAsk: delAsk,
-        del: del
+        del: del,
+        createDirectoryAsk: createDirectoryAsk,
+        createDirectory: createDirectory
     }
 });
 
@@ -152,4 +248,15 @@ window.app = app;
 
 login(localStorage.username, localStorage.password);
 
+$(window).on('hashchange', function () {
+    loadDirectory(window.location.hash.slice(1));
+});
+
+// setup all the dialog focus handling
+['modalcreateDirectory'].forEach(function (id) {
+    $('#' + id).on('shown.bs.modal', function () {
+        $(this).find("[autofocus]:first").focus();
+    });
+});
+
 })();