OWL
data_display
File Viewer
Odoo 19 OWL component — File Viewer (core)
Live preview
Interactive
Source excerpt
web/static/src/core/file_viewer/file_viewer.js
import { Component, useEffect, useRef, useState } from "@odoo/owl";
import { useAutofocus, useService } from "@web/core/utils/hooks";
import { hidePDFJSButtons } from "@web/core/utils/pdfjs";
/**
* @typedef {Object} File
* @property {string} name
* @property {string} downloadUrl
* @property {boolean} [isImage]
* @property {boolean} [isPdf]
* @property {boolean} [isVideo]
* @property {boolean} [isText]
* @property {string} [defaultSource]
* @property {boolean} [isUrlYoutube]
* @property {string} [mimetype]
* @property {boolean} [isViewable]
* @typedef {Object} Props
* @property {Array<File>} files
* @property {number} startIndex
* @property {function} close
* @property {boolean} [modal]
* @extends {Component<Props, Env>}
*/
export class FileViewer extends Component {
static template = "web.FileViewer";
static components = {};
static props = ["files", "startIndex", "close?", "modal?"];
static defaultProps = {
modal: true,
};
setup() {
useAutofocus();
this.imageRef = useRef("image");
this.zoomerRef = useRef("zoomer");
this.iframeViewerPdfRef = useRef("iframeViewerPdf");
this.isDragging = false;
this.dragStartX = 0;
this.dragStartY = 0;
this.scrollZoomStep = 0.1;
this.zoomStep = 0.5;
this.minScale = 0.5;
this.translate = {
dx: 0,
dy: 0,
x: 0,
y: 0,
};
this.state = useState({
index: this.props.startIndex,
file: this.props.files[this.props.startIndex],
imageLoaded: false,
scale: 1,
angle: 0,
});
this.ui = useService("ui");
useEffect(
(el) => {
if (el) {
hidePDFJSButtons(this.iframeViewerPdfRef.el, {
hideDownload: true,
});
}
},
() => [this.iframeViewerPdfRef.el]
);
}
onImageLoaded() {
this.state.imageLoaded = true;
}
close() {
this.props.close && this.props.close();
}
next() {
const last = this.props.files.length - 1;
this.activateFile(this.state.index === last ? 0 : this.state.index + 1);
}
previous() {
const last = this.props.files.length - 1;
this.activateFile(this.state.index === 0 ? last : this.state.index - 1);
}
activateFile(index) {
this.state.index = index;
this.state.file = this.props.files[index];
}
onKeydown(ev) {
switch (ev.key) {
case "ArrowRight":
this.next();
break;
case "ArrowLeft":
this.previous();
break;
case "Escape":
this.close();
break;
case "q":
this.close();
break;
}
if (this.state.file.isImage) {
switch (ev.key) {
case "r":
this.rotate();
break;
case "+":
this.zoomIn();
break;
case "-":
this.zoomOut();
break;
Registry / API
- Registry name
FileViewer- Category
—- Module
web- Slug
file-viewer- Nav group
data_display