diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index b9d089c6a..0fc70b681 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -103,6 +103,14 @@ define([ common.userObjectCommand = function (data, cb) { postMessage("DRIVE_USEROBJECT", data, cb); }; + common.restoreDrive = function (data, cb) { + postMessage("SET", { + key:['drive'], + value: data + }, function (obj) { + cb(obj); + }); + }; common.drive = {}; common.drive.onLog = Util.mkEvent(); common.drive.onChange = Util.mkEvent(); diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 7c3ec7376..c76f73814 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1173,6 +1173,8 @@ define([ var id; nThen(function (waitFor) { // TODO XXX get the folder data (href, title, ...) + // XXX href should be stored in your drive's .sharedFolders + // and title should be stored in the sharef folder's metadata var folderData = data.folderData || {}; // 1. add the shared folder to our list of shared folders store.userObject.pushSharedFolder(folderData, waitFor(function (err, folderId) { diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index 2047a017a..6712da200 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -677,6 +677,15 @@ define([ return Env.user.userObject.getOwnedPads(edPublic); }; + var getSharedFolderData = function (Env, id) { + if (!Env.folders[id]) { return; } + var obj = Env.folders[id].proxy.metadata || {}; + for (var k in Env.user.proxy[UserObject.SHARED_FOLDERS][id] || {}) { + obj[k] = Env.user.proxy[UserObject.SHARED_FOLDERS][id][k]; + } + return obj; + }; + /* Generic: doesn't need access to a proxy */ var isFile = function (Env, el, allowStr) { return Env.user.userObject.isFile(el, allowStr); @@ -762,6 +771,7 @@ define([ getTagsList: callWithEnv(getTagsList), findFile: callWithEnv(findFile), findChannels: callWithEnv(findChannels), + getSharedFolderData: callWithEnv(getSharedFolderData), // Generic isFile: callWithEnv(isFile), isFolder: callWithEnv(isFolder), diff --git a/www/common/sframe-protocol.js b/www/common/sframe-protocol.js index a23124a65..cc41dcbf3 100644 --- a/www/common/sframe-protocol.js +++ b/www/common/sframe-protocol.js @@ -203,6 +203,7 @@ define({ // Inner drive needs to send command and receive updates from the async store 'Q_DRIVE_USEROBJECT': true, 'Q_DRIVE_GETOBJECT': true, + 'Q_DRIVE_RESTORE': true, // Get the pads deleted from the server by other users to remove them from the drive 'Q_DRIVE_GETDELETED': true, // Store's userObject need to send log messages to inner to display them in the UI diff --git a/www/drive/inner.js b/www/drive/inner.js index 844557f0f..2c78b1904 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -71,6 +71,7 @@ define([ // Icons var faFolder = 'fa-folder'; var faFolderOpen = 'fa-folder-open'; + var faSharedFolder = 'fa-users'; var faReadOnly = 'fa-eye'; var faRename = 'fa-pencil'; var faTrash = 'fa-trash'; @@ -88,6 +89,8 @@ define([ var $folderOpenedIcon = $('', {"class": faFolderOpen + " fa cp-app-drive-icon-folder"}); //var $folderOpenedIcon = $('', {src: "/customize/images/icons/folderOpen.svg", "class": "folder icon"}); var $folderOpenedEmptyIcon = $folderOpenedIcon.clone(); + var $sharedFolderIcon = $('', {"class": faSharedFolder + " fa cp-app-drive-icon-folder"}); + var $sharedFolderOpenedIcon = $sharedFolderIcon.clone(); //var $upIcon = $('', {"class": "fa fa-arrow-circle-up"}); var $unsortedIcon = $('', {"class": "fa fa-files-o"}); var $templateIcon = $('', {"class": "fa fa-cubes"}); @@ -1336,6 +1339,12 @@ define([ var addFolderData = function (element, key, $span) { if (!element || !manager.isFolder(element)) { return; } // The element with the class '.name' is underlined when the 'li' is hovered + if (manager.isSharedFolder(element)) { + var data = manager.getSharedFolderData(element); + key = data && data.title ? data.title : key; + element = manager.folders[element].proxy[manager.user.userObject.ROOT]; + } + var sf = manager.hasSubfolder(element); var files = manager.hasFile(element); var $name = $('', {'class': 'cp-app-drive-element-name'}).text(key); @@ -1372,13 +1381,18 @@ define([ } var element = manager.find(newPath); + var isSharedFolder = manager.isSharedFolder(element); + var $icon = !isFolder ? getFileIcon(element) : undefined; var ro = manager.isReadOnlyFile(element); // ro undefined means it's an old hash which doesn't support read-only var roClass = typeof(ro) === 'undefined' ?' cp-app-drive-element-noreadonly' : ro ? ' cp-app-drive-element-readonly' : ''; var liClass = 'cp-app-drive-element-file cp-app-drive-element' + roClass; - if (isFolder) { + if (isSharedFolder) { + liClass = 'cp-app-drive-element-folder cp-app-drive-element'; + $icon = $sharedFolderIcon.clone(); + } else if (isFolder) { liClass = 'cp-app-drive-element-folder cp-app-drive-element'; $icon = manager.isFolderEmpty(root[key]) ? $folderEmptyIcon.clone() : $folderIcon.clone(); } @@ -1474,11 +1488,20 @@ define([ var isVirtual = virtualCategories.indexOf(path[0]) !== -1; var el = isVirtual ? undefined : manager.find(path); path = path[0] === SEARCH ? path.slice(0,1) : path; + + var skipNext = false; // When encountering a shared folder, skip a key in the path path.forEach(function (p, idx) { + if (skipNext) { return skipNext = false; } if (isTrash && [2,3].indexOf(idx) !== -1) { return; } var name = p; + var el = manager.find(path.slice(0, idx+1)); + if (manager.isSharedFolder(el)) { + name = manager.getSharedFolderData(el).title; + skipNext = true; + } + var $span = $('', {'class': 'cp-app-drive-path-element'}); if (idx < path.length - 1) { if (!noStyle) { @@ -1844,7 +1867,12 @@ define([ if (keys.length < 2) { return keys; } var mult = asc ? 1 : -1; var getProp = function (el, prop) { - if (folder) { return el.toLowerCase(); } + if (folder && root[el] && manager.isSharedFolder(root[el])) { + var title = manager.getSharedFolderData(root[el]).title || el; + return title.toLowerCase(); + } else if (folder) { + return el.toLowerCase(); + } var id = useId ? el : root[el]; var data = manager.getFileData(id); if (!data) { return ''; } @@ -2541,12 +2569,28 @@ define([ if (!manager.isFolder(root[key])) { return; } var newPath = path.slice(); newPath.push(key); - var isCurrentFolder = manager.comparePath(newPath, currentPath); - var isEmpty = manager.isFolderEmpty(root[key]); - var subfolder = manager.hasSubfolder(root[key]); - var $icon = isEmpty ? - (isCurrentFolder ? $folderOpenedEmptyIcon : $folderEmptyIcon) : - (isCurrentFolder ? $folderOpenedIcon : $folderIcon); + var isSharedFolder = manager.isSharedFolder(root[key]); + var $icon, isCurrentFolder, subfolder; + if (isSharedFolder) { + var fId = root[key]; + // Fix path + newPath.push(manager.user.userObject.ROOT); + isCurrentFolder = manager.comparePath(newPath, currentPath); + // Subfolders? + root = manager.folders[fId].proxy[manager.user.userObject.ROOT]; + subfolder = manager.hasSubfolder(root); + // Fix name + key = manager.getSharedFolderData(fId).title; + // Fix icon + $icon = $sharedFolderIcon; + } else { + var isEmpty = manager.isFolderEmpty(root[key]); + subfolder = manager.hasSubfolder(root[key]); + isCurrentFolder = manager.comparePath(newPath, currentPath); + $icon = isEmpty ? + (isCurrentFolder ? $folderOpenedEmptyIcon : $folderEmptyIcon) : + (isCurrentFolder ? $folderOpenedIcon : $folderIcon); + } var $element = createTreeElement(key, $icon.clone(), newPath, true, true, subfolder, isCurrentFolder); $element.appendTo($list); $element.find('>.cp-app-drive-element-row').contextmenu(openContextMenu('tree')); @@ -3113,6 +3157,7 @@ define([ APP.histConfig = { onLocal: function () { proxy.drive = history.currentObj.drive; + sframeChan.query("Q_DRIVE_RESTORE", history.currentObj.drive, function () {}); }, onRemote: function () {}, setHistory: setHistory, diff --git a/www/drive/main.js b/www/drive/main.js index 3e96f2e6f..3a600d18c 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -52,6 +52,9 @@ define([ sframeChan.on('Q_DRIVE_USEROBJECT', function (data, cb) { Cryptpad.userObjectCommand(data, cb); }); + sframeChan.on('Q_DRIVE_RESTORE', function (data, cb) { + Cryptpad.restoreDrive(data, cb); + }); sframeChan.on('Q_DRIVE_GETOBJECT', function (data, cb) { if (data && data.sharedFolder) { Cryptpad.getSharedFolder(data.sharedFolder, function (obj) {