forked from extern/egroupware
Implements pdf-player custom element
This commit is contained in:
parent
18f2af2ce8
commit
44d632be2a
400
api/js/etemplate/CustomHtmlElements/pdf-player.ts
Normal file
400
api/js/etemplate/CustomHtmlElements/pdf-player.ts
Normal file
@ -0,0 +1,400 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
import pdfjs from "@bundled-es-modules/pdfjs-dist/build/pdf";
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = 'node_modules/@bundled-es-modules/pdfjs-dist/build/pdf.worker.js';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
type PdfViewArray = {
|
||||
pdf: any,
|
||||
zoom: number,
|
||||
currentPage: number
|
||||
};
|
||||
|
||||
// Create a class for the element
|
||||
class pdf_player extends HTMLElement {
|
||||
|
||||
/**
|
||||
* shadow dom container
|
||||
* @private
|
||||
*/
|
||||
private readonly _shadow = null;
|
||||
/**
|
||||
* wrapper container holds canvas
|
||||
* @private
|
||||
*/
|
||||
private readonly _wrapper : HTMLDivElement;
|
||||
/**
|
||||
* Canvas element to render pdf
|
||||
* @private
|
||||
*/
|
||||
private _canvas : HTMLCanvasElement;
|
||||
/**
|
||||
* Styling contianer
|
||||
* @private
|
||||
*/
|
||||
private readonly _style : HTMLStyleElement;
|
||||
/**
|
||||
* keeps duration time internally
|
||||
* @private
|
||||
*/
|
||||
private _duration : number = 0;
|
||||
/**
|
||||
* keeps currentTime internally
|
||||
* @private
|
||||
*/
|
||||
private _currentTime : number = 0;
|
||||
/**
|
||||
* Keeps playing state internally
|
||||
* @private
|
||||
*/
|
||||
private __playing: boolean = false;
|
||||
/**
|
||||
* keeps playing interval id
|
||||
* @private
|
||||
*/
|
||||
private __playingInterval : number = 0;
|
||||
/**
|
||||
* keeps play back rate
|
||||
* @private
|
||||
*/
|
||||
private _playBackRate : number = 1000;
|
||||
/**
|
||||
* keeps ended state of playing pdf
|
||||
* @private
|
||||
*/
|
||||
private _ended : boolean = false;
|
||||
/**
|
||||
* keep paused state
|
||||
* @private
|
||||
*/
|
||||
private _paused : boolean = false;
|
||||
/**
|
||||
* keeps pdf doc states
|
||||
* @private
|
||||
*/
|
||||
private __pdfViewState : PdfViewArray = {
|
||||
pdf: null,
|
||||
currentPage: 1,
|
||||
zoom: 1
|
||||
};
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
|
||||
// Create a shadow root
|
||||
this._shadow = this.attachShadow({mode: 'open'});
|
||||
|
||||
// Create wrapper
|
||||
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[]}
|
||||
*/
|
||||
static get observedAttributes() {
|
||||
return ['src', 'type'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets called on observable attributes changes
|
||||
* @param name attribute name
|
||||
* @param _
|
||||
* @param newVal new value
|
||||
*/
|
||||
attributeChangedCallback(name, _, newVal) {
|
||||
switch(name)
|
||||
{
|
||||
case 'src':
|
||||
this.__buildPDFView(newVal);
|
||||
break;
|
||||
case 'type':
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* init/update pdf tag
|
||||
* @param _value
|
||||
* @private
|
||||
*/
|
||||
private __buildPDFView(_value)
|
||||
{
|
||||
this._canvas = document.createElement('canvas');
|
||||
this._wrapper.appendChild(this._canvas);
|
||||
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
|
||||
this.__render(1).then(_ =>{
|
||||
this.__pushEvent('loadedmetadata');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Render given page from pdf into the canvas container
|
||||
*
|
||||
* @param _page
|
||||
* @private
|
||||
*/
|
||||
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;
|
||||
// don't ty to render if page is under proccess
|
||||
if (typeof page.intentStates.display == 'undefined')
|
||||
{
|
||||
page.render({
|
||||
canvasContext: canvasContext,
|
||||
viewport: viewport
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates event and dispatches it
|
||||
* @param _name
|
||||
*/
|
||||
private __pushEvent(_name: string)
|
||||
{
|
||||
let event = document.createEvent("Event");
|
||||
event.initEvent(_name, true, true);
|
||||
this.dispatchEvent(event);
|
||||
}
|
||||
|
||||
/**************************** PUBLIC ATTRIBUTES & METHODES *************************************************/
|
||||
|
||||
/****************************** ATTRIBUTES **************************************/
|
||||
|
||||
/**
|
||||
* set src
|
||||
* @param _value
|
||||
*/
|
||||
set src(_value)
|
||||
{
|
||||
this._wrapper.children.forEach(_ch=>{
|
||||
_ch.remove();
|
||||
});
|
||||
this.__buildPDFView(_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* get src
|
||||
* @return string returns comma separated sources
|
||||
*/
|
||||
get src ()
|
||||
{
|
||||
return this.src;
|
||||
}
|
||||
|
||||
/**
|
||||
* currentTime
|
||||
* @param _time
|
||||
*/
|
||||
set currentTime(_time : number)
|
||||
{
|
||||
let time = Math.floor(_time < 1 ? 1 : _time);
|
||||
|
||||
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
|
||||
return;
|
||||
}
|
||||
|
||||
// set ended state to false as it's not the end of the pdf
|
||||
this._ended = false;
|
||||
this._currentTime = time;
|
||||
this.__pdfViewState.currentPage = time;
|
||||
this.__render(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* get currentTime
|
||||
* @return {number}
|
||||
*/
|
||||
get currentTime()
|
||||
{
|
||||
return this._currentTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* get duration time
|
||||
*/
|
||||
get duration()
|
||||
{
|
||||
return this._duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* get paused attribute
|
||||
*/
|
||||
get paused()
|
||||
{
|
||||
return this._paused;
|
||||
}
|
||||
|
||||
/**
|
||||
* set muted attribute
|
||||
* @param _value
|
||||
*/
|
||||
set muted(_value: boolean)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* get muted attribute
|
||||
*/
|
||||
get muted()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
set ended (_value : boolean)
|
||||
{
|
||||
this._ended = _value;
|
||||
}
|
||||
|
||||
/**
|
||||
* get ended attribute
|
||||
*/
|
||||
get ended()
|
||||
{
|
||||
return this._ended;
|
||||
}
|
||||
|
||||
/**
|
||||
* set playbackRate
|
||||
* @param _value
|
||||
*/
|
||||
set playbackRate(_value: number)
|
||||
{
|
||||
this._playBackRate = _value*1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* get playbackRate
|
||||
*/
|
||||
get playbackRate()
|
||||
{
|
||||
return this._playBackRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* set volume
|
||||
*/
|
||||
set volume(_value: number)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* get volume
|
||||
*/
|
||||
get volume()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/************************************************* METHODES ******************************************/
|
||||
|
||||
/**
|
||||
* Play
|
||||
*/
|
||||
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();
|
||||
}
|
||||
self.currentTime +=1;
|
||||
self.__pushEvent('timeupdate');
|
||||
}, self._playBackRate);
|
||||
_resolve();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* pause
|
||||
*/
|
||||
pause()
|
||||
{
|
||||
this.__playing = false;
|
||||
this._paused = true;
|
||||
window.clearInterval(this.__playingInterval);
|
||||
}
|
||||
|
||||
/**
|
||||
* seek previous page
|
||||
*/
|
||||
prevPage()
|
||||
{
|
||||
this.currentTime -=1;
|
||||
}
|
||||
|
||||
/**
|
||||
* seek next page
|
||||
*/
|
||||
nextPage()
|
||||
{
|
||||
this.currentTime +=1;
|
||||
}
|
||||
}
|
||||
|
||||
// Define pdf-player element
|
||||
customElements.define('pdf-player', pdf_player);
|
@ -20,6 +20,7 @@ import {ClassWithAttributes} from "./et2_core_inheritance";
|
||||
import {WidgetConfig, et2_register_widget} from "./et2_core_widget";
|
||||
import {et2_IDOMNode} from "./et2_core_interfaces";
|
||||
import "./CustomHtmlElements/multi-video";
|
||||
import "./CustomHtmlElements/pdf-player";
|
||||
|
||||
/**
|
||||
* This widget represents the HTML5 video tag with all its optional attributes
|
||||
@ -174,7 +175,8 @@ export class et2_video extends et2_baseWidget implements et2_IDOMNode
|
||||
return;
|
||||
}
|
||||
//Create Video tag
|
||||
this.video = jQuery(document.createElement(this._isYoutube()?"div":(this.options.multi_src ? "multi-video" : "video")))
|
||||
this.video = jQuery(document.createElement(this._isYoutube() ? "div" :
|
||||
(_type.match('pdf') ? "pdf-player" : (this.options.multi_src ? 'multi-video' : 'video' ))))
|
||||
.addClass('et2_video')
|
||||
.attr('id', this.dom_id);
|
||||
|
||||
|
11
package-lock.json
generated
11
package-lock.json
generated
@ -10,6 +10,7 @@
|
||||
"license": "GPL-2.0",
|
||||
"dependencies": {
|
||||
"@andxor/jquery-ui-touch-punch-fix": "^1.0.2",
|
||||
"@bundled-es-modules/pdfjs-dist": "^2.5.207-rc1",
|
||||
"@lion/button": "^0.14.2",
|
||||
"@lion/core": "^0.18.2",
|
||||
"@lion/input": "^0.15.4",
|
||||
@ -533,6 +534,11 @@
|
||||
"resolved": "https://registry.npmjs.org/@bundled-es-modules/message-format/-/message-format-6.0.4.tgz",
|
||||
"integrity": "sha512-NGUoPxqsBzDwvRhY3A3L/AhS1hzS9OWappfyDOyCwE7G3W4ua28gau7QwvJz7QzA6ArbAdeb8c1mLjvd1WUFAA=="
|
||||
},
|
||||
"node_modules/@bundled-es-modules/pdfjs-dist": {
|
||||
"version": "2.5.207-rc1",
|
||||
"resolved": "https://registry.npmjs.org/@bundled-es-modules/pdfjs-dist/-/pdfjs-dist-2.5.207-rc1.tgz",
|
||||
"integrity": "sha512-e/UVP1g6dwjQLnu4MPf/mlESCIvyr/KgpoMUyxGcv4evCIuJwKR/fcfhG3p1NYo+49gJsd0hL2yz9kzhkCZ32A=="
|
||||
},
|
||||
"node_modules/@esm-bundle/chai": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@esm-bundle/chai/-/chai-4.3.4.tgz",
|
||||
@ -6480,6 +6486,11 @@
|
||||
"resolved": "https://registry.npmjs.org/@bundled-es-modules/message-format/-/message-format-6.0.4.tgz",
|
||||
"integrity": "sha512-NGUoPxqsBzDwvRhY3A3L/AhS1hzS9OWappfyDOyCwE7G3W4ua28gau7QwvJz7QzA6ArbAdeb8c1mLjvd1WUFAA=="
|
||||
},
|
||||
"@bundled-es-modules/pdfjs-dist": {
|
||||
"version": "2.5.207-rc1",
|
||||
"resolved": "https://registry.npmjs.org/@bundled-es-modules/pdfjs-dist/-/pdfjs-dist-2.5.207-rc1.tgz",
|
||||
"integrity": "sha512-e/UVP1g6dwjQLnu4MPf/mlESCIvyr/KgpoMUyxGcv4evCIuJwKR/fcfhG3p1NYo+49gJsd0hL2yz9kzhkCZ32A=="
|
||||
},
|
||||
"@esm-bundle/chai": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@esm-bundle/chai/-/chai-4.3.4.tgz",
|
||||
|
@ -54,6 +54,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@andxor/jquery-ui-touch-punch-fix": "^1.0.2",
|
||||
"@bundled-es-modules/pdfjs-dist": "^2.5.207-rc1",
|
||||
"@lion/button": "^0.14.2",
|
||||
"@lion/core": "^0.18.2",
|
||||
"@lion/input": "^0.15.4",
|
||||
|
Loading…
Reference in New Issue
Block a user