Implement review changes

This commit is contained in:
DianaXWiki 2025-11-27 13:42:33 +02:00
parent d25951b816
commit ba5c0661cb
2 changed files with 184 additions and 255 deletions

View File

@ -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 = $('<span>', { 'class': 'cp-app-drive-element' }).text(name);
var $collapse;
if (collapsable) {
$collapse = $('<span>').attr('tabindex', 0).attr('class', 'cp-app-drive-icon-expcol').append($expandIcon.clone());
var $name = $('<span>', { 'class': 'cp-app-drive-element' }).text(name);
var $collapse;
if (collapsable) {
$collapse = $('<span>').attr('tabindex', 0).attr('class', 'cp-app-drive-icon-expcol').append($expandIcon.clone());
}
var $elementRow = $('<span>', {
'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 = $('<span>', {
'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 = $('<li>').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 = $('<li>').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);

View File

@ -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 = $('<ul>', { 'class': 'cp-app-drive-tree-category' }).append($trashElementContent.contents());
onContextMenu: openContextMenu('trashtree')
}, [], currentPath, { addDragAndDropHandlers: addDragAndDropHandlers });
$trashElement.addClass('cp-app-drive-tree-root');
var $trashList = $('<ul>', { '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 = $('<ul>', { 'class': 'cp-app-drive-tree-category' }).append($categoriesElementContent.contents());
}, [], currentPath, { addDragAndDropHandlers: addDragAndDropHandlers });
$element.addClass('cp-app-drive-tree-root');
var $list = $('<ul>', { 'class': 'cp-app-drive-tree-category' }).append($element);
$container.append($list);
};