parent
03f05c8afa
commit
61c0dfee38
8 changed files with 160 additions and 28 deletions
|
@ -220,6 +220,19 @@
|
|||
label="&zotero.pdfReader.zoomPageHeight;"
|
||||
oncommand="menuCmd('zoomPageHeight')"
|
||||
/>
|
||||
<menuseparator class="menu-type-reader"/>
|
||||
<menuitem
|
||||
id="view-menuitem-split-vertically"
|
||||
type="checkbox"
|
||||
label="&zotero.pdfReader.splitVertically;"
|
||||
oncommand="menuCmd('splitVertically')"
|
||||
/>
|
||||
<menuitem
|
||||
id="view-menuitem-split-horizontally"
|
||||
type="checkbox"
|
||||
label="&zotero.pdfReader.splitHorizontally;"
|
||||
oncommand="menuCmd('splitHorizontally')"
|
||||
/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
<menu
|
||||
|
|
|
@ -405,6 +405,8 @@ const ZoteroStandalone = new function() {
|
|||
this.updateMenuItemCheckmark('view-menuitem-zoom-auto', reader.isZoomAutoActive());
|
||||
this.updateMenuItemCheckmark('view-menuitem-zoom-page-width', reader.isZoomPageWidthActive());
|
||||
this.updateMenuItemCheckmark('view-menuitem-zoom-page-height', reader.isZoomPageHeightActive());
|
||||
this.updateMenuItemCheckmark('view-menuitem-split-vertically', reader.isSplitVerticallyActive());
|
||||
this.updateMenuItemCheckmark('view-menuitem-split-horizontally', reader.isSplitHorizontallyActive());
|
||||
}
|
||||
|
||||
// Layout mode
|
||||
|
|
|
@ -89,6 +89,12 @@ var Zotero_Tabs = new function () {
|
|||
return tab && tab.id;
|
||||
};
|
||||
|
||||
this.setSecondViewState = function (tabID, state) {
|
||||
let { tab } = this._getTab(tabID);
|
||||
tab.data.secondViewState = state;
|
||||
Zotero.Session.debounceSave();
|
||||
};
|
||||
|
||||
this.init = function () {
|
||||
ReactDOM.render(
|
||||
<TabBar
|
||||
|
@ -138,7 +144,8 @@ var Zotero_Tabs = new function () {
|
|||
null,
|
||||
{
|
||||
title: tab.title,
|
||||
openInBackground: !tab.selected
|
||||
openInBackground: !tab.selected,
|
||||
secondViewState: tab.data.secondViewState
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -352,7 +359,8 @@ var Zotero_Tabs = new function () {
|
|||
tabID: tab.id,
|
||||
title: tab.title,
|
||||
tabIndex,
|
||||
allowDuplicate: true
|
||||
allowDuplicate: true,
|
||||
secondViewState: tab.data.secondViewState
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -461,7 +469,7 @@ var Zotero_Tabs = new function () {
|
|||
};
|
||||
|
||||
this._openMenu = function (x, y, id) {
|
||||
var { tabIndex } = this._getTab(id);
|
||||
var { tab, tabIndex } = this._getTab(id);
|
||||
window.Zotero_Tooltip.stop();
|
||||
let menuitem;
|
||||
let popup = document.createXULElement('menupopup');
|
||||
|
@ -518,7 +526,8 @@ var Zotero_Tabs = new function () {
|
|||
var reader = Zotero.Reader.getByTabID(id);
|
||||
if (reader) {
|
||||
this.close(id);
|
||||
Zotero.Reader.open(reader.itemID, null, { openInWindow: true });
|
||||
let { secondViewState } = tab.data;
|
||||
Zotero.Reader.open(reader.itemID, null, { openInWindow: true, secondViewState });
|
||||
}
|
||||
});
|
||||
menupopup.appendChild(menuitem);
|
||||
|
@ -526,11 +535,10 @@ var Zotero_Tabs = new function () {
|
|||
menuitem = document.createXULElement('menuitem');
|
||||
menuitem.setAttribute('label', Zotero.getString('tabs.duplicate'));
|
||||
menuitem.addEventListener('command', () => {
|
||||
var { tab, tabIndex } = this._getTab(id);
|
||||
if (tab.data.itemID) {
|
||||
tabIndex++;
|
||||
Zotero.Reader.open(tab.data.itemID, null, { tabIndex, allowDuplicate: true });
|
||||
|
||||
let { secondViewState } = tab.data;
|
||||
Zotero.Reader.open(tab.data.itemID, null, { tabIndex, allowDuplicate: true, secondViewState });
|
||||
}
|
||||
});
|
||||
popup.appendChild(menuitem);
|
||||
|
|
|
@ -52,6 +52,11 @@ class ReaderInstance {
|
|||
}
|
||||
}
|
||||
|
||||
getSecondViewState() {
|
||||
let state = this._iframeWindow.wrappedJSObject.getSecondViewState();
|
||||
return state ? JSON.parse(JSON.stringify(state)) : undefined;
|
||||
}
|
||||
|
||||
async migrateMendeleyColors(libraryID, annotations) {
|
||||
let colorMap = new Map();
|
||||
colorMap.set('#fff5ad', '#ffd400');
|
||||
|
@ -88,7 +93,7 @@ class ReaderInstance {
|
|||
return true;
|
||||
}
|
||||
|
||||
async open({ itemID, state, location }) {
|
||||
async open({ itemID, state, location, secondViewState }) {
|
||||
let { libraryID } = Zotero.Items.getLibraryAndKeyFromID(itemID);
|
||||
let library = Zotero.Libraries.get(libraryID);
|
||||
await library.waitForDataLoad('item');
|
||||
|
@ -122,6 +127,7 @@ class ReaderInstance {
|
|||
buf,
|
||||
annotations,
|
||||
state,
|
||||
secondViewState,
|
||||
location,
|
||||
readOnly: this._isReadOnly(),
|
||||
authorName: item.library.libraryType === 'group' ? Zotero.Users.getCurrentName() : '',
|
||||
|
@ -258,7 +264,15 @@ class ReaderInstance {
|
|||
isZoomPageHeightActive() {
|
||||
return this._iframeWindow.wrappedJSObject.PDFViewerApplication.pdfViewer.currentScaleValue === 'page-fit';
|
||||
}
|
||||
|
||||
|
||||
isSplitVerticallyActive() {
|
||||
return this._iframeWindow.wrappedJSObject.getSplitType() === 'vertical';
|
||||
}
|
||||
|
||||
isSplitHorizontallyActive() {
|
||||
return this._iframeWindow.wrappedJSObject.getSplitType() === 'horizontal';
|
||||
}
|
||||
|
||||
allowNavigateFirstPage() {
|
||||
return this._iframeWindow.wrappedJSObject.PDFViewerApplication.pdfViewer.currentPageNumber > 1;
|
||||
}
|
||||
|
@ -365,6 +379,12 @@ class ReaderInstance {
|
|||
}
|
||||
return;
|
||||
}
|
||||
else if (cmd === 'splitVertically') {
|
||||
this._splitVertically();
|
||||
}
|
||||
else if (cmd === 'splitHorizontally') {
|
||||
this._splitHorizontally();
|
||||
}
|
||||
|
||||
let data = {
|
||||
action: 'menuCmd',
|
||||
|
@ -578,6 +598,26 @@ class ReaderInstance {
|
|||
return `data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><rect shape-rendering="geometricPrecision" fill="${fill}" stroke-width="2" x="2" y="2" stroke="${stroke}" width="12" height="12" rx="3"/></svg>`;
|
||||
}
|
||||
|
||||
_splitVertically() {
|
||||
if (this.isSplitVerticallyActive()) {
|
||||
this._iframeWindow.wrappedJSObject.unsplitView();
|
||||
}
|
||||
else {
|
||||
this._iframeWindow.wrappedJSObject.splitView();
|
||||
}
|
||||
setTimeout(() => this._updateSecondViewState(), 500);
|
||||
}
|
||||
|
||||
_splitHorizontally() {
|
||||
if (this.isSplitHorizontallyActive()) {
|
||||
this._iframeWindow.wrappedJSObject.unsplitView();
|
||||
}
|
||||
else {
|
||||
this._iframeWindow.wrappedJSObject.splitView(true);
|
||||
}
|
||||
setTimeout(() => this._updateSecondViewState(), 500);
|
||||
}
|
||||
|
||||
_openTagsPopup(item, selector) {
|
||||
let menupopup = this._window.document.createXULElement('menupopup');
|
||||
menupopup.addEventListener('popuphidden', function (event) {
|
||||
|
@ -601,8 +641,8 @@ class ReaderInstance {
|
|||
tagsbox.newTag();
|
||||
}
|
||||
}
|
||||
|
||||
_openPagePopup(data) {
|
||||
|
||||
_openPagePopup(data, secondView) {
|
||||
let popup = this._window.document.createXULElement('menupopup');
|
||||
this._popupset.appendChild(popup);
|
||||
popup.addEventListener('popuphidden', function () {
|
||||
|
@ -623,14 +663,14 @@ class ReaderInstance {
|
|||
menuitem = this._window.document.createXULElement('menuitem');
|
||||
menuitem.setAttribute('label', Zotero.getString('pdfReader.zoomIn'));
|
||||
menuitem.addEventListener('command', () => {
|
||||
this._postMessage({ action: 'popupCmd', cmd: 'zoomIn' });
|
||||
this._postMessage({ action: 'popupCmd', cmd: 'zoomIn' }, [], secondView);
|
||||
});
|
||||
popup.appendChild(menuitem);
|
||||
// Zoom out
|
||||
menuitem = this._window.document.createXULElement('menuitem');
|
||||
menuitem.setAttribute('label', Zotero.getString('pdfReader.zoomOut'));
|
||||
menuitem.addEventListener('command', () => {
|
||||
this._postMessage({ action: 'popupCmd', cmd: 'zoomOut' });
|
||||
this._postMessage({ action: 'popupCmd', cmd: 'zoomOut' }, [], secondView);
|
||||
});
|
||||
popup.appendChild(menuitem);
|
||||
// Zoom 'Auto'
|
||||
|
@ -639,7 +679,7 @@ class ReaderInstance {
|
|||
menuitem.setAttribute('type', 'checkbox');
|
||||
menuitem.setAttribute('checked', data.isZoomAuto);
|
||||
menuitem.addEventListener('command', () => {
|
||||
this._postMessage({ action: 'popupCmd', cmd: 'zoomAuto' });
|
||||
this._postMessage({ action: 'popupCmd', cmd: 'zoomAuto' }, [], secondView);
|
||||
});
|
||||
popup.appendChild(menuitem);
|
||||
// Zoom 'Page Width'
|
||||
|
@ -648,7 +688,7 @@ class ReaderInstance {
|
|||
menuitem.setAttribute('type', 'checkbox');
|
||||
menuitem.setAttribute('checked', data.isZoomPageWidth);
|
||||
menuitem.addEventListener('command', () => {
|
||||
this._postMessage({ action: 'popupCmd', cmd: 'zoomPageWidth' });
|
||||
this._postMessage({ action: 'popupCmd', cmd: 'zoomPageWidth' }, [], secondView);
|
||||
});
|
||||
popup.appendChild(menuitem);
|
||||
// Zoom 'Page Height'
|
||||
|
@ -657,17 +697,33 @@ class ReaderInstance {
|
|||
menuitem.setAttribute('type', 'checkbox');
|
||||
menuitem.setAttribute('checked', data.isZoomPageHeight);
|
||||
menuitem.addEventListener('command', () => {
|
||||
this._postMessage({ action: 'popupCmd', cmd: 'zoomPageHeight' });
|
||||
this._postMessage({ action: 'popupCmd', cmd: 'zoomPageHeight' }, [], secondView);
|
||||
});
|
||||
popup.appendChild(menuitem);
|
||||
// Separator
|
||||
popup.appendChild(this._window.document.createXULElement('menuseparator'));
|
||||
// Split Vertically
|
||||
menuitem = this._window.document.createXULElement('menuitem');
|
||||
menuitem.setAttribute('label', Zotero.getString('pdfReader.splitVertically'));
|
||||
menuitem.setAttribute('type', 'checkbox');
|
||||
menuitem.setAttribute('checked', this.isSplitVerticallyActive());
|
||||
menuitem.addEventListener('command', () => this._splitVertically());
|
||||
popup.appendChild(menuitem);
|
||||
// Split Horizontally
|
||||
menuitem = this._window.document.createXULElement('menuitem');
|
||||
menuitem.setAttribute('label', Zotero.getString('pdfReader.splitHorizontally'));
|
||||
menuitem.setAttribute('type', 'checkbox');
|
||||
menuitem.setAttribute('checked', this.isSplitHorizontallyActive());
|
||||
menuitem.addEventListener('command', () => this._splitHorizontally());
|
||||
popup.appendChild(menuitem);
|
||||
// Separator
|
||||
popup.appendChild(this._window.document.createXULElement('menuseparator'));
|
||||
// Next page
|
||||
menuitem = this._window.document.createXULElement('menuitem');
|
||||
menuitem.setAttribute('label', Zotero.getString('pdfReader.nextPage'));
|
||||
menuitem.setAttribute('disabled', !data.enableNextPage);
|
||||
menuitem.addEventListener('command', () => {
|
||||
this._postMessage({ action: 'popupCmd', cmd: 'nextPage' });
|
||||
this._postMessage({ action: 'popupCmd', cmd: 'nextPage' }, [], secondView);
|
||||
});
|
||||
popup.appendChild(menuitem);
|
||||
// Previous page
|
||||
|
@ -675,7 +731,7 @@ class ReaderInstance {
|
|||
menuitem.setAttribute('label', Zotero.getString('pdfReader.previousPage'));
|
||||
menuitem.setAttribute('disabled', !data.enablePrevPage);
|
||||
menuitem.addEventListener('command', () => {
|
||||
this._postMessage({ action: 'popupCmd', cmd: 'prevPage' });
|
||||
this._postMessage({ action: 'popupCmd', cmd: 'prevPage' }, [], secondView);
|
||||
});
|
||||
popup.appendChild(menuitem);
|
||||
popup.openPopupAtScreen(data.x, data.y, true);
|
||||
|
@ -899,25 +955,52 @@ class ReaderInstance {
|
|||
popup.openPopupAtScreen(data.x, data.y, true);
|
||||
}
|
||||
|
||||
async _postMessage(message, transfer) {
|
||||
async _postMessage(message, transfer, secondView) {
|
||||
await this._waitForReader();
|
||||
this._iframeWindow.postMessage({ itemID: this._itemID, message }, this._iframeWindow.origin, transfer);
|
||||
this._iframeWindow.postMessage({ itemID: this._itemID, message, secondView }, this._iframeWindow.origin, transfer);
|
||||
}
|
||||
|
||||
_updateSecondViewState() {
|
||||
if (this.tabID) {
|
||||
let win = Zotero.getMainWindow();
|
||||
if (win) {
|
||||
win.Zotero_Tabs.setSecondViewState(this.tabID, this.getSecondViewState());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_handleMessage = async (event) => {
|
||||
let message;
|
||||
let secondViewIframeWindow = this._iframeWindow.document.getElementById('secondViewIframe');
|
||||
if (secondViewIframeWindow) {
|
||||
secondViewIframeWindow = secondViewIframeWindow.contentWindow;
|
||||
}
|
||||
try {
|
||||
if (event.source !== this._iframeWindow) {
|
||||
if (event.source !== this._iframeWindow
|
||||
&& event.source !== secondViewIframeWindow) {
|
||||
return;
|
||||
}
|
||||
// Clone data to avoid the dead object error when the window is closed
|
||||
let data = JSON.parse(JSON.stringify(event.data));
|
||||
let { secondView } = data;
|
||||
// Filter messages coming from previous reader instances,
|
||||
// except for `setAnnotation` to still allow saving it
|
||||
if (data.itemID !== this._itemID && data.message.action !== 'setAnnotation') {
|
||||
return;
|
||||
}
|
||||
message = data.message;
|
||||
|
||||
if (secondView) {
|
||||
switch (message.action) {
|
||||
case 'openPagePopup': break;
|
||||
case 'setState': {
|
||||
this._updateSecondViewState();
|
||||
return;
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (message.action) {
|
||||
case 'initialized': {
|
||||
this._resolveInitPromise();
|
||||
|
@ -1004,7 +1087,7 @@ class ReaderInstance {
|
|||
return;
|
||||
}
|
||||
case 'openPagePopup': {
|
||||
this._openPagePopup(message.data);
|
||||
this._openPagePopup(message.data, secondView);
|
||||
return;
|
||||
}
|
||||
case 'openAnnotationPopup': {
|
||||
|
@ -1308,6 +1391,8 @@ class ReaderWindow extends ReaderInstance {
|
|||
this._window.document.getElementById('view-menuitem-zoom-auto').setAttribute('checked', this.isZoomAutoActive());
|
||||
this._window.document.getElementById('view-menuitem-zoom-page-width').setAttribute('checked', this.isZoomPageWidthActive());
|
||||
this._window.document.getElementById('view-menuitem-zoom-page-height').setAttribute('checked', this.isZoomPageHeightActive());
|
||||
this._window.document.getElementById('view-menuitem-split-vertically').setAttribute('checked', this.isSplitVerticallyActive());
|
||||
this._window.document.getElementById('view-menuitem-split-horizontally').setAttribute('checked', this.isSplitHorizontallyActive());
|
||||
}
|
||||
|
||||
_onGoMenuOpen() {
|
||||
|
@ -1367,7 +1452,7 @@ class Reader {
|
|||
await Zotero.uiReadyPromise;
|
||||
Zotero.Session.state.windows
|
||||
.filter(x => x.type == 'reader' && Zotero.Items.exists(x.itemID))
|
||||
.forEach(x => this.open(x.itemID, null, { title: x.title, openInWindow: true }));
|
||||
.forEach(x => this.open(x.itemID, null, { title: x.title, openInWindow: true, secondViewState: x.secondViewState }));
|
||||
}
|
||||
|
||||
_loadSidebarState() {
|
||||
|
@ -1490,7 +1575,12 @@ class Reader {
|
|||
getWindowStates() {
|
||||
return this._readers
|
||||
.filter(r => r instanceof ReaderWindow)
|
||||
.map(r => ({ type: 'reader', itemID: r._itemID, title: r._title }));
|
||||
.map(r => ({
|
||||
type: 'reader',
|
||||
itemID: r._itemID,
|
||||
title: r._title,
|
||||
secondViewState: r.getSecondViewState()
|
||||
}));
|
||||
}
|
||||
|
||||
async openURI(itemURI, location, options) {
|
||||
|
@ -1499,7 +1589,7 @@ class Reader {
|
|||
await this.open(item.id, location, options);
|
||||
}
|
||||
|
||||
async open(itemID, location, { title, tabIndex, tabID, openInBackground, openInWindow, allowDuplicate } = {}) {
|
||||
async open(itemID, location, { title, tabIndex, tabID, openInBackground, openInWindow, allowDuplicate, secondViewState } = {}) {
|
||||
this._loadSidebarState();
|
||||
this.triggerAnnotationsImportCheck(itemID);
|
||||
let reader;
|
||||
|
@ -1540,7 +1630,7 @@ class Reader {
|
|||
bottomPlaceholderHeight: this._bottomPlaceholderHeight
|
||||
});
|
||||
this._readers.push(reader);
|
||||
if (!(await reader.open({ itemID, location }))) {
|
||||
if (!(await reader.open({ itemID, location, secondViewState }))) {
|
||||
return;
|
||||
}
|
||||
Zotero.Session.debounceSave();
|
||||
|
@ -1561,7 +1651,7 @@ class Reader {
|
|||
bottomPlaceholderHeight: this._bottomPlaceholderHeight
|
||||
});
|
||||
this._readers.push(reader);
|
||||
if (!(await reader.open({ itemID, location }))) {
|
||||
if (!(await reader.open({ itemID, location, secondViewState }))) {
|
||||
return;
|
||||
}
|
||||
reader.onChangeSidebarWidth = (width) => {
|
||||
|
|
|
@ -393,6 +393,21 @@
|
|||
oncommand="ZoteroStandalone.onReaderCmd('zoomPageHeight')"
|
||||
/>
|
||||
<menuseparator class="menu-type-reader"/>
|
||||
<menuitem
|
||||
id="view-menuitem-split-vertically"
|
||||
class="menu-type-reader"
|
||||
type="checkbox"
|
||||
label="&zotero.pdfReader.splitVertically;"
|
||||
oncommand="ZoteroStandalone.onReaderCmd('splitVertically')"
|
||||
/>
|
||||
<menuitem
|
||||
id="view-menuitem-split-horizontally"
|
||||
class="menu-type-reader"
|
||||
type="checkbox"
|
||||
label="&zotero.pdfReader.splitHorizontally;"
|
||||
oncommand="ZoteroStandalone.onReaderCmd('splitHorizontally')"
|
||||
/>
|
||||
<menuseparator class="menu-type-reader"/>
|
||||
|
||||
<menu id="layout-menu" label="&layout.label;">
|
||||
<menupopup oncommand="ZoteroStandalone.onViewMenuItemClick(event)">
|
||||
|
|
|
@ -325,4 +325,6 @@
|
|||
<!ENTITY zotero.pdfReader.zoomAuto "Automatically Resize">
|
||||
<!ENTITY zotero.pdfReader.zoomPageWidth "Zoom to Page Width">
|
||||
<!ENTITY zotero.pdfReader.zoomPageHeight "Zoom to Page Height">
|
||||
<!ENTITY zotero.pdfReader.splitVertically "Split Vertically">
|
||||
<!ENTITY zotero.pdfReader.splitHorizontally "Split Horizontally">
|
||||
<!ENTITY zotero.pdfReader.transferFromPDF "Import Annotations…">
|
||||
|
|
|
@ -1368,6 +1368,8 @@ pdfReader.zoomOut = Zoom Out
|
|||
pdfReader.zoomAuto = Automatically Resize
|
||||
pdfReader.zoomPageWidth = Zoom to Page Width
|
||||
pdfReader.zoomPageHeight = Zoom to Page Height
|
||||
pdfReader.splitVertically = Split Vertically
|
||||
pdfReader.splitHorizontally = Split Horizontally
|
||||
pdfReader.nextPage = Next Page
|
||||
pdfReader.previousPage = Previous Page
|
||||
pdfReader.page = Page
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 40f5d26b7cc754fb72ba10eff979560721d4fe0e
|
||||
Subproject commit 9587442831c46491c9a0a4066a37c0863d1c9efd
|
Loading…
Reference in a new issue