2013-03-31 09:41:38 +00:00
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab filetype=javascript : */
2013-10-22 07:03:07 +00:00
/** @license pdf2htmlEX.js * Copyright 2012,2013 Lu Wang <coolwanglu@gmail.com> and other contributors * https://github.com/coolwanglu/pdf2htmlex * https://github.com/coolwanglu/pdf2htmlEX/blob/master/share/LICENSE */
2012-09-22 14:47:44 +00:00
/ *
2013-10-22 07:03:07 +00:00
* pdf2htmlEX . js : a simple UI for pdf2htmlEX
2012-09-22 14:47:44 +00:00
*
2013-10-19 07:06:32 +00:00
* Copyright 2012 , 2013 Lu Wang < coolwanglu @ gmail . com > and other contributors
* /
/ *
* Dependencies :
* jQuery
2012-09-22 14:47:44 +00:00
* /
2013-10-20 08:35:31 +00:00
/ *
* Attention :
* This files is to be optimized by closure - compiler ,
* so pay attention to the forms of property names :
*
* string / bracket form is safe , won ' t be optimized :
* var obj = { 'a' : 'b' } ; obj [ 'a' ] = 'b' ;
* name / dot form will be optimized , the name is likely to be modified :
* var obj = { a : 'b' } ; obj . a = 'b' ;
*
* Either form can be used for internal objects ,
* but must be consistent for each one respectively .
*
* string / bracket form must be used for external objects
* e . g . DEFAULT _CONFIG , object stored in page - data
* property names are part of the ` protocol ` in these cases .
*
* /
2013-05-29 18:31:48 +00:00
'use strict' ;
2013-09-30 07:50:15 +00:00
/* The namespace */
2013-10-19 07:06:32 +00:00
( function ( pdf2htmlEX ) {
2013-10-22 13:32:02 +00:00
/ * *
* @ const
* @ struct
* /
2013-10-22 07:03:07 +00:00
var CSS _CLASS _NAMES = {
page _frame : '@CSS_PAGE_FRAME_CN@' ,
page _decoration : '@CSS_PAGE_DECORATION_CN@' ,
page _content _box : '@CSS_PAGE_CONTENT_BOX_CN@' ,
page _data : '@CSS_PAGE_DATA_CN@' ,
background _image : '@CSS_BACKGROUND_IMAGE_CN@' ,
link : '@CSS_LINK_CN@' ,
_ _dummy _ _ : 'no comma'
} ;
2013-09-30 07:50:15 +00:00
2013-10-22 13:32:02 +00:00
/ * *
* @ const
* @ dict
* /
2013-10-05 08:11:03 +00:00
var DEFAULT _CONFIG = {
// id of the element to put the pages in
2013-10-19 07:06:32 +00:00
'container_id' : 'page-container' ,
2013-10-05 08:11:03 +00:00
// id of the element for sidebar (to open and close)
2013-10-19 07:06:32 +00:00
'sidebar_id' : 'sidebar' ,
2013-10-05 08:11:03 +00:00
// id of the element for outline
2013-10-19 07:06:32 +00:00
'outline_id' : 'outline' ,
2013-10-05 08:11:03 +00:00
// class for the loading indicator
2013-10-20 08:35:31 +00:00
'loading_indicator_cls' : 'loading-indicator' ,
2013-10-05 08:11:03 +00:00
// How many page shall we preload that are below the last visible page
2013-10-19 07:06:32 +00:00
'preload_pages' : 3 ,
2013-10-05 08:11:03 +00:00
// Smooth zoom is enabled when the number of pages shown is less than the threshold
// Otherwise page content is hidden and redrawn after a delay (function schedule_render).
// 0: disable smooth zoom optimizations (less CPU usage but flickering on zoom)
2013-10-19 07:06:32 +00:00
'smooth_zoom_threshold' : 4 ,
2013-10-05 08:26:24 +00:00
// how many ms should we wait before actually rendering the pages and after a scroll event
2013-10-19 07:06:32 +00:00
'render_timeout' : 100 ,
2013-10-05 08:26:24 +00:00
// zoom ratio step for each zoom in/out event
2013-10-19 07:06:32 +00:00
'scale_step' : 0.9 ,
2013-09-30 07:50:15 +00:00
2013-10-22 13:32:02 +00:00
'__dummy__' : 'no comma'
2013-10-05 08:11:03 +00:00
} ;
2012-09-25 16:27:58 +00:00
2013-10-22 07:03:07 +00:00
/** @const */
2012-09-23 09:26:12 +00:00
var EPS = 1e-6 ;
2013-10-22 13:32:02 +00:00
function invert ( ctm ) {
2012-09-25 11:29:59 +00:00
var det = ctm [ 0 ] * ctm [ 3 ] - ctm [ 1 ] * ctm [ 2 ] ;
2013-10-22 13:32:02 +00:00
return [ ctm [ 3 ] / det
, - ctm [ 1 ] / det
, - ctm [ 2 ] / det
, ctm [ 0 ] / det
, ( ctm [ 2 ] * ctm [ 5 ] - ctm [ 3 ] * ctm [ 4 ] ) / det
, ( ctm [ 1 ] * ctm [ 4 ] - ctm [ 0 ] * ctm [ 5 ] ) / det
] ;
2012-09-25 11:29:59 +00:00
} ;
2013-10-22 13:32:02 +00:00
function transform ( ctm , pos ) {
2012-09-25 11:29:59 +00:00
return [ ctm [ 0 ] * pos [ 0 ] + ctm [ 2 ] * pos [ 1 ] + ctm [ 4 ]
, ctm [ 1 ] * pos [ 0 ] + ctm [ 3 ] * pos [ 1 ] + ctm [ 5 ] ] ;
} ;
2013-10-22 07:03:07 +00:00
/ * *
* @ constructor
* @ struct
* /
2013-10-22 13:32:02 +00:00
function Page ( page , container ) {
if ( ! page ) return ;
2012-09-25 11:29:59 +00:00
2013-06-12 15:53:14 +00:00
this . loaded = false ;
2013-07-16 15:42:02 +00:00
this . shown = false ;
2013-06-13 15:00:42 +00:00
this . $p = $ ( page ) ;
this . $container = $ ( container ) ;
2013-06-12 15:53:14 +00:00
2013-06-13 15:00:42 +00:00
this . n = parseInt ( this . $p . data ( 'page-no' ) , 16 ) ;
2013-10-20 08:35:31 +00:00
this . $b = $ ( '.' + CSS _CLASS _NAMES . page _content _box , this . $p ) ;
this . $d = this . $p . parent ( '.' + CSS _CLASS _NAMES . page _decoration ) ;
2013-06-12 15:53:14 +00:00
2013-09-30 07:50:15 +00:00
// page size
// Need to make rescale work when page_content_box is not loaded, yet
this . h = this . $p . height ( ) ;
2013-06-13 15:00:42 +00:00
this . w = this . $p . width ( ) ;
2012-09-25 11:29:59 +00:00
2013-06-12 15:53:14 +00:00
// if page is loaded
2013-06-13 15:00:42 +00:00
if ( this . $b . length > 0 ) {
2013-06-12 15:53:14 +00:00
/ *
* scale ratios
*
* default _r : the first one
* set _r : last set
* cur _r : currently using
* /
2013-07-16 18:19:25 +00:00
this . default _r = this . set _r = this . cur _r = this . h / this . $b . height ( ) ;
2013-10-20 08:35:31 +00:00
this . page _data = $ ( $ ( '.' + CSS _CLASS _NAMES . page _data , this . $p ) [ 0 ] ) . data ( 'data' ) ;
2012-09-25 11:29:59 +00:00
2013-10-20 08:35:31 +00:00
this . ctm = this . page _data [ 'ctm' ] ;
2013-06-12 15:53:14 +00:00
this . ictm = invert ( this . ctm ) ;
this . loaded = true ;
}
2012-09-23 09:26:12 +00:00
} ;
2013-10-22 07:03:07 +00:00
$ . extend ( Page . prototype , /** @lends {Page.prototype} */ {
2013-02-06 11:52:34 +00:00
/* hide & show are for contents, the page frame is still there */
2012-09-25 16:27:58 +00:00
hide : function ( ) {
2013-06-13 15:00:42 +00:00
this . $b . removeClass ( 'opened' ) ;
2013-07-16 15:42:02 +00:00
this . shown = false ;
2012-09-25 16:27:58 +00:00
} ,
show : function ( ) {
2013-07-16 18:19:25 +00:00
if ( this . loaded ) {
if ( Math . abs ( this . set _r - this . cur _r ) > EPS ) {
this . cur _r = this . set _r ;
this . $b . css ( 'transform' , 'scale(' + this . cur _r . toFixed ( 3 ) + ')' ) ;
}
if ( ! this . shown ) {
this . $b . addClass ( 'opened' ) ;
this . shown = true ;
}
2012-09-25 16:27:58 +00:00
}
} ,
2013-07-16 18:19:25 +00:00
rescale : function ( ratio , keep _shown ) {
2012-09-25 16:27:58 +00:00
if ( ratio == 0 ) {
this . set _r = this . default _r ;
} else {
this . set _r = ratio ;
}
2012-09-23 05:04:29 +00:00
2013-07-17 07:47:13 +00:00
if ( keep _shown )
this . show ( ) ; // Refresh content
else
this . hide ( ) ; // Wait for redraw
2012-09-25 13:56:48 +00:00
2013-07-16 18:19:25 +00:00
this . $d . height ( this . h * this . set _r ) ;
this . $d . width ( this . w * this . set _r ) ;
2012-09-25 16:27:58 +00:00
} ,
2013-05-02 08:45:00 +00:00
/* return if any part of this page is shown in the container */
2012-09-25 16:27:58 +00:00
is _visible : function ( ) {
var off = this . position ( ) ;
2013-07-16 18:19:25 +00:00
return ! ( ( off [ 1 ] > this . h ) || ( off [ 1 ] + this . $container . height ( ) < 0 ) ) ;
2012-09-25 16:27:58 +00:00
} ,
2013-05-02 08:45:00 +00:00
/* return if this page or any neighbor of it is visible */
is _nearly _visible : function ( ) {
var off = this . position ( ) ;
/ * I s h o u l d u s e t h e h e i g h t o f t h e p r e v i o u s p a g e o r t h e n e x t p a g e h e r e
* but since they are not easily available , just use '*2' , which should be a good estimate in most cases
* /
2013-07-16 18:19:25 +00:00
return ! ( ( off [ 1 ] > this . h * 2 ) || ( off [ 1 ] + this . $container . height ( ) * 2 < 0 ) ) ;
2013-05-02 08:45:00 +00:00
} ,
2012-09-25 16:27:58 +00:00
/ * r e t u r n t h e c o o r d i n a t e o f t h e t o p - l e f t c o r n e r o f c o n t a i n e r
2013-08-08 22:53:44 +00:00
* in our coordinate system
2012-09-25 16:27:58 +00:00
* /
position : function ( ) {
2013-06-13 15:00:42 +00:00
var off = this . $p . offset ( ) ;
var off _c = this . $container . offset ( ) ;
2012-09-25 16:27:58 +00:00
return [ off _c . left - off . left , off _c . top - off . top ] ;
}
} ) ;
2012-09-23 05:04:29 +00:00
2013-10-22 07:03:07 +00:00
/ * *
* export pdf2htmlEX . Viewer
* @ constructor
* /
2013-10-22 13:32:02 +00:00
function Viewer ( config ) {
2013-10-21 07:04:34 +00:00
/* do nothing if jQuery is not ready */
if ( ! window . jQuery ) return ;
2013-10-05 08:11:03 +00:00
this . config = $ . extend ( { } , DEFAULT _CONFIG , config ) ;
2013-10-28 08:05:24 +00:00
this . pages _loading = [ ] ;
2012-09-25 14:40:21 +00:00
this . init _before _loading _content ( ) ;
2012-09-23 05:04:29 +00:00
2012-09-25 14:40:21 +00:00
var _ = this ;
$ ( function ( ) { _ . init _after _loading _content ( ) ; } ) ;
} ;
2013-10-22 07:03:07 +00:00
$ . extend ( Viewer . prototype , /** @lends {Viewer.prototype} */ {
2013-07-16 15:42:02 +00:00
scale : 1 ,
2012-09-23 05:04:29 +00:00
2012-09-23 09:26:12 +00:00
init _before _loading _content : function ( ) {
/*hide all pages before loading, will reveal only visible ones later */
this . pre _hide _pages ( ) ;
} ,
2013-06-13 15:00:42 +00:00
2012-09-23 09:26:12 +00:00
init _after _loading _content : function ( ) {
2013-10-05 08:11:03 +00:00
this . $sidebar = $ ( '#' + this . config [ 'sidebar_id' ] ) ;
this . $outline = $ ( '#' + this . config [ 'outline_id' ] ) ;
this . $container = $ ( '#' + this . config [ 'container_id' ] ) ;
this . $loading _indicator = $ ( '.' + this . config [ 'loading_indicator_cls' ] ) ;
2012-09-23 05:04:29 +00:00
2013-03-01 06:02:11 +00:00
// Open the outline if nonempty
2013-07-16 15:42:02 +00:00
if ( this . $outline . children ( ) . length > 0 ) {
2013-06-13 15:00:42 +00:00
this . $sidebar . addClass ( 'opened' ) ;
2013-01-28 14:11:42 +00:00
}
2013-06-12 15:53:14 +00:00
2013-05-02 08:09:42 +00:00
this . find _pages ( ) ;
2012-09-23 05:04:29 +00:00
2013-03-01 06:02:11 +00:00
// register schedule rendering
2012-09-23 09:26:12 +00:00
var _ = this ;
2013-06-13 15:00:42 +00:00
this . $container . scroll ( function ( ) { _ . schedule _render ( ) ; } ) ;
2012-09-23 05:04:29 +00:00
2013-10-06 11:53:37 +00:00
//this.register_key_handler();
2013-07-03 07:57:00 +00:00
2013-03-01 06:02:11 +00:00
// handle links
2013-10-20 08:35:31 +00:00
this . $container . add ( this . $outline ) . on ( 'click' , '.' + CSS _CLASS _NAMES . link , this , this . link _handler ) ;
2012-09-23 05:04:29 +00:00
2012-09-23 09:26:12 +00:00
this . render ( ) ;
2013-05-02 08:09:42 +00:00
} ,
2013-07-16 15:42:02 +00:00
2013-10-28 08:05:24 +00:00
/ *
* set up this . pages and this . page _map
* pages is an array holding all the Page objects
* page - Map maps an original page number ( in PDF ) to the corresponding index in page
* /
2013-05-02 08:09:42 +00:00
find _pages : function ( ) {
2013-10-28 08:05:24 +00:00
var new _pages = [ ] ;
var new _page _map = { } ;
2013-10-20 08:35:31 +00:00
var $pl = $ ( '.' + CSS _CLASS _NAMES . page _frame , this . $container ) ;
2013-09-30 07:50:15 +00:00
/* don't use for(..in..) since $pl is more than an Array */
2013-06-13 15:00:42 +00:00
for ( var i = 0 , l = $pl . length ; i < l ; ++ i ) {
var p = new Page ( $pl [ i ] , this . $container ) ;
2013-10-28 08:05:24 +00:00
new _pages . push ( p ) ;
new _page _map [ p . n ] = p ;
2013-05-02 08:09:42 +00:00
}
this . pages = new _pages ;
2013-10-28 08:05:24 +00:00
this . page _map = new _page _map ;
2013-05-02 08:09:42 +00:00
} ,
2013-06-13 15:00:42 +00:00
2013-06-13 10:39:52 +00:00
load _page : function ( idx , pages _to _preload , successCallback , errorCallback ) {
if ( idx >= this . pages . length )
return ; // Page does not exist
if ( this . pages [ idx ] . loaded )
2013-06-12 15:53:14 +00:00
return ; // Page is loaded
2013-06-13 10:39:52 +00:00
if ( this . pages _loading [ idx ] )
2013-06-12 15:53:14 +00:00
return ; // Page is already loading
2013-06-13 10:39:52 +00:00
var page _no _hex = idx . toString ( 16 ) ;
2013-10-20 08:35:31 +00:00
var $pf = this . $container . find ( '#' + CSS _CLASS _NAMES . page _frame + page _no _hex ) ;
2013-06-12 15:53:14 +00:00
if ( $pf . length == 0 )
return ; // Page does not exist
2013-09-28 05:20:45 +00:00
this . $loading _indicator . clone ( ) . show ( ) . appendTo ( $pf ) ;
2013-09-28 03:58:01 +00:00
2013-06-12 15:53:14 +00:00
var _ = this ;
var url = $pf . data ( 'page-url' ) ;
if ( url && url . length > 0 ) {
2013-06-13 10:39:52 +00:00
this . pages _loading [ idx ] = true ; // Set semaphore
2013-06-12 15:53:14 +00:00
2013-05-02 08:09:42 +00:00
$ . ajax ( {
2013-06-12 15:53:14 +00:00
url : url ,
2013-05-02 08:09:42 +00:00
dataType : 'text'
} ) . done ( function ( data ) {
2013-10-07 07:25:47 +00:00
// replace the old page with loaded data
// the loading indicator on this page should also be destroyed
2013-10-06 11:53:37 +00:00
_ . pages [ idx ] . $d . replaceWith ( data ) ;
2013-06-12 15:53:14 +00:00
2013-10-20 08:35:31 +00:00
var $new _pf = _ . $container . find ( '#' + CSS _CLASS _NAMES . page _frame + page _no _hex ) ;
2013-10-06 11:53:37 +00:00
_ . pages [ idx ] = new Page ( $new _pf , _ . $container ) ;
_ . pages [ idx ] . hide ( ) ;
_ . pages [ idx ] . rescale ( _ . scale ) ;
_ . schedule _render ( ) ;
2013-06-12 15:53:14 +00:00
2013-10-06 11:53:37 +00:00
// disable background image dragging
2013-10-20 08:35:31 +00:00
$new _pf . find ( '.' + CSS _CLASS _NAMES . background _image ) . on ( 'dragstart' , function ( e ) { return false ; } ) ;
2013-06-12 15:53:14 +00:00
2013-10-06 11:53:37 +00:00
// Reset loading token
delete _ . pages _loading [ idx ] ;
2013-06-12 15:53:14 +00:00
2013-10-06 11:53:37 +00:00
if ( successCallback ) successCallback ( ) ;
}
2013-06-13 10:39:52 +00:00
) . fail ( function ( jqXHR , textStatus , errorThrown ) {
// Reset loading token
delete _ . pages _loading [ idx ] ;
if ( errorCallback ) errorCallback ( ) ;
} ) ;
2013-05-02 08:09:42 +00:00
}
2013-06-12 15:53:14 +00:00
// Concurrent prefetch of the next pages
if ( pages _to _preload === undefined )
2013-10-05 08:11:03 +00:00
pages _to _preload = this . config [ 'preload_pages' ] ;
2013-06-12 15:53:14 +00:00
if ( -- pages _to _preload > 0 )
_ . load _page ( idx + 1 , pages _to _preload ) ;
2012-09-23 09:26:12 +00:00
} ,
2013-06-13 15:00:42 +00:00
2012-09-23 09:26:12 +00:00
pre _hide _pages : function ( ) {
/* pages might have not been loaded yet, so add a CSS rule */
2013-10-20 08:35:31 +00:00
var s = '@media screen{.' + CSS _CLASS _NAMES . page _content _box + '{display:none;}}' ;
2012-09-25 11:29:59 +00:00
var n = document . createElement ( 'style' ) ;
n . type = 'text/css' ;
2012-09-23 09:26:12 +00:00
if ( n . styleSheet ) {
n . styleSheet . cssText = s ;
} else {
n . appendChild ( document . createTextNode ( s ) ) ;
}
2012-09-25 11:29:59 +00:00
document . getElementsByTagName ( 'head' ) [ 0 ] . appendChild ( n ) ;
2012-09-23 09:26:12 +00:00
} ,
hide _pages : function ( ) {
var pl = this . pages ;
2013-10-28 08:05:24 +00:00
for ( var i = 0 , l = pl . length ; i < l ; ++ i )
2012-09-23 09:26:12 +00:00
pl [ i ] . hide ( ) ;
} ,
render : function ( ) {
/* hide (positional) invisible pages */
var pl = this . pages ;
2013-10-28 08:05:24 +00:00
for ( var i = 0 , l = pl . length ; i < l ; ++ i ) {
2012-09-23 09:26:12 +00:00
var p = pl [ i ] ;
2013-05-02 08:45:00 +00:00
if ( p . is _nearly _visible ( ) ) {
2013-06-12 15:53:14 +00:00
if ( p . loaded ) {
p . show ( ) ;
} else
2013-06-13 10:39:52 +00:00
this . load _page ( p . n ) ;
2012-09-25 13:56:48 +00:00
} else {
2012-09-25 11:29:59 +00:00
p . hide ( ) ;
2012-09-25 13:56:48 +00:00
}
2012-09-22 14:47:44 +00:00
}
2012-09-23 09:26:12 +00:00
} ,
schedule _render : function ( ) {
if ( this . render _timer )
clearTimeout ( this . render _timer ) ;
var _ = this ;
this . render _timer = setTimeout ( function ( ) {
_ . render ( ) ;
2013-10-05 08:26:24 +00:00
} , this . config [ 'render_timeout' ] ) ;
2012-09-23 09:26:12 +00:00
} ,
2013-10-06 11:53:37 +00:00
/ *
* Handling key events , zooming , scrolling etc .
* /
register _key _handler : function ( ) {
2012-09-23 09:26:12 +00:00
/ *
* When user try to zoom in /out using ctrl + +/ - or mouse wheel
* handle this and prevent the default behaviours
*
* Code credit to PDF . js
* /
var _ = this ;
// Firefox specific event, so that we can prevent browser from zooming
$ ( window ) . on ( 'DOMMouseScroll' , function ( e ) {
if ( e . ctrlKey ) {
e . preventDefault ( ) ;
2013-10-05 08:26:24 +00:00
_ . rescale ( Math . pow ( _ . config [ 'scale_step' ] , e . detail ) , true ) ;
2012-09-23 09:26:12 +00:00
}
} ) ;
$ ( window ) . on ( 'keydown' , function keydown ( e ) {
2013-10-06 11:53:37 +00:00
var handled = false ;
2013-10-22 13:32:02 +00:00
var cmd = ( e . ctrlKey ? 1 : 0 )
| ( e . altKey ? 2 : 0 )
| ( e . shiftKey ? 4 : 0 )
| ( e . metaKey ? 8 : 0 )
;
2013-10-06 11:53:37 +00:00
var with _ctrl = ( cmd == 9 ) ;
var with _alt = ( cmd == 2 ) ;
switch ( e . keyCode ) {
case 61 : // FF/Mac '='
case 107 : // FF '+' and '='
case 187 : // Chrome '+'
if ( with _ctrl ) {
2013-10-05 08:26:24 +00:00
_ . rescale ( 1.0 / _ . config [ 'scale_step' ] , true ) ;
2013-10-06 11:53:37 +00:00
handled = true ;
}
break ;
case 173 : // FF/Mac '-'
case 109 : // FF '-'
case 189 : // Chrome '-'
if ( with _ctrl ) {
2013-10-05 08:26:24 +00:00
_ . rescale ( _ . config [ 'scale_step' ] , true ) ;
2013-10-06 11:53:37 +00:00
handled = true ;
}
break ;
case 48 : // '0'
if ( with _ctrl ) {
2012-09-23 09:26:12 +00:00
_ . rescale ( 0 , false ) ;
2013-10-06 11:53:37 +00:00
handled = true ;
}
break ;
case 33 : // Page UP:
if ( with _alt ) { // alt-pageup -> scroll one page up
_ . scroll _to ( _ . get _prev _page ( ) ) ;
} else { // pageup -> scroll one screen up
_ . $container . scrollTop ( _ . $container . scrollTop ( ) - _ . $container . height ( ) ) ;
}
handled = true ;
break ;
case 34 : // Page DOWN
if ( with _alt ) { // alt-pagedown -> scroll one page down
_ . scroll _to ( _ . get _next _page ( ) ) ;
} else { // pagedown -> scroll one screen down
_ . $container . scrollTop ( _ . $container . scrollTop ( ) + _ . $container . height ( ) ) ;
}
handled = true ;
break ;
case 35 : // End
if ( with _ctrl ) {
_ . $container . scrollTop ( _ . $container [ 0 ] . scrollHeight ) ;
handled = true ;
}
break ;
case 36 : // Home
if ( e . with _ctrl ) {
_ . $container . scrollTop ( 0 ) ;
handled = true ;
}
break ;
2012-09-22 16:17:30 +00:00
}
2013-10-06 11:53:37 +00:00
if ( handled ) {
2012-09-24 12:20:34 +00:00
e . preventDefault ( ) ;
2013-07-03 20:02:53 +00:00
return ;
2012-09-22 16:17:30 +00:00
}
2013-10-06 11:57:44 +00:00
} ) ;
2013-07-03 07:57:00 +00:00
} ,
2013-10-22 13:32:02 +00:00
// TODO
get _next _page : function ( ) { return undefined ; } ,
get _prev _page : function ( ) { return undefined ; } ,
2012-09-23 09:26:12 +00:00
2013-07-16 15:42:02 +00:00
rescale : function ( ratio , is _relative , offsetX , offsetY ) {
if ( ! offsetX )
offsetX = 0 ;
if ( ! offsetY )
offsetY = 0 ;
2013-07-16 18:19:25 +00:00
2013-07-16 15:42:02 +00:00
// Save offset of the active page
var active _page = this . get _active _page ( ) ;
2013-09-30 07:50:15 +00:00
if ( ! active _page ) return ;
2013-07-16 15:42:02 +00:00
var prev _offset = active _page . $p . offset ( ) ;
var old _scale = this . scale ;
2013-09-30 07:50:15 +00:00
var pl = this . pages ;
2013-07-16 15:42:02 +00:00
2013-07-16 18:19:25 +00:00
var prerendering _enabled = false ;
2013-10-05 08:11:03 +00:00
if ( this . config [ 'smooth_zoom_threshold' ] > 0 ) {
2013-07-16 18:19:25 +00:00
// Immediate rendering optimizations enabled to improve reactiveness while zooming
// Find out which pages are visible
var min _visible , max _visible ;
min _visible = max _visible = active _page . n ;
2013-09-30 07:50:15 +00:00
while ( pl [ min _visible ] && pl [ min _visible ] . is _visible ( ) ) { -- min _visible ; }
++ min _visible ;
while ( pl [ max _visible ] && pl [ max _visible ] . is _visible ( ) ) { ++ max _visible ; }
-- max _visible ;
2013-07-16 18:19:25 +00:00
// If less then the threshold, enable prerendering on selected pages
2013-10-05 08:11:03 +00:00
if ( max _visible - min _visible + 1 < this . config [ 'smooth_zoom_threshold' ] )
2013-07-16 18:19:25 +00:00
prerendering _enabled = true ;
}
2013-07-16 15:42:02 +00:00
// Set new scale
if ( is _relative )
this . scale *= ratio ;
else
this . scale = ratio ;
// Rescale pages
2013-10-28 08:05:24 +00:00
for ( var i = 0 , l = pl . length ; i < l ; ++ i ) {
2013-09-30 07:50:15 +00:00
if ( prerendering _enabled && i >= min _visible && i <= max _visible )
2013-07-17 07:47:13 +00:00
pl [ i ] . rescale ( this . scale , true ) ; // Force immediate refresh
else
pl [ i ] . rescale ( this . scale ) ; // Delayed refresh
2012-09-23 05:04:29 +00:00
}
2012-09-22 16:17:30 +00:00
2013-07-16 15:42:02 +00:00
// Correct container scroll to keep view aligned while zooming
var correction _top = active _page . $p . offset ( ) . top - prev _offset . top ;
2013-07-16 18:19:25 +00:00
this . $container . scrollTop ( this . $container . scrollTop ( ) + correction _top + offsetY ) ;
2013-07-16 15:42:02 +00:00
// Take the center of the view as a reference
var prev _center _x = this . $container . width ( ) / 2 - prev _offset . left ;
// Calculate the difference respect the center of the view after the zooming
var correction _left = prev _center _x * ( this . scale / old _scale - 1 ) + active _page . $p . offset ( ) . left - prev _offset . left ;
// Scroll the container accordingly to keep alignment to the initial reference
2013-07-16 18:19:25 +00:00
this . $container . scrollLeft ( this . $container . scrollLeft ( ) + correction _left + offsetX ) ;
2013-07-16 15:42:02 +00:00
2013-07-16 18:19:25 +00:00
// Delayed rendering for pages not already shown
2012-09-23 09:26:12 +00:00
this . schedule _render ( ) ;
} ,
2012-09-22 16:17:30 +00:00
2013-07-16 15:42:02 +00:00
fit _width : function ( ) {
2013-07-16 18:19:25 +00:00
var active _page = this . get _active _page ( ) ;
2013-09-30 07:50:15 +00:00
if ( ! active _page ) return ;
2013-07-16 15:42:02 +00:00
2013-07-16 18:19:25 +00:00
this . rescale ( this . $container . width ( ) / active _page . w , false ) ;
this . scroll _to ( active _page . n , [ 0 , 0 ] ) ;
2013-07-16 15:42:02 +00:00
} ,
fit _height : function ( ) {
var active _page = this . get _active _page ( ) ;
2013-09-30 07:50:15 +00:00
if ( ! active _page ) return ;
2013-07-16 15:42:02 +00:00
2013-07-16 18:19:25 +00:00
this . rescale ( this . $container . height ( ) / active _page . h , false ) ;
2013-07-16 15:42:02 +00:00
this . scroll _to ( active _page . n , [ 0 , 0 ] ) ;
} ,
get _active _page : function ( ) {
2013-10-06 11:53:37 +00:00
// get page that are on the center of the view //TODO better on top?!
var y _center = this . $container . offset ( ) . top + this . $container . height ( ) / 2 ;
var pl = this . pages ;
var last _page = - 1 ;
2013-10-28 08:05:24 +00:00
for ( var i = 0 , l = pl . length ; i < l ; ++ i ) {
2013-10-06 11:53:37 +00:00
if ( pl [ i ] . $p . offset ( ) . top > y _center )
break ;
last _page = i ;
}
return pl [ last _page ] ;
2013-07-16 15:42:02 +00:00
} ,
2012-09-25 11:29:59 +00:00
get _containing _page : function ( obj ) {
/* get the page obj containing obj */
2013-10-28 08:05:24 +00:00
var $p = obj . closest ( '.' + CSS _CLASS _NAMES . page _frame ) ;
if ( $p . length == 0 ) return ;
/ *
* Get original page number and map it to index of pages
* TODO : store the index on the dom element
* /
var pn = ( new Page ( $p [ 0 ] , null ) ) . n ;
var pm = this . page _map ;
return ( pn in pm ) && this . pages [ pm [ pn ] ] ;
2012-09-25 11:29:59 +00:00
} ,
2013-01-28 13:01:02 +00:00
link _handler : function ( e ) {
2012-09-25 11:29:59 +00:00
var _ = e . data ;
var t = $ ( e . currentTarget ) ;
2012-09-25 13:56:48 +00:00
2013-01-28 15:58:00 +00:00
var cur _pos = [ 0 , 0 ] ;
// cur_page might be undefined, e.g. from Outline
var cur _page = _ . get _containing _page ( t ) ;
2013-10-22 11:42:56 +00:00
if ( cur _page !== undefined )
2013-01-28 15:58:00 +00:00
{
cur _pos = cur _page . position ( ) ;
//get the coordinates in default user system
2013-07-16 18:19:25 +00:00
cur _pos = transform ( cur _page . ictm , [ cur _pos [ 0 ] , cur _page . h - cur _pos [ 1 ] ] ) ;
2013-01-28 15:58:00 +00:00
}
2012-09-25 11:29:59 +00:00
2013-10-22 13:32:02 +00:00
var detail _str = /** @type{string} */ ( t . attr ( 'data-dest-detail' ) ) ;
2013-10-22 11:42:56 +00:00
if ( detail _str === undefined ) return ;
2012-09-25 11:29:59 +00:00
var ok = false ;
2012-09-26 08:00:55 +00:00
var detail = JSON . parse ( detail _str ) ;
2012-09-25 11:29:59 +00:00
2013-10-28 08:05:24 +00:00
var target _page _no = detail [ 0 ] ;
var page _map = this . page _map ;
if ( ! ( target _page _no in page _map ) ) return ;
var target _page _idx = page _map [ target _page _no ] ;
var target _page = _ . pages [ target _page _idx ] ;
2012-09-25 13:56:48 +00:00
2012-09-26 08:00:55 +00:00
var pos = [ 0 , 0 ] ;
var upside _down = true ;
// TODO: zoom
// TODO: BBox
switch ( detail [ 1 ] ) {
case 'XYZ' :
pos = [ ( detail [ 2 ] == null ) ? cur _pos [ 0 ] : detail [ 2 ]
2013-10-06 11:53:37 +00:00
, ( detail [ 3 ] == null ) ? cur _pos [ 1 ] : detail [ 3 ] ] ;
2012-09-26 08:00:55 +00:00
ok = true ;
break ;
case 'Fit' :
case 'FitB' :
pos = [ 0 , 0 ] ;
ok = true ;
break ;
case 'FitH' :
case 'FitBH' :
2013-07-16 18:19:25 +00:00
pos = [ 0 , ( detail [ 2 ] == null ) ? cur _pos [ 1 ] : detail [ 2 ] ] ;
2012-09-26 08:00:55 +00:00
ok = true ;
break ;
case 'FitV' :
case 'FitBV' :
pos = [ ( detail [ 2 ] == null ) ? cur _pos [ 0 ] : detail [ 2 ] , 0 ] ;
ok = true ;
break ;
case 'FitR' :
/* locate the top-left corner of the rectangle */
pos = [ detail [ 2 ] , detail [ 5 ] ] ;
upside _down = false ;
ok = true ;
break ;
2012-09-25 11:29:59 +00:00
default :
2012-09-26 08:00:55 +00:00
ok = false ;
2012-09-25 11:29:59 +00:00
break ;
}
2012-09-26 08:00:55 +00:00
if ( ok ) {
2013-10-28 08:05:24 +00:00
/* page should of type Page */
var transform _and _scroll = function ( page ) {
pos = transform ( page . ctm , pos ) ;
2013-06-13 10:39:52 +00:00
if ( upside _down ) {
2013-10-28 08:05:24 +00:00
pos [ 1 ] = page . h - pos [ 1 ] ;
2013-06-12 15:53:14 +00:00
}
2013-10-28 08:05:24 +00:00
_ . scroll _to ( target _page _idx , pos ) ;
2013-07-16 18:19:25 +00:00
} ;
2013-06-13 10:39:52 +00:00
if ( target _page . loaded ) {
2013-10-28 08:05:24 +00:00
transform _and _scroll ( target _page ) ;
2013-06-12 15:53:14 +00:00
} else {
// Scroll to the exact position once loaded.
2013-10-28 08:05:24 +00:00
_ . load _page ( target _page . n , undefined , transform _and _scroll ) ;
2013-06-12 15:53:14 +00:00
// In the meantime page gets loaded, scroll approximately position for maximum responsiveness.
2013-10-28 08:05:24 +00:00
_ . scroll _to ( target _page _idx , [ 0 , 0 ] ) ;
2012-09-26 08:00:55 +00:00
}
2012-09-25 11:29:59 +00:00
e . preventDefault ( ) ;
2012-09-26 08:00:55 +00:00
}
2012-09-25 14:24:36 +00:00
} ,
2013-07-03 07:57:00 +00:00
2012-09-26 08:00:55 +00:00
/* pos=[x,y], where (0,0) is the top-left corner */
2013-10-28 08:05:24 +00:00
scroll _to : function ( page _idx , pos ) {
var target _page = this . pages [ page _idx ] ;
2013-10-22 11:42:56 +00:00
if ( target _page === undefined ) return ;
2012-09-25 14:24:36 +00:00
2013-10-22 11:42:56 +00:00
if ( pos === undefined )
2013-10-06 11:53:37 +00:00
pos = [ 0 , 0 ] ;
2012-09-25 14:24:36 +00:00
var cur _target _pos = target _page . position ( ) ;
2013-06-13 15:00:42 +00:00
this . $container . scrollLeft ( this . $container . scrollLeft ( ) - cur _target _pos [ 0 ] + pos [ 0 ] ) ;
this . $container . scrollTop ( this . $container . scrollTop ( ) - cur _target _pos [ 1 ] + pos [ 1 ] ) ;
2012-09-25 14:24:36 +00:00
} ,
_ _last _member _ _ : 'no comma' /*,*/
2012-09-25 14:40:21 +00:00
} ) ;
2013-10-22 13:32:02 +00:00
pdf2htmlEX [ 'Viewer' ] = Viewer ;
2013-10-22 07:03:07 +00:00
} ) ( window [ 'pdf2htmlEX' ] = window [ 'pdf2htmlEX' ] || { } ) ;