mirror of
https://github.com/zotero/zotero.git
synced 2026-09-27 01:21:27 +00:00
Expand collectionTree containers on dragover (#5024)
- when something is dragged over a collapsed collection or group, it will be expanded to reveal children so one could drop the dragged item/collection/ into them - when drag is over, the expanded collections will collapse, except for the ancestors of the newly selected collection - trigger collapse of expanded collections on dragend on the entire document (in case dragend happens not over the collection tree), or from onDrop handler, from where we will wait for selection to change before collapsing rows Fixes: #4952
This commit is contained in:
parent
1c089bf448
commit
e690b0b18e
3 changed files with 111 additions and 1 deletions
|
|
@ -97,6 +97,8 @@ var CollectionTree = class CollectionTree extends LibraryTree {
|
|||
this._editing = null;
|
||||
this._editingInput = null;
|
||||
this._dropRow = null;
|
||||
this._dragoverRow = null;
|
||||
this._flashingRow = null;
|
||||
this._typingTimeout = null;
|
||||
this._customRowHeights = [];
|
||||
this._separatorHeight = 8;
|
||||
|
|
@ -107,6 +109,9 @@ var CollectionTree = class CollectionTree extends LibraryTree {
|
|||
this._filterInitialCollapsedRows = [];
|
||||
this._treeWasFocused = false;
|
||||
this._hiddenFocusedRow = null;
|
||||
this._expandedRowsOnDrag = new Set();
|
||||
this._expandRowOnHoverTimer = null;
|
||||
this._collapseExpandedRowsTimer = null;
|
||||
|
||||
this.onLoad = this.createEventBinding('load', true, true);
|
||||
}
|
||||
|
|
@ -135,6 +140,9 @@ var CollectionTree = class CollectionTree extends LibraryTree {
|
|||
componentDidMount() {
|
||||
this.selection.select(0);
|
||||
this.makeVisible();
|
||||
if (this.props.dragAndDrop) {
|
||||
this.domEl.addEventListener('dragleave', this.onDragLeaveFromTheTree);
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
|
|
@ -304,6 +312,7 @@ var CollectionTree = class CollectionTree extends LibraryTree {
|
|||
div.classList.toggle('selected', selection.isSelected(index));
|
||||
div.classList.toggle('highlighted', this._highlightedRows.has(treeRow.id));
|
||||
div.classList.toggle('drop', this._dropRow == index);
|
||||
div.classList.toggle('flashing', this._flashingRow == index);
|
||||
div.classList.toggle('unread', treeRow.ref && treeRow.ref.unreadCount > 0);
|
||||
let { matchesFilter, hasChildMatchingFilter } = this._matchesFilter(treeRow.ref);
|
||||
div.classList.toggle('context-row', !matchesFilter && hasChildMatchingFilter);
|
||||
|
|
@ -1441,11 +1450,46 @@ var CollectionTree = class CollectionTree extends LibraryTree {
|
|||
onDragOver(event, index) {
|
||||
if (!event.currentTarget.classList.contains('row')) return;
|
||||
const treeRow = this.getRow(index);
|
||||
let previousDragoverRow = this._dragoverRow;
|
||||
this._dragoverRow = index;
|
||||
try {
|
||||
// Prevent modifier keys from doing their normal things
|
||||
event.preventDefault();
|
||||
var previousOrientation = Zotero.DragDrop.currentOrientation;
|
||||
Zotero.DragDrop.currentOrientation = getDragTargetOrient(event);
|
||||
|
||||
// Expand collapsed collections and groups when they are dragged over for 1 second
|
||||
if (!this.isContainerEmpty(index) && !this.isContainerOpen(index)) {
|
||||
// If dragged over row has changed, clear the timer
|
||||
if (this._expandRowOnHoverTimer && previousDragoverRow !== index) {
|
||||
clearTimeout(this._expandRowOnHoverTimer);
|
||||
this._expandRowOnHoverTimer = null;
|
||||
}
|
||||
// set a new timer for currently hovered row if it does not yet exist
|
||||
if (!this._expandRowOnHoverTimer) {
|
||||
this._expandRowOnHoverTimer = setTimeout(async () => {
|
||||
// if the dragged over row is still the same after delay, expand it
|
||||
if (!this.isContainerOpen(index) && this._dragoverRow == index) {
|
||||
this._flashingRow = index;
|
||||
this.tree.invalidateRow(index);
|
||||
// wait for the flashing to finish and then expand the container
|
||||
await Zotero.Promise.delay(300); // 0.2s CSS animation length * 1.5 runs
|
||||
this._flashingRow = null;
|
||||
this._expandedRowsOnDrag.add(treeRow.id);
|
||||
if (!this.isContainerOpen(index)) {
|
||||
this.toggleOpenState(index);
|
||||
}
|
||||
}
|
||||
this._expandRowOnHoverTimer = null;
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
// If the expanded rows were to be collapsed after the mouse left collectionTree,
|
||||
// don't do it because now the mouse is back in the collectionTree
|
||||
if (this._collapseExpandedRowsTimer) {
|
||||
clearTimeout(this._collapseExpandedRowsTimer);
|
||||
this._collapseExpandedRowsTimer = null;
|
||||
}
|
||||
|
||||
if (!this.canDropCheck(index, Zotero.DragDrop.currentOrientation, event.dataTransfer)) {
|
||||
this.setDropEffect(event, "none");
|
||||
|
|
@ -1554,9 +1598,24 @@ var CollectionTree = class CollectionTree extends LibraryTree {
|
|||
if (!e.currentTarget.classList.contains('row')) return;
|
||||
let dropRow = this._dropRow;
|
||||
this._dropRow = null;
|
||||
this._dragoverRow = null;
|
||||
this.tree.invalidateRow(dropRow);
|
||||
}
|
||||
|
||||
// when something is dragged over the container rows, they may be expanded.
|
||||
// if the mouse then leaves the collectionTree, collapse all expanded rows after delay
|
||||
// (unless onDragOver is called soon, which will clear the timeout)
|
||||
onDragLeaveFromTheTree = (e) => {
|
||||
if (!e.relatedTarget) return;
|
||||
let fromOutOfTree = this.domEl.contains(e.target) && !this.domEl.contains(e.relatedTarget);
|
||||
if (fromOutOfTree && !this._collapseExpandedRowsTimer) {
|
||||
this._collapseExpandedRowsTimer = setTimeout(() => {
|
||||
this.closeContainersExpandedOnDrag();
|
||||
this._collapseExpandedRowsTimer = null;
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
canDropCheck = (row, orient, dataTransfer) => {
|
||||
const treeRow = this.getRow(row);
|
||||
// TEMP
|
||||
|
|
@ -2094,6 +2153,13 @@ var CollectionTree = class CollectionTree extends LibraryTree {
|
|||
let row = this._rowMap[treeRow.id];
|
||||
let dataTransfer = event.dataTransfer;
|
||||
|
||||
// Prevent potential container row opening and flashing started in onDragOver
|
||||
clearTimeout(this._expandRowOnHoverTimer);
|
||||
this._expandRowOnHoverTimer = null;
|
||||
let oldFlashing = this._flashingRow;
|
||||
this._flashingRow = null;
|
||||
this.tree.invalidateRow(oldFlashing);
|
||||
|
||||
if (!dataTransfer.dropEffect || dataTransfer.dropEffect == "none"
|
||||
|| !(await this.canDropCheckAsync(row, orient, dataTransfer))) {
|
||||
return false;
|
||||
|
|
@ -2378,6 +2444,30 @@ var CollectionTree = class CollectionTree extends LibraryTree {
|
|||
// Automatically retrieve metadata for PDFs and ebooks
|
||||
Zotero.RecognizeDocument.autoRecognizeItems(addedItems);
|
||||
}
|
||||
this.closeContainersExpandedOnDrag();
|
||||
}
|
||||
|
||||
async closeContainersExpandedOnDrag() {
|
||||
let expandedRows = [...this._expandedRowsOnDrag];
|
||||
if (!expandedRows.length) return;
|
||||
this._expandedRowsOnDrag.clear();
|
||||
// Record the ancestors of the currently selected collection to not collapse them
|
||||
let col = this.selectedTreeRow.ref;
|
||||
let parentIDs = new Set();
|
||||
parentIDs.add(Zotero.Libraries.get(col.libraryID).treeViewID);
|
||||
while (col.parentID) {
|
||||
col = Zotero.Collections.get(col.parentID);
|
||||
parentIDs.add(col.treeViewID);
|
||||
}
|
||||
|
||||
// Collapse all remaining rows that were expanded during drag-drop
|
||||
for (let rowID of expandedRows) {
|
||||
let index = this.getRowIndexByID(rowID);
|
||||
let row = this._rows[index];
|
||||
if (row && row.isOpen && !parentIDs.has(row.ref.treeViewID)) {
|
||||
this.toggleOpenState(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -54,6 +54,14 @@ $icons: (
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.row.flashing:not(.drop) {
|
||||
animation: row-flash 0.2s ease-in-out 2;
|
||||
}
|
||||
|
||||
.row.flashing.drop {
|
||||
animation: row-flash-selected 0.2s ease-in-out 2;
|
||||
}
|
||||
}
|
||||
|
||||
.virtualized-table-body {
|
||||
|
|
@ -101,3 +109,15 @@ $icons: (
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// flashing effect applied to the row container when it is about to be expanded on dragover
|
||||
// two different background colors are used for containers with .drop class and without
|
||||
@keyframes row-flash {
|
||||
0%, 100% { background-color: transparent; }
|
||||
50% { background-color: var(--accent-azure); }
|
||||
}
|
||||
|
||||
@keyframes row-flash-selected {
|
||||
0%, 100% { background-color: var(--fill-secondary); }
|
||||
50% { background-color: var(--accent-blue50); }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@
|
|||
box-sizing: border-box;
|
||||
border-radius: 5px;
|
||||
|
||||
&.drop {
|
||||
&.drop:not(.flashing) {
|
||||
color: var(--material-background) !important;
|
||||
background: var(--fill-secondary) !important;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue