From c88fa345586c410ca5dab8596a97920d23cce3bb Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 24 Nov 2016 18:58:29 +0100 Subject: [PATCH] Improve UI, fix issues with new file manager channels --- customize.dist/DecorateToolbar.js | 2 +- www/file/file.css | 34 ++--- www/file/fileObject.js | 57 +++---- www/file/index.html | 4 +- www/file/main.js | 245 ++++++++++-------------------- 5 files changed, 119 insertions(+), 223 deletions(-) diff --git a/customize.dist/DecorateToolbar.js b/customize.dist/DecorateToolbar.js index 6ec6eac89..51a01aa8c 100644 --- a/customize.dist/DecorateToolbar.js +++ b/customize.dist/DecorateToolbar.js @@ -10,7 +10,7 @@ define([ var main = function () { var url = window.location.pathname; var isHtml = /\.html/.test(url) || url === '/' || url === ''; - var isPoll = /\/poll\//.test(url); + var isPoll = /\/poll\//.test(url) || /\/file\//.test(url); if (!isHtml && !isPoll) { Messages._applyTranslation(); return; diff --git a/www/file/file.css b/www/file/file.css index de79d2c6f..77fbae134 100644 --- a/www/file/file.css +++ b/www/file/file.css @@ -61,7 +61,7 @@ li { #tree { - border: 2px solid blue; + border-right: 1px solid #ccc; box-sizing: border-box; background: white; overflow: auto; @@ -70,6 +70,7 @@ li { white-space: nowrap; max-width: 500px; min-width: 200px; + padding: 10px 0px; } #tree li { @@ -165,7 +166,6 @@ li { /* CONTENT */ #content { - border: 2px solid green; box-sizing: border-box; background: #eee; overflow: auto; @@ -174,6 +174,10 @@ li { flex-flow: column; } +#content h1 { + padding-left: 10px; +} + .topButtonContainer { border: 1px solid #ccc; float: right; @@ -241,10 +245,13 @@ li { cursor: default; color: #008; } -#content .list li.header .element span { +#content .list li.header .element span:not(.fa) { border-right: 1px solid #CCC; text-align: left; } +#content .list li.header .element span.fa { + float: right; +} #content .list li.header span.name { padding-left: 0; } @@ -264,27 +271,8 @@ li { #content .list .header span.name { width: 500px; } -/*#content .list .element span.name { - flex: 1; -} -#content .list .file-element span.name { - min-width: 378px; - max-width: 478px; -} -#content .list .file-header span.name { - min-width: 400px; - max-width: 500px; -} -@media screen and (max-width: 1570px) { - #content .list .file-header span.name { - max-width: 400px; - } - #content .list .file-element span.name { - max-width: 378px; - } -}*/ #content .list .element span.type, #content .list .element span.atime, #content .list .element span.ctime { - width: 150px; + width: 175px; } #content .list .element span.title { width: 250px; diff --git a/www/file/fileObject.js b/www/file/fileObject.js index 16ec918d1..174c8bd46 100644 --- a/www/file/fileObject.js +++ b/www/file/fileObject.js @@ -14,7 +14,9 @@ define([ var init = module.init = function (files, config) { FILES_DATA = config.storageKey; var DEBUG = config.DEBUG || false; - var logging = console.log; + var logging = function () { + console.log.apply(console, arguments); + }; var log = config.log || logging; var logError = config.logError || logging; var debug = config.debug || logging; @@ -23,7 +25,7 @@ define([ var error = exp.error = function() { exp.fixFiles(); - console.error.apply(null, arguments); + console.error.apply(console, arguments); }; var comparePath = exp.comparePath = function (a, b) { @@ -154,7 +156,10 @@ define([ }; var getUnsortedFiles = exp.getUnsortedFiles = function () { - return files[UNSORTED]; + if (!files[UNSORTED]) { + files[UNSORTED] = []; + } + return files[UNSORTED].slice(); }; var getFilesRecursively = function (root, arr) { @@ -221,9 +226,9 @@ define([ }; var checkDeletedFiles = function () { - var rootFiles = getRootFiles().slice(); - var unsortedFiles = getUnsortedFiles().slice(); - var trashFiles = getTrashFiles().slice(); + var rootFiles = getRootFiles(); + var unsortedFiles = getUnsortedFiles(); + var trashFiles = getTrashFiles(); var toRemove = []; files[FILES_DATA].forEach(function (arr) { var f = arr.href; @@ -356,7 +361,7 @@ define([ log(Messages.fo_moveUnsortedError); return; } else { - if (isPathInUnsorted(elementPath)) { console.log('inunsorted'); return; } + if (isPathInUnsorted(elementPath)) { return; } if (files[UNSORTED].indexOf(element) === -1) { files[UNSORTED].push(element); } @@ -557,9 +562,9 @@ define([ }; var addUnsortedPad = exp.addPad = function (href, path, name) { - var unsortedFiles = getUnsortedFiles().slice(); - var rootFiles = getRootFiles().slice(); - var trashFiles = getTrashFiles().slice(); + var unsortedFiles = getUnsortedFiles(); + var rootFiles = getRootFiles(); + var trashFiles = getTrashFiles(); if (path && name) { var newPath = decodeURIComponent(path).split(','); var parentEl = findElement(files, newPath); @@ -574,30 +579,13 @@ define([ } }; - var checkNewPads = exp.checkNewPads = function () { - var fd = files[FILES_DATA]; - var rootFiles = getRootFiles().slice(); - var unsortedFiles = getUnsortedFiles().slice(); - var trashFiles = getTrashFiles().slice(); - fd.forEach(function (el, idx) { - if (!el.href) { return; } - if (rootFiles.indexOf(el.href) === -1 - && unsortedFiles.indexOf(el.href) === -1 - && trashFiles.indexOf(el.href) === -1) { - debug("An element in filesData was not in ROOT, UNSORTED or TRASH.", el); - files[UNSORTED].push(el.href); - } + var uniq = function (a) { + var seen = {}; + return a.filter(function(item) { + return seen.hasOwnProperty(item) ? false : (seen[item] = true); }); }; - var checkRemovedPads = exp.checkRemovedPads = function () { - var fd = files[FILES_DATA]; - var rootFiles = getRootFiles().slice(); - var unsortedFiles = getUnsortedFiles().slice(); - var trashFiles = getTrashFiles().slice(); - - }; - var fixFiles = exp.fixFiles = function () { // Explore the tree and check that everything is correct: // * 'root', 'trash' and 'filesData' exist and are objects @@ -663,12 +651,13 @@ define([ } }); }; + files[UNSORTED] = uniq(files[UNSORTED]); fixUnsorted(files[UNSORTED]); var fixFilesData = function (fd) { - var rootFiles = getRootFiles().slice(); - var unsortedFiles = getUnsortedFiles().slice(); - var trashFiles = getTrashFiles().slice(); + var rootFiles = getRootFiles(); + var unsortedFiles = getUnsortedFiles(); + var trashFiles = getTrashFiles(); var toClean = []; fd.forEach(function (el, idx) { if (typeof(el) !== "object") { diff --git a/www/file/index.html b/www/file/index.html index 1f5d4f4df..997d88c62 100644 --- a/www/file/index.html +++ b/www/file/index.html @@ -21,12 +21,12 @@ } #pad-iframe { position:fixed; - top:0px; + top:2.5em; left:0px; bottom:0px; right:0px; width:100%; - height:100%; + height:calc(100% - 2.5em); border:none; margin:0; padding:0; diff --git a/www/file/main.js b/www/file/main.js index 46ec7e64f..234a5dd76 100644 --- a/www/file/main.js +++ b/www/file/main.js @@ -19,8 +19,7 @@ define([ var $iframe = $('#pad-iframe').contents(); var ifrw = $('#pad-iframe')[0].contentWindow; - //var hash = Cryptpad.getAttribute('FS_hash', cb); - var hash = localStorage.FS_hash; + var hash = window.location.hash || localStorage.FS_hash; var secret = Cryptpad.getSecrets(hash); var ROOT = "root"; @@ -41,8 +40,12 @@ define([ var config = {}; config.storageKey = FILES_DATA; var DEBUG = config.DEBUG = true; - var debug = config.debug = DEBUG ? console.log : function() {return;}; - var logError = config.logError = console.error; + var debug = config.debug = DEBUG ? function () { + console.log.apply(console, arguments); + } : function () { return; }; + var logError = config.logError = function () { + console.error.apply(console, arguments); + }; var log = config.log = Cryptpad.log; var DEBUG_LS = module.DEBUG_LS = { resetLocalStorage : function () { @@ -51,151 +54,6 @@ define([ } }; - var filesObject = { - root: { - "Directory 1": { - "Dir A": { - "Dir D": { - "Dir E": {}, - }, - "File a": "https://cryptpad.fr/slide/#hash_a", - "File b": "https://cryptpad.fr/pad/#hash_b", - "File c": "https://cryptpad.fr/pad/#hash_c", - "File d": "https://cryptpad.fr/pad/#hash_d", - "File e": "https://cryptpad.fr/pad/#hash_e", - "File f": "https://cryptpad.fr/pad/#hash_f", - "File g": "https://cryptpad.fr/pad/#hash_g", - "File h": "https://cryptpad.fr/pad/#hash_h", - "File i": "https://cryptpad.fr/pad/#hash_i", - "File j": "https://cryptpad.fr/pad/#hash_j", - "File k": "https://cryptpad.fr/pad/#hash_k" - }, - "Dir C": {}, - "Dir B": {}, - "File A": "https://cryptpad.fr/pad/#hash_A" - }, - "Directory 2": { - "File B": "https://cryptpad.fr/pad/#hash_B", - "File C": "https://cryptpad.fr/pad/#hash_C" - } - }, - unsorted: ["https://cryptpad.fr/pad/#href1", "https://cryptpad.fr/pad/#href2", "https://cryptpad.fr/pad/#href3"], - filesData: { - "https://cryptpad.fr/slide/#hash_a": { - ctime: "Tue Nov 08 2016 16:42:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:42:21 GMT+0100 (CET)", - title: "Pad A" - }, - "https://cryptpad.fr/pad/#hash_b": { - ctime: "Mon Nov 07 2016 16:38:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:38:21 GMT+0100 (CET)", - title: "Pad B" - }, - "https://cryptpad.fr/pad/#hash_c": { - ctime: "Tue Nov 08 2016 16:34:21 GMT+0100 (CET)", - atime: "Sun Nov 06 2016 12:34:21 GMT+0100 (CET)", - title: "Pad C With A Very Very Very Long Title" - }, - "https://cryptpad.fr/pad/#hash_e": { - ctime: "Tue Nov 08 2016 16:26:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:26:21 GMT+0100 (CET)", - title: "Pad E" - }, - "https://cryptpad.fr/pad/#hash_f": { - ctime: "Tue Nov 08 2016 16:22:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:22:21 GMT+0100 (CET)", - title: "Pad F" - }, - "https://cryptpad.fr/pad/#hash_g": { - ctime: "Tue Nov 08 2016 16:42:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:42:21 GMT+0100 (CET)", - title: "Pad A" - }, - "https://cryptpad.fr/pad/#hash_h": { - ctime: "Tue Nov 08 2016 16:42:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:42:21 GMT+0100 (CET)", - title: "Pad A" - }, - "https://cryptpad.fr/pad/#hash_i": { - ctime: "Tue Nov 08 2016 16:42:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:42:21 GMT+0100 (CET)", - title: "Pad A" - }, - "https://cryptpad.fr/pad/#hash_j": { - ctime: "Tue Nov 08 2016 16:42:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:42:21 GMT+0100 (CET)", - title: "Pad A" - }, - "https://cryptpad.fr/pad/#hash_k": { - ctime: "Tue Nov 08 2016 16:42:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:42:21 GMT+0100 (CET)", - title: "Pad A" - }, - "https://cryptpad.fr/pad/#hash_Z": { - ctime: "Tue Nov 08 2016 16:42:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:42:21 GMT+0100 (CET)", - title: "Code Z" - }, - "https://cryptpad.fr/pad/#hash_A": { - ctime: "Tue Nov 08 2016 16:42:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:42:21 GMT+0100 (CET)", - title: "Code A" - }, - "https://cryptpad.fr/pad/#hash_B": { - ctime: "Tue Nov 08 2016 16:42:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:42:21 GMT+0100 (CET)", - title: "Code B" - }, - "https://cryptpad.fr/pad/#hash_C": { - ctime: "Tue Nov 08 2016 16:42:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:42:21 GMT+0100 (CET)", - title: "Code C" - }, - "https://cryptpad.fr/pad/#hash_1": { - ctime: "Tue Nov 08 2016 16:42:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:42:21 GMT+0100 (CET)", - title: "Code C" - }, - "https://cryptpad.fr/pad/#hash_2": { - ctime: "Tue Nov 08 2016 16:42:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:42:21 GMT+0100 (CET)", - title: "Code C" - }, - "https://cryptpad.fr/pad/#hash_3": { - ctime: "Tue Nov 08 2016 16:42:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:42:21 GMT+0100 (CET)", - title: "Code C" - }, - "https://cryptpad.fr/pad/#hash_4": { - ctime: "Tue Nov 08 2016 16:42:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:42:21 GMT+0100 (CET)", - title: "Code C" - }, - "https://cryptpad.fr/pad/#href1": { - ctime: "Tue Nov 08 2016 16:42:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:42:21 GMT+0100 (CET)", - title: "Pad unsorted 1" - }, - "https://cryptpad.fr/pad/#href2": { - ctime: "Tue Nov 08 2016 16:42:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:42:21 GMT+0100 (CET)", - title: "Pad unsorted 2" - }, - "https://cryptpad.fr/pad/#href3": { - ctime: "Tue Nov 08 2016 16:42:21 GMT+0100 (CET)", - atime: "Tue Nov 08 2016 12:42:21 GMT+0100 (CET)", - title: "Pad unsorted 3" - } - }, - trash: { - "File Z": [{ - element: "https://cryptpad.fr/pad/#hash_Z", - path: [ROOT] - }] - } - }; - module.defaultFiles = JSON.parse(JSON.stringify(filesObject)); - var getLastOpenedFolder = function () { var path; try { @@ -289,11 +147,12 @@ define([ var $contentContextMenu = $iframe.find("#contentContextMenu"); var $trashTreeContextMenu = $iframe.find("#trashTreeContextMenu"); var $trashContextMenu = $iframe.find("#trashContextMenu"); + + + // Icons var $folderIcon = $('', {"class": "fa fa-folder folder", style:"color:#FEDE8B;text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;"}); - //var $folderEmptyIcon = $('', {"class": "fa fa-folder folder", style:"color:pink"}); var $folderEmptyIcon = $folderIcon.clone(); var $folderOpenedIcon = $('', {"class": "fa fa-folder-open folder", style:"color:#FEDE8B;text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;"}); - //var $folderOpenedEmptyIcon = $('', {"class": "fa fa-folder-open-o folder"}); var $folderOpenedEmptyIcon = $folderOpenedIcon.clone(); var $fileIcon = $('', {"class": "fa fa-file-text-o file"}); var $upIcon = $('', {"class": "fa fa-arrow-circle-up"}); @@ -304,6 +163,10 @@ define([ var $expandIcon = $('', {"class": "fa fa-plus-square-o expcol"}); var $listIcon = $('', {"class": "fa fa-list"}); var $gridIcon = $('', {"class": "fa fa-th"}); + var $sortAscIcon = $('', {"class": "fa fa-angle-up"}); + var $sortDescIcon = $('', {"class": "fa fa-angle-down"}); + + var appStatus = { isReady: true, @@ -838,6 +701,15 @@ define([ refresh(); }; + var addFolderSortIcon = function ($list) { + var $icon = $sortAscIcon.clone(); + if (files[SORT_FOLDER_DESC]) { + $icon = $sortDescIcon.clone(); + } + if (typeof(files[SORT_FOLDER_DESC]) !== "undefined") { + $list.find('.foldername').prepend($icon); + } + }; var getFolderListHeader = function () { var $folderHeader = $('
  • ', {'class': 'header listElement'}); var $fohElement = $('', {'class': 'element'}).appendTo($folderHeader); @@ -845,8 +717,21 @@ define([ var $subfolders = $('', {'class': 'folders listElement'}).text(Messages.fm_numberOfFolders); var $files = $('', {'class': 'files listElement'}).text(Messages.fm_numberOfFiles); $fohElement.append($name).append($subfolders).append($files); + addFolderSortIcon($fohElement); return $folderHeader; }; + var addFileSortIcon = function ($list) { + var $icon = $sortAscIcon.clone(); + if (files[SORT_FILE_DESC]) { + $icon = $sortDescIcon.clone(); + } + var classSorted; + if (files[SORT_FILE_BY] === '') { classSorted = 'filename'; } + else if (files[SORT_FILE_BY]) { classSorted = files[SORT_FILE_BY]; } + if (classSorted) { + $list.find('.' + classSorted).prepend($icon); + } + }; var getFileListHeader = function (displayTitle) { var $fileHeader = $('
  • ', {'class': 'file-header header listElement'}); var $fihElement = $('', {'class': 'element'}).appendTo($fileHeader); @@ -860,6 +745,7 @@ define([ $fihElement.append($fhTitle); } $fihElement.append($fhType).append($fhAdate).append($fhCdate); + addFileSortIcon($fihElement); return $fileHeader; }; @@ -931,12 +817,13 @@ define([ $container.append($fileHeader); var keys = unsorted; var sortedFiles = sortElements(false, [UNSORTED], keys, files[SORT_FILE_BY], !files[SORT_FILE_DESC], true); - sortedFiles.forEach(function (href, idx) { + sortedFiles.forEach(function (href) { var file = filesOp.getFileData(href); if (!file) { debug("getUnsortedFiles returns an element not present in filesData: ", href); return; } + var idx = files[UNSORTED].indexOf(href); var $icon = $fileIcon.clone(); var $name = $('', { 'class': 'file-element element' }); addFileData(href, file.title, $name, false); @@ -963,7 +850,7 @@ define([ $container.append($fileHeader); var keys = allfiles; var sortedFiles = sortElements(false, [FILES_DATA], keys, files[SORT_FILE_BY], !files[SORT_FILE_DESC], false, true); - sortedFiles.forEach(function (file, idx) { + sortedFiles.forEach(function (file) { var $icon = $fileIcon.clone(); var $name = $('', { 'class': 'file-element element' }); addFileData(file.href, file.title, $name, false); @@ -1247,6 +1134,40 @@ define([ $contentContextMenu.hide(); }; + var stringifyPath = function (path) { + if (!$.isArray(path)) { return; } + var rootName = function (s) { + var prettyName; + switch (s) { + case ROOT: + prettyName = ROOT_NAME; + break; + case UNSORTED: + prettyName = UNSORTED_NAME; + break; + case FILES_DATA: + prettyName = FILES_DATA_NAME; + break; + case TRASH: + prettyName = TRASH_NAME; + break; + default: + prettyName = s; + } + return prettyName; + }; + var $div = $('
    '); + var i = 0; + var space = 10; + path.forEach(function (s) { + if (i === 0) { s = rootName(s) } + $div.append($('', {'style': 'margin: 0 0 0 ' + i * space + 'px;'}).text(s)); + $div.append($('
    ')); + i++; + }); + return $div.html(); + }; + $contextMenu.on("click", "a", function(e) { e.stopPropagation(); var path = $(this).data('path'); @@ -1337,7 +1258,8 @@ define([ else if ($(this).hasClass("properties")) { if (path.length !== 4) { return; } var element = filesOp.getTrashElementData(path); - Cryptpad.alert(Messages.fm_originalPath + ":
    " + element.path.join('/')); + var sPath = stringifyPath(element.path); + Cryptpad.alert('' + Messages.fm_originalPath + ":
    " + sPath); } module.hideMenu(); }); @@ -1404,9 +1326,7 @@ define([ (path.length >= currentPath.length && filesOp.isSubpath(path, currentPath)) || (filesOp.isPathInTrash(currentPath) && filesOp.isPathInTrash(path))) { // Reload after 50ms to make sure all the change events have been received - window.setTimeout(function () { - module.displayDirectory(currentPath); - }, 200); + window.setTimeout(refresh, 200); } else if (path.length && path[0] === FILES_DATA) { refreshFilesData(); } @@ -1417,14 +1337,12 @@ define([ (path.length >= currentPath.length && filesOp.isSubpath(path, currentPath)) || (filesOp.isPathInTrash(currentPath) && filesOp.isPathInTrash(path))) { // Reload after 50ms to make sure all the change events have been received - window.setTimeout(function () { - module.displayDirectory(currentPath); - }, 200); + window.setTimeout(refresh, 200); } module.resetTree(); }); - module.displayDirectory(currentPath); + refresh(); }; /* @@ -1450,8 +1368,9 @@ define([ var realtime = module.realtime = info.realtime; var editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys); - //Cryptpad.setAttribute("FS_hash", editHash, cb, store); - localStorage.FS_hash = editHash; + if (!window.location.hash) { + localStorage.FS_hash = editHash; + } module.patchText = TextPatcher.create({ realtime: realtime,