2022-03-31 14:40:12 +02:00
/ * *
* EGroupware Custom Html Elements - pdf player Web Components
*
* @ license http : //opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @ package etemplate
* @ subpackage api
* @ link https : //www.egroupware.org
* @ author Hadi Nategh < hn [ at ] egroupware . org >
* @ copyright EGroupware GmbH
* /
2022-04-04 17:13:29 +02:00
// Unfortunately compiled version of module:ES2015 TS would break webcomponent constructor.
// Since we don't have ES2020 available on 21.1 we have to use dynamic import.
import ( egw . webserverUrl + "/node_modules/@bundled-es-modules/pdfjs-dist/build/pdf.js" ) . then ( ( _module ) => {
const pdfjs = _module . default ;
pdfjs . GlobalWorkerOptions . workerSrc = egw . webserverUrl + '/node_modules/@bundled-es-modules/pdfjs-dist/build/pdf.worker.js' ;
/ *
This web component allows to display and play pdf file like a video player widget / element . Its attributes and
methodes are mostley identical as video html . No controls attribute supported yet .
* /
class pdf _player extends HTMLElement {
2022-04-07 15:32:47 +02:00
constructor ( ) {
super ( ) ; // Create a shadow root
2022-04-04 17:13:29 +02:00
2022-04-07 15:32:47 +02:00
/ * *
* keeps duration time internally
* @ private
* /
2022-04-08 13:45:55 +02:00
this . _duration = 0 ;
2022-04-07 15:32:47 +02:00
/ * *
* keeps currentTime internally
* @ private
* /
2022-04-04 17:13:29 +02:00
2022-04-08 13:45:55 +02:00
this . _currentTime = 0 ;
2022-04-07 15:32:47 +02:00
/ * *
* Keeps playing state internally
* @ private
* /
2022-04-04 17:13:29 +02:00
2022-04-08 13:45:55 +02:00
this . _ _playing = false ;
2022-04-07 15:32:47 +02:00
/ * *
* keeps playing interval id
* @ private
* /
2022-04-04 17:13:29 +02:00
2022-04-08 13:45:55 +02:00
this . _ _playingInterval = 0 ;
2022-04-07 15:32:47 +02:00
/ * *
* keeps play back rate
* @ private
* /
2022-04-04 17:13:29 +02:00
2022-04-08 13:45:55 +02:00
this . _playBackRate = 1000 ;
2022-04-07 15:32:47 +02:00
/ * *
* keeps ended state of playing pdf
* @ private
* /
2022-04-04 17:13:29 +02:00
2022-04-08 13:45:55 +02:00
this . _ended = false ;
2022-04-07 15:32:47 +02:00
/ * *
* keep paused state
* @ private
* /
2022-04-04 17:13:29 +02:00
2022-04-08 13:45:55 +02:00
this . _paused = false ;
2022-04-07 15:32:47 +02:00
/ * *
* keeps pdf doc states
* @ private
* /
2022-04-04 17:13:29 +02:00
2022-04-08 13:45:55 +02:00
this . _ _pdfViewState = {
2022-04-07 15:32:47 +02:00
pdf : null ,
currentPage : 1 ,
zoom : 1
} ;
2022-04-04 17:13:29 +02:00
2022-04-07 15:32:47 +02:00
/ * *
* shadow dom container
* @ private
* /
2022-04-04 17:13:29 +02:00
this . _shadow = this . attachShadow ( {
mode : 'open'
} ) ; // Create wrapper
2022-04-07 15:32:47 +02:00
/ * *
* wrapper container holds canvas
* @ private
* /
2022-04-04 17:13:29 +02:00
this . _wrapper = document . createElement ( 'div' ) ;
this . _wrapper . setAttribute ( 'class' , 'wrapper' ) ; // Create some CSS to apply to the shadow dom
this . _style = document . createElement ( 'style' ) ;
this . _style . textContent = '.wrapper {' + 'width: 100%;' + 'height: auto;' + 'display: block;' + '}' + '.wrapper canvas {' + 'width: 100%;' + 'height: auto;' + '}' ; // attach to the shadow dom
this . _shadow . appendChild ( this . _style ) ;
this . _shadow . appendChild ( this . _wrapper ) ;
}
/ * *
* set observable attributes
* @ return { string [ ] }
* /
2022-04-04 13:35:42 +02:00
2022-03-31 14:40:12 +02:00
2022-04-04 17:13:29 +02:00
static get observedAttributes ( ) {
return [ 'src' , 'type' ] ;
}
/ * *
* Gets called on observable attributes changes
* @ param name attribute name
* @ param _
* @ param newVal new value
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
attributeChangedCallback ( name , _ , newVal ) {
switch ( name ) {
case 'src' :
this . _ _buildPDFView ( newVal ) ;
break ;
case 'type' :
// do nothing
break ;
}
2022-04-04 13:35:42 +02:00
}
2022-04-04 17:13:29 +02:00
/ * *
* init / update pdf tag
* @ param _value
* @ private
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
_ _buildPDFView ( _value ) {
this . _canvas = document . createElement ( 'canvas' ) ;
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
this . _wrapper . appendChild ( this . _canvas ) ;
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
let longTask = pdfjs . getDocument ( _value ) ;
longTask . promise . then ( pdf => {
this . _ _pdfViewState . pdf = pdf ;
this . _duration = this . _ _pdfViewState . pdf . _pdfInfo . numPages ; // initiate the pdf file viewer for the first time after loading
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
this . _ _render ( 1 ) . then ( _ => {
this . _ _pushEvent ( 'loadedmetadata' ) ;
} ) ;
2022-04-04 13:35:42 +02:00
} ) ;
2022-04-04 17:13:29 +02:00
}
/ * *
* Render given page from pdf into the canvas container
*
* @ param _page
* @ private
* /
_ _render ( _page ) {
if ( ! this . _ _pdfViewState . pdf ) return ;
let p = _page || this . _ _pdfViewState . currentPage ;
let self = this ;
return this . _ _pdfViewState . pdf . getPage ( p ) . then ( page => {
let canvasContext = self . _canvas . getContext ( '2d' ) ;
let viewport = page . getViewport ( {
scale : self . _ _pdfViewState . zoom
} ) ;
self . _canvas . width = viewport . width ;
self . _canvas . height = viewport . height ;
page . render ( {
canvasContext : canvasContext ,
viewport : viewport
} ) ;
2022-04-04 13:35:42 +02:00
} ) ;
2022-04-04 17:13:29 +02:00
}
/ * *
* Creates event and dispatches it
* @ param _name
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
_ _pushEvent ( _name ) {
let event = document . createEvent ( "Event" ) ;
event . initEvent ( _name , true , true ) ;
this . dispatchEvent ( event ) ;
}
/**************************** PUBLIC ATTRIBUTES & METHODES *************************************************/
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
/****************************** ATTRIBUTES **************************************/
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
/ * *
* set src
* @ param _value
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
set src ( _value ) {
Array . from ( this . _wrapper . children ) . forEach ( _ch => {
_ch . remove ( ) ;
} ) ;
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
this . _ _buildPDFView ( _value ) ;
}
/ * *
* get src
* @ return string returns comma separated sources
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
get src ( ) {
return this . src ;
}
/ * *
* currentTime
* @ param _time
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
set currentTime ( _time ) {
let time = Math . floor ( _time < 1 ? 1 : _time ) ;
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
if ( time > this . _duration ) {
// set ended state to true as it's the last page of pdf
this . _ended = true ; // don't go further because it's litterally the last page
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
return ;
} // set ended state to false as it's not the end of the pdf
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
this . _ended = false ;
this . _currentTime = time ;
this . _ _pdfViewState . currentPage = time ;
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
this . _ _render ( time ) ;
}
/ * *
* get currentTime
* @ return { number }
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
get currentTime ( ) {
return this . _currentTime ;
}
/ * *
* get duration time
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
get duration ( ) {
return this . _duration ;
}
/ * *
* get paused attribute
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
get paused ( ) {
return this . _paused ;
}
/ * *
* set muted attribute
* @ param _value
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
set muted ( _value ) {
return ;
}
/ * *
* get muted attribute
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
get muted ( ) {
return true ;
}
set ended ( _value ) {
this . _ended = _value ;
}
/ * *
* get ended attribute
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
get ended ( ) {
return this . _ended ;
}
/ * *
* set playbackRate
* @ param _value
* /
set playbackRate ( _value ) {
this . _playBackRate = _value * 1000 ;
}
/ * *
* get playbackRate
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
get playbackRate ( ) {
return this . _playBackRate ;
}
/ * *
* set volume
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
set volume ( _value ) {
return ;
}
/ * *
* get volume
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
get volume ( ) {
return 0 ;
}
/************************************************* METHODES ******************************************/
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
/ * *
* Play
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
play ( ) {
this . _ _playing = true ;
let self = this ;
return new Promise ( function ( _resolve , _reject ) {
self . _ _playingInterval = window . setInterval ( _ => {
if ( self . currentTime >= self . _duration ) {
self . ended = true ;
self . pause ( ) ;
}
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
self . currentTime += 1 ;
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
self . _ _pushEvent ( 'timeupdate' ) ;
} , self . _playBackRate ) ;
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
_resolve ( ) ;
} ) ;
}
/ * *
* pause
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
pause ( ) {
this . _ _playing = false ;
this . _paused = true ;
window . clearInterval ( this . _ _playingInterval ) ;
}
/ * *
* seek previous page
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
prevPage ( ) {
this . currentTime -= 1 ;
}
/ * *
* seek next page
* /
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
nextPage ( ) {
this . currentTime += 1 ;
}
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
} // Define pdf-player element
2022-04-04 13:35:42 +02:00
2022-04-04 17:13:29 +02:00
customElements . define ( 'pdf-player' , pdf _player ) ;
} ) ;
2022-04-04 13:35:42 +02:00