@ -18,9 +18,9 @@
@@ -18,9 +18,9 @@
'use strict' ;
var DELAY _BEFORE _RESETTING _SWITCH _IN _PROGRESS = 1500 ; // in ms
var DELAY _BEFORE _HIDING _CONTROLS = 3000 ; // in ms
var SELECTOR = 'presentationControls' ;
var DELAY _BEFORE _RESETTING _SWITCH _IN _PROGRESS = 1000 ; // in ms
/ * *
* @ typedef { Object } PDFPresentationModeOptions
@ -32,30 +32,25 @@ var DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS = 1000; // in ms
@@ -32,30 +32,25 @@ var DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS = 1000; // in ms
* to the context menu in Presentation Mode .
* /
var PDFPresentationMode = {
initialized : false ,
active : false ,
args : null ,
contextMenuOpen : false ,
mouseScrollTimeStamp : 0 ,
mouseScrollDelta : 0 ,
/ * *
* @ class
* /
var PDFPresentationMode = ( function PDFPresentationModeClosure ( ) {
/ * *
* @ constructs PDFPresentationMode
* @ param { PDFPresentationModeOptions } options
* /
initialize : function pdfPresentationModeInitialize ( options ) {
this . initialized = true ;
function PDFPresentationMode ( options ) {
this . container = options . container ;
this . viewer = options . viewer || options . container . firstElementChild ;
this . pdfThumbnailViewer = options . pdfThumbnailViewer || null ;
var contextMenuItems = options . contextMenuItems || null ;
window . addEventListener ( 'fullscreenchange' , this . _fullscreenChange ) ;
window . addEventListener ( 'mozfullscreenchange' , this . _fullscreenChange ) ;
//#if !(FIREFOX || MOZCENTRAL)
window . addEventListener ( 'webkitfullscreenchange' , this . _fullscreenChange ) ;
window . addEventListener ( 'MSFullscreenChange' , this . _fullscreenChange ) ;
//#endif
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 ++ ) {
@ -66,276 +61,336 @@ var PDFPresentationMode = {
@@ -66,276 +61,336 @@ var PDFPresentationMode = {
} . bind ( this , item . handler ) ) ;
}
}
} ,
/ * *
* Request the browser to enter fullscreen mode .
* @ returns { boolean } Indicating if the request was successful .
* /
request : function pdfPresentationModeRequest ( ) {
if ( ! this . initialized || this . switchInProgress || this . active ||
! 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 ;
} ,
/ * *
* 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 pdfPresentationModeMouseScroll ( delta ) {
if ( ! this . initialized && ! 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 page again.
if ( currentTime > storedTime &&
currentTime - storedTime < MOUSE _SCROLL _COOLDOWN _TIME ) {
return ;
}
// If the user changes scroll direction, 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 already on the first/last page, we don't need to do anything.
if ( ( page === 1 && pageSwitchDirection === PageSwitchDirection . UP ) ||
( page === PDFViewerApplication . pagesCount &&
pageSwitchDirection === PageSwitchDirection . DOWN ) ) {
return ;
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 ;
}
PDFViewerApplication . page = ( page + pageSwitchDirection ) ;
this . mouseScrollTimeStamp = currentTime ;
}
} ,
get isFullscreen ( ) {
return ! ! ( document . fullscreenElement ||
document . mozFullScreen ||
document . webkitIsFullScreen ||
document . msFullscreenElement ) ;
} ,
/ * *
* @ private
* /
_fullscreenChange : function pdfPresentationModeFullscreenChange ( ) {
var self = PDFPresentationMode ;
if ( self . isFullscreen ) {
self . _enter ( ) ;
} else {
self . _exit ( ) ;
}
} ,
/ * *
* @ private
* /
_notifyStateChange : function pdfPresentationModeNotifyStateChange ( ) {
var self = PDFPresentationMode ;
var event = document . createEvent ( 'CustomEvent' ) ;
event . initCustomEvent ( 'presentationmodechanged' , true , true , {
active : self . active ,
switchInProgress : ! ! self . 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 ( ) {
delete this . switchInProgress ;
this . _addFullscreenChangeListeners ( ) ;
this . _setSwitchInProgress ( ) ;
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 pdfPresentationModeEnter ( ) {
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.
setTimeout ( function enterPresentationModeTimeout ( ) {
PDFViewerApplication . page = this . args . page ;
PDFViewerApplication . setScale ( 'page-fit' , true ) ;
} . bind ( this ) , 0 ) ;
window . addEventListener ( 'mousemove' , this . _showControls , false ) ;
window . addEventListener ( 'mousedown' , this . _mouseDown , false ) ;
window . addEventListener ( 'keydown' , this . _resetMouseScrollState , false ) ;
window . addEventListener ( 'contextmenu' , this . _contextMenu , false ) ;
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 pdfPresentationModeExit ( ) {
var page = PDFViewerApplication . page ;
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 ;
}
// 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 . 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 ( ) ;
PDFViewerApplication . setScale ( this . args . previousScale , true ) ;
PDFViewerApplication . page = page ;
this . args = null ;
} . bind ( this ) , 0 ) ;
// 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 ;
window . removeEventListener ( 'mousemove' , this . _showControls , false ) ;
window . removeEventListener ( 'mousedown' , this . _mouseDown , false ) ;
window . removeEventListener ( 'keydown' , this . _resetMouseScrollState , false ) ;
window . removeEventListener ( 'contextmenu' , this . _contextMenu , false ) ;
// 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 ( ) ;
this . _hideControls ( ) ;
this . _resetMouseScrollState ( ) ;
this . container . removeAttribute ( 'contextmenu' ) ;
this . contextMenuOpen = false ;
PDFViewerApplication . setScale ( this . args . previousScale , true ) ;
PDFViewerApplication . page = page ;
this . args = null ;
} . bind ( this ) , 0 ) ;
if ( this . pdfThumbnailViewer ) {
this . pdfThumbnailViewer . ensureThumbnailVisible ( page ) ;
}
} ,
this . _removeWindowListeners ( ) ;
this . _hideControls ( ) ;
this . _resetMouseScrollState ( ) ;
this . container . removeAttribute ( 'contextmenu' ) ;
this . contextMenuOpen = false ;
/ * *
* @ private
* /
_mouseDown : function pdfPresentationModeMouseDown ( evt ) {
var self = PDFPresentationMode ;
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.
if ( this . pdfThumbnailViewer ) {
this . pdfThumbnailViewer . ensureThumbnailVisible ( page ) ;
}
} ,
/ * *
* @ private
* /
_mouseDown : function PDFPresentationMode _mouseDown ( evt ) {
if ( this . contextMenuOpen ) {
this . contextMenuOpen = false ;
evt . preventDefault ( ) ;
PDFViewerApplication . page += ( evt . shiftKey ? - 1 : 1 ) ;
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 ( SELECTOR ) ;
}
this . controlsTimeout = setTimeout ( function showControlsTimeout ( ) {
this . container . classList . remove ( 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 ( 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
* /
_contextMenu : function pdfPresentationModeContextMenu ( evt ) {
PDFPresentationMode . contextMenuOpen = true ;
} ,
/ * *
* @ private
* /
_addFullscreenChangeListeners :
function PDFPresentationMode _addFullscreenChangeListeners ( ) {
this . fullscreenChangeBind = this . _fullscreenChange . bind ( this ) ;
/ * *
* @ private
* /
_showControls : function pdfPresentationModeShowControls ( ) {
var self = PDFPresentationMode ;
if ( self . controlsTimeout ) {
clearTimeout ( self . controlsTimeout ) ;
} else {
self . container . classList . add ( SELECTOR ) ;
}
self . controlsTimeout = setTimeout ( function showControlsTimeout ( ) {
self . container . classList . remove ( SELECTOR ) ;
delete self . controlsTimeout ;
} , DELAY _BEFORE _HIDING _CONTROLS ) ;
} ,
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
/ * *
* @ private
* /
_hideControls : function pdfPresentationModeHideControls ( ) {
var self = PDFPresentationMode ;
if ( ! self . controlsTimeout ) {
return ;
delete this . fullscreenChangeBind ;
}
clearTimeout ( self . controlsTimeout ) ;
self . container . classList . remove ( SELECTOR ) ;
delete self . controlsTimeout ;
} ,
} ;
/ * *
* Resets the properties used for tracking mouse scrolling events .
* @ private
* /
_resetMouseScrollState : function pdfPresentationModeResetMouseScrollState ( ) {
var self = PDFPresentationMode ;
self . mouseScrollTimeStamp = 0 ;
self . mouseScrollDelta = 0 ;
}
} ;
return PDFPresentationMode ;
} ) ( ) ;