diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 5c72ff96f..cce188734 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -4578,139 +4578,134 @@ define([ return comp; }; - UIElements.getTree = function (data, config) { - config = config || {}; - config.events = config.events || {}; - config.openFolders = config.openFolders || []; - config.currentPath = config.currentPath || null; + var isSubpath = function(child, parentPath) { + if (!child || !parentPath || child.length <= parentPath.length) { return false; } + for (var i = 0; i < parentPath.length; i++) { + if (child[i] !== parentPath[i]) { return false; } + } + return true; + }; - // Check if current path is a subpath of given path - var isSubpath = function(child, parent) { - if (!child || !parent || child.length <= parent.length) { return false; } - for (var i = 0; i < parent.length; i++) { - if (child[i] !== parent[i]) { return false; } - } - return true; - }; - - // Check if folder should be initially opened - var shouldBeOpened = function(path) { - if (config.openFolders && config.openFolders.length) { - for (var i = 0; i < config.openFolders.length; i++) { - var openPath = config.openFolders[i]; - if (JSON.stringify(openPath) === JSON.stringify(path)) { - return true; - } - } - } - // Auto-expand parent folders of current path, but only when viewing tree - if (config.currentPath && config.rootPath && isSubpath(config.currentPath, path) && path.length < config.currentPath.length) { - if (config.currentPath.length > 0 && config.rootPath.length > 0 && - config.currentPath[0] === config.rootPath[0]) { + var shouldBeOpened = function(path, openFolders, currentPath) { + if (openFolders && openFolders.length) { + for (var i = 0; i < openFolders.length; i++) { + var openPath = openFolders[i]; + if (JSON.stringify(openPath) === JSON.stringify(path)) { return true; } } - - return false; - }; - - var hasOpenedChild = function(path) { - if (!config.openFolders || !config.openFolders.length) { return false; } - for (var i = 0; i < config.openFolders.length; i++) { - var openPath = config.openFolders[i]; - if (openPath.length > path.length) { - var match = true; - for (var j = 0; j < path.length; j++) { - if (openPath[j] !== path[j]) { - match = false; - break; - } - } - if (match) { return true; } - } + } + // Auto-expand parent folders of current path + if (currentPath && isSubpath(currentPath, path) && path.length < currentPath.length) { + if (currentPath.length > 0) { + return true; } - return false; - }; + } + return false; + }; + UIElements.createTreeElement = function (name, $icon, path, draggable, droppable, collapsable, active, events, openFolders, currentPath, setup) { + events = events || {}; + openFolders = openFolders || []; + currentPath = currentPath || null; + setup = setup || {}; var $expandIcon = $(Icons.get('chevron-right')); var $expandedIcon = $(Icons.get('chevron-down')); - var $folderIcon = $(Icons.get('folder')); - var $folderOpenedIcon = $(Icons.get('folder-open')); - var createTreeElement = function (name, $icon, path, collapsable, active) { - var $name = $('', { 'class': 'cp-app-drive-element' }).text(name); - var $collapse; - if (collapsable) { - $collapse = $('').attr('tabindex', 0).attr('class', 'cp-app-drive-icon-expcol').append($expandIcon.clone()); + var $name = $('', { 'class': 'cp-app-drive-element' }).text(name); + var $collapse; + if (collapsable) { + $collapse = $('').attr('tabindex', 0).attr('class', 'cp-app-drive-icon-expcol').append($expandIcon.clone()); + } + var $elementRow = $('', { + 'class': 'cp-app-drive-element-row cp-app-drive-element-folder', + 'tabindex': 0 + }).append($collapse).append($icon).append($name).on('click keypress', function (e) { + if (e.type === 'keypress' && e.which !== 13) { + return; } - var $elementRow = $('', { - 'class': 'cp-app-drive-element-row cp-app-drive-element-folder', - 'tabindex': 0 - }).append($collapse).append($icon).append($name).on('click keypress', function (e) { + e.stopPropagation(); + if (events.onFolderClicked) { + events.onFolderClicked(path, e); + } + }); + + if (events.onContextMenu) { + $elementRow.on('contextmenu', function(e) { + e.preventDefault(); + e.stopPropagation(); + events.onContextMenu(path, e); + }); + } + + var $element = $('
  • ').append($elementRow); + if (draggable) { + $elementRow.attr('draggable', true); + } + if (collapsable) { + $element.addClass('cp-app-drive-element-collapsed'); + $collapse.attr({ + 'aria-expanded': 'false', + 'role': 'button', + 'aria-label': Messages.ui_expand + }); + $collapse.on('click keypress', function(e) { if (e.type === 'keypress' && e.which !== 13) { return; } e.stopPropagation(); - if (config.events.onFolderClicked) { - config.events.onFolderClicked(path, e); - } - }); - - if (config.events.onContextMenu) { - $elementRow.on('contextmenu', function(e) { - e.preventDefault(); - e.stopPropagation(); - config.events.onContextMenu(path, e); - }); - } - - var $element = $('
  • ').append($elementRow); - if (collapsable) { - $element.addClass('cp-app-drive-element-collapsed'); - $collapse.attr({ - 'aria-expanded': 'false', - 'role': 'button', - 'aria-label': Messages.ui_expand - }); - $collapse.on('click keypress', function(e) { - if (e.type === 'keypress' && e.which !== 13) { - return; - } - e.stopPropagation(); - if ($element.hasClass('cp-app-drive-element-collapsed')) { - $element.removeClass('cp-app-drive-element-collapsed'); - $collapse.empty().append($expandedIcon.clone()); - $collapse.attr('aria-expanded', 'true'); - $collapse.attr('aria-label', Messages.ui_collapse); - if (config.events.onFolderExpanded) { - config.events.onFolderExpanded(path, true); - } - } else { - $element.addClass('cp-app-drive-element-collapsed'); - $collapse.empty().append($expandIcon.clone()); - $collapse.attr('aria-expanded', 'false'); - $collapse.attr('aria-label', Messages.ui_expand); - if (config.events.onFolderExpanded) { - config.events.onFolderExpanded(path, false); - } - } - }); - // Auto-expand if explicitly marked as opened - var shouldExpand = shouldBeOpened(path); - - if (shouldExpand) { + if ($element.hasClass('cp-app-drive-element-collapsed')) { $element.removeClass('cp-app-drive-element-collapsed'); $collapse.empty().append($expandedIcon.clone()); $collapse.attr('aria-expanded', 'true'); $collapse.attr('aria-label', Messages.ui_collapse); + if (events.onFolderExpanded) { + events.onFolderExpanded(path, true); + } + } else { + $element.addClass('cp-app-drive-element-collapsed'); + $collapse.empty().append($expandIcon.clone()); + $collapse.attr('aria-expanded', 'false'); + $collapse.attr('aria-label', Messages.ui_expand); + if (events.onFolderExpanded) { + events.onFolderExpanded(path, false); + } } + }); + // Auto-expand if explicitly marked as opened + var shouldExpand = shouldBeOpened(path, openFolders, currentPath); + + if (shouldExpand) { + $element.removeClass('cp-app-drive-element-collapsed'); + $collapse.empty().append($expandedIcon.clone()); + $collapse.attr('aria-expanded', 'true'); + $collapse.attr('aria-label', Messages.ui_collapse); } - $elementRow.data('path', path); - if (active) { - $elementRow.addClass('cp-app-drive-element-active cp-leftside-active'); - } - return $element; - }; + } + $elementRow.data('path', path); + if (typeof setup.addDragAndDropHandlers === 'function') { + setup.addDragAndDropHandlers($elementRow, path, true, droppable); + } + if (active) { + $elementRow.addClass('cp-app-drive-element-active cp-leftside-active'); + } + return $element; + }; + + UIElements.getTree = function (data, config) { + config = config || {}; + config.events = config.events || {}; + config.setup = config.setup || {}; + // Support legacy cb parameter for backward compatibility + if (config.cb && !config.setup.addDragAndDropHandlers) { + config.setup.addDragAndDropHandlers = config.cb; + } + config.openFolders = config.openFolders || []; + config.currentPath = config.currentPath || null; + + var $folderIcon = $(Icons.get('folder')); + var $folderOpenedIcon = $(Icons.get('folder-open')); + var createTree = function ($container, folderData, path) { if (!folderData || !folderData.content) { return; } @@ -4744,13 +4739,15 @@ define([ $icon = $(item.icon); } } else { - var shouldShowOpened = shouldBeOpened(newPath); + var shouldShowOpened = shouldBeOpened(newPath, config.openFolders, config.currentPath); $icon = shouldShowOpened ? $folderOpenedIcon.clone() : $folderIcon.clone(); } var hasSubfolder = item.content && Object.keys(item.content).length > 0; var isActive = config.currentPath && JSON.stringify(newPath) === JSON.stringify(config.currentPath); - var $element = createTreeElement(name, $icon.clone(), newPath, hasSubfolder, isActive); + var draggable = config.draggable !== undefined ? config.draggable : true; + var droppable = config.droppable !== undefined ? config.droppable : true; + var $element = UIElements.createTreeElement(name, $icon.clone(), newPath, draggable, droppable, hasSubfolder, isActive, config.events, config.openFolders, config.currentPath, config.setup); $element.appendTo($list); if (hasSubfolder) { @@ -4759,16 +4756,20 @@ define([ }); }; var content = []; - if (data && data.root) { - var rootName = data.root.name || 'Root'; - var rootPath = config.rootPath || ['root']; - var $rootIcon = data.root.icon ? - (typeof data.root.icon === 'string' ? $(Icons.get(data.root.icon)) : $(data.root.icon)) : + var rootKey = Object.keys(data)[0]; + var rootData = data[rootKey]; + + if (rootData) { + var rootName = rootData.name || Messages.fm_rootName; + var $rootIcon = rootData.icon ? + (typeof rootData.icon === 'string' ? $(Icons.get(rootData.icon)) : $(rootData.icon)) : $(Icons.get('drive')); - var hasContent = data.root.content && Object.keys(data.root.content).length > 0; - var isRootActive = config.currentPath && JSON.stringify(rootPath) === JSON.stringify(config.currentPath); - var $rootElement = createTreeElement(rootName, $rootIcon, rootPath, hasContent, isRootActive); + var hasContent = rootData.content && Object.keys(rootData.content).length > 0; + var isRootActive = config.currentPath && JSON.stringify([rootKey]) === JSON.stringify(config.currentPath); + var rootDraggable = config.rootDraggable !== undefined ? config.rootDraggable : false; + var rootDroppable = config.rootDroppable !== undefined ? config.rootDroppable : (config.droppable !== undefined ? config.droppable : true); + var $rootElement = UIElements.createTreeElement(rootName, $rootIcon, [rootKey], rootDraggable, rootDroppable, hasContent, isRootActive, config.events, config.openFolders, config.currentPath, config.setup); $rootElement.addClass('cp-app-drive-tree-root'); if (!hasContent) { @@ -4778,7 +4779,7 @@ define([ content.push($rootList[0]); if (hasContent) { - createTree($rootElement, data.root, rootPath); + createTree($rootElement, rootData, [rootKey]); } } return h('div.cp-drive-tree', content); diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 996f38fd8..4ffd4d031 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -2913,10 +2913,7 @@ define([ iconClass: 'destroy', name: Messages.fc_delete_owned, onClick: function () { - manager.emptyTrash(true, function() { - LS.removeFoldersOpened([TRASH]); - refresh(); - }); + manager.emptyTrash(true, refresh); }, keys: [] }); @@ -2927,10 +2924,7 @@ define([ iconClass: 'trash-full', name: hasOwned ? Messages.fc_remove : Messages.okButton, onClick: function () { - manager.emptyTrash(false, function() { - LS.removeFoldersOpened([TRASH]); - refresh(); - }); + manager.emptyTrash(false, refresh); }, keys: [13] }); @@ -4603,12 +4597,10 @@ define([ var sfId = manager.isInSharedFolder(newPath) || (isSharedFolder && root[key]); var $icon, isCurrentFolder, subfolder, folderName = key; var randomKey = Util.uid(); - var pathForRecursion = newPath; if (isSharedFolder) { // Fix path - var navPath = newPath.slice(); - navPath.push(manager.user.userObject.ROOT); - isCurrentFolder = manager.comparePath(navPath, currentPath); + newPath.push(manager.user.userObject.ROOT); + isCurrentFolder = manager.comparePath(newPath, currentPath); // Subfolders? var newRoot = Util.find(manager, ['folders', sfId, 'proxy', manager.user.userObject.ROOT]) || {}; subfolder = manager.hasSubfolder(newRoot); @@ -4617,14 +4609,7 @@ define([ folderName = sfData.title || sfData.lastTitle || Messages.fm_deletedFolder; // Fix icon $icon = isCurrentFolder ? $sharedFolderOpenedIcon : $sharedFolderIcon; - data.content[randomKey] = { - name: folderName, - icon: $icon, - navPath: navPath, - content: {} - }; isSharedFolder = sfId; - pathForRecursion = navPath; } else { var isEmpty = manager.isFolderEmpty(root[key]); subfolder = manager.hasSubfolder(root[key]); @@ -4632,19 +4617,19 @@ define([ $icon = isEmpty ? (isCurrentFolder ? $folderOpenedEmptyIcon : $folderEmptyIcon) : (isCurrentFolder ? $folderOpenedIcon : $folderIcon); - data.content[randomKey] = { - name: folderName, - icon: $icon, - navPath: newPath, - content: {} - }; } + data.content[randomKey] = { + name: folderName, + icon: $icon, + navPath: newPath, + content: {} + }; if (subfolder) { var subRoot = isSharedFolder ? - Util.find(manager, ['folders', sfId, 'proxy', manager.user.userObject.ROOT]) : + Util.find(manager, ['folders', sfId, 'proxy', ROOT]) : root[key]; if (subRoot) { - data.content[randomKey].content = buildTreeData(subRoot, pathForRecursion, currentPath).content; + data.content[randomKey].content = buildTreeData(subRoot, newPath, currentPath).content; } } }); @@ -4679,31 +4664,26 @@ define([ } }; var openFolders = LS.getOpenedFolders(); - var filteredOpenFolders = openFolders.filter(function(p) { - return p && p.length > 0 && p[0] === path[0]; - }); var treeElement = UIElements.getTree(data, { currentPath: currentPath, rootPath: path, + draggable: true, + droppable: true, + setup: { + addDragAndDropHandlers: addDragAndDropHandlers + }, events: { onFolderClicked: function (clickedPath, event) { // Check for shared folder restrictions - var pathToCheck = clickedPath.slice(1); // Remove 'root' - if (pathToCheck.length > 0) { - var checkRoot = manager.find([ROOT]); - var firstKey = pathToCheck[0]; - if (checkRoot && checkRoot[firstKey]) { - var sfId = manager.isSharedFolder(checkRoot[firstKey]) && checkRoot[firstKey]; - if (sfId) { - if (!manager.folders[sfId]) { - UI.warn(Messages.fm_deletedFolder); - return; - } - if (files.restrictedFolders[sfId]) { - UI.warn(Messages.fm_restricted); - return; - } - } + var sfId = manager.isInSharedFolder(clickedPath); + if (sfId) { + if (!manager.folders[sfId]) { + UI.warn(Messages.fm_deletedFolder); + return; + } + if (files.restrictedFolders[sfId]) { + UI.warn(Messages.fm_restricted); + return; } } APP.displayDirectory(clickedPath); @@ -4713,14 +4693,9 @@ define([ }, onFolderExpanded: function (clickedPath, isOpen) { LS.setFolderOpened(clickedPath, isOpen); - if (clickedPath.length === 1) { return; } - // When collapsing a folder, close all its children - if (!isOpen) { - LS.removeFoldersOpened(clickedPath); - } } }, - openFolders: filteredOpenFolders + openFolders: openFolders }); var $treeElement = $(treeElement); @@ -4729,37 +4704,30 @@ define([ var $row = $(this); var elPath = $row.data('path'); if (!elPath || elPath.length === 0) { return; } - var pathToCheck = elPath[0] === 'root' ? elPath : [ROOT].concat(elPath); + var pathToCheck = elPath[0] === ROOT ? elPath : [ROOT].concat(elPath); var isSharedFolderPath = pathToCheck.length > 1 && pathToCheck[pathToCheck.length - 1] === ROOT; $row.find('.cp-app-drive-icon-folder').css("color", isSharedFolderPath ? getFolderColor(pathToCheck.slice(0, -1)) : getFolderColor(pathToCheck)); - var checkRoot = manager.find([ROOT]); - var sfId = null; + var sfId = manager.isInSharedFolder(elPath); var f = null; var droppable = true; - if (elPath.length > 1 && elPath[0] === 'root') { - var firstKey = elPath[1]; - if (checkRoot && checkRoot[firstKey]) { - sfId = manager.isSharedFolder(checkRoot[firstKey]) && checkRoot[firstKey]; - if (sfId) { - f = folders[sfId]; - var editable = !(f && f.readOnly); - droppable = editable; - - $row.addClass('cp-app-drive-element-sharedf'); - if (!editable) { - $row.closest('li').attr('data-ro', true); - } - var sfData = manager.getSharedFolderData(sfId); - _addOwnership($row, $(), sfData); - if (files.restrictedFolders[sfId]) { - $row.addClass('cp-app-drive-element-restricted'); - } - } + if (sfId) { + f = folders[sfId]; + var editable = !(f && f.readOnly); + droppable = editable; + + $row.addClass('cp-app-drive-element-sharedf'); + if (!editable) { + $row.closest('li').attr('data-ro', true); + } + var sfData = manager.getSharedFolderData(sfId); + _addOwnership($row, $(), sfData); + if (files.restrictedFolders[sfId]) { + $row.addClass('cp-app-drive-element-restricted'); } - } - addDragAndDropHandlers($row, elPath, true, droppable); + addDragAndDropHandlers($row, elPath, true, droppable); + } $row.attr('draggable', true); }); $treeElement.find('.cp-app-drive-element-row').first().removeAttr('draggable'); @@ -4768,33 +4736,15 @@ define([ var createTrash = function ($container, path) { var $icon = manager.isFolderEmpty(files[TRASH]) ? $trashEmptyIcon.clone() : $trashIcon.clone(); - var data = { - root: { - name: TRASH_NAME, - icon: $icon, - content: {} - } - }; - var trashElement = UIElements.getTree(data, { - currentPath: currentPath, - rootPath: [TRASH], - events: { - onFolderClicked: function (clickedPath, event) { - APP.displayDirectory(clickedPath); - }, - onContextMenu: function (clickedPath, event) { - openContextMenu('trashtree')(event); - } + var isOpened = manager.comparePath(path, currentPath); + var $trashElement = UIElements.createTreeElement(TRASH_NAME, $icon, [TRASH], false, true, false, isOpened, { + onFolderClicked: function (clickedPath, event) { + APP.displayDirectory(clickedPath); }, - openFolders: [] - }); - var $trashElement = $(trashElement); - var $trashRow = $trashElement.find('.cp-app-drive-element-row').first(); - if ($trashRow.length) { - addDragAndDropHandlers($trashRow, [TRASH], true, true); - } - var $trashElementContent = $trashElement.find('.cp-app-drive-tree-docs'); - var $trashList = $('
      ', { 'class': 'cp-app-drive-tree-category' }).append($trashElementContent.contents()); + onContextMenu: openContextMenu('trashtree') + }, [], currentPath, { addDragAndDropHandlers: addDragAndDropHandlers }); + $trashElement.addClass('cp-app-drive-tree-root'); + var $trashList = $('
        ', { 'class': 'cp-app-drive-tree-category' }).append($trashElement); $container.append($trashList); }; @@ -4827,36 +4777,14 @@ define([ var createCategory = function ($container, cat) { var options = categories[cat]; var $icon = options.$icon.clone(); - var data = { - root: { - name: options.name, - icon: $icon, - content: {} + var isOpened = manager.comparePath([cat], currentPath); + var $element = UIElements.createTreeElement(options.name, $icon, [cat], false, options.droppable, false, isOpened, { + onFolderClicked: function (clickedPath, event) { + APP.displayDirectory(clickedPath); } - }; - var categoriesElement = UIElements.getTree(data, { - currentPath: currentPath, - rootPath: [cat], - events: { - onFolderClicked: function (clickedPath, event) { - APP.displayDirectory(clickedPath); - } - }, - openFolders: [] - }); - var $categoriesElement = $(categoriesElement); - if (options.droppable !== undefined) { - $categoriesElement.find('.cp-app-drive-element-row').each(function() { - var $row = $(this); - var elPath = $row.data('path'); - if (elPath && elPath.length > 0 && elPath[0] === cat) { - $row.off('dragover drop dragenter dragleave'); - addDragAndDropHandlers($row, elPath, true, options.droppable); - } - }); - } - var $categoriesElementContent = $categoriesElement.find('.cp-app-drive-tree-docs'); - var $list = $('
          ', { 'class': 'cp-app-drive-tree-category' }).append($categoriesElementContent.contents()); + }, [], currentPath, { addDragAndDropHandlers: addDragAndDropHandlers }); + $element.addClass('cp-app-drive-tree-root'); + var $list = $('
            ', { 'class': 'cp-app-drive-tree-category' }).append($element); $container.append($list); };