diff --git a/chrome/content/zotero/components/virtualized-table.jsx b/chrome/content/zotero/components/virtualized-table.jsx
index ae1e6b24b7..f25d10e7ff 100644
--- a/chrome/content/zotero/components/virtualized-table.jsx
+++ b/chrome/content/zotero/components/virtualized-table.jsx
@@ -682,6 +682,7 @@ class VirtualizedTable extends React.Component {
if (!modifierClick && !this.selection.isSelected(index)) {
this._onSelection(index, false, false);
}
+ this.focus();
}
_handleMouseUp = async (e, index) => {
@@ -693,6 +694,7 @@ class VirtualizedTable extends React.Component {
return;
}
this._onSelection(index, shiftSelect, toggleSelection);
+ this.focus();
}
_activateNode = (event, indices) => {
@@ -850,6 +852,32 @@ class VirtualizedTable extends React.Component {
return [aColumn, bColumn, resizingColumn];
}
+ /**
+ * Toggle [title] attribute on cells when text is truncated
+ * so that a tooltip gets displayed on hover.
+ * @param event
+ */
+ _handleMouseOver = (event) => {
+ let elem = event.target;
+ if (!elem.classList.contains('cell') || elem.classList.contains('cell-icon')) return;
+ let textElem = elem.querySelector('.label, .cell-text');
+ // .label is used in the header, .cell-text on primary cells,
+ // otherwise the .cell element if its immediate child is a text node
+ // should be used.
+ if (!textElem) {
+ if (elem.childNodes[0].nodeType != window.Node.TEXT_NODE) return;
+ textElem = elem;
+ }
+ // We need to set the [title] attribute on the .label element in the header
+ if (textElem.classList.contains('label')) elem = textElem;
+ if (textElem.offsetWidth < textElem.scrollWidth) {
+ elem.setAttribute('title', textElem.textContent);
+ }
+ else {
+ elem.removeAttribute('title');
+ }
+ }
+
_handleResizerDragStop = (event) => {
event.stopPropagation();
const result = this._getResizeColumns();
@@ -943,6 +971,7 @@ class VirtualizedTable extends React.Component {
this.props.treeboxRef && this.props.treeboxRef(this._jsWindow);
this._setAlternatingRows();
+ this._setXulTooltip();
window.addEventListener("resize", () => {
this._debouncedRerender();
@@ -959,6 +988,31 @@ class VirtualizedTable extends React.Component {
this.forceUpdate();
}
}
+
+ /**
+ * Make HTML [title] attribute display a tooltip. Without this
+ * HTML [title] attribute when embedded in a XUL window does not
+ * trigger a tooltip to be displayed
+ * @private
+ */
+ _setXulTooltip() {
+ // Make sure container xul element has a tooltip set
+ let xulElem = this._topDiv.closest('.virtualized-table-container');
+ if (xulElem.getAttribute('tooltip') != 'html-tooltip') {
+ xulElem.setAttribute('tooltip', 'html-tooltip');
+ }
+ if (document.querySelector('tooltip#html-tooltip')) return;
+ let tooltip = document.createElement('tooltip');
+ tooltip.id = 'html-tooltip';
+ tooltip.addEventListener('popupshowing', function(e) {
+ let tooltipTitleNode = document.tooltipNode.closest('div *[title], iframe *[title], browser *[title]');
+ if (document.tooltipNode && tooltipTitleNode) {
+ this.setAttribute('label', tooltipTitleNode.getAttribute('title'));
+ }
+ e.preventDefault();
+ });
+ document.documentElement.appendChild(tooltip);
+ }
_setAlternatingRows() {
if (this.props.alternatingRowColors) {
@@ -1052,7 +1106,7 @@ class VirtualizedTable extends React.Component {
+ title={column.iconLabel ? columnName : ""}>
{label}
{sortIndicator}
@@ -1081,6 +1135,7 @@ class VirtualizedTable extends React.Component {
onDragOver: this._onDragOver,
onDrop: e => this.props.onDrop && this.props.onDrop(e),
onFocus: e => this.props.onFocus && this.props.onFocus(e),
+ onMouseOver: e => this._handleMouseOver(e),
className: cx(["virtualized-table", { resizing: this.state.resizing }]),
id: this.props.id,
ref: ref => this._topDiv = ref,
diff --git a/chrome/content/zotero/itemTree.jsx b/chrome/content/zotero/itemTree.jsx
index f5709c6e93..479a350c43 100644
--- a/chrome/content/zotero/itemTree.jsx
+++ b/chrome/content/zotero/itemTree.jsx
@@ -2684,6 +2684,7 @@ var ItemTree = class ItemTree extends LibraryTree {
//}
if (ariaLabel) {
icon.setAttribute('aria-label', ariaLabel + '.');
+ span.setAttribute('title', ariaLabel);
}
span.append(icon);
diff --git a/chrome/content/zotero/zoteroPane.xul b/chrome/content/zotero/zoteroPane.xul
index 53adedefe2..1846f8cdd4 100644
--- a/chrome/content/zotero/zoteroPane.xul
+++ b/chrome/content/zotero/zoteroPane.xul
@@ -358,7 +358,7 @@
-
+
diff --git a/scss/components/_virtualized-table.scss b/scss/components/_virtualized-table.scss
index c81ac266a1..73e4834ece 100644
--- a/scss/components/_virtualized-table.scss
+++ b/scss/components/_virtualized-table.scss
@@ -219,7 +219,6 @@
padding: 2px 5px;
text-overflow: ellipsis;
overflow: hidden;
- pointer-events: none;
max-height: 100%;
}
}