Improve column resizing robustness (#2588)
Also: * Add staticWidth and minWidth column properties
This commit is contained in:
parent
01645c5e51
commit
c49a05d486
5 changed files with 25 additions and 33 deletions
|
@ -36,6 +36,9 @@ const { IconDownChevron, getDOMElement } = require('components/icons');
|
|||
const TYPING_TIMEOUT = 1000;
|
||||
const MINIMUM_ROW_HEIGHT = 20; // px
|
||||
const RESIZER_WIDTH = 5; // px
|
||||
const COLUMN_MIN_WIDTH = 20;
|
||||
const COLUMN_NORMALIZATION_WIDTH = 8192;
|
||||
const COLUMN_PADDING = 10; // N.B. MUST BE INLINE WITH CSS!!!
|
||||
|
||||
const noop = () => 0;
|
||||
|
||||
|
@ -760,21 +763,6 @@ class VirtualizedTable extends React.Component {
|
|||
|
||||
// ------------------------ Column Methods ------------------------- //
|
||||
|
||||
/**
|
||||
* A public function to update the column CSS flex widths. To be used
|
||||
* upon window resize and similar. Especially important on macOS where
|
||||
* column borders are used and get out of sync with column headers.
|
||||
*/
|
||||
updateColumnWidths = Zotero.Utilities.debounce(() => {
|
||||
let resizeData = {};
|
||||
const columns = this._getVisibleColumns();
|
||||
for (const column of columns) {
|
||||
const elem = document.querySelector(`#${this.props.id} .virtualized-table-header .cell.${column.dataKey}`)
|
||||
resizeData[column.dataKey] = elem.getBoundingClientRect().width;
|
||||
}
|
||||
this._columns.onResize(resizeData, true);
|
||||
}, 200)
|
||||
|
||||
_handleResizerDragStart = (index, event) => {
|
||||
if (event.button !== 0) return false;
|
||||
event.stopPropagation();
|
||||
|
@ -811,8 +799,9 @@ class VirtualizedTable extends React.Component {
|
|||
offset += resizingRect.width;
|
||||
}
|
||||
const widthSum = aRect.width + bRect.width;
|
||||
// Column min-width: 20px;
|
||||
const aColumnWidth = Math.min(widthSum - 20, Math.max(20, event.clientX - (RESIZER_WIDTH / 2) - offset));
|
||||
const aSpacingOffset = (aColumn.minWidth ? aColumn.minWidth : COLUMN_MIN_WIDTH) + COLUMN_PADDING;
|
||||
const bSpacingOffset = (bColumn.minWidth ? bColumn.minWidth : COLUMN_MIN_WIDTH) + COLUMN_PADDING;
|
||||
const aColumnWidth = Math.min(widthSum - bSpacingOffset, Math.max(aSpacingOffset, event.clientX - (RESIZER_WIDTH / 2) - offset));
|
||||
const bColumnWidth = widthSum - aColumnWidth;
|
||||
let onResizeData = {};
|
||||
onResizeData[aColumn.dataKey] = aColumnWidth;
|
||||
|
@ -1477,6 +1466,8 @@ var Columns = class {
|
|||
if (storePrefs) {
|
||||
var prefs = this._getPrefs();
|
||||
}
|
||||
const header = document.querySelector(`#${this._styleKey} .virtualized-table-header`);
|
||||
const headerWidth = header ? header.getBoundingClientRect().width : 300;
|
||||
for (let [dataKey, width] of Object.entries(columnWidths)) {
|
||||
if (typeof dataKey == "number") {
|
||||
dataKey = this._columns[dataKey].dataKey;
|
||||
|
@ -1487,11 +1478,15 @@ var Columns = class {
|
|||
column.width = width;
|
||||
prefs[dataKey] = this._getColumnPrefsToPersist(column);
|
||||
}
|
||||
if (column.fixedWidth && column.width) {
|
||||
if (column.fixedWidth) {
|
||||
width = column.width;
|
||||
}
|
||||
if (column.fixedWidth && column.width || column.staticWidth) {
|
||||
this._stylesheet.sheet.cssRules[styleIndex].style.setProperty('flex', `0 0`, `important`);
|
||||
this._stylesheet.sheet.cssRules[styleIndex].style.setProperty('max-width', `${column.width}px`, 'important');
|
||||
this._stylesheet.sheet.cssRules[styleIndex].style.setProperty('min-width', `${column.width}px`, 'important');
|
||||
this._stylesheet.sheet.cssRules[styleIndex].style.setProperty('max-width', `${width}px`, 'important');
|
||||
this._stylesheet.sheet.cssRules[styleIndex].style.setProperty('min-width', `${width}px`, 'important');
|
||||
} else {
|
||||
width = (width - COLUMN_PADDING) * COLUMN_NORMALIZATION_WIDTH / headerWidth;
|
||||
this._stylesheet.sheet.cssRules[styleIndex].style.setProperty('flex-basis', `${width}px`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2734,7 +2734,7 @@ var ItemTree = class ItemTree extends LibraryTree {
|
|||
const depth = this.getLevel(index);
|
||||
let firstChildIndent = 0;
|
||||
if (column.ordinal == 0) {
|
||||
firstChildIndent = 6;
|
||||
firstChildIndent = 5;
|
||||
}
|
||||
span.style.paddingInlineStart = ((CHILD_INDENT * depth) + firstChildIndent) + 'px';
|
||||
|
||||
|
|
|
@ -38,6 +38,9 @@ const Icons = require('components/icons');
|
|||
* flex: number, // Default: 1. When the column is added to the tree how much space it should occupy as a flex ratio
|
||||
* width: string, // A column width instead of flex ratio. See above.
|
||||
* fixedWidth: boolean // Default: false. Set to true to disable column resizing
|
||||
* staticWidth: boolean // Default: false. Set to true to prevent columns from changing width when
|
||||
* // the width of the tree increases or decreases
|
||||
* minWidth: number, // Override the default [20px] column min-width for resizing
|
||||
*
|
||||
* label: string, // The column label. Either a string or the id to an i18n string.
|
||||
* iconLabel: React.Component, // Set an Icon label instead of a text-based one
|
||||
|
@ -86,6 +89,7 @@ const COLUMNS = [
|
|||
defaultSort: -1,
|
||||
label: "zotero.items.year_column",
|
||||
flex: 1,
|
||||
staticWidth: true,
|
||||
zoteroPersist: new Set(["width", "hidden", "sortDirection"])
|
||||
},
|
||||
{
|
||||
|
@ -298,6 +302,8 @@ const COLUMNS = [
|
|||
label: "zotero.tabs.notes.label",
|
||||
iconLabel: <Icons.IconTreeitemNoteSmall />,
|
||||
width: "14",
|
||||
minWidth: 14,
|
||||
staticWidth: true,
|
||||
zoteroPersist: new Set(["width", "hidden", "sortDirection"])
|
||||
}
|
||||
];
|
||||
|
|
|
@ -108,7 +108,6 @@ var ZoteroPane = new function()
|
|||
if (!tabsDeck || tabsDeck.getAttribute('selectedIndex') == 0) {
|
||||
this.updateToolbarPosition();
|
||||
this.updateTagsBoxSize();
|
||||
this.updateItemTreeColumnWidths();
|
||||
}
|
||||
});
|
||||
window.setTimeout(this.updateToolbarPosition.bind(this), 0);
|
||||
|
@ -5485,11 +5484,6 @@ var ZoteroPane = new function()
|
|||
}
|
||||
};
|
||||
|
||||
this.updateItemTreeColumnWidths = function() {
|
||||
if (!ZoteroPane.itemsView || !ZoteroPane.itemsView.tree) return;
|
||||
ZoteroPane.itemsView.tree.updateColumnWidths();
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens the about dialog
|
||||
*/
|
||||
|
|
|
@ -39,10 +39,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.cell:first-child {
|
||||
padding-inline-start: 6px;
|
||||
}
|
||||
|
||||
.cell {
|
||||
min-width: 30px;
|
||||
cursor: default;
|
||||
|
@ -63,7 +59,7 @@
|
|||
flex-shrink: 1;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
margin-inline-start: 6px;
|
||||
margin-inline-start: 5px;
|
||||
}
|
||||
|
||||
.twisty + .cell-text, .spacer-twisty + .cell-text {
|
||||
|
@ -178,6 +174,7 @@
|
|||
position: relative;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
padding: 0 5px;
|
||||
|
||||
&:hover {
|
||||
background: #fff;
|
||||
|
@ -199,7 +196,7 @@
|
|||
}
|
||||
|
||||
.label {
|
||||
margin-inline-start: 10px;
|
||||
margin-inline-start: 5px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
flex: 1;
|
||||
|
|
Loading…
Reference in a new issue