Unload tabs (#2500)
- Keep all tabs unloaded on Zotero opening. - Keep loaded only the last five selected tabs. - Keep loaded only in the last 24h selected tabs. Fixes #2383
This commit is contained in:
parent
578986ab1e
commit
142e3b09f8
3 changed files with 82 additions and 18 deletions
|
@ -181,13 +181,13 @@ var ZoteroContextPane = new function () {
|
|||
// It seems that changing `hidden` or `collapsed` values might
|
||||
// be related with significant slow down when there are too many
|
||||
// DOM nodes (i.e. 10k notes)
|
||||
if (Zotero_Tabs.selectedIndex == 0) {
|
||||
if (Zotero_Tabs.selectedType == 'library') {
|
||||
_contextPaneSplitter.setAttribute('hidden', true);
|
||||
_contextPane.setAttribute('collapsed', true);
|
||||
_tabToolbar.hidden = true;
|
||||
_tabCover.hidden = true;
|
||||
}
|
||||
else {
|
||||
else if (Zotero_Tabs.selectedType == 'reader') {
|
||||
var reader = Zotero.Reader.getByTabID(Zotero_Tabs.selectedID);
|
||||
if (reader) {
|
||||
_tabCover.hidden = false;
|
||||
|
@ -217,7 +217,7 @@ var ZoteroContextPane = new function () {
|
|||
});
|
||||
_tabToolbar.hidden = false;
|
||||
}
|
||||
|
||||
|
||||
_selectItemContext(ids[0]);
|
||||
_update();
|
||||
}
|
||||
|
|
|
@ -30,11 +30,18 @@ var React = require('react');
|
|||
var ReactDOM = require('react-dom');
|
||||
import TabBar from 'components/tabBar';
|
||||
|
||||
const MAX_LOADED_TABS = 5;
|
||||
const UNLOAD_UNUSED_AFTER = 86400; // 24h
|
||||
|
||||
var Zotero_Tabs = new function () {
|
||||
Object.defineProperty(this, 'selectedID', {
|
||||
get: () => this._selectedID
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'selectedType', {
|
||||
get: () => this._getTab(this._selectedID).tab.type
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'selectedIndex', {
|
||||
get: () => this._getTab(this._selectedID).tabIndex
|
||||
});
|
||||
|
@ -53,6 +60,10 @@ var Zotero_Tabs = new function () {
|
|||
this._prevSelectedID = null;
|
||||
this._history = [];
|
||||
|
||||
this._unloadInterval = setInterval(() => {
|
||||
this.unloadUnusedTabs();
|
||||
}, 60000); // Trigger every minute
|
||||
|
||||
this._getTab = function (id) {
|
||||
var tabIndex = this._tabs.findIndex(tab => tab.id == id);
|
||||
return { tab: this._tabs[tabIndex], tabIndex };
|
||||
|
@ -90,8 +101,12 @@ var Zotero_Tabs = new function () {
|
|||
|
||||
this.getState = function () {
|
||||
return this._tabs.map((tab) => {
|
||||
let type = tab.type;
|
||||
if (type === 'reader-unloaded') {
|
||||
type = 'reader';
|
||||
}
|
||||
var o = {
|
||||
type: tab.type,
|
||||
type,
|
||||
title: tab.title,
|
||||
};
|
||||
if (tab.data) {
|
||||
|
@ -103,21 +118,21 @@ var Zotero_Tabs = new function () {
|
|||
return o;
|
||||
});
|
||||
};
|
||||
|
||||
this.restoreState = function(tabs) {
|
||||
for (let tab of tabs) {
|
||||
|
||||
this.restoreState = function (tabs) {
|
||||
for (let i = 0; i < tabs.length; i++) {
|
||||
let tab = tabs[i];
|
||||
if (tab.type === 'library') {
|
||||
this.rename('zotero-pane', tab.title);
|
||||
}
|
||||
else if (tab.type === 'reader') {
|
||||
if (Zotero.Items.exists(tab.data.itemID)) {
|
||||
Zotero.Reader.open(tab.data.itemID,
|
||||
null,
|
||||
{
|
||||
title: tab.title,
|
||||
openInBackground: !tab.selected
|
||||
}
|
||||
);
|
||||
this.add({
|
||||
type: 'reader-unloaded',
|
||||
title: tab.title,
|
||||
index: i,
|
||||
data: tab.data
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -292,10 +307,22 @@ var Zotero_Tabs = new function () {
|
|||
* @param {Boolean} reopening
|
||||
*/
|
||||
this.select = function (id, reopening) {
|
||||
var { tab } = this._getTab(id);
|
||||
var { tab, tabIndex } = this._getTab(id);
|
||||
if (!tab || tab.id === this._selectedID) {
|
||||
return;
|
||||
}
|
||||
if (this._selectedID) {
|
||||
let { tab: selectedTab } = this._getTab(this._selectedID);
|
||||
selectedTab.timeUnselected = Zotero.Date.getUnixTimestamp();
|
||||
}
|
||||
if (tab.type === 'reader-unloaded') {
|
||||
this.close(tab.id);
|
||||
Zotero.Reader.open(tab.data.itemID, null, {
|
||||
title: tab.title,
|
||||
tabIndex
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (this._selectedID === 'zotero-pane') {
|
||||
var { tab: selectedTab } = this._getTab(this._selectedID);
|
||||
selectedTab.lastFocusedElement = document.activeElement;
|
||||
|
@ -312,12 +339,18 @@ var Zotero_Tabs = new function () {
|
|||
}
|
||||
tab.lastFocusedElement = null;
|
||||
}
|
||||
let tabNode = document.querySelector(`.tab[data-id="${tab.id}"]`);
|
||||
let tabsContainerNode = document.querySelector('#tab-bar-container .tabs');
|
||||
document.querySelector(`.tab[data-id="${tab.id}"]`).scrollIntoView({ behavior: 'smooth' });
|
||||
// Allow React to create a tab node
|
||||
setTimeout(() => {
|
||||
document.querySelector(`.tab[data-id="${tab.id}"]`).scrollIntoView({ behavior: 'smooth' });
|
||||
});
|
||||
// Border is not included when scrolling element node into view, therefore we do it manually.
|
||||
// TODO: `scroll-padding` since Firefox 68 can probably be used instead
|
||||
setTimeout(() => {
|
||||
let tabNode = document.querySelector(`.tab[data-id="${tab.id}"]`);
|
||||
if (!tabNode) {
|
||||
return;
|
||||
}
|
||||
let tabsContainerNode = document.querySelector('#tab-bar-container .tabs');
|
||||
if (tabNode.offsetLeft + tabNode.offsetWidth - tabsContainerNode.offsetWidth + 1 >= tabsContainerNode.scrollLeft) {
|
||||
document.querySelector('#tab-bar-container .tabs').scrollLeft += 1;
|
||||
}
|
||||
|
@ -325,6 +358,36 @@ var Zotero_Tabs = new function () {
|
|||
document.querySelector('#tab-bar-container .tabs').scrollLeft -= 1;
|
||||
}
|
||||
}, 500);
|
||||
tab.timeSelected = Zotero.Date.getUnixTimestamp();
|
||||
this.unloadUnusedTabs();
|
||||
};
|
||||
|
||||
this.unload = function (id) {
|
||||
var { tab, tabIndex } = this._getTab(id);
|
||||
if (!tab || tab.id === this._selectedID || tab.type !== 'reader') {
|
||||
return;
|
||||
}
|
||||
this.close(tab.id);
|
||||
this.add({
|
||||
type: 'reader-unloaded',
|
||||
title: tab.title,
|
||||
index: tabIndex,
|
||||
data: tab.data
|
||||
});
|
||||
};
|
||||
|
||||
this.unloadUnusedTabs = function () {
|
||||
for (let tab of this._tabs) {
|
||||
if (Zotero.Date.getUnixTimestamp() - tab.timeUnselected > UNLOAD_UNUSED_AFTER) {
|
||||
this.unload(tab.id);
|
||||
}
|
||||
}
|
||||
let tabs = this._tabs.slice().filter(x => x.type === 'reader');
|
||||
tabs.sort((a, b) => b.timeUnselected - a.timeUnselected);
|
||||
tabs = tabs.slice(MAX_LOADED_TABS);
|
||||
for (let tab of tabs) {
|
||||
this.unload(tab.id);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -969,6 +969,7 @@ class ReaderTab extends ReaderInstance {
|
|||
// i.e. note-editor. There should be a better way to solve this
|
||||
this._window.addEventListener('pointerup', (event) => {
|
||||
if (this._window.Zotero_Tabs.selectedID === this.tabID
|
||||
&& this._iframeWindow
|
||||
&& event.target
|
||||
&& event.target.closest
|
||||
&& !event.target.closest('#outerContainer')) {
|
||||
|
|
Loading…
Reference in a new issue