[IMP] website_slides: add zoom controls, and set default zoom
- use a default scale when the viewer is shown, to fit the document to the available space - avoid using CSS scaling on the canvas, as this makes the output blurry - add some zoom controls in the viewer - fix CSS class for icon on the full-screen toggle (this toggle was previously not displayed because of it) - move download button left (to avoid overlapping with "Chat with Us" box on odoo.com) opw-2389716 closes odoo/odoo#62836 X-original-commit: 0247a94f252186aae33f5f137021fa04747fa2fb Signed-off-by: Nicolas Lempereur (nle) <nle@odoo.com> Signed-off-by: Nicolas Galler <ngaller@users.noreply.github.com>
This commit is contained in:
@@ -8,14 +8,13 @@
|
||||
// !!!!!!!!! use window.pdfjsLib and not pdfjsLib
|
||||
|
||||
var PDFSlidesViewer = (function(){
|
||||
|
||||
function PDFSlidesViewer(pdf_url, $canvas, disableWorker){
|
||||
// pdf variables
|
||||
this.pdf = null;
|
||||
this.pdf_url = pdf_url || false;
|
||||
this.pdf_scale = 1.5;
|
||||
this.pdf_page_total = 0;
|
||||
this.pdf_page_current = 1; // default is the first page
|
||||
this.pdf_zoom = 1; // 1 = scale to fit to available space
|
||||
// promise business
|
||||
this.pageRendering = false;
|
||||
this.pageNumPending = null;
|
||||
@@ -59,7 +58,10 @@ var PDFSlidesViewer = (function(){
|
||||
this.pageRendering = true;
|
||||
return this.pdf.getPage(page_number).then(function(page) {
|
||||
// Each PDF page has its own viewport which defines the size in pixels and initial rotation.
|
||||
var viewport = page.getViewport(self.pdf_scale);
|
||||
// We provide the scale at which to render it (relative to the natural size of the document)
|
||||
var scale = self.getScaleToFit(page) * self.pdf_zoom;
|
||||
var viewport = page.getViewport({ scale: scale });
|
||||
// important to match, otherwise the browser will scale the rendered output and it will be ugly
|
||||
self.canvas.height = viewport.height;
|
||||
self.canvas.width = viewport.width;
|
||||
// Render PDF page into canvas context
|
||||
@@ -71,6 +73,10 @@ var PDFSlidesViewer = (function(){
|
||||
// Wait for rendering to finish
|
||||
return renderTask.promise.then(function () {
|
||||
self.pageRendering = false;
|
||||
if (self.pdf_zoom === 1 && scale > self.getScaleToFit(page)) {
|
||||
// if the scale has changed (because we just added scrollbars) and we no longer fit the space
|
||||
return self.renderPage(page_number);
|
||||
}
|
||||
if (self.pageNumPending !== null) {
|
||||
// New page rendering is pending
|
||||
self.renderPage(self.pageNumPending);
|
||||
@@ -117,6 +123,17 @@ var PDFSlidesViewer = (function(){
|
||||
return this.queueRenderPage(this.pdf_page_current);
|
||||
};
|
||||
|
||||
/*
|
||||
* Calculate a scale to fit the document on the available space.
|
||||
*/
|
||||
PDFSlidesViewer.prototype.getScaleToFit = function(page) {
|
||||
var maxWidth = this.canvas.parentNode.clientWidth;
|
||||
var maxHeight = this.canvas.parentNode.clientHeight;
|
||||
var hScale = maxWidth / page.view[2];
|
||||
var vScale = maxHeight / page.view[3];
|
||||
return Math.min(hScale, vScale);
|
||||
};
|
||||
|
||||
/**
|
||||
* Displays the given page.
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
$(function () {
|
||||
|
||||
if ($('#PDFViewer') && $('#PDFViewerCanvas')) { // check if presentation only
|
||||
var MIN_ZOOM=1, MAX_ZOOM=10, ZOOM_INCREMENT=.5;
|
||||
|
||||
// define embedded viewer (minimal object of the website.slide.PDFViewer widget)
|
||||
var EmbeddedViewer = function ($viewer) {
|
||||
@@ -46,9 +47,12 @@ $(function () {
|
||||
this.navUpdate(pageNumber);
|
||||
}
|
||||
},
|
||||
on_resize: function() {
|
||||
this.render_page(this.pdf_viewer.pdf_page_current);
|
||||
},
|
||||
// page switching
|
||||
render_page: function (pageNumber) {
|
||||
this.pdf_viewer.renderPage(pageNumber).then(this.on_rendered_page.bind(this));
|
||||
this.pdf_viewer.queueRenderPage(pageNumber).then(this.on_rendered_page.bind(this));
|
||||
this.navUpdate(pageNumber);
|
||||
},
|
||||
change_page: function () {
|
||||
@@ -96,10 +100,24 @@ $(function () {
|
||||
self.$("#slide_suggest").addClass('d-none');
|
||||
});
|
||||
},
|
||||
zoomIn: function() {
|
||||
if(this.pdf_viewer.pdf_zoom < MAX_ZOOM) {
|
||||
this.pdf_viewer.pdf_zoom += ZOOM_INCREMENT;
|
||||
this.render_page(this.pdf_viewer.pdf_page_current);
|
||||
}
|
||||
},
|
||||
zoomOut: function() {
|
||||
if(this.pdf_viewer.pdf_zoom > MIN_ZOOM) {
|
||||
this.pdf_viewer.pdf_zoom -= ZOOM_INCREMENT;
|
||||
this.render_page(this.pdf_viewer.pdf_page_current);
|
||||
}
|
||||
},
|
||||
navUpdate: function (pageNum) {
|
||||
this.$('#first').toggleClass('disabled', pageNum < 3 );
|
||||
this.$('#previous').toggleClass('disabled', pageNum < 2 );
|
||||
this.$('#next, #last').removeClass('disabled');
|
||||
this.$('#zoomout').toggleClass('disabled', this.pdf_viewer.pdf_zoom <= MIN_ZOOM);
|
||||
this.$('#zoomin').toggleClass('disabled', this.pdf_viewer.pdf_zoom >= MAX_ZOOM);
|
||||
},
|
||||
// full screen mode
|
||||
fullscreen: function () {
|
||||
@@ -133,6 +151,12 @@ $(function () {
|
||||
$('#last').on('click', function () {
|
||||
embeddedViewer.last();
|
||||
});
|
||||
$('#zoomin').on('click', function () {
|
||||
embeddedViewer.zoomIn();
|
||||
});
|
||||
$('#zoomout').on('click', function () {
|
||||
embeddedViewer.zoomOut();
|
||||
});
|
||||
$('#page_number').on('change', function () {
|
||||
embeddedViewer.change_page();
|
||||
});
|
||||
@@ -142,6 +166,19 @@ $(function () {
|
||||
$('#PDFViewer').on('click', function (ev) {
|
||||
embeddedViewer.fullScreenFooter(ev);
|
||||
});
|
||||
$('#PDFViewer').on('wheel', function (ev) {
|
||||
if (ev.metaKey || ev.ctrlKey) {
|
||||
if (ev.originalEvent.deltaY > 0) {
|
||||
embeddedViewer.zoomOut();
|
||||
} else if(ev.originalEvent.deltaY < 0) {
|
||||
embeddedViewer.zoomIn();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
$(window).on('resize', _.debounce(function() {
|
||||
embeddedViewer.on_resize();
|
||||
}, 500));
|
||||
|
||||
// switching slide with keyboard
|
||||
$(document).keydown(function (ev) {
|
||||
|
||||
@@ -77,8 +77,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<t t-if="slide.slide_type in ('presentation', 'document')">
|
||||
<div id="PDFViewerLoader" class="oe_slides_loader position-absolute mt-3 mr-3" style="right:0">
|
||||
<div class="toast show">
|
||||
<div id="PDFViewerLoader" class="oe_slides_loader mt-3 mx-2 w-100">
|
||||
<div class="toast show mx-auto">
|
||||
<div class="toast-header">
|
||||
<i class="fa fa-circle-o-notch fa-spin mr-2"/><b>Loading...</b>
|
||||
</div>
|
||||
@@ -87,7 +87,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<canvas id="PDFViewerCanvas" class="img-fluid w-100" style="display: none;"></canvas>
|
||||
<canvas id="PDFViewerCanvas" class="mx-auto" style="display: none;"></canvas>
|
||||
</t>
|
||||
<t t-if="slide.slide_type == 'infographic'">
|
||||
<img t-att-src="website.image_url(slide, 'image_1024')" class="img-fluid" style="width: 100%" alt="Slide image"/>
|
||||
@@ -97,28 +97,34 @@
|
||||
<div id="PDFViewerNav" class="pt-2 pb-2 bg-light text-white" role="navigation" t-if="slide.slide_type in ('presentation', 'document')">
|
||||
<div class="container-fluid oe_slides_panel_footer">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-2 flex-grow-0">
|
||||
<div class="col-3 d-flex align-items-center">
|
||||
<div class="input-group input-group-sm flex-nowrap" style="max-width: 100px">
|
||||
<input type="number" class="form-control text-center" id="page_number" style="min-width: 60px"/>
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text" id="page_count"/>
|
||||
</div>
|
||||
</div>
|
||||
<a id="zoomout" href="#" class="text-decoration-none d-none d-sm-inline ml-2 mr-2" title="Zoom out" aria-label="Zoom out" role="button">
|
||||
<i class="fa fa-search-minus" />
|
||||
</a>
|
||||
<a id="zoomin" href="#" class="text-decoration-none d-none d-sm-inline" title="Zoom in" aria-label="Zoom in" role="button">
|
||||
<i class="fa fa-search-plus" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<a id="first" href="#" class="text-decoration-none mr-1 mr-sm-2" title="First slide" role="button" aria-label="First slide"> <i class="fa fa-step-backward"/> </a>
|
||||
<a id="previous" href="#" class="text-decoration-none mx-1 mx-sm-2" title="Previous slide" aria-label="Previous slide" role="button"> <i class="fa fa-arrow-circle-left"/> </a>
|
||||
<a id="next" href="#" class="text-decoration-none mx-1 mx-sm-2" title="Next slide" aria-label="Next slide" role="button"> <i class="fa fa-arrow-circle-right"/> </a>
|
||||
<a id="last" href="#" class="text-decoration-none ml-1 ml-sm-2" title="Last slide" aria-label="Last slide" role="button"> <i class="fa fa-step-forward"/> </a>
|
||||
</div>
|
||||
<div class="col-2 flex-grow-0 text-right">
|
||||
<a id="last" href="#" class="text-decoration-none mx-1 mx-sm-2" title="Last slide" aria-label="Last slide" role="button"> <i class="fa fa-step-forward"/> </a>
|
||||
<a t-if="slide.slide_resource_downloadable" id="download" t-attf-href="/web/content/slide.slide/#{slide.id}/datas?download=true"
|
||||
class="text-decoration-none mr-1 mr-sm-2" title="Download Content" role="img" aria-label="Download">
|
||||
class="text-decoration-none ml-1 ml-sm-2" title="Download Content" role="img" aria-label="Download">
|
||||
<i class="fa fa-download" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-3 text-right flex-grow-0">
|
||||
<a id="fullscreen" href="#" class="text-decoration-none ml-1 ml-sm-2"
|
||||
title="View fullscreen" role="img" aria-label="Fullscreen">
|
||||
<i class="fas fa-expand-arrows-alt"/>
|
||||
<i class="fa fa-arrows-alt"/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user