Fix a bug where first column is clipped if it has fixed or static width (#3605)
Also: * Fix issues with notes and attachment columns * Tweak first-column attachment column alignment
This commit is contained in:
parent
418ec5cfc0
commit
41294e0ff7
5 changed files with 82 additions and 13 deletions
|
@ -36,7 +36,7 @@ const TYPING_TIMEOUT = 1000;
|
||||||
const MINIMUM_ROW_HEIGHT = 20; // px
|
const MINIMUM_ROW_HEIGHT = 20; // px
|
||||||
const RESIZER_WIDTH = 5; // px
|
const RESIZER_WIDTH = 5; // px
|
||||||
const COLUMN_MIN_WIDTH = 20;
|
const COLUMN_MIN_WIDTH = 20;
|
||||||
const COLUMN_PADDING = 10; // N.B. MUST BE INLINE WITH CSS!!!
|
const COLUMN_PADDING = 16; // N.B. MUST BE INLINE WITH CSS!!!
|
||||||
|
|
||||||
const noop = () => 0;
|
const noop = () => 0;
|
||||||
|
|
||||||
|
@ -414,6 +414,7 @@ class VirtualizedTable extends React.Component {
|
||||||
staticColumns: PropTypes.bool,
|
staticColumns: PropTypes.bool,
|
||||||
// Used for initial column widths calculation
|
// Used for initial column widths calculation
|
||||||
containerWidth: PropTypes.number,
|
containerWidth: PropTypes.number,
|
||||||
|
firstColumnExtraWidth: PropTypes.number,
|
||||||
|
|
||||||
// Internal windowed-list ref
|
// Internal windowed-list ref
|
||||||
treeboxRef: PropTypes.func,
|
treeboxRef: PropTypes.func,
|
||||||
|
@ -848,8 +849,8 @@ class VirtualizedTable extends React.Component {
|
||||||
offset += resizingRect.width;
|
offset += resizingRect.width;
|
||||||
}
|
}
|
||||||
const widthSum = aRect.width + bRect.width;
|
const widthSum = aRect.width + bRect.width;
|
||||||
const aSpacingOffset = (aColumn.minWidth ? aColumn.minWidth : COLUMN_MIN_WIDTH) + COLUMN_PADDING;
|
const aSpacingOffset = (aColumn.minWidth ? aColumn.minWidth : COLUMN_MIN_WIDTH) + (aColumn.noPadding ? 0 : COLUMN_PADDING);
|
||||||
const bSpacingOffset = (bColumn.minWidth ? bColumn.minWidth : COLUMN_MIN_WIDTH) + COLUMN_PADDING;
|
const bSpacingOffset = (bColumn.minWidth ? bColumn.minWidth : COLUMN_MIN_WIDTH) + (bColumn.noPadding ? 0 : COLUMN_PADDING);
|
||||||
const aColumnWidth = Math.min(widthSum - bSpacingOffset, Math.max(aSpacingOffset, event.clientX - (RESIZER_WIDTH / 2) - offset));
|
const aColumnWidth = Math.min(widthSum - bSpacingOffset, Math.max(aSpacingOffset, event.clientX - (RESIZER_WIDTH / 2) - offset));
|
||||||
const bColumnWidth = widthSum - aColumnWidth;
|
const bColumnWidth = widthSum - aColumnWidth;
|
||||||
let onResizeData = {};
|
let onResizeData = {};
|
||||||
|
@ -1425,6 +1426,12 @@ var Columns = class {
|
||||||
if (column.type) {
|
if (column.type) {
|
||||||
column.className += ` cell-${column.type}`;
|
column.className += ` cell-${column.type}`;
|
||||||
}
|
}
|
||||||
|
if (column.fixedWidth) {
|
||||||
|
column.originalWidth = column.width;
|
||||||
|
}
|
||||||
|
if (column.staticWidth) {
|
||||||
|
column.originalMinWidth = column.minWidth || 20;
|
||||||
|
}
|
||||||
columns.push(column);
|
columns.push(column);
|
||||||
}
|
}
|
||||||
// Sort columns by their `ordinal` field
|
// Sort columns by their `ordinal` field
|
||||||
|
@ -1456,6 +1463,7 @@ var Columns = class {
|
||||||
// Storing back persist settings to account for legacy upgrades
|
// Storing back persist settings to account for legacy upgrades
|
||||||
this._storePrefs(columnsSettings);
|
this._storePrefs(columnsSettings);
|
||||||
|
|
||||||
|
this._adjustColumnWidths();
|
||||||
// Set column width CSS rules
|
// Set column width CSS rules
|
||||||
this.onResize(columnWidths);
|
this.onResize(columnWidths);
|
||||||
// Whew, all this just to get a list of columns
|
// Whew, all this just to get a list of columns
|
||||||
|
@ -1520,6 +1528,24 @@ var Columns = class {
|
||||||
this._virtualizedTable.props.storeColumnPrefs(prefs);
|
this._virtualizedTable.props.storeColumnPrefs(prefs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_adjustColumnWidths = () => {
|
||||||
|
if (!this._virtualizedTable.props.firstColumnExtraWidth) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const extraWidth = this._virtualizedTable.props.firstColumnExtraWidth;
|
||||||
|
this._columns.filter(c => !c.hidden).forEach((column, index) => {
|
||||||
|
const isFirstColumn = index === 0;
|
||||||
|
if (column.fixedWidth) {
|
||||||
|
column.width = isFirstColumn ? parseInt(column.originalWidth) + extraWidth : column.originalWidth;
|
||||||
|
}
|
||||||
|
if (column.staticWidth) {
|
||||||
|
column.minWidth = isFirstColumn ? (column.originalMinWidth ?? 20) + extraWidth : column.originalMinWidth;
|
||||||
|
column.width = isFirstColumn ? Math.max(parseInt(column.width) ?? 0, column.minWidth) : column.width;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Programatically sets the injected CSS width rules for each column.
|
* Programatically sets the injected CSS width rules for each column.
|
||||||
* This is necessary for performance reasons
|
* This is necessary for performance reasons
|
||||||
|
@ -1530,8 +1556,7 @@ var Columns = class {
|
||||||
if (storePrefs) {
|
if (storePrefs) {
|
||||||
var prefs = this._getPrefs();
|
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)) {
|
for (let [dataKey, width] of Object.entries(columnWidths)) {
|
||||||
if (typeof dataKey == "number") {
|
if (typeof dataKey == "number") {
|
||||||
dataKey = this._columns[dataKey].dataKey;
|
dataKey = this._columns[dataKey].dataKey;
|
||||||
|
@ -1569,6 +1594,10 @@ var Columns = class {
|
||||||
if (a.ordinal == b.ordinal) return a == column ? -1 : 1;
|
if (a.ordinal == b.ordinal) return a == column ? -1 : 1;
|
||||||
return a.ordinal - b.ordinal;
|
return a.ordinal - b.ordinal;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this._adjustColumnWidths();
|
||||||
|
this.onResize(Object.fromEntries(this._columns.map(c => [c.dataKey, c.width])));
|
||||||
|
|
||||||
let prefs = this._getPrefs();
|
let prefs = this._getPrefs();
|
||||||
// reassign columns their ordinal values and set the prefs
|
// reassign columns their ordinal values and set the prefs
|
||||||
this._columns.forEach((column, index) => {
|
this._columns.forEach((column, index) => {
|
||||||
|
@ -1596,6 +1625,8 @@ var Columns = class {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._columns.sort((a, b) => a.ordinal - b.ordinal);
|
this._columns.sort((a, b) => a.ordinal - b.ordinal);
|
||||||
|
this._adjustColumnWidths();
|
||||||
|
this.onResize(Object.fromEntries(this._columns.map(c => [c.dataKey, c.width])));
|
||||||
this._storePrefs(prefs);
|
this._storePrefs(prefs);
|
||||||
this._updateVirtualizedTable();
|
this._updateVirtualizedTable();
|
||||||
}
|
}
|
||||||
|
@ -1608,6 +1639,8 @@ var Columns = class {
|
||||||
if (prefs[column.dataKey]) {
|
if (prefs[column.dataKey]) {
|
||||||
prefs[column.dataKey].hidden = column.hidden;
|
prefs[column.dataKey].hidden = column.hidden;
|
||||||
}
|
}
|
||||||
|
this._adjustColumnWidths();
|
||||||
|
this.onResize(Object.fromEntries(this._columns.map(c => [c.dataKey, c.width])));
|
||||||
this._storePrefs(prefs);
|
this._storePrefs(prefs);
|
||||||
this._updateVirtualizedTable();
|
this._updateVirtualizedTable();
|
||||||
}
|
}
|
||||||
|
|
|
@ -985,6 +985,7 @@ var ItemTree = class ItemTree extends LibraryTree {
|
||||||
storeColumnPrefs: this._storeColumnPrefs,
|
storeColumnPrefs: this._storeColumnPrefs,
|
||||||
getDefaultColumnOrder: this._getDefaultColumnOrder,
|
getDefaultColumnOrder: this._getDefaultColumnOrder,
|
||||||
containerWidth: this.domEl.clientWidth,
|
containerWidth: this.domEl.clientWidth,
|
||||||
|
firstColumnExtraWidth: 28, // 16px for twisty + 16px for icon - 8px column padding + 4px margin
|
||||||
|
|
||||||
multiSelect: true,
|
multiSelect: true,
|
||||||
|
|
||||||
|
@ -2720,6 +2721,10 @@ var ItemTree = class ItemTree extends LibraryTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (column.noPadding) {
|
||||||
|
cell.classList.add('no-padding');
|
||||||
|
}
|
||||||
|
|
||||||
if (isFirstColumn) {
|
if (isFirstColumn) {
|
||||||
// Add depth indent, twisty and icon
|
// Add depth indent, twisty and icon
|
||||||
const depth = this.getLevel(index);
|
const depth = this.getLevel(index);
|
||||||
|
|
|
@ -40,6 +40,7 @@ const Icons = require('components/icons');
|
||||||
* @property {string} [width] - A column width instead of flex ratio. See above.
|
* @property {string} [width] - A column width instead of flex ratio. See above.
|
||||||
* @property {boolean} [fixedWidth] - Default: false. Set to true to disable column resizing
|
* @property {boolean} [fixedWidth] - Default: false. Set to true to disable column resizing
|
||||||
* @property {boolean} [staticWidth] - Default: false. Set to true to prevent columns from changing width when the width of the tree increases or decreases
|
* @property {boolean} [staticWidth] - Default: false. Set to true to prevent columns from changing width when the width of the tree increases or decreases
|
||||||
|
* @property {boolean} [noPadding] - Set to true for columns with padding disabled in stylesheet
|
||||||
* @property {number} [minWidth] - Override the default [20px] column min-width for resizing
|
* @property {number} [minWidth] - Override the default [20px] column min-width for resizing
|
||||||
* @property {React.Component} [iconLabel] - Set an Icon label instead of a text-based one
|
* @property {React.Component} [iconLabel] - Set an Icon label instead of a text-based one
|
||||||
* @property {string} [iconPath] - Set an Icon path, overrides {iconLabel}
|
* @property {string} [iconPath] - Set an Icon path, overrides {iconLabel}
|
||||||
|
@ -337,7 +338,8 @@ const COLUMNS = [
|
||||||
label: "zotero.tabs.attachments.label",
|
label: "zotero.tabs.attachments.label",
|
||||||
iconLabel: <Icons.IconAttachSmall />,
|
iconLabel: <Icons.IconAttachSmall />,
|
||||||
fixedWidth: true,
|
fixedWidth: true,
|
||||||
width: "16",
|
width: "32",
|
||||||
|
noPadding: true,
|
||||||
zoteroPersist: ["hidden", "sortDirection"]
|
zoteroPersist: ["hidden", "sortDirection"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -346,9 +348,10 @@ const COLUMNS = [
|
||||||
showInColumnPicker: true,
|
showInColumnPicker: true,
|
||||||
label: "zotero.tabs.notes.label",
|
label: "zotero.tabs.notes.label",
|
||||||
iconLabel: <Icons.IconTreeitemNoteSmall />,
|
iconLabel: <Icons.IconTreeitemNoteSmall />,
|
||||||
width: "14",
|
width: "26",
|
||||||
minWidth: 14,
|
minWidth: 26,
|
||||||
staticWidth: true,
|
staticWidth: true,
|
||||||
|
noPadding: true,
|
||||||
zoteroPersist: ["width", "hidden", "sortDirection"]
|
zoteroPersist: ["width", "hidden", "sortDirection"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,16 @@
|
||||||
padding-inline-end: calc(8px + var(--scrollbar-width, 0px));
|
padding-inline-end: calc(8px + var(--scrollbar-width, 0px));
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.cell.hasAttachment,
|
||||||
|
.cell.numNotes {
|
||||||
|
padding: 0;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&.first-column {
|
||||||
|
padding-inline-start: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.first-column {
|
.first-column {
|
||||||
&::before {
|
&::before {
|
||||||
content: "";
|
content: "";
|
||||||
|
@ -150,18 +160,34 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cell.no-padding {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.cell.hasAttachment {
|
.cell.hasAttachment {
|
||||||
box-sizing: content-box;
|
|
||||||
// Don't show ellipsis
|
|
||||||
text-overflow: unset;
|
text-overflow: unset;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.cell-text {
|
||||||
|
text-overflow: unset;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
.icon-missing-file {
|
.icon-missing-file {
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.cell.numNotes {
|
.numNotes, .hasAttachment {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
|
.cell-text {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,9 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
&:not(:first-child) {
|
&:not(:first-child) {
|
||||||
margin-inline-start: 4px;
|
@include state(".cell.first-column:not(.hasAttachment)") {
|
||||||
|
margin-inline-start: 4px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue