Merge pull request #5699 from Snuffleupagus/presentationMode-refactor

Refactor the Presentation Mode code
This commit is contained in:
Tim van der Meij 2015-04-21 21:58:59 +02:00
commit 71ab5e5ac5
10 changed files with 521 additions and 422 deletions

View File

@ -51,6 +51,17 @@ var HandTool = {
}
}.bind(this), function rejected(reason) {});
}.bind(this));
window.addEventListener('presentationmodechanged', function (evt) {
if (evt.detail.switchInProgress) {
return;
}
if (evt.detail.active) {
this.enterPresentationMode();
} else {
this.exitPresentationMode();
}
}.bind(this));
}
},

View File

@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* globals PDFJS, PresentationMode */
'use strict';
@ -31,6 +30,7 @@ var PDFHistory = {
this.reInitialized = false;
this.allowHashChange = true;
this.historyUnlocked = true;
this.isViewerInPresentationMode = false;
this.previousHash = window.location.hash.substring(1);
this.currentBookmark = '';
@ -122,6 +122,10 @@ var PDFHistory = {
// the 'DOMContentLoaded' event is not fired on 'pageshow'.
window.addEventListener('beforeunload', pdfHistoryBeforeUnload, false);
}, false);
window.addEventListener('presentationmodechanged', function(e) {
self.isViewerInPresentationMode = !!e.detail.active;
});
},
_isStateObjectDefined: function pdfHistory_isStateObjectDefined(state) {
@ -286,7 +290,7 @@ var PDFHistory = {
return null;
}
var params = { hash: this.currentBookmark, page: this.currentPage };
if (PresentationMode.active) {
if (this.isViewerInPresentationMode) {
params.hash = null;
}
return params;

View File

@ -0,0 +1,399 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* globals PDFViewerApplication */
'use strict';
var DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS = 1500; // in ms
var DELAY_BEFORE_HIDING_CONTROLS = 3000; // in ms
var ACTIVE_SELECTOR = 'pdfPresentationMode';
var CONTROLS_SELECTOR = 'pdfPresentationModeControls';
/**
* @typedef {Object} PDFPresentationModeOptions
* @property {HTMLDivElement} container - The container for the viewer element.
* @property {HTMLDivElement} viewer - (optional) The viewer element.
* @property {PDFThumbnailViewer} pdfThumbnailViewer - (optional) The thumbnail
* viewer.
* @property {Array} contextMenuItems - (optional) The menuitems that are added
* to the context menu in Presentation Mode.
*/
/**
* @class
*/
var PDFPresentationMode = (function PDFPresentationModeClosure() {
/**
* @constructs PDFPresentationMode
* @param {PDFPresentationModeOptions} options
*/
function PDFPresentationMode(options) {
this.container = options.container;
this.viewer = options.viewer || options.container.firstElementChild;
this.pdfThumbnailViewer = options.pdfThumbnailViewer || null;
var contextMenuItems = options.contextMenuItems || null;
this.active = false;
this.args = null;
this.contextMenuOpen = false;
this.mouseScrollTimeStamp = 0;
this.mouseScrollDelta = 0;
if (contextMenuItems) {
for (var i = 0, ii = contextMenuItems.length; i < ii; i++) {
var item = contextMenuItems[i];
item.element.addEventListener('click', function (handler) {
this.contextMenuOpen = false;
handler();
}.bind(this, item.handler));
}
}
}
PDFPresentationMode.prototype = {
/**
* Request the browser to enter fullscreen mode.
* @returns {boolean} Indicating if the request was successful.
*/
request: function PDFPresentationMode_request() {
if (this.switchInProgress || this.active ||
!this.viewer.hasChildNodes()) {
return false;
}
this._addFullscreenChangeListeners();
this._setSwitchInProgress();
this._notifyStateChange();
if (this.container.requestFullscreen) {
this.container.requestFullscreen();
} else if (this.container.mozRequestFullScreen) {
this.container.mozRequestFullScreen();
} else if (this.container.webkitRequestFullscreen) {
this.container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
} else if (this.container.msRequestFullscreen) {
this.container.msRequestFullscreen();
} else {
return false;
}
this.args = {
page: PDFViewerApplication.page,
previousScale: PDFViewerApplication.currentScaleValue
};
return true;
},
/**
* Switches page when the user scrolls (using a scroll wheel or a touchpad)
* with large enough motion, to prevent accidental page switches.
* @param {number} delta - The delta value from the mouse event.
*/
mouseScroll: function PDFPresentationMode_mouseScroll(delta) {
if (!this.active) {
return;
}
var MOUSE_SCROLL_COOLDOWN_TIME = 50;
var PAGE_SWITCH_THRESHOLD = 120;
var PageSwitchDirection = {
UP: -1,
DOWN: 1
};
var currentTime = (new Date()).getTime();
var storedTime = this.mouseScrollTimeStamp;
// If we've already switched page, avoid accidentally switching again.
if (currentTime > storedTime &&
currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) {
return;
}
// If the scroll direction changed, reset the accumulated scroll delta.
if ((this.mouseScrollDelta > 0 && delta < 0) ||
(this.mouseScrollDelta < 0 && delta > 0)) {
this._resetMouseScrollState();
}
this.mouseScrollDelta += delta;
if (Math.abs(this.mouseScrollDelta) >= PAGE_SWITCH_THRESHOLD) {
var pageSwitchDirection = (this.mouseScrollDelta > 0) ?
PageSwitchDirection.UP : PageSwitchDirection.DOWN;
var page = PDFViewerApplication.page;
this._resetMouseScrollState();
// If we're at the first/last page, we don't need to do anything.
if ((page === 1 && pageSwitchDirection === PageSwitchDirection.UP) ||
(page === PDFViewerApplication.pagesCount &&
pageSwitchDirection === PageSwitchDirection.DOWN)) {
return;
}
PDFViewerApplication.page = (page + pageSwitchDirection);
this.mouseScrollTimeStamp = currentTime;
}
},
get isFullscreen() {
return !!(document.fullscreenElement ||
document.mozFullScreen ||
document.webkitIsFullScreen ||
document.msFullscreenElement);
},
/**
* @private
*/
_notifyStateChange: function PDFPresentationMode_notifyStateChange() {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('presentationmodechanged', true, true, {
active: this.active,
switchInProgress: !!this.switchInProgress
});
window.dispatchEvent(event);
},
/**
* Used to initialize a timeout when requesting Presentation Mode,
* i.e. when the browser is requested to enter fullscreen mode.
* This timeout is used to prevent the current page from being scrolled
* partially, or completely, out of view when entering Presentation Mode.
* NOTE: This issue seems limited to certain zoom levels (e.g. page-width).
* @private
*/
_setSwitchInProgress: function PDFPresentationMode_setSwitchInProgress() {
if (this.switchInProgress) {
clearTimeout(this.switchInProgress);
}
this.switchInProgress = setTimeout(function switchInProgressTimeout() {
this._removeFullscreenChangeListeners();
delete this.switchInProgress;
this._notifyStateChange();
}.bind(this), DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS);
},
/**
* @private
*/
_resetSwitchInProgress:
function PDFPresentationMode_resetSwitchInProgress() {
if (this.switchInProgress) {
clearTimeout(this.switchInProgress);
delete this.switchInProgress;
}
},
/**
* @private
*/
_enter: function PDFPresentationMode_enter() {
this.active = true;
this._resetSwitchInProgress();
this._notifyStateChange();
this.container.classList.add(ACTIVE_SELECTOR);
// Ensure that the correct page is scrolled into view when entering
// Presentation Mode, by waiting until fullscreen mode in enabled.
setTimeout(function enterPresentationModeTimeout() {
PDFViewerApplication.page = this.args.page;
PDFViewerApplication.setScale('page-fit', true);
}.bind(this), 0);
this._addWindowListeners();
this._showControls();
this.contextMenuOpen = false;
this.container.setAttribute('contextmenu', 'viewerContextMenu');
// Text selection is disabled in Presentation Mode, thus it's not possible
// for the user to deselect text that is selected (e.g. with "Select all")
// when entering Presentation Mode, hence we remove any active selection.
window.getSelection().removeAllRanges();
},
/**
* @private
*/
_exit: function PDFPresentationMode_exit() {
var page = PDFViewerApplication.page;
this.container.classList.remove(ACTIVE_SELECTOR);
// Ensure that the correct page is scrolled into view when exiting
// Presentation Mode, by waiting until fullscreen mode is disabled.
setTimeout(function exitPresentationModeTimeout() {
this.active = false;
this._removeFullscreenChangeListeners();
this._notifyStateChange();
PDFViewerApplication.setScale(this.args.previousScale, true);
PDFViewerApplication.page = page;
this.args = null;
}.bind(this), 0);
this._removeWindowListeners();
this._hideControls();
this._resetMouseScrollState();
this.container.removeAttribute('contextmenu');
this.contextMenuOpen = false;
if (this.pdfThumbnailViewer) {
this.pdfThumbnailViewer.ensureThumbnailVisible(page);
}
},
/**
* @private
*/
_mouseDown: function PDFPresentationMode_mouseDown(evt) {
if (this.contextMenuOpen) {
this.contextMenuOpen = false;
evt.preventDefault();
return;
}
if (evt.button === 0) {
// Enable clicking of links in presentation mode. Please note:
// Only links pointing to destinations in the current PDF document work.
var isInternalLink = (evt.target.href &&
evt.target.classList.contains('internalLink'));
if (!isInternalLink) {
// Unless an internal link was clicked, advance one page.
evt.preventDefault();
PDFViewerApplication.page += (evt.shiftKey ? -1 : 1);
}
}
},
/**
* @private
*/
_contextMenu: function PDFPresentationMode_contextMenu() {
this.contextMenuOpen = true;
},
/**
* @private
*/
_showControls: function PDFPresentationMode_showControls() {
if (this.controlsTimeout) {
clearTimeout(this.controlsTimeout);
} else {
this.container.classList.add(CONTROLS_SELECTOR);
}
this.controlsTimeout = setTimeout(function showControlsTimeout() {
this.container.classList.remove(CONTROLS_SELECTOR);
delete this.controlsTimeout;
}.bind(this), DELAY_BEFORE_HIDING_CONTROLS);
},
/**
* @private
*/
_hideControls: function PDFPresentationMode_hideControls() {
if (!this.controlsTimeout) {
return;
}
clearTimeout(this.controlsTimeout);
this.container.classList.remove(CONTROLS_SELECTOR);
delete this.controlsTimeout;
},
/**
* Resets the properties used for tracking mouse scrolling events.
* @private
*/
_resetMouseScrollState:
function PDFPresentationMode_resetMouseScrollState() {
this.mouseScrollTimeStamp = 0;
this.mouseScrollDelta = 0;
},
/**
* @private
*/
_addWindowListeners: function PDFPresentationMode_addWindowListeners() {
this.showControlsBind = this._showControls.bind(this);
this.mouseDownBind = this._mouseDown.bind(this);
this.resetMouseScrollStateBind = this._resetMouseScrollState.bind(this);
this.contextMenuBind = this._contextMenu.bind(this);
window.addEventListener('mousemove', this.showControlsBind);
window.addEventListener('mousedown', this.mouseDownBind);
window.addEventListener('keydown', this.resetMouseScrollStateBind);
window.addEventListener('contextmenu', this.contextMenuBind);
},
/**
* @private
*/
_removeWindowListeners:
function PDFPresentationMode_removeWindowListeners() {
window.removeEventListener('mousemove', this.showControlsBind);
window.removeEventListener('mousedown', this.mouseDownBind);
window.removeEventListener('keydown', this.resetMouseScrollStateBind);
window.removeEventListener('contextmenu', this.contextMenuBind);
delete this.showControlsBind;
delete this.mouseDownBind;
delete this.resetMouseScrollStateBind;
delete this.contextMenuBind;
},
/**
* @private
*/
_fullscreenChange: function PDFPresentationMode_fullscreenChange() {
if (this.isFullscreen) {
this._enter();
} else {
this._exit();
}
},
/**
* @private
*/
_addFullscreenChangeListeners:
function PDFPresentationMode_addFullscreenChangeListeners() {
this.fullscreenChangeBind = this._fullscreenChange.bind(this);
window.addEventListener('fullscreenchange', this.fullscreenChangeBind);
window.addEventListener('mozfullscreenchange', this.fullscreenChangeBind);
//#if !(FIREFOX || MOZCENTRAL)
window.addEventListener('webkitfullscreenchange',
this.fullscreenChangeBind);
window.addEventListener('MSFullscreenChange', this.fullscreenChangeBind);
//#endif
},
/**
* @private
*/
_removeFullscreenChangeListeners:
function PDFPresentationMode_removeFullscreenChangeListeners() {
window.removeEventListener('fullscreenchange', this.fullscreenChangeBind);
window.removeEventListener('mozfullscreenchange',
this.fullscreenChangeBind);
//#if !(FIREFOX || MOZCENTRAL)
window.removeEventListener('webkitfullscreenchange',
this.fullscreenChangeBind);
window.removeEventListener('MSFullscreenChange',
this.fullscreenChangeBind);
//#endif
delete this.fullscreenChangeBind;
}
};
return PDFPresentationMode;
})();

View File

@ -57,22 +57,22 @@
box-shadow: 0px 2px 10px #ff0;
}
:-webkit-full-screen .pdfViewer .page {
.pdfPresentationMode:-webkit-full-screen .pdfViewer .page {
margin-bottom: 100%;
border: 0;
}
:-moz-full-screen .pdfViewer .page {
.pdfPresentationMode:-moz-full-screen .pdfViewer .page {
margin-bottom: 100%;
border: 0;
}
:-ms-fullscreen .pdfViewer .page {
.pdfPresentationMode:-ms-fullscreen .pdfViewer .page {
margin-bottom: 100% !important;
border: 0;
}
:fullscreen .pdfViewer .page {
.pdfPresentationMode:fullscreen .pdfViewer .page {
margin-bottom: 100%;
border: 0;
}

View File

@ -374,11 +374,8 @@ var PDFViewer = (function pdfViewer() {
if (!noScroll) {
var page = this._currentPageNumber, dest;
var inPresentationMode =
this.presentationModeState === PresentationModeState.CHANGING ||
this.presentationModeState === PresentationModeState.FULLSCREEN;
if (this.location && !inPresentationMode &&
!IGNORE_CURRENT_POSITION_ON_ZOOM) {
if (this.location && !IGNORE_CURRENT_POSITION_ON_ZOOM &&
!(this.isInPresentationMode || this.isChangingPresentationMode)) {
page = this.location.pageNumber;
dest = [null, { name: 'XYZ' }, this.location.left,
this.location.top, null];
@ -402,11 +399,9 @@ var PDFViewer = (function pdfViewer() {
if (!currentPage) {
return;
}
var inPresentationMode =
this.presentationModeState === PresentationModeState.FULLSCREEN;
var hPadding = (inPresentationMode || this.removePageBorders) ?
var hPadding = (this.isInPresentationMode || this.removePageBorders) ?
0 : SCROLLBAR_PADDING;
var vPadding = (inPresentationMode || this.removePageBorders) ?
var vPadding = (this.isInPresentationMode || this.removePageBorders) ?
0 : VERTICAL_PADDING;
var pageWidthScale = (this.container.clientWidth - hPadding) /
currentPage.width * currentPage.scale;
@ -452,8 +447,7 @@ var PDFViewer = (function pdfViewer() {
dest) {
var pageView = this.pages[pageNumber - 1];
if (this.presentationModeState ===
PresentationModeState.FULLSCREEN) {
if (this.isInPresentationMode) {
if (this.linkService.page !== pageView.id) {
// Avoid breaking getVisiblePages in presentation mode.
this.linkService.page = pageView.id;
@ -607,7 +601,7 @@ var PDFViewer = (function pdfViewer() {
currentId = visiblePages[0].id;
}
if (this.presentationModeState !== PresentationModeState.FULLSCREEN) {
if (!this.isInPresentationMode) {
this.currentPageNumber = currentId;
}
@ -632,13 +626,21 @@ var PDFViewer = (function pdfViewer() {
this.container.blur();
},
get isInPresentationMode() {
return this.presentationModeState === PresentationModeState.FULLSCREEN;
},
get isChangingPresentationMode() {
return this.PresentationModeState === PresentationModeState.CHANGING;
},
get isHorizontalScrollbarEnabled() {
return (this.presentationModeState === PresentationModeState.FULLSCREEN ?
return (this.isInPresentationMode ?
false : (this.container.scrollWidth > this.container.clientWidth));
},
_getVisiblePages: function () {
if (this.presentationModeState !== PresentationModeState.FULLSCREEN) {
if (!this.isInPresentationMode) {
return getVisibleElements(this.container, this.pages, true);
} else {
// The algorithm in getVisibleElements doesn't work in all browsers and
@ -709,13 +711,11 @@ var PDFViewer = (function pdfViewer() {
* @returns {TextLayerBuilder}
*/
createTextLayerBuilder: function (textLayerDiv, pageIndex, viewport) {
var isViewerInPresentationMode =
this.presentationModeState === PresentationModeState.FULLSCREEN;
return new TextLayerBuilder({
textLayerDiv: textLayerDiv,
pageIndex: pageIndex,
viewport: viewport,
findController: isViewerInPresentationMode ? null : this.findController
findController: this.isInPresentationMode ? null : this.findController
});
},

View File

@ -1,268 +0,0 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* globals scrollIntoView, HandTool, PDFViewerApplication */
'use strict';
var DELAY_BEFORE_HIDING_CONTROLS = 3000; // in ms
var SELECTOR = 'presentationControls';
var DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS = 1000; // in ms
var PresentationMode = {
active: false,
args: null,
contextMenuOpen: false,
//#if (GENERIC || CHROME)
prevCoords: { x: null, y: null },
//#endif
initialize: function presentationModeInitialize(options) {
this.container = options.container;
this.secondaryToolbar = options.secondaryToolbar;
this.viewer = this.container.firstElementChild;
this.firstPage = options.firstPage;
this.lastPage = options.lastPage;
this.pageRotateCw = options.pageRotateCw;
this.pageRotateCcw = options.pageRotateCcw;
this.firstPage.addEventListener('click', function() {
this.contextMenuOpen = false;
this.secondaryToolbar.firstPageClick();
}.bind(this));
this.lastPage.addEventListener('click', function() {
this.contextMenuOpen = false;
this.secondaryToolbar.lastPageClick();
}.bind(this));
this.pageRotateCw.addEventListener('click', function() {
this.contextMenuOpen = false;
this.secondaryToolbar.pageRotateCwClick();
}.bind(this));
this.pageRotateCcw.addEventListener('click', function() {
this.contextMenuOpen = false;
this.secondaryToolbar.pageRotateCcwClick();
}.bind(this));
},
get isFullscreen() {
return (document.fullscreenElement ||
document.mozFullScreen ||
document.webkitIsFullScreen ||
document.msFullscreenElement);
},
/**
* Initialize a timeout that is used to specify switchInProgress when the
* browser transitions to fullscreen mode. Since resize events are triggered
* multiple times during the switch to fullscreen mode, this is necessary in
* order to prevent the page from being scrolled partially, or completely,
* out of view when Presentation Mode is enabled.
* Note: This is only an issue at certain zoom levels, e.g. 'page-width'.
*/
_setSwitchInProgress: function presentationMode_setSwitchInProgress() {
if (this.switchInProgress) {
clearTimeout(this.switchInProgress);
}
this.switchInProgress = setTimeout(function switchInProgressTimeout() {
delete this.switchInProgress;
this._notifyStateChange();
}.bind(this), DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS);
},
_resetSwitchInProgress: function presentationMode_resetSwitchInProgress() {
if (this.switchInProgress) {
clearTimeout(this.switchInProgress);
delete this.switchInProgress;
}
},
request: function presentationModeRequest() {
if (!PDFViewerApplication.supportsFullscreen || this.isFullscreen ||
!this.viewer.hasChildNodes()) {
return false;
}
this._setSwitchInProgress();
this._notifyStateChange();
if (this.container.requestFullscreen) {
this.container.requestFullscreen();
} else if (this.container.mozRequestFullScreen) {
this.container.mozRequestFullScreen();
} else if (this.container.webkitRequestFullscreen) {
this.container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
} else if (this.container.msRequestFullscreen) {
this.container.msRequestFullscreen();
} else {
return false;
}
this.args = {
page: PDFViewerApplication.page,
previousScale: PDFViewerApplication.currentScaleValue
};
return true;
},
_notifyStateChange: function presentationModeNotifyStateChange() {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('presentationmodechanged', true, true, {
active: PresentationMode.active,
switchInProgress: !!PresentationMode.switchInProgress
});
window.dispatchEvent(event);
},
enter: function presentationModeEnter() {
this.active = true;
this._resetSwitchInProgress();
this._notifyStateChange();
// Ensure that the correct page is scrolled into view when entering
// Presentation Mode, by waiting until fullscreen mode in enabled.
// Note: This is only necessary in non-Mozilla browsers.
setTimeout(function enterPresentationModeTimeout() {
PDFViewerApplication.page = this.args.page;
PDFViewerApplication.setScale('page-fit', true);
}.bind(this), 0);
window.addEventListener('mousemove', this.mouseMove, false);
window.addEventListener('mousedown', this.mouseDown, false);
window.addEventListener('contextmenu', this.contextMenu, false);
this.showControls();
HandTool.enterPresentationMode();
this.contextMenuOpen = false;
this.container.setAttribute('contextmenu', 'viewerContextMenu');
// Text selection is disabled in Presentation Mode, thus it's not possible
// for the user to deselect text that is selected (e.g. with "Select all")
// when entering Presentation Mode, hence we remove any active selection.
window.getSelection().removeAllRanges();
},
exit: function presentationModeExit() {
var page = PDFViewerApplication.page;
// Ensure that the correct page is scrolled into view when exiting
// Presentation Mode, by waiting until fullscreen mode is disabled.
// Note: This is only necessary in non-Mozilla browsers.
setTimeout(function exitPresentationModeTimeout() {
this.active = false;
this._notifyStateChange();
PDFViewerApplication.setScale(this.args.previousScale, true);
PDFViewerApplication.page = page;
this.args = null;
}.bind(this), 0);
window.removeEventListener('mousemove', this.mouseMove, false);
window.removeEventListener('mousedown', this.mouseDown, false);
window.removeEventListener('contextmenu', this.contextMenu, false);
this.hideControls();
PDFViewerApplication.clearMouseScrollState();
HandTool.exitPresentationMode();
this.container.removeAttribute('contextmenu');
this.contextMenuOpen = false;
// Ensure that the thumbnail of the current page is visible
// when exiting presentation mode.
scrollIntoView(document.getElementById('thumbnailContainer' + page));
},
showControls: function presentationModeShowControls() {
if (this.controlsTimeout) {
clearTimeout(this.controlsTimeout);
} else {
this.container.classList.add(SELECTOR);
}
this.controlsTimeout = setTimeout(function hideControlsTimeout() {
this.container.classList.remove(SELECTOR);
delete this.controlsTimeout;
}.bind(this), DELAY_BEFORE_HIDING_CONTROLS);
},
hideControls: function presentationModeHideControls() {
if (!this.controlsTimeout) {
return;
}
this.container.classList.remove(SELECTOR);
clearTimeout(this.controlsTimeout);
delete this.controlsTimeout;
},
mouseMove: function presentationModeMouseMove(evt) {
//#if (GENERIC || CHROME)
// Workaround for a bug in WebKit browsers that causes the 'mousemove' event
// to be fired when the cursor is changed. For details, see:
// http://code.google.com/p/chromium/issues/detail?id=103041.
var currCoords = { x: evt.clientX, y: evt.clientY };
var prevCoords = PresentationMode.prevCoords;
PresentationMode.prevCoords = currCoords;
if (currCoords.x === prevCoords.x && currCoords.y === prevCoords.y) {
return;
}
//#endif
PresentationMode.showControls();
},
mouseDown: function presentationModeMouseDown(evt) {
var self = PresentationMode;
if (self.contextMenuOpen) {
self.contextMenuOpen = false;
evt.preventDefault();
return;
}
if (evt.button === 0) {
// Enable clicking of links in presentation mode. Please note:
// Only links pointing to destinations in the current PDF document work.
var isInternalLink = (evt.target.href &&
evt.target.classList.contains('internalLink'));
if (!isInternalLink) {
// Unless an internal link was clicked, advance one page.
evt.preventDefault();
PDFViewerApplication.page += (evt.shiftKey ? -1 : 1);
}
}
},
contextMenu: function presentationModeContextMenu(evt) {
PresentationMode.contextMenuOpen = true;
}
};
(function presentationModeClosure() {
function presentationModeChange(e) {
if (PresentationMode.isFullscreen) {
PresentationMode.enter();
} else {
PresentationMode.exit();
}
}
window.addEventListener('fullscreenchange', presentationModeChange, false);
window.addEventListener('mozfullscreenchange', presentationModeChange, false);
window.addEventListener('webkitfullscreenchange', presentationModeChange,
false);
window.addEventListener('MSFullscreenChange', presentationModeChange, false);
})();

View File

@ -25,7 +25,6 @@ var SecondaryToolbar = {
initialize: function secondaryToolbarInitialize(options) {
this.toolbar = options.toolbar;
this.presentationMode = options.presentationMode;
this.documentProperties = options.documentProperties;
this.buttonContainer = this.toolbar.firstElementChild;
@ -72,7 +71,7 @@ var SecondaryToolbar = {
// Event handling functions.
presentationModeClick: function secondaryToolbarPresentationModeClick(evt) {
this.presentationMode.request();
PDFViewerApplication.requestPresentationMode();
this.close();
},

View File

@ -47,7 +47,7 @@ select {
display: none !important;
}
#viewerContainer:-webkit-full-screen {
#viewerContainer.pdfPresentationMode:-webkit-full-screen {
top: 0px;
border-top: 2px solid transparent;
background-color: #000;
@ -58,7 +58,7 @@ select {
-webkit-user-select: none;
}
#viewerContainer:-moz-full-screen {
#viewerContainer.pdfPresentationMode:-moz-full-screen {
top: 0px;
border-top: 2px solid transparent;
background-color: #000;
@ -69,7 +69,7 @@ select {
-moz-user-select: none;
}
#viewerContainer:-ms-fullscreen {
#viewerContainer.pdfPresentationMode:-ms-fullscreen {
top: 0px !important;
border-top: 2px solid transparent;
width: 100%;
@ -79,11 +79,11 @@ select {
-ms-user-select: none;
}
#viewerContainer:-ms-fullscreen::-ms-backdrop {
#viewerContainer.pdfPresentationMode:-ms-fullscreen::-ms-backdrop {
background-color: #000;
}
#viewerContainer:fullscreen {
#viewerContainer.pdfPresentationMode:fullscreen {
top: 0px;
border-top: 2px solid transparent;
background-color: #000;
@ -96,36 +96,40 @@ select {
-ms-user-select: none;
}
:-webkit-full-screen a:not(.internalLink) {
.pdfPresentationMode:-webkit-full-screen a:not(.internalLink) {
display: none;
}
:-moz-full-screen a:not(.internalLink) {
.pdfPresentationMode:-moz-full-screen a:not(.internalLink) {
display: none;
}
:-ms-fullscreen a:not(.internalLink) {
.pdfPresentationMode:-ms-fullscreen a:not(.internalLink) {
display: none !important;
}
:fullscreen a:not(.internalLink) {
.pdfPresentationMode:fullscreen a:not(.internalLink) {
display: none;
}
:-webkit-full-screen .textLayer > div {
.pdfPresentationMode:-webkit-full-screen .textLayer > div {
cursor: none;
}
:-moz-full-screen .textLayer > div {
.pdfPresentationMode:-moz-full-screen .textLayer > div {
cursor: none;
}
:fullscreen .textLayer > div {
.pdfPresentationMode:-ms-fullscreen .textLayer > div {
cursor: none;
}
#viewerContainer.presentationControls,
#viewerContainer.presentationControls .textLayer > div {
.pdfPresentationMode:fullscreen .textLayer > div {
cursor: none;
}
.pdfPresentationMode.pdfPresentationModeControls > *,
.pdfPresentationMode.pdfPresentationModeControls .textLayer > div {
cursor: default;
}

View File

@ -81,7 +81,7 @@ http://sourceforge.net/adobe/cmap/wiki/License/
<script src="pdf_find_controller.js"></script>
<script src="pdf_history.js"></script>
<script src="secondary_toolbar.js"></script>
<script src="presentation_mode.js"></script>
<script src="pdf_presentation_mode.js"></script>
<script src="grab_to_pan.js"></script>
<script src="hand_tool.js"></script>
<script src="overlay_manager.js"></script>

View File

@ -15,10 +15,10 @@
* limitations under the License.
*/
/* globals PDFJS, PDFBug, FirefoxCom, Stats, Cache, ProgressBar,
DownloadManager, getFileName, scrollIntoView, getPDFFileNameFromURL,
DownloadManager, getFileName, getPDFFileNameFromURL,
PDFHistory, Preferences, SidebarView, ViewHistory, Stats,
PDFThumbnailViewer, URL, noContextMenuHandler, SecondaryToolbar,
PasswordPrompt, PresentationMode, HandTool, Promise,
PasswordPrompt, PDFPresentationMode, HandTool, Promise,
DocumentProperties, PDFOutlineView, PDFAttachmentView,
OverlayManager, PDFFindController, PDFFindBar, getVisibleElements,
watchScroll, PDFViewer, PDFRenderingQueue, PresentationModeState,
@ -84,7 +84,7 @@ var mozL10n = document.mozL10n || document.webL10n;
//#include pdf_find_controller.js
//#include pdf_history.js
//#include secondary_toolbar.js
//#include presentation_mode.js
//#include pdf_presentation_mode.js
//#include hand_tool.js
//#include overlay_manager.js
//#include password_prompt.js
@ -107,12 +107,12 @@ var PDFViewerApplication = {
pdfThumbnailViewer: null,
/** @type {PDFRenderingQueue} */
pdfRenderingQueue: null,
/** @type {PDFPresentationMode} */
pdfPresentationMode: null,
pageRotation: 0,
updateScaleControls: true,
isInitialViewSet: false,
animationStartedPromise: null,
mouseScrollTimeStamp: 0,
mouseScrollDelta: 0,
preferenceSidebarViewOnLoad: SidebarView.NONE,
preferencePdfBugEnabled: false,
preferenceShowPreviousViewOnLoad: true,
@ -174,7 +174,6 @@ var PDFViewerApplication = {
SecondaryToolbar.initialize({
toolbar: document.getElementById('secondaryToolbar'),
presentationMode: PresentationMode,
toggleButton: document.getElementById('secondaryToolbarToggle'),
presentationModeButton:
document.getElementById('secondaryPresentationMode'),
@ -190,14 +189,24 @@ var PDFViewerApplication = {
documentPropertiesButton: document.getElementById('documentProperties')
});
PresentationMode.initialize({
container: container,
secondaryToolbar: SecondaryToolbar,
firstPage: document.getElementById('contextFirstPage'),
lastPage: document.getElementById('contextLastPage'),
pageRotateCw: document.getElementById('contextPageRotateCw'),
pageRotateCcw: document.getElementById('contextPageRotateCcw')
});
if (this.supportsFullscreen) {
var toolbar = SecondaryToolbar;
this.pdfPresentationMode = new PDFPresentationMode({
container: container,
viewer: viewer,
pdfThumbnailViewer: this.pdfThumbnailViewer,
contextMenuItems: [
{ element: document.getElementById('contextFirstPage'),
handler: toolbar.firstPageClick.bind(toolbar) },
{ element: document.getElementById('contextLastPage'),
handler: toolbar.lastPageClick.bind(toolbar) },
{ element: document.getElementById('contextPageRotateCw'),
handler: toolbar.pageRotateCwClick.bind(toolbar) },
{ element: document.getElementById('contextPageRotateCcw'),
handler: toolbar.pageRotateCcwClick.bind(toolbar) }
]
});
}
PasswordPrompt.initialize({
overlayName: 'passwordOverlay',
@ -318,8 +327,8 @@ var PDFViewerApplication = {
get supportsFullscreen() {
var doc = document.documentElement;
var support = doc.requestFullscreen || doc.mozRequestFullScreen ||
doc.webkitRequestFullScreen || doc.msRequestFullscreen;
var support = !!(doc.requestFullscreen || doc.mozRequestFullScreen ||
doc.webkitRequestFullScreen || doc.msRequestFullscreen);
if (document.fullscreenEnabled === false ||
document.mozFullScreenEnabled === false ||
@ -1334,72 +1343,21 @@ var PDFViewerApplication = {
this.pdfViewer.scrollPageIntoView(pageNumber);
},
/**
* This function flips the page in presentation mode if the user scrolls up
* or down with large enough motion and prevents page flipping too often.
*
* @this {PDFView}
* @param {number} mouseScrollDelta The delta value from the mouse event.
*/
mouseScroll: function pdfViewMouseScroll(mouseScrollDelta) {
var MOUSE_SCROLL_COOLDOWN_TIME = 50;
var currentTime = (new Date()).getTime();
var storedTime = this.mouseScrollTimeStamp;
// In case one page has already been flipped there is a cooldown time
// which has to expire before next page can be scrolled on to.
if (currentTime > storedTime &&
currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) {
requestPresentationMode: function pdfViewRequestPresentationMode() {
if (!this.pdfPresentationMode) {
return;
}
// In case the user decides to scroll to the opposite direction than before
// clear the accumulated delta.
if ((this.mouseScrollDelta > 0 && mouseScrollDelta < 0) ||
(this.mouseScrollDelta < 0 && mouseScrollDelta > 0)) {
this.clearMouseScrollState();
}
this.mouseScrollDelta += mouseScrollDelta;
var PAGE_FLIP_THRESHOLD = 120;
if (Math.abs(this.mouseScrollDelta) >= PAGE_FLIP_THRESHOLD) {
var PageFlipDirection = {
UP: -1,
DOWN: 1
};
// In presentation mode scroll one page at a time.
var pageFlipDirection = (this.mouseScrollDelta > 0) ?
PageFlipDirection.UP :
PageFlipDirection.DOWN;
this.clearMouseScrollState();
var currentPage = this.page;
// In case we are already on the first or the last page there is no need
// to do anything.
if ((currentPage === 1 && pageFlipDirection === PageFlipDirection.UP) ||
(currentPage === this.pagesCount &&
pageFlipDirection === PageFlipDirection.DOWN)) {
return;
}
this.page += pageFlipDirection;
this.mouseScrollTimeStamp = currentTime;
}
this.pdfPresentationMode.request();
},
/**
* This function clears the member attributes used with mouse scrolling in
* presentation mode.
*
* @this {PDFView}
* @param {number} delta - The delta value from the mouse event.
*/
clearMouseScrollState: function pdfViewClearMouseScrollState() {
this.mouseScrollTimeStamp = 0;
this.mouseScrollDelta = 0;
scrollPresentationMode: function pdfViewScrollPresentationMode(delta) {
if (!this.pdfPresentationMode) {
return;
}
this.pdfPresentationMode.mouseScroll(delta);
}
};
//#if GENERIC
@ -1976,11 +1934,12 @@ function handleMouseWheel(evt) {
evt.wheelDelta / MOUSE_WHEEL_DELTA_FACTOR;
var direction = (ticks < 0) ? 'zoomOut' : 'zoomIn';
if (PresentationMode.active) {
if (PDFViewerApplication.pdfViewer.isInPresentationMode) {
evt.preventDefault();
PDFViewerApplication.mouseScroll(ticks * MOUSE_WHEEL_DELTA_FACTOR);
PDFViewerApplication.scrollPresentationMode(ticks *
MOUSE_WHEEL_DELTA_FACTOR);
} else if (evt.ctrlKey || evt.metaKey) {
// Only zoom the pages, not the entire viewer
// Only zoom the pages, not the entire viewer.
evt.preventDefault();
PDFViewerApplication[direction](Math.abs(ticks));
}
@ -1990,15 +1949,9 @@ window.addEventListener('DOMMouseScroll', handleMouseWheel);
window.addEventListener('mousewheel', handleMouseWheel);
window.addEventListener('click', function click(evt) {
if (!PresentationMode.active) {
if (SecondaryToolbar.opened &&
if (SecondaryToolbar.opened &&
PDFViewerApplication.pdfViewer.containsElement(evt.target)) {
SecondaryToolbar.close();
}
} else if (evt.button === 0) {
// Necessary since preventDefault() in 'mousedown' won't stop
// the event propagation in all circumstances in presentation mode.
evt.preventDefault();
SecondaryToolbar.close();
}
}, false);
@ -2013,15 +1966,13 @@ window.addEventListener('keydown', function keydown(evt) {
(evt.shiftKey ? 4 : 0) |
(evt.metaKey ? 8 : 0);
var pdfViewer = PDFViewerApplication.pdfViewer;
var isViewerInPresentationMode = pdfViewer && pdfViewer.isInPresentationMode;
// First, handle the key bindings that are independent whether an input
// control is selected or not.
if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) {
// either CTRL or META key with optional SHIFT.
var pdfViewer = PDFViewerApplication.pdfViewer;
var inPresentationMode = pdfViewer &&
(pdfViewer.presentationModeState === PresentationModeState.CHANGING ||
pdfViewer.presentationModeState === PresentationModeState.FULLSCREEN);
switch (evt.keyCode) {
case 70: // f
if (!PDFViewerApplication.supportsIntegratedFind) {
@ -2040,7 +1991,7 @@ window.addEventListener('keydown', function keydown(evt) {
case 107: // FF '+' and '='
case 187: // Chrome '+'
case 171: // FF with German keyboard
if (!inPresentationMode) {
if (!isViewerInPresentationMode) {
PDFViewerApplication.zoomIn();
}
handled = true;
@ -2048,14 +1999,14 @@ window.addEventListener('keydown', function keydown(evt) {
case 173: // FF/Mac '-'
case 109: // FF '-'
case 189: // Chrome '-'
if (!inPresentationMode) {
if (!isViewerInPresentationMode) {
PDFViewerApplication.zoomOut();
}
handled = true;
break;
case 48: // '0'
case 96: // '0' on Numpad of Swedish keyboard
if (!inPresentationMode) {
if (!isViewerInPresentationMode) {
// keeping it unhandled (to restore page zoom to 100%)
setTimeout(function () {
// ... and resetting the scale after browser adjusts its scale
@ -2083,7 +2034,7 @@ window.addEventListener('keydown', function keydown(evt) {
if (cmd === 3 || cmd === 10) {
switch (evt.keyCode) {
case 80: // p
SecondaryToolbar.presentationModeClick();
PDFViewerApplication.requestPresentationMode();
handled = true;
break;
case 71: // g
@ -2117,15 +2068,15 @@ window.addEventListener('keydown', function keydown(evt) {
case 38: // up arrow
case 33: // pg up
case 8: // backspace
if (!PresentationMode.active &&
PDFViewerApplication.currentScaleValue !== 'page-fit') {
if (!isViewerInPresentationMode &&
PDFViewerApplication.currentScaleValue !== 'page-fit') {
break;
}
/* in presentation mode */
/* falls through */
case 37: // left arrow
// horizontal scrolling using arrow keys
if (PDFViewerApplication.pdfViewer.isHorizontalScrollbarEnabled) {
if (pdfViewer.isHorizontalScrollbarEnabled) {
break;
}
/* falls through */
@ -2148,14 +2099,14 @@ window.addEventListener('keydown', function keydown(evt) {
case 40: // down arrow
case 34: // pg down
case 32: // spacebar
if (!PresentationMode.active &&
if (!isViewerInPresentationMode &&
PDFViewerApplication.currentScaleValue !== 'page-fit') {
break;
}
/* falls through */
case 39: // right arrow
// horizontal scrolling using arrow keys
if (PDFViewerApplication.pdfViewer.isHorizontalScrollbarEnabled) {
if (pdfViewer.isHorizontalScrollbarEnabled) {
break;
}
/* falls through */
@ -2166,13 +2117,13 @@ window.addEventListener('keydown', function keydown(evt) {
break;
case 36: // home
if (PresentationMode.active || PDFViewerApplication.page > 1) {
if (isViewerInPresentationMode || PDFViewerApplication.page > 1) {
PDFViewerApplication.page = 1;
handled = true;
}
break;
case 35: // end
if (PresentationMode.active || (PDFViewerApplication.pdfDocument &&
if (isViewerInPresentationMode || (PDFViewerApplication.pdfDocument &&
PDFViewerApplication.page < PDFViewerApplication.pagesCount)) {
PDFViewerApplication.page = PDFViewerApplication.pagesCount;
handled = true;
@ -2180,7 +2131,7 @@ window.addEventListener('keydown', function keydown(evt) {
break;
case 72: // 'h'
if (!PresentationMode.active) {
if (!isViewerInPresentationMode) {
HandTool.toggle();
}
break;
@ -2193,7 +2144,7 @@ window.addEventListener('keydown', function keydown(evt) {
if (cmd === 4) { // shift-key
switch (evt.keyCode) {
case 32: // spacebar
if (!PresentationMode.active &&
if (!isViewerInPresentationMode &&
PDFViewerApplication.currentScaleValue !== 'page-fit') {
break;
}
@ -2207,25 +2158,25 @@ window.addEventListener('keydown', function keydown(evt) {
}
}
if (!handled && !PresentationMode.active) {
if (!handled && !isViewerInPresentationMode) {
// 33=Page Up 34=Page Down 35=End 36=Home
// 37=Left 38=Up 39=Right 40=Down
if (evt.keyCode >= 33 && evt.keyCode <= 40 &&
!PDFViewerApplication.pdfViewer.containsElement(curElement)) {
!pdfViewer.containsElement(curElement)) {
// The page container is not focused, but a page navigation key has been
// pressed. Change the focus to the viewer container to make sure that
// navigation by keyboard works as expected.
PDFViewerApplication.pdfViewer.focus();
pdfViewer.focus();
}
// 32=Spacebar
if (evt.keyCode === 32 && curElementTagName !== 'BUTTON') {
//#if (FIREFOX || MOZCENTRAL)
// // Workaround for issue in Firefox, that prevents scroll keys from
// // working when elements with 'tabindex' are focused. (#3498)
// PDFViewerApplication.pdfViewer.blur();
// pdfViewer.blur();
//#else
if (!PDFViewerApplication.pdfViewer.containsElement(curElement)) {
PDFViewerApplication.pdfViewer.focus();
if (!pdfViewer.containsElement(curElement)) {
pdfViewer.focus();
}
//#endif
}
@ -2234,13 +2185,13 @@ window.addEventListener('keydown', function keydown(evt) {
if (cmd === 2) { // alt-key
switch (evt.keyCode) {
case 37: // left arrow
if (PresentationMode.active) {
if (isViewerInPresentationMode) {
PDFHistory.back();
handled = true;
}
break;
case 39: // right arrow
if (PresentationMode.active) {
if (isViewerInPresentationMode) {
PDFHistory.forward();
handled = true;
}
@ -2250,7 +2201,6 @@ window.addEventListener('keydown', function keydown(evt) {
if (handled) {
evt.preventDefault();
PDFViewerApplication.clearMouseScrollState();
}
});